docs(03-01): complete dashboard API + components plan summary

This commit is contained in:
lorentz 2026-05-03 16:51:30 -04:00
parent bfe9549d02
commit 464c02a7f4

View file

@ -0,0 +1,140 @@
---
phase: 03-dashboard-restyle
plan: 01
subsystem: api, ui
tags: [mobile, dashboard, nextjs, postgres, tailwind, shadcn, lucide]
# Dependency graph
requires:
- phase: 02-mobile-shell-more-drawer
provides: mobile layout shell (HeaderBar, BottomNav, MoreDrawer) that wraps all /mobile/* pages
provides:
- GET /api/mobile/dashboard returning MobileDashboardResponse (kpis, needsAttention, workers)
- KpiCardMobile component (phone-sized KPI card, tone-aware destructive border)
- NeedsAttentionStrip component (horizontal-scroll strip of compact attention cards)
- WorkerStatusRow component (3-cell worker/backup status row with status dot indicators)
affects:
- 03-02 (plan 02 wires these components into app/mobile/dashboard/page.tsx)
# Tech tracking
tech-stack:
added: []
patterns:
- "Mobile API endpoint: single Promise.all with 6 parameterless queries, company_scope exclusion filter, manual snake→camel transform"
- "Mobile component comment block: /* ComponentName — phase 03 (DASH-XX). */ header with purpose description"
- "Tone-aware KPI card: TONE_BORDER record maps tone to Tailwind border class"
- "Worker status derivation: down if fail_1h>0 and in_flight=0, warn if fail_1h>0, ok otherwise"
key-files:
created:
- components/mobile/KpiCardMobile.tsx
- components/mobile/NeedsAttentionStrip.tsx
- components/mobile/WorkerStatusRow.tsx
modified:
- app/api/mobile/dashboard/route.ts
key-decisions:
- "Reused sla_breaches integer from KPI query for overdue_tickets count in needsAttention — avoids a 7th query"
- "Default export import (not named) for postgresClient matches app/api/dashboard/overview/route.ts reference route pattern"
- "captions left undefined for now — plan 02 can add vs-yesterday deltas without an API change"
patterns-established:
- "Mobile endpoint pattern: requireAuth at top, single Promise.all, typed query generics, manual int parse with ?? '0' fallback"
- "Mobile component pattern: 'use client'; /* Name — phase NN (REQ-NN). */ block, pure presentational, no fetch"
requirements-completed: [DASH-01, DASH-02, DASH-03]
# Metrics
duration: 18min
completed: 2026-05-03
---
# Phase 3 Plan 1: Dashboard API + Presentational Components Summary
**Mobile dashboard API reshaped to return kpis/needsAttention/workers in a single round-trip, plus three presentational components (KpiCardMobile, NeedsAttentionStrip, WorkerStatusRow) ready for plan 02 to wire into the page.**
## Performance
- **Duration:** ~18 min
- **Started:** 2026-05-03T00:00:00Z
- **Completed:** 2026-05-03T00:18:00Z
- **Tasks:** 2
- **Files modified:** 4 (1 rewritten, 3 created)
## Accomplishments
- Rewrote `app/api/mobile/dashboard/route.ts` to return `MobileDashboardResponse` (4 KPIs, 3 Needs Attention items, 3 worker entries) in a single Promise.all of 6 parameterless queries
- Exported 4 TypeScript interfaces (`KpiResponse`, `AttentionResponse`, `WorkerResponse`, `MobileDashboardResponse`) so plan 02 can `import type` them without re-exploring the codebase
- Created `KpiCardMobile` — phone-sized KPI card with optional destructive left border for `tone='attention'` (SLA breaches)
- Created `NeedsAttentionStrip` — horizontal-scroll snap strip of compact attention cards, renders null when empty
- Created `WorkerStatusRow` — 3-cell status row with emerald/amber/destructive status dots, each a next/link to the corresponding admin page
## Response Shape
```typescript
export interface MobileDashboardResponse {
kpis: KpiResponse[]; // 4 entries: open_total, opened_today, resolved_today, sla_breaches
needsAttention: AttentionResponse[]; // 3 entries: overdue_tickets, failed_backups, stalled_workflows
workers: WorkerResponse[]; // 3 entries: analyzer, rmm, backup_success_rate
}
```
## Component Export Signatures
```typescript
// KpiCardMobile.tsx
export type KpiTone = 'default' | 'attention';
export function KpiCardMobile({ label, value, caption, tone }: KpiCardMobileProps): JSX.Element
// NeedsAttentionStrip.tsx
export interface NeedsAttentionItem { id, label, count, href }
export function NeedsAttentionStrip({ items }: NeedsAttentionStripProps): JSX.Element | null
// WorkerStatusRow.tsx
export type WorkerStatus = 'ok' | 'warn' | 'down';
export interface WorkerStatusEntry { id, label, value, status, href }
export function WorkerStatusRow({ entries }: WorkerStatusRowProps): JSX.Element
```
## Task Commits
1. **Task 1: Rewrite /api/mobile/dashboard to return kpis/needsAttention/workers shape** - `24e20c7` (feat)
2. **Task 2: Add KpiCardMobile, NeedsAttentionStrip, WorkerStatusRow components** - `bfe9549` (feat)
## Files Created/Modified
- `app/api/mobile/dashboard/route.ts` — Completely rewritten; exports 4 interfaces + GET handler returning MobileDashboardResponse
- `components/mobile/KpiCardMobile.tsx` — New; phone-sized KPI card with tone-aware destructive left border
- `components/mobile/NeedsAttentionStrip.tsx` — New; horizontal-scroll attention strip with snap-x
- `components/mobile/WorkerStatusRow.tsx` — New; 3-cell worker/backup status row with color-coded dots
## Decisions Made
- **Reuse sla_breaches for overdue_tickets:** The overdue_tickets count in `needsAttention` is the same value as `sla_breaches` in `kpis` — computed from the same KPI query row, avoiding a 7th query.
- **Default postgresClient import:** Used `import postgresClient from '@/lib/services/postgres-client'` (default export) to match `app/api/dashboard/overview/route.ts` reference route, not the named export used in the old mobile route.
- **Captions deferred:** `caption` fields on KpiResponse are left `undefined` for now; plan 02 can add vs-yesterday deltas without an API shape change.
## Deviations from Plan
None - plan executed exactly as written.
## Issues Encountered
None.
## Known Stubs
None — all data flows are wired to live DB queries.
## Threat Flags
No new security surface introduced. The `/api/mobile/dashboard` endpoint was already an existing route; it now enforces `requireAuth()` (T-03-01) and applies the `company_scope` exclusion on all ticket queries (T-03-02), both as specified in the plan's threat model.
## Next Phase Readiness
- Plan 02 (`03-02`) can immediately import `MobileDashboardResponse`, `KpiCardMobile`, `NeedsAttentionStrip`, and `WorkerStatusRow` — no codebase exploration needed
- No blockers. `app/mobile/dashboard/page.tsx` untouched as required (reserved for plan 02)
---
*Phase: 03-dashboard-restyle*
*Completed: 2026-05-03*