docs(01-05): complete super-admin panel plan

Tasks completed: 2/2
- Task 1: Super-admin API routes and middleware guard
- Task 2: Super-admin UI panel and comprehensive test harness

Phase 1 Foundation: COMPLETE (5/5 plans)
93 tests passing across auth, RBAC, tenant isolation, super-admin

SUMMARY: .planning/phases/01-foundation/01-05-SUMMARY.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
kevin-asprec
2026-03-04 19:08:38 +08:00
parent 25a12effb0
commit 9d8c45ce10
2 changed files with 171 additions and 14 deletions

View File

@@ -5,33 +5,33 @@
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:** Phase 1 - Foundation
**Current focus:** Phase 2 - Billing/Accounting
## Current Position
Phase: 1 of 5 (Foundation)
Plan: 4 of 5 in current phase
Status: In progress
Last activity: 2026-03-04 — Completed 01-04-PLAN.md (CASL RBAC, 5-role permission matrix, API middleware, 66 tests)
Phase: 1 of 5 (Foundation) — COMPLETE
Plan: 5 of 5 in phase 1 complete
Status: Phase 1 complete. Ready for Phase 2.
Last activity: 2026-03-04 — Completed 01-05-PLAN.md (super-admin panel, tenant management, 93 tests)
Progress: [████░░░░░] 20% (4/20 plans across all phases)
Progress: [████░░░░░] 25% (5/20 plans across all phases)
## Performance Metrics
**Velocity:**
- Total plans completed: 4
- Average duration: 8.75 min
- Total execution time: 35 min
- Total plans completed: 5
- Average duration: 8.2 min
- Total execution time: 41 min
**By Phase:**
| Phase | Plans | Total | Avg/Plan |
|-------|-------|-------|----------|
| 01-foundation | 4/5 complete | 35 min | 8.75 min |
| 01-foundation | 5/5 complete | 41 min | 8.2 min |
**Recent Trend:**
- Last 5 plans: 01-01 (11 min), 01-02 (8 min), 01-03 (9 min), 01-04 (7 min)
- Trend: stable at ~8-9 min/plan
- Last 5 plans: 01-01 (11 min), 01-02 (8 min), 01-03 (9 min), 01-04 (7 min), 01-05 (6 min)
- Trend: gradually accelerating (11 → 6 min)
*Updated after each plan completion*
@@ -64,6 +64,10 @@ Recent decisions affecting current work:
- [01-04]: Condition objects cast via any for string subjects — CASL infers MongoQuery<never> for strings; tighten when Prisma models defined in Phase 2+
- [01-04]: Technician can("read", "Subscriber") coarse-grained — data layer enforces actual scope to assigned job contacts only
- [01-04]: withPermission() HOF wraps Next.js route handlers; authorize() as convenience alias
- [01-05]: withSuperAdmin() implemented as standalone HOF (not via CASL) — super-admin access is binary, not permission-based
- [01-05]: Next.js 15 route params wrapped in Promise<P> — HOF awaits params before passing to handler
- [01-05]: subscriberCount hardcoded to 0 in admin API — Subscriber model added in Phase 2; API shape is forward-compatible
- [01-05]: Dual guard strategy for /admin: middleware.ts (JWT edge), layout.tsx (server), API handlers (endpoint) — three defense-in-depth layers
### Pending Todos
@@ -74,9 +78,10 @@ None.
- [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)
- [01-04 note]: CASL condition types for string subjects use any cast — upgrade to class-based subjects when Phase 2 Prisma models (Subscriber, Invoice, etc.) are defined
- [01-05 note]: /admin/tenants/[id] detail page is a stub link ("View") — detail view not implemented yet (out of Phase 1 scope)
## Session Continuity
Last session: 2026-03-04T10:57:37Z
Stopped at: Completed 01-04-PLAN.md (CASL RBAC + 5-role permission matrix + API middleware + 66 tests)
Last session: 2026-03-04T11:07:04Z
Stopped at: Completed 01-05-PLAN.md (super-admin panel + tenant management + 93 total tests)
Resume file: None

View File

@@ -0,0 +1,152 @@
---
phase: 01-foundation
plan: 05
subsystem: auth
tags: [super-admin, next-auth, prisma, next.js, tailwind, vitest, rbac, multi-tenant]
requires:
- phase: 01-04
provides: "CASL RBAC with withPermission() middleware pattern (super-admin is parallel middleware)"
- phase: 01-02
provides: "getCurrentUser() from session, isSuperAdmin in JWT token"
- phase: 01-01
provides: "Tenant schema with status/suspendedAt/gracePeriodEndsAt fields"
provides:
- "withSuperAdmin() HOF middleware guard (parallel to withPermission, no CASL needed)"
- "GET /api/admin/tenants — lists all tenants with userCount, subscriberCount=0"
- "GET /api/admin/tenants/[id] — tenant detail with users list"
- "POST /api/admin/tenants/[id]/suspend — suspend (PENDING_SUSPENSION + 7-day grace) or activate"
- "(super-admin)/layout.tsx — server guard + sidebar nav for /admin/* routes"
- "/admin dashboard with total/active/suspended counts"
- "/admin/tenants table with status badges, suspend/activate actions"
- "middleware.ts updated: /admin/* requires isSuperAdmin in JWT token"
- "93 total tests passing across all Phase 1 test files"
- "Second demo tenant (Test ISP 2 + admin2@demo.com) added to seed for isolation tests"
affects:
- "02-billing: super-admin API pattern for platform-level views"
- "All phases: withSuperAdmin() is the reference guard for platform endpoints"
tech-stack:
added: []
patterns:
- "withSuperAdmin(handler) HOF — mirrors withPermission() but uses isSuperAdmin instead of CASL"
- "Super-admin layout as server component with getCurrentUser() redirect guard"
- "Client component tenant table with optimistic refresh after suspend/activate actions"
- "Next.js 15 dynamic route params resolved with Promise<P> await in HOF"
key-files:
created:
- src/lib/middleware/super-admin.ts
- src/app/api/admin/tenants/route.ts
- src/app/api/admin/tenants/[id]/route.ts
- src/app/api/admin/tenants/[id]/suspend/route.ts
- src/app/(super-admin)/layout.tsx
- src/app/(super-admin)/admin/page.tsx
- src/app/(super-admin)/admin/tenants/page.tsx
- src/lib/__tests__/super-admin.test.ts
modified:
- prisma/seed.ts
- src/middleware.ts
key-decisions:
- "withSuperAdmin() implemented as standalone HOF (not via CASL) — super-admin access is binary, not permission-based"
- "Next.js 15 route params wrapped in Promise<P> — HOF awaits params before passing to handler"
- "Tenant table page is a client component — requires useEffect + fetch for suspend/activate interactivity"
- "Admin dashboard page fetches /api/admin/tenants via server-side fetch with forwarded session cookie"
- "subscriberCount hardcoded to 0 — Subscriber model added in Phase 2; API shape is forward-compatible"
- "middleware.ts redirects non-super-admin to /login on /admin/* paths — layout provides second guard layer"
patterns-established:
- "Super-admin API routes: always wrap with withSuperAdmin() — never withPermission()"
- "Dynamic route HOFs: use generic type parameter <P = Record<string, string>> for type-safe params"
- "Super-admin UI: server layout guards redirect, client pages fetch /api/admin/* endpoints"
duration: 6min
completed: 2026-03-04
---
# Phase 1 Plan 5: Super-Admin Panel Summary
**withSuperAdmin() middleware + /admin tenant management UI + 93 tests validating full Phase 1 foundation (auth, RBAC, tenant isolation, super-admin)**
## Performance
- **Duration:** 6 min
- **Started:** 2026-03-04T11:01:34Z
- **Completed:** 2026-03-04T11:07:04Z
- **Tasks:** 2
- **Files modified:** 10
## Accomplishments
- withSuperAdmin() HOF middleware guard that checks isSuperAdmin from JWT session (returns 401/403 otherwise)
- Full admin API: list all tenants, get tenant detail, suspend/activate with 7-day grace period
- /admin/* UI panel: server-guarded layout, dashboard stats, tenant table with status badges and action buttons
- 93 tests passing across all Phase 1 test files (auth 8, RBAC 66, tenant isolation 6, super-admin 11, setup 2)
- Second demo tenant (Test ISP 2 + admin2@demo.com) added to seed for cross-tenant isolation testing
## Task Commits
Each task was committed atomically:
1. **Task 1: Super-admin API routes and middleware guard** - `df40eae` (feat)
2. **Task 2: Super-admin UI panel and comprehensive test harness** - `25a12ef` (feat)
**Plan metadata:** _(docs commit follows)_
## Files Created/Modified
- `src/lib/middleware/super-admin.ts` - withSuperAdmin() HOF: 401 if no session, 403 if not isSuperAdmin
- `src/app/api/admin/tenants/route.ts` - GET all tenants with userCount, sorted by createdAt desc
- `src/app/api/admin/tenants/[id]/route.ts` - GET single tenant detail with users list
- `src/app/api/admin/tenants/[id]/suspend/route.ts` - POST suspend (PENDING_SUSPENSION + grace) or activate
- `src/app/(super-admin)/layout.tsx` - Server guard + sidebar nav (Dashboard, Tenants) + sign out
- `src/app/(super-admin)/admin/page.tsx` - Dashboard: total/active/pending/suspended counts
- `src/app/(super-admin)/admin/tenants/page.tsx` - Tenant table with status badges + suspend/activate buttons
- `src/lib/__tests__/super-admin.test.ts` - 11 tests: middleware guard (401/403/allow), suspension logic
- `prisma/seed.ts` - Added Test ISP 2 tenant + admin2@demo.com user
- `src/middleware.ts` - /admin/* requires isSuperAdmin in JWT token at edge middleware level
## Decisions Made
- **withSuperAdmin() as standalone HOF**: Super-admin access is binary (isSuperAdmin: true/false), not permission-based — using CASL for this would be over-engineering. Parallel pattern to withPermission() but simpler.
- **Next.js 15 params as Promise**: Route handler params in Next.js 15 can be a Promise. HOF awaits params before passing to handler for forward compatibility.
- **Client component for tenant table**: Suspend/activate interactivity requires useState + fetch. Server component for layout guard, client component for interactive table.
- **subscriberCount=0 placeholder**: Subscriber model is Phase 2. API shape is forward-compatible — clients can expect this field to grow.
- **Dual guard strategy**: middleware.ts provides JWT-level edge guard; layout.tsx provides server component guard; API handlers provide endpoint-level guard. Three layers for defense in depth.
## Deviations from Plan
None - plan executed exactly as written.
## Issues Encountered
None.
## User Setup Required
None - no external service configuration required.
## Next Phase Readiness
Phase 1 Foundation is complete. All requirements met:
- TENANT-01: Multi-tenant architecture with tenant isolation (01-03)
- TENANT-02: RBAC with 5-role permission matrix (01-04)
- TENANT-03: Super-admin can view/manage all tenants (01-05)
- AUTH-01: JWT sessions with NextAuth credentials provider (01-02)
- AUTH-02: Tenant-scoped email uniqueness (01-01)
- AUTH-03: Super-admin has no tenant scope (01-01, 01-02)
- AUTH-04: Grace period suspension (01-01, 01-05)
- INFRA-01: Docker PostgreSQL + Redis dev environment (01-01)
- INFRA-02: 93 unit/integration tests across auth, RBAC, isolation, super-admin (01-04, 01-05)
Phase 2 (Billing/Accounting) can begin. Relevant handoffs:
- Subscriber model will use tenantId from same schema pattern as User
- JournalEntryService COA structure defined in Phase 2 (cannot retrofit)
- CASL string subject casts (any) should be upgraded to class-based subjects when Prisma models are defined
---
*Phase: 01-foundation*
*Completed: 2026-03-04*