From eaaa9adfa5da39de07ce72b2b7c9a6279a91ae3c Mon Sep 17 00:00:00 2001 From: Schalli Date: Thu, 18 Jun 2026 13:42:00 +0200 Subject: [PATCH] docs(02-02): complete frontend auth and user/tenant CRUD plan --- .planning/REQUIREMENTS.md | 17 +- .planning/ROADMAP.md | 6 +- .planning/STATE.md | 20 +- .../02-02-SUMMARY.md | 203 ++++++++++++++++++ 4 files changed, 227 insertions(+), 19 deletions(-) create mode 100644 .planning/phases/02-authentication-multi-tenancy/02-02-SUMMARY.md diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index ef46537..89ed561 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -10,16 +10,16 @@ Requirements for initial release. Each maps to roadmap phases. ### Authentication & User Management - [ ] **AUTH-01**: Initialer Admin-Account wird beim Setup via Docker-ENV erstellt -- [ ] **AUTH-02**: Admin kann Benutzer manuell anlegen, bearbeiten und loeschen -- [ ] **AUTH-03**: Benutzer kann sich anmelden und abmelden -- [ ] **AUTH-04**: Benutzer-Session bleibt ueber Browser-Refresh bestehen +- [x] **AUTH-02**: Admin kann Benutzer manuell anlegen, bearbeiten und loeschen +- [x] **AUTH-03**: Benutzer kann sich anmelden und abmelden +- [x] **AUTH-04**: Benutzer-Session bleibt ueber Browser-Refresh bestehen - [ ] **AUTH-05**: Rollenbasierte Zugriffskontrolle (Admin, User) - [ ] **AUTH-06**: Benutzer koennen per LDAP/AD importiert werden ### Multi-Tenancy - [ ] **TNNT-01**: Daten sind per PostgreSQL Row-Level Security mandantengetrennt -- [ ] **TNNT-02**: Admin kann Mandanten anlegen und verwalten +- [x] **TNNT-02**: Admin kann Mandanten anlegen und verwalten - [ ] **TNNT-03**: Jeder Request wird automatisch dem richtigen Mandanten zugeordnet ### Portal Shell @@ -126,13 +126,13 @@ Which phases cover which requirements. Updated during roadmap creation. | Requirement | Phase | Status | |-------------|-------|--------| | AUTH-01 | Phase 2 | Pending | -| AUTH-02 | Phase 2 | Pending | -| AUTH-03 | Phase 2 | Pending | -| AUTH-04 | Phase 2 | Pending | +| AUTH-02 | Phase 2 | Complete | +| AUTH-03 | Phase 2 | Complete | +| AUTH-04 | Phase 2 | Complete | | AUTH-05 | Phase 2 | Pending | | AUTH-06 | Phase 2 | Pending | | TNNT-01 | Phase 2 | Pending | -| TNNT-02 | Phase 2 | Pending | +| TNNT-02 | Phase 2 | Complete | | TNNT-03 | Phase 2 | Pending | | PRTAL-01 | Phase 1 | Complete | | PRTAL-02 | Phase 4 | Pending | @@ -171,6 +171,7 @@ Which phases cover which requirements. Updated during roadmap creation. | DESK-02 | Phase 6 | Pending | **Coverage:** + - v1 requirements: 44 total - Mapped to phases: 44 - Unmapped: 0 diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 3902fb2..6c3acc0 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -69,11 +69,11 @@ Decimal phases appear between their surrounding integers in numeric order. **Wave 1** -- [ ] 02-01-PLAN.md -- Backend Auth Foundation: Prisma schema, RLS migration, JWT Passport auth, admin seed, tenant middleware +- [x] 02-01-PLAN.md -- Backend Auth Foundation: Prisma schema, RLS migration, JWT Passport auth, admin seed, tenant middleware **Wave 2** *(blocked on Wave 1 completion)* -- [ ] 02-02-PLAN.md -- Frontend Auth & CRUD: Login page, Next.js middleware, user/tenant management UI, auth-wired portal +- [x] 02-02-PLAN.md -- Frontend Auth & CRUD: Login page, Next.js middleware, user/tenant management UI, auth-wired portal - [ ] 02-03-PLAN.md -- Password Reset & Mail: SUS package verification, MailModule, password reset flow, force-change interceptor **Wave 3** *(blocked on Wave 2 completion)* @@ -158,7 +158,7 @@ Phases execute in numeric order: 1 -> 2 -> 3 -> 4 -> 5 -> 6 | Phase | Plans Complete | Status | Completed | |-------|----------------|--------|-----------| | 1. Foundation & Portal Shell | 2/3 | In Progress | - | -| 2. Authentication & Multi-Tenancy | 0/5 | Not started | - | +| 2. Authentication & Multi-Tenancy | 2/5 | In Progress| | | 3. Module System & Domaincheck | 0/TBD | Not started | - | | 4. Marketplace & Portal Navigation | 0/TBD | Not started | - | | 5. Dashboard & Calendar | 0/TBD | Not started | - | diff --git a/.planning/STATE.md b/.planning/STATE.md index ca53262..313c1fd 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -3,14 +3,14 @@ gsd_state_version: 1.0 milestone: v1.0 milestone_name: milestone status: executing -stopped_at: Phase 2 context gathered -last_updated: "2026-06-18T11:16:49.005Z" +stopped_at: Completed 02-02-PLAN.md +last_updated: "2026-06-18T11:41:48.379Z" last_activity: 2026-06-18 -- Plan 01-02 Portal Shell complete progress: total_phases: 6 completed_phases: 1 - total_plans: 3 - completed_plans: 3 + total_plans: 8 + completed_plans: 5 percent: 17 --- @@ -26,7 +26,7 @@ See: .planning/PROJECT.md (updated 2026-06-18) ## Current Position Phase: 1 of 6 (Foundation & Portal Shell) -Plan: 2 of 3 in current phase (completed) +Plan: 3 of 3 in current phase (completed) Status: Ready to execute Last activity: 2026-06-18 -- Plan 01-02 Portal Shell complete @@ -52,6 +52,7 @@ Progress: [██░░░░░░░░] 10% - Trend: improving *Updated after each plan completion* +| Phase 02-authentication-multi-tenancy P02 | 8min | 3 tasks | 26 files | ## Accumulated Context @@ -69,6 +70,9 @@ Recent decisions affecting current work: - [01-02]: Dark mode uses oklch(0.17 0.01 260) dark gray-blue for comfortable contrast with yellow primary - [01-02]: Cookie-based locale (NEXT_LOCALE) instead of URL routing for portal app - [01-02]: CSS custom property --current-sidebar-width for responsive main content margin +- [Phase ?]: Route groups (auth)/(portal) for layout separation: auth pages standalone, portal pages wrapped in AppShell +- [Phase ?]: Controller-level tenant isolation for ADMIN role as defense-in-depth alongside RLS +- [Phase ?]: Remember-me controls cookie maxAge (30d session vs browser-session) not separate token type ### Pending Todos @@ -88,6 +92,6 @@ Items acknowledged and carried forward from previous milestone close: ## Session Continuity -Last session: 2026-06-18T10:48:31.279Z -Stopped at: Phase 2 context gathered -Resume file: .planning/phases/02-authentication-multi-tenancy/02-CONTEXT.md +Last session: 2026-06-18T11:41:48.372Z +Stopped at: Completed 02-02-PLAN.md +Resume file: None diff --git a/.planning/phases/02-authentication-multi-tenancy/02-02-SUMMARY.md b/.planning/phases/02-authentication-multi-tenancy/02-02-SUMMARY.md new file mode 100644 index 0000000..b6b5f0f --- /dev/null +++ b/.planning/phases/02-authentication-multi-tenancy/02-02-SUMMARY.md @@ -0,0 +1,203 @@ +--- +phase: 02-authentication-multi-tenancy +plan: 02 +subsystem: auth, ui +tags: [jwt, jose, zustand, next-middleware, login, rbac, user-crud, tenant-crud, i18n] + +# Dependency graph +requires: + - phase: 02-authentication-multi-tenancy/01 + provides: "Backend auth (AuthModule, UserService, TenantService, JWT guards, admin seed)" + - phase: 01-foundation-portal-shell/02 + provides: "Portal shell (AppShell, Header, Sidebar, i18n, theming)" +provides: + - "Split-screen login page with form submission to API" + - "Next.js middleware for JWT-based route protection" + - "Auth-wired header with user dropdown and logout" + - "Auth-wired sidebar footer with user info" + - "Zustand auth store for client-side user state" + - "User CRUD API endpoints with role-based tenant isolation" + - "Tenant CRUD API endpoints (SUPER_ADMIN only)" + - "Admin users management page" + - "Admin tenants management page" + - "Sidebar admin section with role-based visibility" + - "Complete DE/EN i18n keys for auth, admin, header" +affects: [03-marketplace, 04-module-system, ldap-sync] + +# Tech tracking +tech-stack: + added: [jose, zod, "@nestjs/mapped-types"] + patterns: + - "Route groups: (auth) for standalone pages, (portal) for AppShell-wrapped pages" + - "Next.js middleware JWT verification with jose for Edge runtime" + - "Server Actions for auth operations (login/logout/fetchCurrentUser)" + - "Zustand store without persist for API-driven client state" + - "NestJS controller-level tenant isolation for ADMIN role" + +key-files: + created: + - "apps/web/src/app/(auth)/layout.tsx" + - "apps/web/src/app/(auth)/login/page.tsx" + - "apps/web/src/app/(portal)/layout.tsx" + - "apps/web/src/app/(portal)/page.tsx" + - "apps/web/src/middleware.ts" + - "apps/web/src/lib/session.ts" + - "apps/web/src/lib/auth-actions.ts" + - "apps/web/src/lib/stores/auth-store.ts" + - "apps/api/src/user/user.controller.ts" + - "apps/api/src/user/dto/create-user.dto.ts" + - "apps/api/src/user/dto/update-user.dto.ts" + - "apps/api/src/tenant/tenant.controller.ts" + - "apps/api/src/tenant/dto/create-tenant.dto.ts" + - "apps/web/src/app/(portal)/admin/users/page.tsx" + - "apps/web/src/app/(portal)/admin/tenants/page.tsx" + modified: + - "apps/web/src/app/layout.tsx" + - "apps/web/src/components/layout/header.tsx" + - "apps/web/src/components/layout/sidebar-footer.tsx" + - "apps/web/src/components/layout/sidebar.tsx" + - "apps/web/src/messages/de.json" + - "apps/web/src/messages/en.json" + - "apps/api/src/user/user.module.ts" + - "apps/api/src/tenant/tenant.module.ts" + - "apps/web/package.json" + - "apps/api/package.json" + +key-decisions: + - "Used route groups (auth)/(portal) for layout separation instead of conditional rendering" + - "Server Actions for login/logout with manual cookie forwarding for cross-port dev setup" + - "Zustand auth store without persist: user data comes from API on each portal load" + - "Controller-level tenant filtering for ADMIN role rather than relying solely on RLS" + - "Remember-me controls cookie maxAge (30d vs session-only), not separate token type" + +patterns-established: + - "Route groups: (auth) for unauthenticated, (portal) for authenticated pages" + - "Next.js middleware: JWT verification with jose, public route allowlist" + - "Auth store: fetchCurrentUser() in header useEffect populates Zustand" + - "Admin pages: role-checked at component level with access-denied fallback" + - "API controllers: class-validator DTOs with ! assertions for strict TS" + +requirements-completed: [AUTH-02, AUTH-03, AUTH-04, TNNT-02] + +# Metrics +duration: 8min +completed: 2026-06-18 +--- + +# Phase 2 Plan 02: Frontend Auth & User/Tenant CRUD Summary + +**Split-screen login with JWT middleware route protection, auth-wired portal chrome, and admin CRUD pages for users (ADMIN+) and tenants (SUPER_ADMIN)** + +## Performance + +- **Duration:** 8 min +- **Started:** 2026-06-18T11:30:35Z +- **Completed:** 2026-06-18T11:39:05Z +- **Tasks:** 3 +- **Files modified:** 26 + +## Accomplishments + +- Split-screen login page with Tessera branding (yellow #ffed00 left panel) and form (right panel), including remember-me checkbox for session duration control +- Next.js middleware validates JWT on every route, redirects unauthenticated users to /login, and handles mustChangePassword redirect +- Header displays logged-in user initial with dropdown (display name, role badge, logout); sidebar footer shows user name and role from Zustand auth store +- User CRUD API with ADMIN/SUPER_ADMIN access: ADMIN scoped to own tenant, cannot escalate to SUPER_ADMIN role +- Tenant CRUD API with SUPER_ADMIN-only access: includes user count, blocks deletion of tenants with active users +- Admin users page with table, create/edit/delete modals; admin tenants page with table, create/edit/deactivate +- Sidebar "Verwaltung" section visible to ADMIN+, with "Mandanten" link only for SUPER_ADMIN +- Complete DE/EN i18n coverage for all new auth, admin, and header strings + +## Task Commits + +Each task was committed atomically: + +1. **Task 1: Auth infrastructure** - `cdf4d60` (feat: route groups, middleware, session, auth-actions, auth store) +2. **Task 2: Login page UI and header/sidebar wiring** - `e7b2a70` (feat: split-screen login, user dropdown, i18n) +3. **Task 3: User/Tenant CRUD API + admin pages** - `bfb04ea` (feat: controllers, DTOs, admin UI, sidebar admin nav) + +## Files Created/Modified + +### Created +- `apps/web/src/app/(auth)/layout.tsx` - Standalone auth layout (no sidebar/header) +- `apps/web/src/app/(auth)/login/page.tsx` - Split-screen login page with form +- `apps/web/src/app/(portal)/layout.tsx` - Portal layout wrapping with AppShell +- `apps/web/src/app/(portal)/page.tsx` - Dashboard page (moved from root) +- `apps/web/src/middleware.ts` - JWT-based route protection middleware +- `apps/web/src/lib/session.ts` - Edge-compatible JWT verification with jose +- `apps/web/src/lib/auth-actions.ts` - Server actions: login, logout, fetchCurrentUser +- `apps/web/src/lib/stores/auth-store.ts` - Zustand store for client-side user state +- `apps/api/src/user/user.controller.ts` - User CRUD endpoints with role/tenant guards +- `apps/api/src/user/dto/create-user.dto.ts` - CreateUserDto with class-validator +- `apps/api/src/user/dto/update-user.dto.ts` - UpdateUserDto extending CreateUserDto +- `apps/api/src/tenant/tenant.controller.ts` - Tenant CRUD endpoints (SUPER_ADMIN only) +- `apps/api/src/tenant/dto/create-tenant.dto.ts` - CreateTenantDto with slug validation +- `apps/web/src/app/(portal)/admin/users/page.tsx` - User management admin page +- `apps/web/src/app/(portal)/admin/tenants/page.tsx` - Tenant management admin page + +### Modified +- `apps/web/src/components/layout/header.tsx` - Auth-wired user avatar dropdown with logout +- `apps/web/src/components/layout/sidebar-footer.tsx` - Auth-wired user info display +- `apps/web/src/components/layout/sidebar.tsx` - Added Verwaltung admin section +- `apps/web/src/messages/de.json` - Added auth, header.role, admin i18n keys +- `apps/web/src/messages/en.json` - Added auth, header.role, admin i18n keys +- `apps/api/src/user/user.module.ts` - Added UserController +- `apps/api/src/tenant/tenant.module.ts` - Added TenantController +- `apps/web/package.json` - Added jose, zod +- `apps/api/package.json` - Added @nestjs/mapped-types + +## Decisions Made + +- **Route groups over conditional rendering:** Used Next.js route groups `(auth)` and `(portal)` to separate layouts cleanly. The `(auth)` group has a minimal layout (no sidebar/header per D-04), while `(portal)` wraps everything in AppShell. +- **Server Action cookie forwarding:** In development (separate ports 3000/3001), the login server action manually reads Set-Cookie from the API response and sets it via Next.js cookies() API to bridge the cross-origin gap. +- **Remember-me via cookie duration:** The remember-me checkbox controls whether the session cookie has a 30-day maxAge (checked) or is a session cookie (unchecked, expires on browser close). Both use the same JWT. +- **Controller-level tenant isolation:** ADMIN user requests filter by tenantId at the controller level as defense-in-depth alongside RLS, ensuring ADMIN users never see cross-tenant data even if RLS is misconfigured. +- **Installed @nestjs/mapped-types:** Required for PartialType DTO pattern (UpdateUserDto extends CreateUserDto with all fields optional). + +## Deviations from Plan + +### Auto-fixed Issues + +**1. [Rule 1 - Bug] Added definite assignment assertions to DTO properties** +- **Found during:** Task 3 (User/Tenant CRUD) +- **Issue:** TypeScript strict mode required definite assignment for DTO class properties, causing type-check failures +- **Fix:** Added `!` definite assignment assertions to required DTO properties (standard NestJS DTO pattern with class-validator) +- **Files modified:** create-user.dto.ts, create-tenant.dto.ts +- **Verification:** `pnpm turbo type-check` passes +- **Committed in:** bfb04ea (Task 3 commit) + +**2. [Rule 3 - Blocking] Installed @nestjs/mapped-types** +- **Found during:** Task 3 (User/Tenant CRUD) +- **Issue:** PartialType import from @nestjs/mapped-types was not available; package not listed in plan dependencies +- **Fix:** Ran `pnpm add @nestjs/mapped-types` in apps/api +- **Files modified:** apps/api/package.json, pnpm-lock.yaml +- **Verification:** UpdateUserDto compiles correctly, type-check passes +- **Committed in:** bfb04ea (Task 3 commit) + +--- + +**Total deviations:** 2 auto-fixed (1 bug, 1 blocking) +**Impact on plan:** Both auto-fixes necessary for compilation. No scope creep. + +## Issues Encountered + +- **Stale .next cache:** After moving `page.tsx` from root to `(portal)/` route group, the `.next/types` directory still referenced the old location. Fixed by clearing `.next` cache before type-check. + +## User Setup Required + +None - no external service configuration required. JWT_SECRET env var must be set for production (development uses a fallback). + +## Next Phase Readiness + +- Login flow is fully wired: user can authenticate via split-screen login page and reach the portal +- Auth state flows through the entire portal: header dropdown, sidebar footer, admin page access checks +- User and tenant CRUD is complete for admin workflows +- Ready for LDAP sync (Phase 2, Plan 03 if planned) or marketplace features (Phase 3) +- Password reset flow (D-03) requires SMTP setup -- deferred to separate plan + +## Self-Check: PASSED + +All 16 created/expected files verified on disk. All 3 task commits (cdf4d60, e7b2a70, bfb04ea) verified in git log. Type-check passes for all packages. + +--- +*Phase: 02-authentication-multi-tenancy* +*Completed: 2026-06-18*