12 KiB
Code Generation Plan — Unit 6: Profile, Settings & CMS Placeholder
Status: 🚧 In Progress
Unit Context
Unit: Unit 6 — Profile, Settings & CMS Placeholder
Type: Frontend (React/TypeScript) + Backend (.NET) — brownfield (modifying existing stubs)
Workspace root: K:\Development\Projects\SlpModularCms
Stories covered: US-15, US-16, US-17, US-20
Key Observations from Code Scan
Existing files to MODIFY (not create):
frontend/src/pages/ProfilePage.tsx— currently a "Coming soon" stubfrontend/src/pages/SettingsPage.tsx— currently a "Coming soon" stubfrontend/src/pages/CmsPage.tsx— currently a "Coming soon" stubfrontend/src/api/useAvailability.ts— hasuseAvailabilityStatusread query; needsuseUpdateAvailabilitymutation addedfrontend/src/router.tsx— has all routes except 403 and 404; needs catch-all addedfrontend/src/mocks/users/handlers.ts— needsPUT /api/v1/Users/memock addedfrontend/src/mocks/auth/handlers.ts— needsPOST /api/v1/Auth/change-passwordmock addedfrontend/src/i18n/locales/en/translation.json— needs profile, settings, error page keysfrontend/src/i18n/locales/nl/translation.json— needs Dutch translationssrc/SlpModularCms.Core/Identity/Models/IdentityRequests.cs— needsUpdateProfileRequest+ChangePasswordRequestsrc/SlpModularCms.Core/Identity/Services/IAuthService.cs— needsChangePasswordmethodsrc/SlpModularCms.Core/Identity/Services/AuthService.cs— needsChangePasswordimplementationsrc/SlpModularCms.Modules.Identity/Controllers/AuthController.cs— needsPOST /change-passwordendpointsrc/SlpModularCms.Modules.Identity/Controllers/UsersController.cs— needsPUT /meendpoint
New files to CREATE:
frontend/src/api/useProfile.ts—useUpdateProfilemutation +useChangePasswordmutationfrontend/src/pages/AccessDeniedPage.tsx— 403 pagefrontend/src/pages/NotFoundPage.tsx— 404 pagefrontend/src/pages/ProfilePage.test.tsxfrontend/src/pages/SettingsPage.test.tsxfrontend/src/pages/CmsPage.test.tsxfrontend/src/pages/AccessDeniedPage.test.tsxfrontend/src/pages/NotFoundPage.test.tsx
Stories
- US-15: View own profile — ProfilePage with name/email edit + change password
- US-16: View availability status in settings — SettingsPage with availability controls
- US-17: Access denied to System Settings for non-Owners — 403 page + RoleGuard (already wired in router)
- US-20: View CMS management placeholder — CmsPage enhanced placeholder
Generation Steps
Backend
-
Step 1: Modify
src/SlpModularCms.Core/Identity/Models/IdentityRequests.cs- Add
record UpdateProfileRequest(string Name, string Email) - Add
record ChangePasswordRequest(string CurrentPassword, string NewPassword)
- Add
-
Step 2: Modify
src/SlpModularCms.Core/Identity/Services/IAuthService.cs- Add
Task ChangePasswordAsync(Guid userId, string currentPassword, string newPassword)
- Add
-
Step 3: Modify
src/SlpModularCms.Core/Identity/Services/AuthService.cs- Implement
ChangePasswordAsync— usesUserManager.ChangePasswordAsync; throwsValidationExceptionif current password is wrong
- Implement
-
Step 4: Modify
src/SlpModularCms.Modules.Identity/Controllers/AuthController.cs- Add
POST /change-passwordendpoint —[Authorize](any authenticated user), reads userId from JWT claims, callsIAuthService.ChangePasswordAsync - Returns 200 OK on success, 400 with error detail on failure
- Add
-
Step 5: Modify
src/SlpModularCms.Modules.Identity/Controllers/UsersController.cs- Add
PUT /meendpoint —[Authorize](any authenticated user), reads userId from JWT claims - Updates
UserName(display name) andEmailon theApplicationUserviaUserManager - Returns
UserDtowith updated data on 200 OK; returns 400 if email already taken
- Add
Frontend — API layer
-
Step 6: Create
frontend/src/api/useProfile.tsuseUpdateProfile()—useMutationcallingPUT /api/v1/Users/mewith{ name, email }; on success callsauth.refresh()fromuseAuth()useChangePassword()—useMutationcallingPOST /api/v1/Auth/change-passwordwith{ currentPassword, newPassword }
-
Step 7: Modify
frontend/src/api/useAvailability.ts- Add
useUpdateAvailability()—useMutationcallingPOST /api/v1/Availability/admin/statuswith{ newStatus, reason }; on success callsqueryClient.invalidateQueries({ queryKey: ['availability', 'status'] })
- Add
-
Step 8: Add MSW mock handlers
- In
frontend/src/mocks/users/handlers.ts: addhttp.put('/api/v1/Users/me', ...)returning updated UserDto - In
frontend/src/mocks/auth/handlers.ts: addhttp.post('/api/v1/Auth/change-password', ...)returning 200 OK (and a 400 error handler variant for wrong-password tests)
- In
Frontend — i18n keys
-
Step 9: Modify
frontend/src/i18n/locales/en/translation.json— add:"profile": { "title": "My Profile", "name": "Full name", "email": "Email address", "role": "Role", "save": "Save changes", "saving": "Saving…", "saveSuccess": "Profile updated successfully", "changePassword": "Change password", "changePassword": { "title": "Change Password", "current": "Current password", "new": "New password", "confirm": "Confirm new password", "submit": "Change password", "submitting": "Changing…", "success": "Password changed successfully", "errorMismatch": "Passwords do not match", "errorCurrent": "Current password is incorrect" } }, "settings": { "title": "System Settings", "availability": { "title": "System Availability", "mode": "Availability mode", "reason": "Message (optional)", "save": "Update availability", "saving": "Updating…", "saveSuccess": "Availability updated", "modes": { "Available": "Available", "Maintenance": "Maintenance", "Unavailable": "Unavailable" } }, "modules": { "title": "Module Management", "comingSoon": "Coming soon" }, "systemConfig": { "title": "System Configuration", "comingSoon": "Coming soon" }, "branding": { "title": "Branding / Theme", "comingSoon": "Coming soon" } }, "error": { "403": { "title": "Access Denied", "message": "You don't have permission to view this page." }, "404": { "title": "Page Not Found", "message": "The page you're looking for doesn't exist." }, "backToDashboard": "Back to Dashboard" } -
Step 10: Modify
frontend/src/i18n/locales/nl/translation.json— add Dutch translations for all keys added in Step 9
Frontend — pages
-
Step 11: Modify
frontend/src/pages/ProfilePage.tsx— full implementation:- Use
useAuth()for current user data (name, email, role) - Use
useUpdateProfile()+react-hook-form+zodfor name/email form - Render Role as read-only badge
- Include "Change Password" button that opens
ChangePasswordDialog ChangePasswordDialog(inline in file or as separate component in same directory): usesuseChangePassword()with ownreact-hook-form+zodvalidation- All interactive elements get
data-testidattributes
- Use
-
Step 12: Modify
frontend/src/pages/SettingsPage.tsx— full implementation:- Use
useAvailabilityStatus()to fetch current status - Use
useUpdateAvailability()for saving changes - Mode selector (radio group or select) + optional reason text area
- Render
AvailabilityStatusBadgeshowing current status - Three
PlaceholderCardsections: Module Management, System Configuration, Branding/Theme - All interactive elements get
data-testidattributes
- Use
-
Step 13: Modify
frontend/src/pages/CmsPage.tsx— enhanced placeholder:- Icon (
LayoutGridfrom lucide-react) + heading "Content Management System" + description text - Use i18n keys; add
data-testid="cms-placeholder"
- Icon (
-
Step 14: Create
frontend/src/pages/AccessDeniedPage.tsx- Icon (
ShieldOfffrom lucide-react) + heading fromt('error.403.title')+ message + "Back to Dashboard" button data-testidon heading, message, and button
- Icon (
-
Step 15: Create
frontend/src/pages/NotFoundPage.tsx- Icon (
FileQuestionfrom lucide-react) + heading fromt('error.404.title')+ message + "Back to Dashboard" button data-testidon heading, message, and button
- Icon (
Frontend — router
- Step 16: Modify
frontend/src/router.tsx- Add
accessDeniedRouteat path/403(under rootRoute, not authenticatedRoute — accessible without auth) - Add
notFoundRouteas catch-all$path (under rootRoute) - Add both routes to
routeTree
- Add
Frontend — tests
-
Step 17: Create
frontend/src/pages/ProfilePage.test.tsx- Test: renders name, email, role from AuthContext
- Test: editing name and email and clicking Save triggers
PUT /api/v1/Users/me - Test: validation errors shown for empty name or invalid email
- Test: "Change Password" button opens dialog
- Test: change password form validates (mismatch, empty fields)
- Test: successful password change closes dialog
-
Step 18: Create
frontend/src/pages/SettingsPage.test.tsx- Test: renders current availability status (mocked via MSW)
- Test: changing mode and clicking save triggers
POST /api/v1/Availability/admin/status - Test: placeholder sections render with correct headings
-
Step 19: Create
frontend/src/pages/CmsPage.test.tsx- Test: renders heading and placeholder description
-
Step 20: Create
frontend/src/pages/AccessDeniedPage.test.tsx- Test: renders "Access Denied" heading and message
- Test: "Back to Dashboard" button navigates to
/dashboard
-
Step 21: Create
frontend/src/pages/NotFoundPage.test.tsx- Test: renders "Page Not Found" heading and message
- Test: "Back to Dashboard" button navigates to
/dashboard
Verification
-
Step 22: Backend migration check
- Review all new/modified entity classes and
ApplicationDbContextto determine if EF Core migrations are needed - Unit 6 backend changes:
PUT /Users/meupdatesApplicationUser.UserNameandEmail(existing columns inAspNetUsers);POST /Auth/change-passwordupdates the password hash (existing column) — no schema changes expected - Verify by checking that no new
DbSet<>properties or[Column]/HasColumnNamechanges were introduced in Steps 1–5 - If a schema change is found: run
dotnet ef migrations add <MigrationName> --project src/SlpModularCms.Core --startup-project src/SlpModularCms.Apiand include the generated migration files - If no schema change: document explicitly in the code summary (Step 25) that no migration was needed
- Review all new/modified entity classes and
-
Step 23: i18n completeness check
- For every
t('...')call added in Steps 11–16 (ProfilePage, SettingsPage, CmsPage, AccessDeniedPage, NotFoundPage, router), verify the key exists in bothen/translation.jsonandnl/translation.json - For every key added in Steps 9–10 to
en/translation.jsonandnl/translation.json, verify it is actually used via at('...')call in at least one component — remove unused keys - Fix any missing or orphaned keys before proceeding
- For every
Documentation
- Step 24: Update
README.md— add "Frontend Development" section:- Prerequisites: Node.js ≥20, pnpm
- Installation:
pnpm installinfrontend/ - Environment: copy
frontend/.env.exampletofrontend/.env - Dev server:
pnpm devinfrontend/(runs on http://localhost:5173) - Build:
pnpm buildinfrontend/ - Tests:
pnpm testinfrontend/ - Security note: production deployment should add security headers (CSP, HSTS)
Code summary
- Step 25: Create
aidlc-docs/features/cms-frontend/construction/unit-6/code/code-generation-summary.md- List all modified and created files with their purpose
- Include migration check outcome (Step 22)
- Include i18n check outcome (Step 23)