Files
NetForge/.planning/phases/05-visibility-and-client-portal/05-04-PLAN.md
kevin-asprec ea58620c7d docs(05): create phase plan
Phase 05: Visibility and Client Portal
- 5 plans in 3 waves
- 2 parallel (wave 1), 1 sequential (wave 2), 2 parallel (wave 3)
- Ready for execution

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

142 lines
5.4 KiB
Markdown

---
phase: 05-visibility-and-client-portal
plan: 04
type: execute
wave: 3
depends_on: ["05-01", "05-02", "05-03"]
files_modified:
- src/lib/__tests__/integration/api-rbac.test.ts
autonomous: true
must_haves:
truths:
- "All API endpoints return 401 for unauthenticated requests"
- "Role-restricted endpoints return 403 for unauthorized roles"
- "Tenant A data is never returned to Tenant B users"
- "COLLECTOR cannot access billing or subscriber management write endpoints"
- "TECHNICIAN cannot access payment or invoice endpoints"
- "CLIENT role can only read their own data"
artifacts:
- path: "src/lib/__tests__/integration/api-rbac.test.ts"
provides: "Comprehensive API RBAC integration tests"
min_lines: 200
key_links:
- from: "src/lib/__tests__/integration/api-rbac.test.ts"
to: "src/lib/middleware/authorize.ts"
via: "tests verify withPermission enforcement"
pattern: "withPermission|401|403"
---
<objective>
Create integration tests that verify API-layer RBAC enforcement across all endpoints, including unauthorized access assertions and two-tenant cross-contamination tests.
Purpose: INFRA-03 — prove that the authorization layer cannot be bypassed at the API level.
Output: Comprehensive integration test suite covering all roles and endpoints.
</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/STATE.md
@src/lib/middleware/authorize.ts
@src/lib/casl/permissions.ts
@src/lib/casl/types.ts
@src/middleware.ts
</context>
<tasks>
<task type="auto">
<name>Task 1: API RBAC integration test suite</name>
<files>src/lib/__tests__/integration/api-rbac.test.ts</files>
<action>
Create a comprehensive integration test file that tests API-layer authorization. Since Next.js API routes cannot be easily called via HTTP in test mode without starting the server, test at the SERVICE + MIDDLEWARE layer instead — test the withPermission HOF behavior and service-level tenant isolation.
**Approach:** Test the authorization logic directly by:
1. Creating users with different roles in the test database
2. Calling service methods with different tenant contexts
3. Verifying CASL ability checks for each role against each subject
**Test structure:**
```
describe("API RBAC Integration Tests")
describe("Authentication (401)")
- Verify getCurrentUser returns null for no session -> would produce 401
- Verify withPermission returns 401 when no user (mock getCurrentUser to return null)
describe("Authorization by Role (403)")
For each role, test what they CAN and CANNOT access:
describe("ADMIN")
- Can access all subjects (manage all)
describe("OFFICE_STAFF")
- Can manage Subscriber, Invoice, Payment, Ticket, JobOrder, Inventory, Expense, Vendor
- Can read Report, Account
- CANNOT create/update/delete Account
describe("COLLECTOR")
- Can read Subscriber, Zone
- Can create Payment, read Payment
- CANNOT read Report, manage Invoice, manage Subscriber, manage Ticket
describe("TECHNICIAN")
- Can read/update JobOrder (own only)
- Can read Subscriber, read Inventory (own only)
- CANNOT manage Payment, Invoice, Report, Ticket
describe("CLIENT")
- Can read Invoice (own), Payment (own), Subscriber (own)
- Can create Ticket, read Ticket (own)
- CANNOT manage User, read Report, manage Subscriber
describe("Tenant Isolation")
- Create Tenant A and Tenant B with subscribers, invoices, payments
- Using Tenant A's context, query subscribers -> returns ONLY Tenant A data
- Using Tenant B's context, query subscribers -> returns ONLY Tenant B data
- Cross-query: Tenant A's subscriber ID passed to Tenant B context -> returns null or throws
- Verify: invoice created in Tenant A is invisible to Tenant B
- Verify: payment recorded in Tenant A is invisible to Tenant B
```
**Implementation details:**
- Use `defineAbilityFor` and `definePermissionsFor` directly to test CASL rules
- Use `withTenantContext` to create tenant-scoped Prisma clients for isolation tests
- Use real database with actual tenant/user/subscriber records
- Test at least 5 role combinations with at least 3 subjects each = 15+ assertions
- Test at least 3 cross-tenant scenarios
**Cleanup order:** Follow the most comprehensive pattern (expense report cleanup from 04-04) since we create data across multiple subsystems.
Minimum test count: 15+ tests across all describe blocks.
</action>
<verify>`npx vitest run src/lib/__tests__/integration/api-rbac.test.ts` — all tests pass</verify>
<done>All 5 roles tested against all relevant subjects; cross-tenant isolation verified with real data; 15+ tests pass; INFRA-03 satisfied</done>
</task>
</tasks>
<verification>
- `npx vitest run src/lib/__tests__/integration/api-rbac.test.ts` — all tests pass
- Every role's can/cannot boundaries are explicitly tested
- Two-tenant cross-contamination test proves data isolation
</verification>
<success_criteria>
- 15+ integration tests covering all 5 roles
- Unauthorized access assertions prove RBAC enforcement
- Two-tenant isolation tests prove no cross-contamination
- INFRA-03 requirement satisfied
</success_criteria>
<output>
After completion, create `.planning/phases/05-visibility-and-client-portal/05-04-SUMMARY.md`
</output>