Stratpoint Engineering

AI Foundational Training

Sign in with your Stratpoint Google account to continue.

AI SDLC Training
AI Foundational Training · Dev Track · Sample Project
Sample Project · Architecture

Architecture Document + ADR-E001

LeaveTrack v1.0 — stack, data model, API design, and the Day 0 mock-auth decision.

Stack

  • Frontend/Backend: Next.js 16 (App Router), TypeScript
  • Database: Postgres via Supabase
  • Auth (Day 0): mock cookie session — see ADR-LeaveTrack-E001 below. Real provider wired in Day 1.
  • Deployment target: Vercel (app), Supabase (managed Postgres)

Rationale: the team already runs Next.js + Supabase on other projects (fits nexus's Day 0 mock-auth-mock-data pattern directly); no NFR here demands anything heavier.

Data Model

users            (id, name, email, role[employee|manager|hr_admin], manager_id nullable FK -> users.id)
leave_types      (id, name, tracks_balance boolean)          -- seeded: Vacation, Sick, Unpaid
leave_policies   (id, user_id FK, leave_type_id FK, accrual_per_month numeric)
leave_balances   (id, user_id FK, leave_type_id FK, balance numeric, updated_at)
leave_requests   (id, user_id FK, leave_type_id FK, start_date, end_date, reason,
                  status[pending|approved|rejected], decided_by FK -> users.id nullable,
                  decided_at nullable, is_deleted boolean default false, created_at)
audit_log        (id, leave_request_id FK, actor_id FK, action, occurred_at)
  • leave_requests.is_deletedsoft delete only, per BR-04 (3-year retention). No hard-delete path exists anywhere in the codebase.
  • users.manager_id is the sole source of truth for the scoped-visibility rule (US-04). A manager's queue query always filters WHERE manager_id = :current_user_id.

API Design (selected)

MethodRouteAuthNotes
POST/api/leave-requestsEmployeeUS-01. Validates date range server-side (AC2).
GET/api/leave-requests?scope=mineEmployeeUS-02 balance context.
GET/api/leave-requests?scope=teamManagerUS-04 — server-side filter on manager_id, never client-side.
POST/api/leave-requests/:id/decisionManagerUS-03. 403 if requester is not a direct report (AC3).
GET/api/audit/:userIdHR AdminUS-05. Reads soft-deleted-excluded, never hard-deleted, rows.
POST/api/jobs/accrualSystem (cron)US-07. Idempotent — see ADR-E001's sibling decision below.

Error format: { success: false, error: { code, message } } on every non-2xx response, per AGENTS.md convention.

Security

  • Every manager-scoped endpoint enforces the manager_id filter in the query itself, not in application logic that could be bypassed — this is the direct implementation of PRD NFR "enforced server-side, never client-side only."
  • Session cookie is httpOnly, 8h expiry (Day 0 mock auth pattern; unchanged shape when real auth replaces it in Day 1).

Deployment Topology

Single Next.js app on Vercel, single Supabase Postgres instance (pooled connection, not direct). Monthly accrual job (US-07) runs as a scheduled Vercel Cron hitting /api/jobs/accrual.

Open Questions

Should leave_policies support mid-year policy changes (e.g., a promotion changing accrual rate)? Flagged for Sprint 2 — not required for Q3 launch (BRD scope).

ADR-LeaveTrack-E001 — Auth & Session Strategy

Status: Accepted

Context

Day 0 (/scaffold) must produce a running app with zero external credentials — no real auth provider configured yet. But the app still needs role-gating (Employee / Manager / HR Admin) from commit one, since every page in the UI shell renders differently per role.

Options Considered

OptionProsCons
1. No auth at all on Day 0 — every route public, role picked via a UI toggleSimplest possible Day 0Doesn't exercise the route-guard pattern the real app needs; Day 1 becomes a bigger jump
2. Mock cookie session — login accepts any input, sets an httpOnly cookie holding a mock role, route guard reads itExercises the exact route-guard shape the real app will use; Day 1 just swaps the cookie's origin, not the guard logicSlightly more Day 0 setup than option 1
3. Mock JWT in localStorageFamiliar patternNot readable server-side without extra plumbing; server components can't gate on it directly

Decision

Option 2 — mock cookie session, per nexus's Day 0 convention (/scaffold's "Mock auth pattern"). Cookie holds mock-role, 8h expiry. Route guard (Next.js proxy.ts) reads the cookie and redirects unauthenticated requests to login. Server components read the cookie directly for the current session — no Context provider needed.

Consequences

  • Positive: Day 1's real-auth task (wiring an actual provider) only replaces how the cookie gets set — the guard, the server-component read pattern, and every role-gated page stay untouched.
  • Negative: until Day 1, "login" accepts any input — this must never ship past the scaffold stage, and AGENTS.md flags it explicitly so no developer mistakes it for production auth.