--- phase: 05-visibility-and-client-portal plan: 01 type: execute wave: 1 depends_on: [] files_modified: - src/lib/services/dashboard-service.ts - src/app/api/dashboard/route.ts - src/lib/__tests__/dashboard-service.test.ts autonomous: true must_haves: truths: - "Dashboard returns revenue collected today and this month" - "Dashboard returns overdue subscriber count and total outstanding amount" - "Dashboard returns active/suspended/cancelled subscriber counts" - "Dashboard returns cash flow summary (money in vs money out)" - "Dashboard returns collector summary (today's collections, unverified remittances)" artifacts: - path: "src/lib/services/dashboard-service.ts" provides: "DashboardService with all metric aggregation methods" exports: ["getRevenueMetrics", "getSubscriberMetrics", "getOverdueMetrics", "getCashFlowSummary", "getCollectorSummary", "getDashboardSummary"] - path: "src/app/api/dashboard/route.ts" provides: "GET endpoint returning all dashboard metrics" exports: ["GET"] - path: "src/lib/__tests__/dashboard-service.test.ts" provides: "Integration tests verifying metric accuracy" key_links: - from: "src/lib/services/dashboard-service.ts" to: "prisma" via: "aggregate queries on Payment, Invoice, Subscriber, Collection, Remittance, JournalEntryLine" pattern: "prisma\\.(payment|invoice|subscriber|collection|remittance|journalEntryLine)\\." - from: "src/app/api/dashboard/route.ts" to: "src/lib/services/dashboard-service.ts" via: "import and call getDashboardSummary" pattern: "getDashboardSummary" --- Build the DashboardService that aggregates financial and operational metrics for the ISP owner dashboard, plus a GET /api/dashboard endpoint and integration tests. Purpose: DASH-01, DASH-02, DASH-03, DASH-04 — the ISP owner's single-page business health overview. Output: DashboardService, API route, passing tests. @C:\Users\KevinAsprec\.claude/get-shit-done/workflows/execute-plan.md @C:\Users\KevinAsprec\.claude/get-shit-done/templates/summary.md @.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/05-visibility-and-client-portal/05-CONTEXT.md @src/lib/services/financial-report-service.ts @src/lib/services/outstanding-report-service.ts @src/lib/services/collection-report-service.ts @src/lib/services/expense-report-service.ts @src/lib/services/payment-service.ts @src/lib/services/collector-service.ts @src/lib/middleware/authorize.ts @prisma/schema.prisma Task 1: DashboardService with metric aggregation src/lib/services/dashboard-service.ts Create DashboardService with these methods, all accepting a TenantPrismaClient (same pattern as all other services): 1. **getRevenueMetrics(db, tenantId)** — Revenue collected today and this month (DASH-01): - Query Payment table with status COMPLETED, grouped by date range - `revenueToday`: sum of payments where createdAt is today (midnight to now) - `revenueThisMonth`: sum of payments where createdAt is current month - Return `{ revenueToday: Decimal, revenueThisMonth: Decimal }` 2. **getOverdueMetrics(db, tenantId)** — Overdue subscriber count and outstanding total (DASH-02): - Query Invoice table for OVERDUE status invoices - Count distinct subscriberIds with overdue invoices - Sum (totalAmount - amountPaid) for all overdue invoices - Return `{ overdueCount: number, totalOutstanding: Decimal }` 3. **getSubscriberMetrics(db, tenantId)** — Status breakdown (DASH-03): - Query Subscriber table grouped by status - Return `{ active: number, suspended: number, cancelled: number, total: number }` 4. **getCashFlowSummary(db, tenantId, startDate, endDate)** — Money in vs money out (DASH-04): - Money in: sum of POSTED JE lines where account is revenue-type (4xxx codes) — use debit/credit with normal balance logic, same as FinancialReportService - Money out: sum of POSTED JE lines where account is expense-type (5xxx codes) - Return `{ moneyIn: Decimal, moneyOut: Decimal, netCashFlow: Decimal }` - Default date range: current month 5. **getCollectorSummary(db, tenantId)** — Today's collections and unverified remittances (from CONTEXT.md): - `collectionsToday`: sum of non-voided Collection amounts where createdAt is today - `unverifiedRemittances`: count of Remittance records with status SUBMITTED (not VERIFIED) - Return `{ collectionsToday: Decimal, unverifiedRemittances: number }` 6. **getDashboardSummary(db, tenantId)** — Aggregator that calls all five methods above and returns a single object. Use Prisma aggregate/groupBy for efficiency. Follow the existing TenantPrismaClient pattern (type as any). Use Decimal from Prisma for all money fields. All date comparisons use UTC. TypeScript compiles: `npx tsc --noEmit src/lib/services/dashboard-service.ts` (or full project compile) DashboardService exports all 6 methods with correct return types Task 2: Dashboard API route and integration tests src/app/api/dashboard/route.ts, src/lib/__tests__/dashboard-service.test.ts **API Route (src/app/api/dashboard/route.ts):** - GET handler wrapped with `withPermission("read", "Report")` — ADMIN and OFFICE_STAFF have this permission - Calls getDashboardSummary with tenant-scoped Prisma client - Returns JSON with all metrics - Accepts optional query params: `startDate`, `endDate` for cash flow date range (defaults to current month) - Follow existing route patterns (see any route.ts in src/app/api/) **Integration Tests (src/lib/__tests__/dashboard-service.test.ts):** Create tests using vitest with live PostgreSQL (same pattern as all other test files): Setup: Create tenant, seed COA, create subscriber, generate invoice, record payment, create collection, create remittance. Tests (minimum 6): 1. `getRevenueMetrics returns today's revenue` — after recording a payment, revenueToday > 0 2. `getOverdueMetrics counts overdue invoices` — create invoice with past due date, verify overdueCount = 1 3. `getSubscriberMetrics returns status breakdown` — create active + suspended subscribers, verify counts 4. `getCashFlowSummary computes net cash flow` — after payment + expense, verify moneyIn and moneyOut 5. `getCollectorSummary returns today's collections` — after collection, verify collectionsToday > 0 6. `getDashboardSummary aggregates all metrics` — verify the composite object has all fields Cleanup order: follow the most comprehensive cleanup pattern from 04-04 (expense report tests) since dashboard touches payments, invoices, collections, remittances, expenses, and JEs. Run tests with: `npx vitest run src/lib/__tests__/dashboard-service.test.ts` `npx vitest run src/lib/__tests__/dashboard-service.test.ts` — all tests pass GET /api/dashboard returns all dashboard metrics; 6+ tests pass verifying metric accuracy - `npx tsc --noEmit` passes (no type errors) - `npx vitest run src/lib/__tests__/dashboard-service.test.ts` — all tests pass - DashboardService correctly derives all metrics from existing data (no new stored balances) - DashboardService aggregates revenue, overdue, subscriber status, cash flow, and collector metrics - GET /api/dashboard returns the composite dashboard object - All integration tests pass, verifying metric accuracy against seeded data - DASH-01, DASH-02, DASH-03, DASH-04 requirements satisfied After completion, create `.planning/phases/05-visibility-and-client-portal/05-01-SUMMARY.md`