Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

12 — API Mapping (Dashboard Module)

Exact endpoints per screen. Wire contract per 00-shared/07: base /api/v1, Bearer JWT, success {success:true,message:"OK",data,meta?, timestamp,requestId}, error envelope with codes. Only shapes in code are used; blueprint-only endpoints marked (planned). Sources: dashboard.controller.ts, dashboard.service.ts, Dashboard.md, permissions.constants.ts, role.schema.ts, redis-cache.service.ts, ws-bridge.service.ts.


E1 — Dashboard overview (implemented)

EndpointGET /api/v1/dashboard/overview (dashboard.controller.ts:13-17)
GuardJwtAuthGuard only (dashboard.controller.ts:8) — RBAC dashboard.read is NOT enforced on this route today (permission exists at permissions.constants.ts:37; enforcement (planned), cf. IMPLEMENTATION_PLAN.md Phase 5 permissions audit)
Requestnone; tenant from JWT only (never from body — 00-shared/07 §1)
Response200 envelope, data (dashboard.service.ts:50-70): {students:{total}, teachers:{total}, staff:{total}, attendance:{total, summary:{status:count}, rate}, finance:{pendingInvoices, totalDueAmount}}
Aggregatesstudents = count status:'active' (:31); teachers = count (:32); staff = count (:33); attendance = today's records {date: {$gte: startOfDay, $lt: tomorrow}} (:34), summary grouped by status (:40-43), rate = round(present/total×100), 0 when none (:57-64); finance = invoices with status in ['issued','partial','overdue'] (:35-37), totalDueAmount = Σ(totalAmount − paidAmount) (:45-48)
Errors401 UNAUTHENTICATED (missing/expired JWT); 429 RATE_LIMITED (api tier 100/min); 5xx INTERNAL (service has no custom errors)
Side effectsNone today — no cache read/write, no event emission. Service live-scans repositories per request (dashboard.service.ts:24-38); blueprint target is Redis-served with TTL 60 s (Dashboard.md:41,49) — (planned)
ClientDashboard Home first load; skeletons → values (06_Screen_Specifications.md §1.3)

Cached response contract (planned) (blueprint target)

Cache keysl:{tenantId}:dashboard:overview — tenant namespacing automatic (redis-cache.service.ts:16-19); fallback platform (:17)
TTL60 s (Dashboard.md:41)
Invalidationon AttendanceMarked, ResultPublished, PaymentRecorded, InvoiceGenerated (Dashboard.md:34) — handler (planned); plus scheduled rebuild worker (Dashboard.md:50)
Client mirrorclient cache sl:{tenant}:dashboard:overview TTL 60 s (volatile, 00-shared/06 §3.3); force-refresh bypasses it (10_Interaction_Specification.md §2)
Stalenessclient renders last-good + StaleBanner beyond 60 s; ≥10 min → offline banner (06_Screen_Specifications.md §1.3)

E2 — Attendance trend (planned)

EndpointGET /api/v1/dashboard/attendance (Dashboard.md:24) — no controller route in code
Request`?period=today
Responserate/summary series for period; today shape from dashboard.service.ts:54-65
Cachesl:{tenantId}:dashboard:attendance:{period} TTL 60 s (planned)
ClientSS2 attendance detail; PeriodSelector disabled until this ships (08_Form_Specifications.md §2)

E3 — Finance trend (planned)

EndpointGET /api/v1/dashboard/finance (Dashboard.md:25)
Request?period= (planned); accountant role access (planned) (role lacks dashboard.readrole.schema.ts:47)
Responsedues + pendingInvoices series; today shape dashboard.service.ts:66-69
Cachesl:{tenantId}:dashboard:finance:{period} TTL 60 s (planned)
ClientSS3 finance detail

E4 — List widgets (planned)

EndpointGET /api/v1/dashboard/widgets (Dashboard.md:26)
Guarddashboard.read (permissions.constants.ts:37); reads user's widget layout
Responseordered widget configs from dashboard_widgets (Dashboard.md:7)
Client/dashboard/customize list + Home layout resolution (planned)

E5 — Update widget (planned)

EndpointPATCH /api/v1/dashboard/widgets/:id (Dashboard.md:27)
Guarddashboard.widget.manage (permissions.constants.ts:38) — the only dashboard write permission; org_admin default (role.schema.ts:23)
Requestvisibility / order / role chips (planned)
Errors404 RESOURCE_NOT_FOUND; 403 (no permission); 409 (concurrent edit)
Clientper-widget save with per-item spinner + conflict snackbar (10_Interaction_Specification.md §7)

E6 — Realtime (not REST)

ChannelWS /ws, JWT auth (ws.gateway.ts:20-23,35-44); client auto-joined to tenant:{tenantId} (ws.gateway.ts:50)
EventsAttendanceMarked, ResultPublished, PaymentRecorded, InvoiceGenerated (Dashboard.md:34) — broadcast by WsBridge for every domain event (ws-bridge.service.ts:16-22), payload {eventType, occurredAt, payload} (:17-21)
Client rulefilter to the 4 event types; 2 s debounce; force-refresh (10_Interaction_Specification.md §4)
Server push of fresh KPIs(forward-looking) — bridge emits event metadata only

Rate limits (client-relevant, 00-shared/07 §4)

TierLimitNotes
api100/minoverview/attendance/finance polling must stay within budget: 60 s poll = 1 req/min per screen, plus pull + WS-triggered refetches — acceptable
admin500/min(planned) if widgets PATCH ships under admin tier

Client contract summary

ConcernRule
AuthBearer JWT; 401 → single-flight refresh → replay; fail → session expiry (00-shared/06 §3.6)
Optimisticnone today (read-only); (planned) customize toggles optimistic with rollback (08_Form_Specifications.md §1)
IdempotencyGETs safe; PATCH widgets (planned) idempotent per widget
Offlinelast-good payload + banners; no writes (09_User_Behaviour.md B8)
Formattingclient formats, never recalculates (09_User_Behaviour.md B9): rate pre-rounded :57-64, dues pre-summed :45-48
Error mapping00-shared/06 §5: 401 reauth, 403 hide, 404 empty, 429 backoff poll, 5xx keep-last-good + snackbar
Role gatingdashboard.read today = org_admin only (role.schema.ts:23); screens hidden without permission; role views (planned) (IMPLEMENTATION_PLAN.md:232)