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>
223 lines
10 KiB
Markdown
223 lines
10 KiB
Markdown
---
|
|
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>
|