docs(05): create phase plan

Phase 05: Visibility and Client Portal
- 5 plans in 3 waves
- 2 parallel (wave 1), 1 sequential (wave 2), 2 parallel (wave 3)
- Ready for execution

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
kevin-asprec
2026-03-05 17:14:54 +08:00
parent 5276f3bbf4
commit ea58620c7d
6 changed files with 929 additions and 6 deletions

View File

@@ -0,0 +1,160 @@
---
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"
---
<objective>
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.
</objective>
<execution_context>
@C:\Users\KevinAsprec\.claude/get-shit-done/workflows/execute-plan.md
@C:\Users\KevinAsprec\.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.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
</context>
<tasks>
<task type="auto">
<name>Task 1: DashboardService with metric aggregation</name>
<files>src/lib/services/dashboard-service.ts</files>
<action>
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.
</action>
<verify>TypeScript compiles: `npx tsc --noEmit src/lib/services/dashboard-service.ts` (or full project compile)</verify>
<done>DashboardService exports all 6 methods with correct return types</done>
</task>
<task type="auto">
<name>Task 2: Dashboard API route and integration tests</name>
<files>src/app/api/dashboard/route.ts, src/lib/__tests__/dashboard-service.test.ts</files>
<action>
**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`
</action>
<verify>`npx vitest run src/lib/__tests__/dashboard-service.test.ts` — all tests pass</verify>
<done>GET /api/dashboard returns all dashboard metrics; 6+ tests pass verifying metric accuracy</done>
</task>
</tasks>
<verification>
- `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)
</verification>
<success_criteria>
- 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
</success_criteria>
<output>
After completion, create `.planning/phases/05-visibility-and-client-portal/05-01-SUMMARY.md`
</output>