- PRD: docs/PRD-MS21.md (43 scope items across 6 phases) - Mission init via mosaic coord - TASKS.md: 31 tasks across 6 milestones - Orchestrator: Jarvis (OpenClaw hybrid orchestration) Refs: MS21-PLAN-001
247 lines
14 KiB
Markdown
247 lines
14 KiB
Markdown
# PRD: MS21 — Multi-Tenant Platform, RBAC Enforcement, and Data Migration
|
|
|
|
## Metadata
|
|
|
|
- Owner: Jason Woltje
|
|
- Orchestrator: Jarvis (OpenClaw)
|
|
- Date: 2026-02-28
|
|
- Status: in-progress
|
|
- Version: 0.0.21
|
|
|
|
## Problem Statement
|
|
|
|
Mosaic Stack is a single-user deployment. The Workspace, Team, WorkspaceMember, and RBAC infrastructure exist in the schema and codebase (PermissionGuard, WorkspaceGuard, roles: OWNER/ADMIN/MEMBER/GUEST), but there is no admin UI for managing users, workspaces, or teams. There is no invitation flow, no user management page, and no break-glass authentication mechanism for emergency access without OIDC. Additionally, the platform has no real operational data — jarvis-brain contains 106 projects and 95 tasks that need migrating into Mosaic Stack to make the dashboard, kanban, and project pages useful.
|
|
|
|
## Objectives
|
|
|
|
1. Build admin UI for user management (list, invite, deactivate, assign roles)
|
|
2. Build workspace management UI (create, configure, manage members)
|
|
3. Build team management UI (create teams within workspaces, assign members)
|
|
4. Implement user invitation flow (email or link-based)
|
|
5. Implement break-glass local authentication (bypass OIDC for emergency access)
|
|
6. Enforce RBAC across all UI surfaces (show/hide based on role)
|
|
7. Build admin Settings pages for workspace and platform configuration
|
|
8. Migrate jarvis-brain data (95 tasks, 106 projects) into Mosaic Stack PostgreSQL
|
|
9. Build data import API endpoint for bulk task/project creation
|
|
|
|
## Completed Work
|
|
|
|
### Existing Infrastructure (Already Built)
|
|
|
|
| Component | Status | Location |
|
|
| ----------------------------------------------------------------- | -------- | ------------------------------------------------------- |
|
|
| Prisma models: User, Workspace, WorkspaceMember, Team, TeamMember | Complete | apps/api/prisma/schema.prisma |
|
|
| WorkspaceMemberRole enum (OWNER, ADMIN, MEMBER, GUEST) | Complete | schema.prisma |
|
|
| TeamMemberRole enum (OWNER, ADMIN, MEMBER) | Complete | schema.prisma |
|
|
| PermissionGuard with role hierarchy | Complete | apps/api/src/common/guards/permission.guard.ts |
|
|
| Permission decorator (@RequirePermission) | Complete | apps/api/src/common/decorators/permissions.decorator.ts |
|
|
| Permission enum (WORKSPACE_OWNER, ADMIN, MEMBER, ANY) | Complete | permissions.decorator.ts |
|
|
| WorkspaceGuard | Complete | apps/api/src/common/guards/workspace.guard.ts |
|
|
| RBAC applied to 18+ controllers | Complete | All resource controllers |
|
|
| Workspaces CRUD API | Complete | apps/api/src/workspaces/ |
|
|
| BetterAuth + Authentik OIDC | Complete | apps/api/src/auth/ |
|
|
| AdminGuard | Complete | apps/api/src/auth/guards/admin.guard.ts |
|
|
|
|
## Scope
|
|
|
|
### In Scope (MS21)
|
|
|
|
#### S1: Admin API Endpoints (Backend)
|
|
|
|
1. GET /api/admin/users — List all users with workspace memberships and roles
|
|
2. POST /api/admin/users/invite — Generate invitation (email or link)
|
|
3. PATCH /api/admin/users/:id — Update user metadata (deactivate, change global role)
|
|
4. DELETE /api/admin/users/:id — Deactivate user (soft delete, preserve data)
|
|
5. POST /api/admin/workspaces — Create workspace with owner assignment
|
|
6. PATCH /api/admin/workspaces/:id — Update workspace settings
|
|
7. POST /api/workspaces/:id/members — Add member to workspace with role
|
|
8. PATCH /api/workspaces/:id/members/:userId — Change member role
|
|
9. DELETE /api/workspaces/:id/members/:userId — Remove member from workspace
|
|
10. POST /api/workspaces/:id/teams — Create team within workspace
|
|
11. POST /api/workspaces/:id/teams/:teamId/members — Add member to team
|
|
12. DELETE /api/workspaces/:id/teams/:teamId/members/:userId — Remove from team
|
|
13. POST /api/import/tasks — Bulk import tasks from jarvis-brain format
|
|
14. POST /api/import/projects — Bulk import projects from jarvis-brain format
|
|
|
|
#### S2: Break-Glass Authentication
|
|
|
|
15. Add isLocalAuth boolean field to User model (Prisma migration)
|
|
16. Add passwordHash optional field to User model (for local auth users)
|
|
17. Implement /api/auth/local/login endpoint (email + password, bcrypt)
|
|
18. Implement /api/auth/local/setup endpoint (first-time break-glass user creation, requires admin token from env)
|
|
19. Break-glass user bypasses OIDC entirely — session-based auth via BetterAuth
|
|
20. Environment variable BREAKGLASS_SETUP_TOKEN controls initial setup access
|
|
|
|
#### S3: Admin UI Pages (Frontend)
|
|
|
|
21. /settings/users — User management page (table: name, email, role, status, workspaces, last login)
|
|
22. User detail/edit dialog (change role, deactivate, view workspace memberships)
|
|
23. Invite user dialog (email input, workspace selection, role selection)
|
|
24. /settings/workspaces — Workspace management page (list workspaces, member counts)
|
|
25. Workspace detail page (members list, team list, settings)
|
|
26. Add/remove workspace member dialog with role picker
|
|
27. /settings/teams — Team management within workspace context
|
|
28. Create team dialog, add/remove team members
|
|
|
|
#### S4: RBAC UI Enforcement
|
|
|
|
29. Navigation sidebar: show/hide admin items based on user role
|
|
30. Settings pages: restrict access to admin-only pages
|
|
31. Action buttons: disable/hide create/delete based on permission level
|
|
32. User profile: show current role and workspace memberships
|
|
|
|
#### S5: Data Migration
|
|
|
|
33. Build scripts/migrate-brain.ts — TypeScript migration script
|
|
34. Read jarvis-brain data/tasks/\*.json (v2.0 format: { version, domain, tasks: [...] })
|
|
35. Read jarvis-brain data/projects/\*.json (format: { version, project: {...}, tasks: [...] })
|
|
36. Map brain status to Mosaic TaskStatus (done->COMPLETED, in-progress->IN_PROGRESS, backlog/pending/scheduled/not-started/planned->NOT_STARTED, blocked/on-hold->PAUSED, cancelled->ARCHIVED)
|
|
37. Map brain priority to Mosaic TaskPriority (critical/high->HIGH, medium->MEDIUM, low->LOW)
|
|
38. Create Domain records for unique domains (work, homelab, finances, family, etc.)
|
|
39. Create Project records from project data, linking to domains
|
|
40. Create Task records linking to projects, preserving brain-specific fields in metadata JSON
|
|
41. Preserve blocks, blocked_by, repo, branch, current_milestone, notes in task/project metadata
|
|
42. Dry-run mode with validation report before actual import
|
|
43. Idempotent — skip records that already exist (match by metadata.brainId)
|
|
|
|
### Out of Scope
|
|
|
|
- Federation (MS22)
|
|
- Agent task mapping and telemetry (MS23)
|
|
- Playwright E2E tests (MS24)
|
|
- Email delivery service (invitations stored as links for now)
|
|
- User self-registration (admin-only invitation model)
|
|
|
|
## User/Stakeholder Requirements
|
|
|
|
1. Jason (admin) can invite Melanie to a shared workspace
|
|
2. Jason can create a "USC IT" workspace and invite employees
|
|
3. Each user sees only their workspace(s) data
|
|
4. Break-glass user can log in without Authentik being available
|
|
5. Admin pages are only visible to OWNER/ADMIN roles
|
|
6. Data from jarvis-brain appears in the dashboard, kanban, and project pages after migration
|
|
7. All existing tests continue to pass after changes
|
|
|
|
## Functional Requirements
|
|
|
|
### FR-001: Admin User Management API
|
|
|
|
- AdminGuard protects all /api/admin/\* routes
|
|
- List users returns: id, name, email, emailVerified, createdAt, workspace memberships with roles
|
|
- Invite creates a User record with a pending invitation token
|
|
- Deactivate sets a deactivatedAt timestamp (new field), does not delete data
|
|
- ASSUMPTION: User deactivation is soft-delete via new deactivatedAt field on User model. Rationale: Hard delete would cascade and destroy workspace data.
|
|
|
|
### FR-002: Workspace Member Management API
|
|
|
|
- Add member requires WORKSPACE_ADMIN or WORKSPACE_OWNER permission
|
|
- Role changes require equal or higher permission (MEMBER cannot promote to ADMIN)
|
|
- Cannot remove the last OWNER of a workspace
|
|
- Cannot change own role to lower than OWNER if sole owner
|
|
|
|
### FR-003: Break-Glass Authentication
|
|
|
|
- Local auth is opt-in per deployment via ENABLE_LOCAL_AUTH=true env var
|
|
- Break-glass setup requires a one-time setup token from environment
|
|
- Password stored as bcrypt hash, minimum 12 characters
|
|
- Break-glass user gets OWNER role on default workspace
|
|
- Session management identical to OIDC users (BetterAuth session tokens)
|
|
- ASSUMPTION: BetterAuth supports custom credential providers alongside OIDC. Rationale: BetterAuth documentation confirms credential-based auth as a built-in feature.
|
|
|
|
### FR-004: Admin UI
|
|
|
|
- User management table with search, sort, filter by role/status
|
|
- Inline role editing via dropdown
|
|
- Confirmation dialog for destructive actions (deactivate user, remove from workspace)
|
|
- PDA-friendly language: "Deactivate" not "Delete", "Pending" not "Expired"
|
|
- Responsive design matching existing Settings page patterns
|
|
- Dark/light theme support via existing design token system
|
|
|
|
### FR-005: Data Migration Script
|
|
|
|
- Standalone TypeScript script in scripts/migrate-brain.ts
|
|
- Reads from jarvis-brain path (configurable via --brain-path flag)
|
|
- Connects to Mosaic Stack database via DATABASE_URL
|
|
- Requires target workspace ID (--workspace-id flag)
|
|
- Requires creator user ID (--user-id flag)
|
|
- Outputs validation report before writing (dry-run by default)
|
|
- --apply flag to execute the migration
|
|
- Creates Activity log entries for all imported records
|
|
|
|
## Technical Design
|
|
|
|
### Schema Changes (Prisma Migration)
|
|
|
|
Add to User model:
|
|
|
|
- deactivatedAt DateTime? (soft delete)
|
|
- isLocalAuth Boolean default(false)
|
|
- passwordHash String? (bcrypt hash for local auth)
|
|
- invitedBy String? Uuid (FK to inviting user)
|
|
- invitationToken String? unique
|
|
- invitedAt DateTime?
|
|
|
|
### New NestJS Module: AdminModule
|
|
|
|
Location: apps/api/src/admin/
|
|
Files: admin.module.ts, admin.controller.ts, admin.service.ts, DTOs, specs
|
|
|
|
### New NestJS Module: LocalAuthModule (Break-Glass)
|
|
|
|
Location: apps/api/src/auth/local/
|
|
Files: local-auth.controller.ts, local-auth.service.ts, DTOs, specs
|
|
|
|
### Frontend Pages
|
|
|
|
Location: apps/web/app/(authenticated)/settings/
|
|
|
|
- users/page.tsx — User management
|
|
- workspaces/page.tsx — Workspace list
|
|
- workspaces/[id]/page.tsx — Workspace detail (members, teams)
|
|
- teams/page.tsx — Team management
|
|
|
|
## Testing and Verification
|
|
|
|
1. Baseline: pnpm lint && pnpm build && pnpm test must pass
|
|
2. Unit tests for AdminService (user CRUD, invitation flow, permission checks)
|
|
3. Unit tests for LocalAuthService (bcrypt hashing, token validation)
|
|
4. Unit tests for AdminController (route guards, DTO validation)
|
|
5. Integration test: invitation -> acceptance -> workspace access
|
|
6. Integration test: break-glass setup -> login -> workspace access
|
|
7. Integration test: RBAC prevents unauthorized role changes
|
|
8. Migration script test: dry-run produces valid report, apply creates correct records
|
|
9. Frontend: admin pages render with correct role gating
|
|
10. All 4,772+ existing tests continue to pass
|
|
|
|
## Quality Gates
|
|
|
|
pnpm lint && pnpm build && pnpm test
|
|
|
|
## Delivery Phases
|
|
|
|
| Phase | Focus | Tasks |
|
|
| ----------------------- | ----------------------------------------------------------------------- | ----------------- |
|
|
| P1: Schema + Admin API | Prisma migration, AdminModule, user/workspace/team management endpoints | S1 items 1-12 |
|
|
| P2: Break-Glass Auth | LocalAuthModule, credential provider, setup flow | S2 items 15-20 |
|
|
| P3: Data Migration | Migration script, jarvis-brain to PostgreSQL | S5 items 33-43 |
|
|
| P4: Admin UI | Settings pages for users, workspaces, teams | S3 items 21-28 |
|
|
| P5: RBAC UI Enforcement | Frontend permission gating, navigation filtering | S4 items 29-32 |
|
|
| P6: Verification | Full test pass, deployment, smoke test | All quality gates |
|
|
|
|
## Risks and Open Questions
|
|
|
|
1. Risk: BetterAuth credential provider may require specific adapter configuration. Mitigation: Review BetterAuth docs for credential auth alongside OIDC; test in isolation first.
|
|
2. Risk: Schema migration on production database. Mitigation: Use Prisma migration with --create-only for review before applying.
|
|
3. Risk: jarvis-brain data has fields that don't map 1:1 to Mosaic schema. Mitigation: Use metadata JSON field for overflow; validate with dry-run.
|
|
4. Open: Should deactivated users retain active sessions? ASSUMPTION: No, deactivation immediately invalidates all sessions. Rationale: Security best practice.
|
|
5. Open: Should break-glass user be auto-created on first deployment? ASSUMPTION: No, requires explicit setup via API with env token. Rationale: Prevents accidental exposure.
|
|
|
|
## Assumptions
|
|
|
|
1. User deactivation is soft-delete via deactivatedAt field. Hard delete cascades and destroys workspace data.
|
|
2. BetterAuth supports custom credential providers alongside OIDC.
|
|
3. Invitation flow uses link-based tokens (no email service required initially).
|
|
4. Break-glass auth is off by default, controlled by ENABLE_LOCAL_AUTH env var.
|
|
5. Migration script runs outside the API server as a standalone script.
|
|
6. Admin pages follow existing Settings page UI patterns (cards, tables, dialogs).
|