fix(02): revise plans based on checker feedback

Split oversized tasks per scope_sanity blockers:
- 02-01 Task 2 (18 files) -> Task 2 (AuthModule, 12 files) + Task 3 (UserModule+TenantModule+wiring, 8 files)
- 02-02 Task 1 (14 files) -> Task 1 (auth infrastructure, 9 files) + Task 2 (login UI+header/sidebar+i18n, 5 files)

Added runtime smoke test to 02-01 Task 3 verify (ts-node startup check).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-18 13:16:26 +02:00
parent e8e89686f5
commit 8f58882db6
2 changed files with 99 additions and 46 deletions
@@ -10,8 +10,6 @@ files_modified:
- 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/app/(portal)/admin/users/page.tsx
- apps/web/src/app/(portal)/admin/tenants/page.tsx
- apps/web/src/app/layout.tsx
- apps/web/src/middleware.ts
- apps/web/src/lib/session.ts
@@ -30,6 +28,8 @@ files_modified:
- apps/api/src/tenant/tenant.controller.ts
- apps/api/src/tenant/tenant.module.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
autonomous: true
requirements:
- AUTH-02
@@ -122,33 +122,23 @@ See Plan 02-01 for the full artifacts table.
<tasks>
<task type="auto">
<name>Task 1: Login page, auth layout, Next.js middleware, auth store, and auth-wired portal components</name>
<name>Task 1: Auth infrastructure -- route groups, middleware, session, auth-actions, and auth store</name>
<read_first>
- apps/web/src/app/layout.tsx (root layout to understand provider structure)
- apps/web/src/components/layout/header.tsx (user avatar placeholder to wire)
- apps/web/src/components/layout/sidebar-footer.tsx (user info placeholder to wire)
- apps/web/src/components/layout/app-shell.tsx (AppShell wrapper for portal routes)
- apps/web/src/lib/stores/sidebar-store.ts (existing Zustand store pattern to follow)
- apps/web/src/messages/de.json (existing i18n keys to extend)
- apps/web/src/messages/en.json (existing i18n keys to extend)
- apps/web/src/app/globals.css (design tokens for styling login page)
- .planning/phases/02-authentication-multi-tenancy/02-RESEARCH.md (Pattern 4: Next.js middleware, session.ts pattern, DAL pattern)
</read_first>
<files>
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/app/layout.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/web/src/components/layout/header.tsx
apps/web/src/components/layout/sidebar-footer.tsx
apps/web/src/messages/de.json
apps/web/src/messages/en.json
apps/web/package.json
apps/web/src/app/layout.tsx
</files>
<action>
Install frontend auth dependencies: cd apps/web and pnpm add jose zod
@@ -184,14 +174,50 @@ See Plan 02-01 for the full artifacts table.
- Zustand store with user state (id, username, displayName, role, tenantId) or null
- Actions: setUser, clearUser
- No persist middleware (user state comes from API, not localStorage)
</action>
<verify>
<automated>cd /home/vicolab/projects/tessera-ctl && pnpm turbo type-check --filter=@tessera/web</automated>
</verify>
<acceptance_criteria>
- (auth) route group has standalone layout without AppShell per D-04
- (portal) route group wraps children with AppShell (header + sidebar)
- Next.js middleware validates JWT cookie and redirects unauthenticated to /login
- middleware.ts allows /login and /reset-password without auth
- session.ts exports verifySession using jose
- auth-actions.ts exports login, logout, fetchCurrentUser
- auth-store.ts exports useAuthStore Zustand hook
- Type-check passes for @tessera/web
</acceptance_criteria>
<done>Route groups created (auth standalone, portal with AppShell); Next.js middleware protects routes via JWT verification; auth-actions provide login/logout/fetchCurrentUser; Zustand auth store created.</done>
</task>
<task type="auto">
<name>Task 2: Login page UI, header/sidebar auth wiring, and i18n keys</name>
<read_first>
- apps/web/src/app/(auth)/layout.tsx (from Task 1 -- standalone layout)
- apps/web/src/lib/auth-actions.ts (from Task 1 -- login action to call)
- apps/web/src/lib/stores/auth-store.ts (from Task 1 -- store to populate)
- apps/web/src/components/layout/header.tsx (user avatar placeholder to wire)
- apps/web/src/components/layout/sidebar-footer.tsx (user info placeholder to wire)
- apps/web/src/messages/de.json (existing i18n keys to extend)
- apps/web/src/messages/en.json (existing i18n keys to extend)
- apps/web/src/app/globals.css (design tokens for styling login page)
</read_first>
<files>
apps/web/src/app/(auth)/login/page.tsx
apps/web/src/components/layout/header.tsx
apps/web/src/components/layout/sidebar-footer.tsx
apps/web/src/messages/de.json
apps/web/src/messages/en.json
</files>
<action>
Create apps/web/src/app/(auth)/login/page.tsx per D-01 split-screen design:
- 'use client' component
- Full-screen split layout: LEFT side (hidden on mobile, flex-1 on md+) shows Tessera branding with primary yellow (#ffed00 / var(--primary)) background, large "Tessera" text, and tagline. RIGHT side (full width mobile, flex-1 desktop) shows login form on white/dark background.
- Form fields: username input, password input, "Angemeldet bleiben" (Remember me) checkbox per D-02
- Submit button with primary color
- Error message display area
- Form submission calls the login action, which POSTs to /auth/login on the API. On success, redirect to '/' (dashboard). On error, show error message.
- Form submission calls the login action from auth-actions.ts, which POSTs to /auth/login on the API. On success, redirect to '/' (dashboard). On error, show error message.
- All strings through useTranslations('auth') hook per UI-03 pattern
- Include i18n keys for: auth.login, auth.username, auth.password, auth.rememberMe, auth.submit, auth.error.invalidCredentials, auth.branding.tagline
@@ -200,7 +226,7 @@ See Plan 02-01 for the full artifacts table.
- Import useAuthStore to get current user
- Show user initial (first letter of displayName or username) in the avatar circle
- On click, show a dropdown with: user display name, role badge, "Abmelden" (Logout) button
- Logout button calls the logout action
- Logout button calls the logout action from auth-actions.ts
- Keep the existing hamburger, logo, breadcrumb, and ThemeToggle structure intact
Update apps/web/src/components/layout/sidebar-footer.tsx:
@@ -217,23 +243,19 @@ See Plan 02-01 for the full artifacts table.
<automated>cd /home/vicolab/projects/tessera-ctl && pnpm turbo type-check --filter=@tessera/web</automated>
</verify>
<acceptance_criteria>
- (auth) route group has standalone layout without AppShell per D-04
- (portal) route group wraps children with AppShell (header + sidebar)
- Login page is split-screen with branding left and form right per D-01
- Login form has username, password, and remember-me checkbox per D-02
- Next.js middleware validates JWT cookie and redirects unauthenticated to /login
- middleware.ts allows /login and /reset-password without auth
- Header shows real user initial and dropdown with logout per auth store
- Sidebar footer shows real user name and role per auth store
- All new UI strings use i18n t() function (no hardcoded text)
- Both de.json and en.json have all new auth/admin translation keys
- Both de.json and en.json have all new auth/header/admin translation keys
- Type-check passes for @tessera/web
</acceptance_criteria>
<done>Login page renders split-screen layout; unauthenticated users are redirected to /login; authenticated users see their name in header and sidebar; all strings are internationalized.</done>
<done>Login page renders split-screen layout per D-01; header shows user dropdown with logout; sidebar footer shows user info; all strings internationalized in DE/EN.</done>
</task>
<task type="auto">
<name>Task 2: User CRUD API + admin page and Tenant CRUD API + admin page</name>
<name>Task 3: User CRUD API + admin page and Tenant CRUD API + admin page</name>
<read_first>
- apps/api/src/user/user.service.ts (from Plan 02-01, user operations)
- apps/api/src/user/user.module.ts (from Plan 02-01)
@@ -349,7 +371,7 @@ See Plan 02-01 for the full artifacts table.
</threat_model>
<verification>
After both tasks complete:
After all three tasks complete:
1. Navigate to http://localhost:3000 -- should redirect to /login
2. Login with admin/admin123 -- should redirect to dashboard, header shows "admin" user
3. Navigate to /admin/users -- should show user table with the admin account