docs(05): complete Visibility and Client Portal phase (gap closure)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
kevin-asprec
2026-03-05 18:41:32 +08:00
parent a7022c33ab
commit d47d108a88
3 changed files with 85 additions and 69 deletions

View File

@@ -16,7 +16,7 @@ Decimal phases appear between their surrounding integers in numeric order.
- [x] **Phase 2: Subscriber and Billing Core** - Subscriber management, billing engine, payment recording, and the double-entry accounting ledger
- [x] **Phase 3: Operational Modules** - Collector workflow, ticketing system, job orders, and technician management
- [x] **Phase 4: Inventory, Expenses, and Financial Reports** - Inventory event-ledger, asset management, expense tracking, and accounting financial statements
- [ ] **Phase 5: Visibility and Client Portal** - Dashboard metrics, client self-service portal, integration tests, and end-to-end tests (gap closure in progress)
- [x] **Phase 5: Visibility and Client Portal** - Dashboard metrics, client self-service portal, integration tests, and end-to-end tests
## Phase Details
@@ -122,8 +122,8 @@ Plans:
- [x] 05-03-PLAN.md — Portal tickets and payment scaffold: ticket submission with conversation threads, online payment "coming soon" page (PORT-03, PORT-05)
- [x] 05-04-PLAN.md — Integration tests: API RBAC enforcement for all 5 roles, unauthorized access assertions, two-tenant isolation tests (INFRA-03)
- [x] 05-05-PLAN.md — End-to-end tests: billing workflow, collection/remittance workflow, ticket-to-job-order workflow (INFRA-04)
- [ ] 05-06-PLAN.md — Gap closure: fix tenant scoping for 6 missing models, add Collection/Remittance CASL subjects (P0 security + tech debt)
- [ ] 05-07-PLAN.md — Gap closure: inventory/expense and portal ticket E2E tests, Phase 2 verification correction (tech debt)
- [x] 05-06-PLAN.md — Gap closure: fix tenant scoping for 6 missing models, add Collection/Remittance CASL subjects (P0 security + tech debt)
- [x] 05-07-PLAN.md — Gap closure: inventory/expense and portal ticket E2E tests, Phase 2 verification correction (tech debt)
---
@@ -138,4 +138,4 @@ Phases execute in numeric order: 1 -> 2 -> 3 -> 4 -> 5
| 2. Subscriber and Billing Core | 5/5 | Complete | 2026-03-04 |
| 3. Operational Modules | 5/5 | Complete | 2026-03-05 |
| 4. Inventory, Expenses, and Financial Reports | 5/5 | Complete | 2026-03-06 |
| 5. Visibility and Client Portal | 5/7 | Gap Closure | 2026-03-05 |
| 5. Visibility and Client Portal | 7/7 | ✓ Complete | 2026-03-05 |

View File

@@ -78,6 +78,6 @@ None.
## Session Continuity
Last session: 2026-03-05T10:29:00Z
Stopped at: Completed 05-06-PLAN.md (gap closure: tenant isolation + CASL subjects)
Last session: 2026-03-05T11:00:00Z
Stopped at: Phase 5 gap closure complete (05-06, 05-07). Phase verified 7/7 must-haves. Milestone v1.0 ready for audit.
Resume file: None

View File

@@ -1,16 +1,31 @@
---
phase: 05-visibility-and-client-portal
verified: 2026-03-05T17:50:00Z
verified: 2026-03-05T19:30:00Z
status: passed
score: 5/5 must-haves verified
score: 7/7 must-haves verified
re_verification:
previous_status: passed
previous_score: 5/5
audit_findings:
- "6 models missing from TENANT_SCOPED_MODELS (fixed in 05-06)"
- "CASL subject naming for collection/remittance routes (fixed in 05-06)"
- "E2E test coverage gaps for inventory/expense and portal ticket flows (fixed in 05-07)"
- "Phase 2 VERIFICATION.md outdated (fixed in 05-07)"
gaps_closed:
- "All 6 missing models registered in TENANT_SCOPED_MODELS with complete extends query blocks"
- "Collection and Remittance API routes use dedicated CASL subjects"
- "E2E tests cover inventory/expense and portal ticket workflows (21 tests across 5 workflows)"
- "Phase 2 VERIFICATION.md corrected to passed 5/5"
gaps_remaining: []
regressions: []
---
# Phase 5: Visibility and Client Portal Verification Report
**Phase Goal:** The ISP owner can see the complete financial and operational picture on a single dashboard; subscribers can log in to view their bills, payment history, and plan details, and submit tickets; and the full system is covered by integration and end-to-end tests on critical workflows.
**Verified:** 2026-03-05T17:50:00Z
**Verified:** 2026-03-05T19:30:00Z
**Status:** PASSED
**Re-verification:** No -- initial verification
**Re-verification:** Yes -- after milestone audit gap closure (plans 05-06 and 05-07)
## Goal Achievement
@@ -18,76 +33,65 @@ score: 5/5 must-haves verified
| # | Truth | Status | Evidence |
|---|-------|--------|----------|
| 1 | Dashboard shows revenue today/month, overdue count, outstanding amount, subscriber breakdown, cash flow summary | VERIFIED | DashboardService (424 lines) with 6 methods: getRevenueMetrics, getOverdueMetrics, getSubscriberMetrics, getCashFlowSummary, getCollectorSummary, getDashboardSummary. GET /api/dashboard returns composite. 6 integration tests pass. |
| 2 | Subscriber can log in to portal and view bill, balance, payment history, plan details -- scoped to own account | VERIFIED | Portal credentials provider in auth-options.ts with subscriberId in JWT. PortalService (123 lines) with getPortalAccount, getPortalInvoices, getPortalPayments. withPortalAuth middleware enforces subscriberId scope. 5 integration tests pass including cross-subscriber isolation test. |
| 3 | Subscriber can submit a support ticket and it appears in staff ticket queue | VERIFIED | PortalTicketService (283 lines) delegates to createTicket() with source=SUBSCRIBER. Shadow User pattern bridges FK constraint. Test explicitly verifies staff listTickets includes portal-created ticket. 6 integration tests pass. |
| 4 | All API endpoints have integration tests asserting RBAC enforcement for authorized/unauthorized roles | VERIFIED | api-rbac.test.ts (851 lines, 43 tests): Authentication 401/403, all 5 roles tested against CASL subjects, withPermission HOF enforcement, two-tenant data isolation with real DB records. All 43 tests pass. |
| 5 | Critical workflows pass end-to-end tests (billing, collection/remittance, ticket/job-order) | VERIFIED | e2e-workflows.test.ts (685 lines, 16 tests): Billing (register -> invoice -> payment -> trial balance -> dashboard), Collection (field collection -> remittance -> verification -> balanced JEs -> dashboard), Ticket (create -> job order -> completion -> auto-resolve -> close). Trial balance verified balanced after each workflow. All 16 tests pass. |
| 1 | Dashboard shows revenue today/month, overdue count, outstanding amount, subscriber breakdown, cash flow summary | VERIFIED | DashboardService (424 lines) with 6 methods. GET /api/dashboard returns composite. Regression check: file unchanged, still substantive. |
| 2 | Subscriber can log in to portal and view bill, balance, payment history, plan details -- scoped to own account | VERIFIED | PortalService (123 lines), withPortalAuth middleware (64 lines). Regression check: files unchanged, still substantive. |
| 3 | Subscriber can submit a support ticket and it appears in staff ticket queue | VERIFIED | PortalTicketService (283 lines). Regression check: file unchanged. NEW: E2E Workflow 5 explicitly tests portal ticket to staff queue flow (lines 846-919). |
| 4 | All API endpoints have integration tests asserting RBAC enforcement for authorized/unauthorized roles | VERIFIED | api-rbac.test.ts (851 lines, 43 tests). Regression check: file unchanged, still substantive. |
| 5 | Critical workflows pass end-to-end tests (billing, collection/remittance, ticket/job-order, inventory/expense, portal ticket) | VERIFIED | e2e-workflows.test.ts (919 lines, 21 tests across 5 workflows). Extended from 16 to 21 tests in plan 05-07. |
| 6 | All tenant-scoped models have application-layer tenant isolation via TENANT_SCOPED_MODELS and extends query blocks | VERIFIED | prisma-tenant.ts (2517 lines) has 28 models in TENANT_SCOPED_MODELS array. All 6 previously missing models have complete extends blocks. |
| 7 | Collection and remittance routes use dedicated CASL subjects with proper role permissions | VERIFIED | types.ts has Collection and Remittance in AppSubjects. permissions.ts grants OFFICE_STAFF manage and COLLECTOR create/read for both. Zero matches for withPermission Subscriber in collections/ or remittances/ routes. |
**Score:** 5/5 truths verified
**Score:** 7/7 truths verified
### Required Artifacts
### Required Artifacts (Gap Closure)
| Artifact | Expected | Status | Details |
|----------|----------|--------|--------|
| src/lib/services/dashboard-service.ts | Dashboard metric aggregation | VERIFIED | 424 lines, 6 methods, Prisma aggregate/groupBy, Promise.all parallel |
| src/app/api/dashboard/route.ts | Dashboard API endpoint | VERIFIED | 49 lines, withPermission read Report, date params |
| src/lib/__tests__/dashboard-service.test.ts | Dashboard tests | VERIFIED | 445 lines, 6 tests passing |
| src/lib/services/portal-service.ts | Subscriber-scoped data retrieval | VERIFIED | 123 lines, 3 methods with pagination |
| src/lib/middleware/portal-auth.ts | Portal auth middleware | VERIFIED | 64 lines, withPortalAuth HOF, 401/403 enforcement |
| src/app/api/portal/account/route.ts | Portal account endpoint | VERIFIED | 20 lines, withPortalAuth, calls getPortalAccount |
| src/app/api/portal/invoices/route.ts | Portal invoices endpoint | VERIFIED | 20 lines, withPortalAuth, calls getPortalInvoices |
| src/app/api/portal/payments/route.ts | Portal payments endpoint | VERIFIED | 20 lines, withPortalAuth, calls getPortalPayments |
| src/lib/__tests__/portal-service.test.ts | Portal service tests | VERIFIED | 352 lines, 5 tests passing |
| src/lib/services/portal-ticket-service.ts | Portal ticket creation + threads | VERIFIED | 283 lines, 5 functions, shadow User pattern |
| src/app/api/portal/tickets/route.ts | Portal ticket list/create | VERIFIED | 46 lines, GET + POST |
| src/app/api/portal/tickets/[id]/route.ts | Portal ticket detail | VERIFIED | 21 lines, GET with thread |
| src/app/api/portal/tickets/[id]/comments/route.ts | Ticket comments | VERIFIED | 61 lines, GET + POST |
| src/app/api/portal/payments/coming-soon/route.ts | Payment scaffold | VERIFIED | 42 lines, outstanding balance + instructions (gateway deferred to v2) |
| src/lib/__tests__/portal-ticket-service.test.ts | Portal ticket tests | VERIFIED | 340 lines, 6 tests passing |
| src/lib/__tests__/integration/api-rbac.test.ts | RBAC integration tests | VERIFIED | 851 lines, 43 tests passing |
| src/lib/__tests__/integration/e2e-workflows.test.ts | E2E workflow tests | VERIFIED | 685 lines, 16 tests passing |
|----------|----------|--------|---------|
| src/lib/prisma-tenant.ts | 28 models with extends blocks | VERIFIED | 2517 lines. 28 entries in TENANT_SCOPED_MODELS. Extends blocks at lines 1900, 1996, 2092, 2188, 2284, 2380. |
| src/lib/casl/types.ts | Collection and Remittance in AppSubjects | VERIFIED | Lines 16-17: Collection and Remittance present in union type. |
| src/lib/casl/permissions.ts | Collection/Remittance rules for OFFICE_STAFF and COLLECTOR | VERIFIED | Lines 70-71 and 95-99. |
| src/app/api/collections/route.ts | Uses Collection CASL subject | VERIFIED | POST=create/Collection, GET=read/Collection |
| src/app/api/collections/[id]/route.ts | Uses Collection CASL subject | VERIFIED | GET=read/Collection |
| src/app/api/collections/[id]/void/route.ts | Uses Collection CASL subject | VERIFIED | update/Collection |
| src/app/api/remittances/route.ts | Uses Remittance CASL subject | VERIFIED | POST=create/Remittance, GET=read/Remittance |
| src/app/api/remittances/[id]/verify/route.ts | Uses Remittance CASL subject | VERIFIED | update/Remittance |
| src/app/api/reports/collections/route.ts | Uses Collection CASL subject | VERIFIED | GET=read/Collection |
| src/lib/__tests__/integration/e2e-workflows.test.ts | 5 workflows | VERIFIED | 919 lines, 21 tests, 5 describe blocks. |
| .planning/phases/02-subscriber-and-billing-core/02-VERIFICATION.md | status: passed, score: 5/5 | VERIFIED | Frontmatter confirmed. |
### Key Link Verification
### Required Artifacts (Original - Regression Check)
| Artifact | Expected | Status | Details |
|----------|----------|--------|---------|
| src/lib/services/dashboard-service.ts | Dashboard metric aggregation | VERIFIED | 424 lines, unchanged |
| src/app/api/dashboard/route.ts | Dashboard API endpoint | VERIFIED | exists |
| src/lib/services/portal-service.ts | Subscriber-scoped data retrieval | VERIFIED | 123 lines, unchanged |
| src/lib/middleware/portal-auth.ts | Portal auth middleware | VERIFIED | 64 lines, unchanged |
| src/lib/services/portal-ticket-service.ts | Portal ticket creation + threads | VERIFIED | 283 lines, unchanged |
| src/lib/__tests__/integration/api-rbac.test.ts | RBAC integration tests | VERIFIED | 851 lines, unchanged |
### Key Link Verification (Gap Closure)
| From | To | Via | Status | Details |
|------|----|-----|--------|--------|
| Dashboard API route | DashboardService | import + getDashboardSummary call | WIRED | Route calls service, returns JSON response |
| DashboardService | Prisma Payment/Invoice/Subscriber/JE | aggregate/groupBy queries | WIRED | Real DB queries with proper filters |
| Portal auth | NextAuth JWT | subscriberId in token + session | WIRED | Dual CredentialsProvider, subscriberId persisted |
| Portal API routes | withPortalAuth | HOF wrapper | WIRED | All portal routes use withPortalAuth, subscriberId passed to service |
| Portal API routes | PortalService | import + function calls | WIRED | Account/invoices/payments endpoints call service functions |
| PortalService | Prisma queries | findFirst/findMany with subscriberId filter | WIRED | All queries scoped to subscriberId |
| Portal ticket | Staff ticket queue | createTicket() delegation with source=SUBSCRIBER | WIRED | Test verifies staff listTickets includes portal ticket |
| Portal ticket | User FK | ensurePortalUser shadow User | WIRED | Lazy creates User with CLIENT role for FK bridge |
| E2E tests | All services | Direct service function imports | WIRED | 12 service imports covering billing, collection, ticketing |
| RBAC tests | CASL + withPermission | Mock getCurrentUser + ability checks | WIRED | All 5 roles tested, HOF enforcement verified |
### Requirements Coverage
| Requirement | Status | Notes |
|-------------|--------|-------|
| DASH-01 | SATISFIED | Revenue today/month via getRevenueMetrics |
| DASH-02 | SATISFIED | Overdue count + outstanding via getOverdueMetrics |
| DASH-03 | SATISFIED | Active/suspended/cancelled via getSubscriberMetrics |
| DASH-04 | SATISFIED | Cash flow (money in vs out) via getCashFlowSummary |
| PORT-01 | SATISFIED | Portal login via account number + password, bill/balance view |
| PORT-02 | SATISFIED | Payment history via getPortalPayments with pagination |
| PORT-03 | SATISFIED | Ticket submission via createPortalTicket with staff visibility |
| PORT-04 | SATISFIED | Plan details in getPortalAccount (name, speed, price, billingType) |
| PORT-05 | SATISFIED (scaffold) | Payment coming-soon endpoint with balance + instructions; gateway deferred to v2 per PROJECT.md |
| INFRA-03 | SATISFIED | 43 RBAC integration tests across 5 roles + tenant isolation |
| INFRA-04 | SATISFIED | 16 e2e tests across 3 critical workflows with balanced trial balance verification |
|------|----|-----|--------|---------|
| prisma-tenant.ts | expense model queries | extends block at line 1900 | WIRED | All query methods inject tenantId |
| prisma-tenant.ts | expenseCategory model queries | extends block at line 1996 | WIRED | Full 14-method override set |
| prisma-tenant.ts | inventoryItem model queries | extends block at line 2092 | WIRED | Full 14-method override set |
| prisma-tenant.ts | stockMovement model queries | extends block at line 2188 | WIRED | Full 14-method override set |
| prisma-tenant.ts | vendor model queries | extends block at line 2284 | WIRED | Full 14-method override set |
| prisma-tenant.ts | ticketComment model queries | extends block at line 2380 | WIRED | Full 14-method override set |
| collections/route.ts | CASL permissions.ts | withPermission create/read Collection | WIRED | Zero Subscriber references remain |
| remittances/route.ts | CASL permissions.ts | withPermission create/read Remittance | WIRED | Zero Subscriber references remain |
| e2e-workflows.test.ts | InventoryService | import + registerItem + recordMovement calls | WIRED | Lines 49, 707, 720 |
| e2e-workflows.test.ts | ExpenseService | import + createCategory + createExpense calls | WIRED | Lines 50, 777, 785 |
| e2e-workflows.test.ts | createPortalTicket | import + function call | WIRED | Lines 51, 864 |
| e2e-workflows.test.ts | listTickets (staff view) | import + function call | WIRED | Lines 43, 880 |
### Anti-Patterns Found
| File | Line | Pattern | Severity | Impact |
|------|------|---------|----------|--------|
| portal-service.ts | 32 | return null | Info | Legitimate null check for subscriber not found |
| portal-ticket-service.ts | 208, 213 | return null | Info | Legitimate null checks for ticket not found / subscriber scoping |
| coming-soon/route.ts | 40 | Online payments coming soon | Info | Intentional scaffold per PORT-05 v2 deferral |
No blockers or warnings found.
| None | - | - | - | No new anti-patterns introduced by gap closure plans |
### Human Verification Required
@@ -106,7 +110,19 @@ No blockers or warnings found.
**Expected:** Ticket appears in staff queue with SUBSCRIBER source label
**Why human:** End-to-end browser flow crossing two auth contexts
### Gaps Summary
No gaps remain. All four issues identified by the milestone audit have been verified as resolved:
1. **Tenant scoping (P0 security):** All 28 tenant-scoped models now have complete extends query blocks in prisma-tenant.ts. The 6 previously missing models (expense, expenseCategory, inventoryItem, stockMovement, vendor, ticketComment) each have 14 query method overrides injecting tenantId.
2. **CASL subject naming:** Collection and Remittance are now first-class CASL subjects. All 8 collection/remittance route files use their dedicated subjects. Zero references to Subscriber remain in those routes. Role permissions are correctly assigned (OFFICE_STAFF: manage, COLLECTOR: create/read).
3. **E2E test coverage:** e2e-workflows.test.ts expanded from 3 workflows (16 tests) to 5 workflows (21 tests). Workflow 4 covers inventory receiving with JE posting and expense recording with auto-post JE, both verified against trial balance. Workflow 5 covers portal ticket creation with shadow user bridge and staff queue visibility.
4. **Phase 2 VERIFICATION.md:** Corrected from gaps_found (4/5) to passed (5/5), accurately reflecting the billing-service.ts fix that was applied earlier.
---
_Verified: 2026-03-05T17:50:00Z_
_Verified: 2026-03-05T19:30:00Z_
_Verifier: Claude (gsd-verifier)_