Files
NetForge/.planning/STATE.md
kevin-asprec a7022c33ab docs(05-06): complete tenant isolation and CASL subjects gap closure plan
Tasks completed: 2/2
- Add 6 missing models to tenant scoping (28 total)
- Add Collection and Remittance CASL subjects, update 8 routes

SUMMARY: .planning/phases/05-visibility-and-client-portal/05-06-SUMMARY.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 18:29:18 +08:00

5.0 KiB

Project State

Project Reference

See: .planning/PROJECT.md (updated 2026-03-04)

Core value: ISP owners can see exactly where their money is — who owes what, what's been collected, what's been spent, and what the business actually looks like financially — in real time. Current focus: All 5 phases complete. Gap closure plans (05-06, 05-07) done. Milestone v1.0 audit-ready.

Current Position

Phase: 5 of 5 (Visibility and Client Portal) Plan: 7 of 7 in phase 5 (30/30 total complete, including gap closure plans 05-06, 05-07) Status: All phases complete. All plans done: 05-01 through 05-07. Last activity: 2026-03-05 — Completed 05-06 gap closure (tenant isolation for 6 models + Collection/Remittance CASL subjects)

Progress: [██████████████████████████████] 100% (30/30 plans across all phases)

Performance Metrics

Velocity:

  • Total plans completed: 30
  • Average duration: ~9 min
  • Total execution time: ~210 min

By Phase:

Phase Plans Total Avg/Plan
01-foundation 5/5 complete 41 min 8.2 min
02-subscriber-and-billing-core 5/5 complete 57 min 11.4 min
03-operational-modules 5/5 complete ~65 min ~13 min
04-inventory-expenses-reports 5/5 complete 71 min 14.2 min
05-visibility-and-client-portal 7/7 complete ~31 min ~4.4 min

Updated after each plan completion

Accumulated Context

Decisions

Decisions are logged in PROJECT.md Key Decisions table. Recent decisions affecting current work:

  • [Roadmap]: Accounting COA and JournalEntryService built in Phase 2 before first invoice — cannot be retrofitted
  • [Roadmap]: Inventory modeled as event-ledger (immutable movements) from Phase 4 — mutable quantity columns explicitly rejected
  • [Roadmap]: Collector balances derived from transaction log, never stored as mutable fields
  • [Roadmap]: PORT-05 (online payment) scaffolded in Phase 5 but payment gateway integration deferred to v2 per project out-of-scope decision
  • [05-01]: Dashboard revenue metrics use Payment.createdAt (not paymentDate) for today/month filtering
  • [05-01]: Cash flow uses same approach as FinancialReportService — POSTED JE lines on revenue (4xxx) and expense (5xxx) accounts with normal balance logic
  • [05-01]: getDashboardSummary runs all 5 metric methods in parallel via Promise.all
  • [05-02]: Dual NextAuth credentials providers (staff id=credentials, portal id=portal-credentials) on same instance — additive, no change to staff auth
  • [05-02]: Subscriber.passwordHash is nullable — only subscribers with a set password can log in to portal
  • [05-02]: subscriberId persisted in JWT token and session — distinguishes portal users from staff users without DB lookup
  • [05-02]: withPortalAuth HOF validates subscriberId in session; 401 if no session, 403 if not portal user
  • [05-03]: ensurePortalUser creates shadow User with CLIENT role and portal-{accountNumber}@portal.local email — bridges Subscriber auth to User FK on Ticket.createdById
  • [05-03]: Portal tickets use source=SUBSCRIBER (not PORTAL) — TicketSource enum has STAFF/SUBSCRIBER only
  • [05-03]: TicketComment is append-only (no updatedAt, no edits/deletes) — conversation integrity preserved
  • [05-03]: Closed tickets reject new comments — enforced at service layer in addTicketComment
  • [05-03]: Payment scaffold computes outstanding balance in JS from SENT/PARTIAL/OVERDUE invoices — same derived-aggregation pattern
  • [05-04]: RBAC tests use definePermissionsFor directly + withPermission/withPortalAuth HOF mocking — 43 tests covering all 5 roles
  • [05-04]: Two-tenant isolation verified with real DB records — cross-tenant queries return null/empty
  • [05-05]: E2E tests exercise services directly (not HTTP) — 16 tests across 3 critical workflows
  • [05-05]: Trial balance verified balanced (debits === credits > 0) after each workflow
  • [05-06]: 6 missing models (expense, expenseCategory, inventoryItem, stockMovement, vendor, ticketComment) added to tenant scoping — TENANT_SCOPED_MODELS now 28 entries
  • [05-06]: Collection and Remittance added as dedicated CASL subjects — routes no longer borrow Subscriber subject
  • [05-07]: E2E coverage extended to 21 tests across 5 workflows (added inventory/expense + portal ticket)
  • [05-07]: Phase 2 VERIFICATION.md corrected from gaps_found (4/5) to passed (5/5) — billing DRAFT-to-SENT fix validated

Pending Todos

None.

Blockers/Concerns

  • [Phase 1 research flag]: MikroTik RouterOS Node.js client library maintenance status is LOW confidence — verify node-routeros vs mikronode before implementing router integration (MikroTik integration is v2, but adapter interface should be planned)
  • [Phase 3 research flag]: Semaphore SMS API pricing/stability for 2026 is MEDIUM confidence — verify before any SMS work (SMS is v2, but abstraction layer design is relevant)

Session Continuity

Last session: 2026-03-05T10:29:00Z Stopped at: Completed 05-06-PLAN.md (gap closure: tenant isolation + CASL subjects) Resume file: None