Every shift, clear.
Companion repository for the article The Build Did Not Start With Code.
Companion article: The Build Did Not Start With Code.
Shiftaar is a self-contained local_poc for bilingual workforce visibility. It ships a mobile-first worker portal, permission-scoped manager operations dashboard, 5,000 synthetic workers, and one continuing read-only Pydantic AI agent over live PostgreSQL facts and cited Qdrant knowledge.
Shiftaar is a working product identity, not a legal trademark clearance. Every person, phone number, employer, site, attendance record, and document in this repository is fictional.
This public repo demonstrates that a serious AI-assisted product build benefits from planning before implementation. The included code shows:
- a local Docker Compose product boundary;
- synthetic workforce data and demo identities;
- PostgreSQL-owned identity, permissions, row-level security, and workforce facts;
- a React/Vite worker and manager experience;
- document ingestion into Qdrant for cited workplace knowledge;
- one read-only Pydantic AI assistant with role-filtered tools;
- deterministic API, contract, retrieval, and browser validation paths.
It does not prove production HR compliance, production security, live model reliability, payroll readiness, or that any product can be built safely from one prompt.
The important boundary is simple: PostgreSQL owns authority, Qdrant supports retrieval, FastAPI owns the application boundary, and the AI assistant receives only role-filtered tools. The model cannot run raw SQL, widen access, or mutate workforce records.
See docs/architecture.md, docs/security.md, and
docs/agent-runtime.md for the detailed boundary.
Prerequisites: Docker Desktop, Node.js 20+, Python 3.12–3.13, and uv.
make setup
make up
make seedOpen:
- Web:
http://localhost:3001 - API docs:
http://localhost:8001/docs - Qdrant:
http://localhost:6333/dashboard
Ports 3000 and 8000 are intentionally never used by this product.
The first document-ingestion run downloads three local FastEmbed models. This can take several minutes; the workforce dashboards remain available while it finishes.
| Experience | Identifier | Secret | Expected access |
|---|---|---|---|
| Worker · English | 910000000001 |
2468 |
Own profile, shifts and attendance |
| Worker · हिन्दी | 910000000002 |
2468 |
Own profile, shifts and attendance |
| Worker · English | 910000000003 |
2468 |
Own profile, shifts and attendance |
| Manager · scoped | manager1@shiftaar.demo |
Shift@123 |
One site plus one team scope |
| Manager · multi-scope | manager2@shiftaar.demo |
Shift@123 |
Multiple active scopes |
| Manager · zero-scope | manager3@shiftaar.demo |
Shift@123 |
Empty workforce view and zero totals |
| Document admin | admin@shiftaar.demo |
Admin@123 |
Organisation data and document upload |
Phase 1:
- 5,000 deterministic synthetic workers, 120 managers, 40 sites in 10 Indian cities, 20 roles, 14,400 shifts, and about 343,000 assignments.
- Worker login with fictional phone/PIN; manager login with fictional email/password.
- Argon2id credentials and opaque hashed server sessions in HTTP-only SameSite cookies.
- PostgreSQL row-level security for workers, shifts, assignments, attendance, scopes, and documents, always queried through the non-bypass
shiftaar_approle. - Worker next/upcoming/previous shifts, shift detail, attendance summary, and English/Hindi switch.
- Manager roster, worker directory/history, URL-backed filters, completion/absence/cancellation/overtime/skill analytics, zero-scope state, and responsive layouts.
- TanStack Query, TanStack Table, Recharts, semantic loading/empty/error states, keyboard focus, and axe checks.
Phase 2:
- One read-only Pydantic AI agent with runtime-filtered worker/manager toolsets and typed output.
- GLM-5.2 through Z.AI as primary;
gpt-5.4-nanoas fallback after a failed startup capability smoke or two consecutive primary failures. - PostgreSQL-owned identity, RLS, query compilation, budgets, evidence and terminal reasons. The model never receives raw SQL or ACL controls.
- Versioned PDF/DOCX/TXT ingestion, 20 MB and 200-page limits, 30 seeded bilingual documents, and PostgreSQL active-version revalidation after Qdrant retrieval.
- Multilingual MiniLM dense retrieval, BM25 sparse retrieval, RRF fusion and optional ColBERT late-interaction reranking.
- 100 English/Hindi deterministic evaluation scenarios covering worker, manager, document, hybrid and adversarial prompts.
- SSE conversation endpoint, 20-turn/30-minute-idle/8-hour-absolute limits, no cross-session memory, sanitised run trajectory and provider/model/usage/citation evidence.
The agent is intentionally reported as unconfigured when neither ZAI_API_KEY nor OPENAI_API_KEY is present. Dashboard readiness remains healthy in that state.
- Canonical rules:
brand/BRAND.md - SVG and PNG exports:
brand/andbrand/exports/ - Article hero:
docs/assets/hero-image.png - Article architecture:
docs/assets/architecture.png - Brand board:
docs/screenshots/golden-brand-board-1440x900.png - Worker reference:
docs/screenshots/golden-worker-390x844.png - Manager reference:
docs/screenshots/golden-manager-1440x900.png - Agent reference:
docs/screenshots/golden-manager-agent-1440x900.png
make test
make verifyFocused commands:
cd apps/api && uv run pytest -q && uv run ruff check app tests alembic
cd apps/web && npm test && npm run lint && npm run build
cd apps/web && npx playwright test tests/e2e.spec.ts --project=chromium
apps/api/.venv/bin/python scripts/evaluate_retrieval.py
apps/api/.venv/bin/python scripts/verify_rls.py
apps/api/.venv/bin/python scripts/perf_smoke.pySee docs/architecture.md, docs/security.md, and docs/agent-runtime.md for the authoritative boundaries.
relation ... does not exist: runmake migratethenmake seed.- Empty manager view: confirm you used
manager1ormanager2;manager3is deliberately zero-scope. - Agent says no provider is configured: set
ZAI_API_KEYorOPENAI_API_KEYin.env, then restart the API. - Old UI or branding after a restart: plain
docker compose upnow rebuilds all local app images.docker compose downremoves containers, not previously built images; on older Compose versions usedocker compose up --build -d. - Documents remain queued: inspect
docker compose logs ingestion-worker; the first model download is large. - Qdrant collection mismatch after changing embedding dimensions: remove only the local Qdrant volume after accepting data loss, then reseed.
- Port conflict: use
lsof -nP -iTCP:3001 -sTCP:LISTENor the equivalent check for8001, stop only the process you own, then rundocker compose up -d weborapi. Shiftaar is configured for3001and8001, never3000or8000.
Real PII, multi-company SaaS, payroll, biometrics, geofencing, leave, SMS OTP, shift mutation, OCR, web search, cross-session memory, multi-agent orchestration and public deployment.
Do not connect this repository directly to real employee records, payroll systems, biometric systems, production identity providers, or write-capable workforce tools. Replace synthetic data, add deployment-grade authentication, complete threat modeling, and run formal domain review before using these patterns in production.
Apache-2.0. See LICENSE.

