docs(01): create phase plan
Phase 01: Foundation - 5 plan(s) in 4 wave(s) - 2 parallel (wave 2: auth + tenant provisioning), 3 sequential - Ready for execution Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
222
.planning/phases/01-foundation/01-05-PLAN.md
Normal file
222
.planning/phases/01-foundation/01-05-PLAN.md
Normal file
@@ -0,0 +1,222 @@
|
||||
---
|
||||
phase: 01-foundation
|
||||
plan: 05
|
||||
type: execute
|
||||
wave: 4
|
||||
depends_on: ["01-04"]
|
||||
files_modified:
|
||||
- src/app/(super-admin)/layout.tsx
|
||||
- src/app/(super-admin)/admin/page.tsx
|
||||
- src/app/(super-admin)/admin/tenants/page.tsx
|
||||
- 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/lib/middleware/super-admin.ts
|
||||
- prisma/seed.ts
|
||||
- src/lib/__tests__/super-admin.test.ts
|
||||
- src/lib/__tests__/tenant-isolation.test.ts
|
||||
autonomous: true
|
||||
|
||||
must_haves:
|
||||
truths:
|
||||
- "Super-admin can log in and view all tenants without being scoped to any single tenant"
|
||||
- "Super-admin can see tenant status, creation date, and subscriber count for each tenant"
|
||||
- "Super-admin can suspend a tenant with a grace period"
|
||||
- "Super-admin cannot access tenant-scoped data (no impersonation)"
|
||||
- "Non-super-admin users cannot access the admin panel"
|
||||
- "Test harness validates core isolation and auth behaviors"
|
||||
artifacts:
|
||||
- path: "src/app/(super-admin)/admin/tenants/page.tsx"
|
||||
provides: "Tenant management list UI"
|
||||
min_lines: 40
|
||||
- path: "src/app/api/admin/tenants/route.ts"
|
||||
provides: "List all tenants API"
|
||||
exports: ["GET"]
|
||||
- path: "src/app/api/admin/tenants/[id]/suspend/route.ts"
|
||||
provides: "Tenant suspension API"
|
||||
exports: ["POST"]
|
||||
- path: "src/lib/middleware/super-admin.ts"
|
||||
provides: "Super-admin route guard"
|
||||
exports: ["withSuperAdmin"]
|
||||
- path: "src/lib/__tests__/super-admin.test.ts"
|
||||
provides: "Super-admin access and tenant management tests"
|
||||
min_lines: 40
|
||||
key_links:
|
||||
- from: "src/app/api/admin/tenants/route.ts"
|
||||
to: "src/lib/middleware/super-admin.ts"
|
||||
via: "withSuperAdmin guard on route"
|
||||
pattern: "withSuperAdmin"
|
||||
- from: "src/app/(super-admin)/admin/tenants/page.tsx"
|
||||
to: "src/app/api/admin/tenants/route.ts"
|
||||
via: "fetch tenant list"
|
||||
pattern: "fetch.*api/admin/tenants"
|
||||
- from: "src/lib/middleware/super-admin.ts"
|
||||
to: "src/lib/auth.ts"
|
||||
via: "Checks isSuperAdmin from session"
|
||||
pattern: "isSuperAdmin"
|
||||
---
|
||||
|
||||
<objective>
|
||||
Implement the super-admin panel: a separate auth context for platform-level management, tenant listing with status/metrics, tenant suspension with grace period, and the consolidated test harness proving all Phase 1 behaviors work together.
|
||||
|
||||
Purpose: The platform owner needs to manage ISP tenants (view, suspend, monitor) without being scoped to any single tenant. This closes the super-admin requirement and validates the entire foundation with comprehensive tests.
|
||||
Output: Working super-admin panel with tenant management, plus full test suite covering auth, isolation, and RBAC.
|
||||
</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/phases/01-foundation/01-CONTEXT.md
|
||||
@.planning/phases/01-foundation/01-02-SUMMARY.md
|
||||
@.planning/phases/01-foundation/01-03-SUMMARY.md
|
||||
@.planning/phases/01-foundation/01-04-SUMMARY.md
|
||||
@src/lib/auth-options.ts
|
||||
@src/lib/casl/ability.ts
|
||||
@src/lib/prisma-tenant.ts
|
||||
@prisma/schema.prisma
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Super-admin API routes and middleware guard</name>
|
||||
<files>
|
||||
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
|
||||
prisma/seed.ts
|
||||
</files>
|
||||
<action>
|
||||
Create `src/lib/middleware/super-admin.ts`:
|
||||
- Export `withSuperAdmin(handler)` — wraps an API route handler
|
||||
- Gets current user session via getCurrentUser()
|
||||
- If no session: return 401
|
||||
- If session.user.isSuperAdmin is not true: return 403 { error: "Super-admin access required" }
|
||||
- If authorized: call handler with user context
|
||||
|
||||
Create `src/app/api/admin/tenants/route.ts`:
|
||||
- GET handler wrapped with withSuperAdmin
|
||||
- Queries ALL tenants (no tenant scoping — super-admin sees everything)
|
||||
- Returns array of: { id, name, slug, status, ownerEmail, createdAt, userCount, subscriberCount (0 for now — no Subscriber model yet) }
|
||||
- userCount: count of users per tenant via Prisma _count
|
||||
- Sort by createdAt descending
|
||||
|
||||
Create `src/app/api/admin/tenants/[id]/route.ts`:
|
||||
- GET handler wrapped with withSuperAdmin
|
||||
- Returns single tenant detail: all fields plus users list (id, email, firstName, lastName, roles, isActive)
|
||||
- Return 404 if tenant not found
|
||||
|
||||
Create `src/app/api/admin/tenants/[id]/suspend/route.ts`:
|
||||
- POST handler wrapped with withSuperAdmin
|
||||
- Accepts JSON body: { action: "suspend" | "activate" }
|
||||
- For suspend:
|
||||
- Set status to PENDING_SUSPENSION
|
||||
- Set suspendedAt to now()
|
||||
- Set gracePeriodEndsAt to 7 days from now
|
||||
- Return { message: "Tenant suspension initiated. Grace period ends on {date}." }
|
||||
- For activate:
|
||||
- Set status to ACTIVE
|
||||
- Clear suspendedAt and gracePeriodEndsAt
|
||||
- Return { message: "Tenant activated." }
|
||||
- Return 404 if tenant not found
|
||||
|
||||
Update `prisma/seed.ts`:
|
||||
- Add a second demo tenant: "Test ISP 2" with a different admin user (admin2@demo.com) for testing cross-tenant isolation
|
||||
- Keep existing demo tenant and super-admin user
|
||||
</action>
|
||||
<verify>
|
||||
Run `npm run db:seed` — seed runs cleanly with both tenants. Start the app. Use curl or an API client to:
|
||||
1. GET /api/admin/tenants without auth — expect 401
|
||||
2. Log in as super-admin, GET /api/admin/tenants — expect 200 with both tenants
|
||||
3. POST /api/admin/tenants/{id}/suspend with { action: "suspend" } — expect tenant status changes to PENDING_SUSPENSION
|
||||
</verify>
|
||||
<done>Super-admin API routes list all tenants and can suspend/activate them. withSuperAdmin middleware blocks non-super-admin access with 403. Grace period suspension works.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Super-admin UI panel and comprehensive test harness</name>
|
||||
<files>
|
||||
src/app/(super-admin)/layout.tsx
|
||||
src/app/(super-admin)/admin/page.tsx
|
||||
src/app/(super-admin)/admin/tenants/page.tsx
|
||||
src/middleware.ts
|
||||
src/lib/__tests__/super-admin.test.ts
|
||||
src/lib/__tests__/tenant-isolation.test.ts
|
||||
</files>
|
||||
<action>
|
||||
Create `src/app/(super-admin)/layout.tsx`:
|
||||
- Server component that checks session
|
||||
- If user is not super-admin, redirect to /login or show 403 page
|
||||
- Simple layout with sidebar navigation: "Dashboard", "Tenants"
|
||||
- Header shows "NetForge Admin" and the super-admin's name
|
||||
- Sign out button
|
||||
|
||||
Create `src/app/(super-admin)/admin/page.tsx`:
|
||||
- Simple admin dashboard showing: total tenants, active tenants, suspended tenants
|
||||
- Fetches stats from /api/admin/tenants
|
||||
|
||||
Create `src/app/(super-admin)/admin/tenants/page.tsx`:
|
||||
- Table listing all tenants: Name, Status (badge with color: green=Active, yellow=Pending Suspension, red=Suspended), Owner Email, Users, Created Date
|
||||
- Each row has actions: View details, Suspend/Activate toggle button
|
||||
- Suspend button triggers confirmation dialog then calls the suspend API
|
||||
- Activate button calls the suspend API with action: "activate"
|
||||
- Clicking tenant name navigates to a detail view (or opens a modal showing users)
|
||||
- Use Tailwind for styling — clean data table with hover states
|
||||
|
||||
Update `src/middleware.ts`:
|
||||
- Add /admin/* routes to be protected
|
||||
- These routes should check for super-admin status specifically (or rely on the layout redirect + API guards)
|
||||
- Public routes remain: /login, /signup, /api/auth/*
|
||||
|
||||
Create `src/lib/__tests__/super-admin.test.ts`:
|
||||
- Test: super-admin user can access admin routes (withSuperAdmin allows)
|
||||
- Test: regular admin user cannot access admin routes (withSuperAdmin returns 403)
|
||||
- Test: tenant suspension sets correct status and grace period dates
|
||||
- Test: tenant activation clears suspension fields
|
||||
|
||||
Enhance `src/lib/__tests__/tenant-isolation.test.ts` (if needed):
|
||||
- Ensure the existing cross-tenant isolation test still passes with the two-tenant seed data
|
||||
- Add test: super-admin query for tenants returns ALL tenants (not scoped)
|
||||
- Add test: regular user query does NOT return other tenants' data
|
||||
|
||||
Run full test suite: `npx vitest run` — all tests must pass.
|
||||
</action>
|
||||
<verify>
|
||||
Run `npx vitest run` — all tests pass (auth, RBAC, tenant isolation, super-admin). Start the app, log in as superadmin@netforge.com, navigate to /admin/tenants — see both demo tenants listed. Suspend a tenant — status badge updates. Activate it — status reverts. Log in as admin@demo.com — navigating to /admin returns forbidden.
|
||||
</verify>
|
||||
<done>Super-admin can log in and manage all tenants via /admin panel (TENANT-03). Non-super-admin users are blocked from admin routes. Full test harness covers auth, RBAC, tenant isolation, and super-admin access. Phase 1 success criteria are met.</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
1. Super-admin logs in and sees tenant list at /admin/tenants
|
||||
2. Tenant table shows status, owner, user count, creation date
|
||||
3. Suspend action sets PENDING_SUSPENSION with 7-day grace period
|
||||
4. Activate action restores ACTIVE status
|
||||
5. Regular admin user gets 403 when accessing /admin routes
|
||||
6. `npx vitest run` passes ALL tests across the entire phase:
|
||||
- Auth config tests
|
||||
- RBAC permission tests for all 5 roles
|
||||
- Tenant isolation tests (zero cross-tenant leakage)
|
||||
- Super-admin access tests
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- Super-admin can log in and view all tenants (TENANT-03)
|
||||
- Super-admin sees tenant status, user count, creation date per tenant
|
||||
- Tenant suspension with grace period works (not immediate lockout)
|
||||
- Non-super-admin blocked from admin panel
|
||||
- Full test suite validates Phase 1 foundation (INFRA-02 partial — unit tests for auth/RBAC/isolation)
|
||||
- All Phase 1 requirements met: TENANT-01, TENANT-02, TENANT-03, AUTH-01, AUTH-02, AUTH-03, AUTH-04, INFRA-01, INFRA-02
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/01-foundation/01-05-SUMMARY.md`
|
||||
</output>
|
||||
Reference in New Issue
Block a user