Files
slp-modular-cms/aidlc-docs/features/cms-frontend/construction/unit-5/code/code-generation-summary.md
T
2026-06-22 21:14:22 +02:00

4.1 KiB
Raw Blame History

Unit 5 Code Generation Summary

What Was Built

Unit 5 implements the User Management feature: listing users, inviting new users, and changing roles.


Backend Changes

Bug Fixes

  • UsersController: Fixed invite link URL from /setup/complete?token=… to /invite/complete?token=…

New Interface Method

  • IInvitationService.GetPendingInvitationByEmailAsync(string email) — returns (bool IsPending, string? Token)

New Service Implementation

  • InvitationService.GetPendingInvitationByEmailAsync — queries Invitations for a non-accepted, non-expired record by email

New Models (IdentityRequests.cs)

  • UserDto — maps a user to the API response including InvitationPending and InviteLink
  • ChangeRoleRequest — carries NewRole

Updated Controller (UsersController)

  • Now injects UserManager<ApplicationUser> alongside IInvitationService
  • GET /api/v1/Users — returns all users with role, status, and pending invite info
  • PUT /api/v1/Users/{userId}/role — enforces RBAC rules (Owner constraint, Admin can only promote User→Admin)

Database Migration

  • No migration needed — all tables (Users, Roles, UserRoles, Invitations) already exist

Frontend Changes

New UI Components (frontend/src/components/ui/)

File Component
dialog.tsx Dialog, DialogContent, DialogHeader, DialogTitle, etc.
select.tsx Select, SelectTrigger, SelectContent, SelectItem, etc.
table.tsx Table, TableHeader, TableBody, TableRow, TableHead, TableCell
badge.tsx Badge with default / secondary / destructive / outline variants

New API Hook (useUsers.ts)

  • useUsers()GET /api/v1/Users, staleTime 30s, queryKey ['users']
  • useInviteUser()POST /api/v1/Users/invite, invalidates ['users']
  • useChangeRole()PUT /api/v1/Users/{userId}/role, invalidates ['users']

Migrated Hook (useInvitation.ts)

  • Converted from useState/useEffect to TanStack Query
  • Uses InvitationValidation from types.ts (field isValid, not the old local valid)

Updated Files

File Change
types.ts Added UserListItem, InviteUserPayload, InviteUserResponse, ChangeRolePayload
InviteCompletePage.tsx validationQuery.data?.validvalidationQuery.data?.isValid (2 places)
mocks/invitation/handlers.ts Response shape updated to { isValid, email, name, errorCode }
mocks/users/handlers.ts Full user list + invite + change-role mock handlers

New Page & Component

  • UsersPage.tsx — table with role/status badges, per-row dropdown (copy link, change role)
  • components/users/InviteUserDialog.tsx — 2-step dialog: email+role form → invite link display

i18n

  • en/translation.json and nl/translation.jsonusers.* key section added (title, table columns, status labels, role labels, invite dialog, action labels)

Tests

File Coverage
useUsers.test.ts useUsers, useInviteUser, useChangeRole — happy path + error
UsersPage.test.tsx Render, table rows, pending badge, copy link action, API error, dialog open
InviteUserDialog.test.tsx Form validation, successful flow (step 2), API error, dialog reset
InviteCompletePage.test.tsx No changes needed — mock now returns correct isValid shape

Key Design Decisions

  • isValid vs valid: The existing InvitationValidation type in types.ts already uses isValid. The old useInvitation.ts had a local interface with valid. Migration aligns the hook to the canonical type.
  • No server-side invite email: Invite flow is link-only (per functional design). The link is shown in the dialog step 2 and copied to clipboard.
  • Role RBAC in frontend: availableRolesFor() in UsersPage restricts the dropdown options; backend enforces the same rules server-side.
  • Pending invite for accepted users: GetPendingInvitationByEmailAsync only returns a token if !IsAccepted && !IsExpired — accepted users correctly show no pending invite.