Files
NetForge/.planning/phases/05-visibility-and-client-portal/05-02-SUMMARY.md
kevin-asprec ab1e94480e docs(05-02): complete Subscriber Portal Auth and API plan
Tasks completed: 2/2
- Portal authentication via subscriber account number
- PortalService, API routes, and integration tests (5 tests)

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

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

4.9 KiB

phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, decisions, metrics
phase plan subsystem tags requires provides affects tech-stack key-files decisions metrics
05-visibility-and-client-portal 02 portal
portal
auth
subscriber
nextauth
credentials
invoices
payments
account
phase provides
01-foundation NextAuth v4 with JWT strategy, withTenantContext, middleware auth exclusions
phase provides
02-subscriber-and-billing-core Subscriber, Invoice, Payment, ServicePlan models
Portal credentials provider (accountNumber + password login)
PortalService with subscriber-scoped data retrieval
Portal API routes (account, invoices, payments)
withPortalAuth middleware for portal endpoint authorization
05-03 (portal UI consumes these APIs)
05-05 (e2e tests)
added patterns
Dual NextAuth credentials provider (staff + portal) on same instance
subscriberId in JWT/session for portal user identification
withPortalAuth HOF for portal-only endpoint authorization
created modified
src/lib/services/portal-service.ts
src/lib/middleware/portal-auth.ts
src/app/api/portal/account/route.ts
src/app/api/portal/invoices/route.ts
src/app/api/portal/payments/route.ts
src/lib/__tests__/portal-service.test.ts
prisma/schema.prisma
src/lib/auth-options.ts
src/types/next-auth.d.ts
src/middleware.ts
id description
portal-dual-provider Two CredentialsProviders on same NextAuth instance (id: credentials, id: portal-credentials) -- additive, no change to staff auth
id description
portal-password-nullable Subscriber.passwordHash is nullable -- only subscribers with a set password can log in to portal
id description
portal-subscriberId-jwt subscriberId persisted in JWT token and session -- distinguishes portal users from staff users without DB lookup
duration completed tasks tests
4 min 2026-03-05 2 5

Phase 05 Plan 02: Subscriber Portal Authentication and API Summary

Portal auth via account number + password with subscriber-scoped read-only API endpoints, 5 tests passing

What Was Done

Task 1: Portal Authentication

  • Added passwordHash (nullable String) to Subscriber model in Prisma schema
  • Added second CredentialsProvider (portal-credentials) to NextAuth config accepting accountNumber + password + tenantId
  • Provider looks up subscriber by @@unique([tenantId, accountNumber]) with non-null passwordHash
  • JWT callback persists subscriberId into token; session callback exposes it on session.user
  • Extended next-auth type definitions (Session, User, JWT) with optional subscriberId
  • Updated middleware matcher to exclude /portal/login and /api/portal/auth from auth requirement

Task 2: PortalService and API Routes

  • Created PortalService with three subscriber-scoped methods:
    • getPortalAccount(db, subscriberId) -- returns profile, plan details, credit balance, billing day
    • getPortalInvoices(db, subscriberId, options) -- paginated invoices with line items, ordered by periodStart DESC
    • getPortalPayments(db, subscriberId, options) -- paginated payments, ordered by createdAt DESC
  • Created withPortalAuth middleware HOF that validates subscriberId in session (401 if no session, 403 if not portal user)
  • Created three portal API routes:
    • GET /api/portal/account -- subscriber profile + plan
    • GET /api/portal/invoices -- paginated invoices (query: page, limit)
    • GET /api/portal/payments -- paginated payments (query: page, limit)

Integration Tests (5/5 passing)

  1. getPortalAccount returns subscriber with plan details -- verifies all fields including plan name, speed, price, billingType
  2. getPortalInvoices returns paginated invoices -- creates 3 invoices, verifies page 1 limit 2 returns 2 with total 3
  3. getPortalPayments returns paginated payment history -- creates 2 payments, verifies list and subscriber scoping
  4. getPortalAccount scoped to subscriberId only -- creates 2 subscribers, verifies each sees only own data
  5. getPortalInvoices includes invoice line items -- verifies lines array populated with description and lineTotal

Deviations from Plan

None -- plan executed exactly as written.

Commits

Hash Message
539564d feat(05-02): portal authentication via subscriber account number
7222dbe feat(05-02): portal service, API routes, and integration tests

Requirements Satisfied

  • PORT-01: Subscriber can log in with account number and password
  • PORT-02: Subscriber can view current bill and outstanding balance (via invoices endpoint + account creditBalance)
  • PORT-04: Subscriber can view full payment history (via payments endpoint)
  • Account overview includes plan details, balance, and billing day
  • Invoice and payment history are paginated
  • Portal API endpoints scoped to logged-in subscriber only