--- 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*