initial commit

This commit is contained in:
2026-04-21 06:25:33 +07:00
commit 85efdb7714
214 changed files with 6821 additions and 0 deletions

View File

@ -0,0 +1,335 @@
# Frontend API Surface (Backend: Current Spring Boot)
Use this as the exact frontend integration reference for the existing backend.
## 1) API Envelope
Most responses use:
```ts
type ApiResponse<T> = {
success: boolean
message: string
data: T
timestamp: string
}
```
### Error policy (actual backend behavior)
- Business errors and validation in request payloads return HTTP `400` with:
- `{ success: false, message: "...", data: null, timestamp: "..." }`
- Authorization failures return HTTP `403`:
- `{ success: false, message: "Access denied", data: null, timestamp: "..." }`
- Unhandled internal exceptions return HTTP `500` with:
- `{ success: false, message: "Internal server error", data: null, timestamp: "..." }`
- Authentication failures from Spring Security typically return `401` and are handled by frontend interceptor.
- JWT/session validation/blacklist failures can return `401` or be handled by security filters before controller.
## 2) Global request headers
For **every protected request** after login:
- `Authorization: Bearer <accessToken>`
- `X-Tenant-Id: <tenantId>`
- Optional: `Accept-Language: en-US` or `id-ID`
`POST /api/auth/login` also requires:
- `X-Tenant-Id`
## 3) Auth APIs
### POST `/api/auth/login`
Request:
```ts
{ username: string; password: string }
```
Success (`200`):
```ts
{
"success": true,
"message": "Login successful",
"data": {
"tokenType": "Bearer",
"accessToken": "eyJhbGciOiJIUzI1NiJ9...",
"refreshToken": "...",
"expiresInSeconds": 900
}
}
```
Common login failures:
- `401`: invalid credentials from security layer
- `400`: `{ message: "Invalid username or password" }`
- `400`: `{ message: "Account locked. Please try again in {0} seconds" }`
- LDAP mode + not provisioned local tenant user: `{ message: "LDAP user authenticated but not provisioned in this tenant" }`
### POST `/api/auth/refresh`
Request:
```ts
{ refreshToken: string }
```
Success:
```ts
{
"success": true,
"message": "Token refreshed successfully",
"data": {
"tokenType": "Bearer",
"accessToken": "...",
"refreshToken": "...",
"expiresInSeconds": 900
}
}
```
Failure:
- `400` with message `Refresh token not found` / `Token expired or revoked`
### POST `/api/auth/logout`
Request headers:
- `Authorization` and `X-Tenant-Id`
- optional body
Success:
```ts
{ "success": true, "message": "Logout successful", "data": null }
```
## 4) Profile API
### GET `/api/users/me`
Success:
```ts
{
"success": true,
"message": "Current user fetched successfully",
"data": {
"tenantId": "acme",
"username": "alice",
"roles": ["ADMIN", "USER_ROLE_ADMIN"],
"permissions": ["USER_MANAGE", "WORKFLOW_APPROVE", "ROLE_MANAGE"]
}
}
```
Use `roles` and `permissions` for:
- menu visibility
- action visibility
- route guards
## 5) Tenant APIs
### GET `/api/tenant/context`
```ts
{ tenantId: "acme" }
```
## 6) User Management APIs (Workflow-first)
### POST `/api/users/management/requests/create`
#### Local mode (default)
```ts
{
username: string,
password: string, // required local mode
enabled?: boolean,
roleCodes: string[]
}
```
#### LDAP mode
```ts
{
username: string,
ldapDn?: string, // optional metadata
enabled?: boolean,
roleCodes: string[]
}
```
Success always returns workflow request:
```ts
{
"success": true,
"message": "User management request created",
"data": {
"id": "uuid",
"resourceType": "USER_MANAGEMENT",
"resourceId": "jane",
"status": "PENDING",
"requiredSteps": 1,
"currentStep": 0
}
}
```
### POST `/api/users/management/requests/update-roles`
```ts
{ username: string; roleCodes: string[] }
```
Returns same response shape as approval response.
## 7) Role Management APIs (Workflow-first)
### POST `/api/roles/management/requests/create`
```ts
{ code: string; name: string; permissionCodes: string[] }
```
### POST `/api/roles/management/requests/update-permissions`
```ts
{ code: string; permissionCodes: string[] }
```
Both return `ApprovalResponse` with request status PENDING.
## 8) Workflow APIs
### POST `/api/workflow/request`
Generic endpoint for custom workflow request:
```ts
{
resourceType: string,
resourceId: string,
payload: string,
requiredSteps: number
}
```
### GET `/api/workflow/requests`
Query params:
- `status` = `DRAFT|PENDING|APPROVED|REJECTED` (optional)
- `resourceType` (optional)
- `makerUsername` (optional)
- `limit` default `50`, max internally clamped to `200`
Response list item:
```ts
{
id: "uuid",
tenantId: "acme",
resourceType: "USER_MANAGEMENT",
resourceId: "jane",
makerUsername: "alice",
payload: "{\"operation\":\"CREATE_USER\",...}",
status: "PENDING",
requiredSteps: 1,
currentStep: 0,
createdAt: "2026-04-20T08:00:00Z",
updatedAt: "2026-04-20T08:00:00Z"
}
```
### POST `/api/workflow/{id}/approve`
```ts
{ notes?: string; checkerRole?: string }
```
- If `checkerRole` omitted, backend uses step role default (`CHECKER` unless overridden by system default).
- Maker cannot approve own request.
- Success returns updated `ApprovalResponse`.
### POST `/api/workflow/{id}/reject`
```ts
{ notes?: string; checkerRole?: string }
```
Same behavior and guards as approve.
## 9) Module APIs (Admin only)
### GET `/api/modules`
Returns:
```ts
{ code: string; name: string; enabled: boolean }[]
```
### POST `/api/modules/{code}/toggle`
```ts
{ enabled: boolean }
```
Requires admin role.
## 10) Audit APIs (Admin only)
### GET `/api/audit?limit=50`
Response items include at least:
- `id`, `tenantId`, `actor`, `correlationId`, `action`, `domain`, `resourceType`, `resourceId`, `outcome`, `httpMethod`, `requestPath`, `beforeState`, `afterState`, `details`, `createdAt`.
Used for security/auditor trail and troubleshooting.
## 11) Statuses and RBAC to gate UI
- Approval status from backend: `DRAFT`, `PENDING`, `APPROVED`, `REJECTED`.
- User create / update role actions: `USER_MANAGE` OR `USER_ROLE_ADMIN`
- Role create / update permissions: `ROLE_MANAGE` OR `USER_ROLE_ADMIN`
- Workflow approve/reject: `WORKFLOW_APPROVE` OR `CHECKER`
- Workflow list: `WORKFLOW_APPROVE` OR `CHECKER` OR `ADMIN`
- Audit & modules listing/toggle: `ADMIN`
- Profile (`/api/users/me`): `USER_READ` OR `ADMIN`
## 12) Frontend negative-path checklist (QA-ready)
1. Login without tenant header should fail on protected flows.
2. Login with valid credentials but wrong tenant should fail on tenant-dependent services.
3. Repeated wrong password:
- eventually returns lockout message after configured threshold.
4. Create user (local mode) without password -> shows localized required validation error.
5. Create user (LDAP mode) with password payload should still be accepted by UI only if intentionally sent; backend ignores and should not rely on it.
6. Create user request duplicate username returns `400 User already exists`.
7. Workflow approve/reject where maker == checker returns error message `Maker cannot approve own request`.
8. Approving/rejecting without proper role returns `403`.
9. Audit API called by non-admin should return `403`.
10. Refresh with invalid token returns `400` and clear token state.
## 13) Suggested QA smoke script
- Validate auth:
- login, refresh, me, logout
- Validate tenant:
- switch tenant header and ensure data partitions by tenant
- Validate management flow:
- create user (local/LDAP variant) -> should appear in workflow as `PENDING`
- role create -> approval created
- approve/reject -> state transition to `APPROVED/REJECTED`
- Validate guard:
- hide actions by permissions and re-check with token from restricted user
## 14) Setup checklist
- Create `.env.local`:
- `NEXT_PUBLIC_API_BASE_URL=http://localhost:9191`
- `NEXT_PUBLIC_DEFAULT_TENANT=acme`
- `NEXT_PUBLIC_LOCALE=en`
- npm install / pnpm install
- Add Axios interceptor for auth and tenant headers
- Add 401/403 interceptor handling for logout and route redirect

View File

@ -0,0 +1,299 @@
You are a senior frontend engineer. Generate a **production-ready Next.js (App Router) admin dashboard** using **Tabler UI** as the design system.
Use this prompt as the current source of truth for backend behavior.
## Backend Summary (Current)
- Base URL: `http://<host>` (Swagger: `/swagger-ui.html`, OpenAPI: `/v3/api-docs`)
- Security: JWT (Bearer token)
- Multi-tenancy: required via header `X-Tenant-Id`
- Optional LDAP mode: `app.ldap.enabled` (backend switch)
- API pattern: most state-changing endpoints are workflow-driven approvals
- Default responses use:
```ts
type ApiResponse<T> = {
success: boolean
message: string
data: T
timestamp: string
}
```
## Tech Stack
- Next.js (App Router)
- React 18+
- TypeScript
- Tabler UI (CSS/React components)
- Axios
- Zustand (recommended)
- Tailwind (optional only for utility overrides)
- react-intl or next-intl for i18n
## Recommended Project Structure
- `app/`
- `(auth)/login/page.tsx`
- `(dashboard)/layout.tsx`
- `(dashboard)/page.tsx`
- `api-proxy/` or service barrel exports
- `components/`
- `layout/` (DashboardShell, Sidebar, Header)
- `ui/` (Table, Form, Modal, Alert, Badge, Drawer)
- `workflow/` (ApprovalTable, StatusBadge, ApprovalActionModal)
- `user/` (UserForm, UpdateRolesForm)
- `role/` (RoleForm, RolePermissionForm)
- `services/`
- `api.ts`
- `auth.ts`
- `users.ts`
- `workflow.ts`
- `tenant.ts`
- `audit.ts`
- `store/`
- `authStore.ts`
- `uiStore.ts`
- `tenantStore.ts`
- `permissionStore.ts`
- `hooks/`
- `useAuth.ts`, `useTenantHeader.ts`, `useApi.ts`, `usePermissions.ts`
- `types/`
- API contracts and DTO types
## API Endpoints to Use (exact)
### Auth
- `POST /api/auth/login`
- `POST /api/auth/refresh`
- `POST /api/auth/logout`
### Authenticated profile
- `GET /api/users/me`
### User management (workflow requests)
- `POST /api/users/management/requests/create`
- `POST /api/users/management/requests/update-roles`
### Role management (workflow requests)
- `POST /api/roles/management/requests/create`
- `POST /api/roles/management/requests/update-permissions`
### Workflow
- `POST /api/workflow/request`
- `POST /api/workflow/{id}/approve`
- `POST /api/workflow/{id}/reject`
- `GET /api/workflow/requests?status=PENDING&resourceType=...&makerUsername=...&limit=50`
### Modules
- `GET /api/modules`
- `POST /api/modules/{code}/toggle`
### Tenant & audit
- `GET /api/tenant/context`
- `GET /api/audit?limit=50`
## Authentication and request headers
For **every request** after login:
- `Authorization: Bearer <accessToken>`
- `X-Tenant-Id: <tenantId>`
Login request also requires tenant context because backend resolves tenant at auth time:
- `POST /api/auth/login` with header `X-Tenant-Id`
Logout request behavior:
- `POST /api/auth/logout` requires a valid Bearer token because backend invalidates/revokes refresh/session context.
Optional:
- `Accept-Language: en-US` or `id-ID`
## JWT/session behavior
- Access token in response includes `tokenType: "Bearer"`, `accessToken`, `refreshToken`, `expiresIn`
- Store tokens in secure storage strategy (HTTP-only cookies preferred if possible; otherwise memory + storage hardening)
- Add request interceptor to attach token and `X-Tenant-Id`
- Add response interceptor for 401:
- clear auth state
- redirect to login
- keep tenant and locale selections persisted
## Important authorization model
Backend sends authorities as roles/permissions:
- Roles come as `ROLE_<code>` (from DB role code)
- Permissions come as plain `...` codes
- Controllers currently check:
- User create/update-roles: `hasAuthority('USER_MANAGE') or hasRole('USER_ROLE_ADMIN')`
- Role create/update-permissions: `hasAuthority('ROLE_MANAGE') or hasRole('USER_ROLE_ADMIN')`
- Create workflow request: `hasAuthority('WORKFLOW_CREATE') or hasRole('MAKER')`
- Approve/reject: `hasAuthority('WORKFLOW_APPROVE') or hasRole('CHECKER')`
- Workflow list: `hasAuthority('WORKFLOW_APPROVE') or hasRole('CHECKER') or hasRole('ADMIN')`
- `/api/audit`: `hasRole('ADMIN')`
- `/api/users/me`: `hasAuthority('USER_READ') or hasRole('ADMIN')`
So frontend should render actions conditionally using permissions derived from `/api/users/me`.
## LDAP mode alignment
Backend has optional LDAP mode (`app.ldap.enabled`).
- **Local mode**
- `/api/users/management/requests/create` requires `password`
- **LDAP mode**
- Password is managed in directory (backend does not require password for user provisioning)
- `password` should not be sent for user creation
- optional `ldapDn` may be included
- Common for both modes
- user update roles still workflow-driven
- role create/update-permissions still workflow-driven
- no direct mutation endpoints for user/role entities
## Required front-end behavior by page
### 1) Login page
- Input: username, password, tenant selector
- Submit `POST /api/auth/login`
- Pass `X-Tenant-Id` header
- Handle error responses from backend localization keys and lockout messages
### 2) Dashboard shell
- Sidebar: Dashboard, Users, Roles, Workflow, Audit, Modules, Settings
- Top bar: tenant selector, locale switch, user menu/logout
- Display auth mode indicator (Local / LDAP) when available
### 3) Dashboard home
- Show summary cards:
- pending workflow count
- pending checker workload (from `/api/workflow/requests?status=PENDING`)
- audit/approval health snapshots (from `/api/audit?limit=50`)
- recent audits (from /api/audit)
### 4) Users page
- There is no direct `/api/users` list endpoint in current backend, so derive list/context from workflow/request history and `/api/users/me` context.
- Actions:
- create user request (workflow)
- update user roles request (workflow)
- In LDAP mode hide password input on create form
- In local mode enforce password validation before submit
### 5) Roles page
- No direct role list endpoint exists in current backend; show role/permission operations using current user context and workflow history as available.
- Implement create role request + permission update request flows.
- Permission selector from current in-app permission catalog (from `/api/users/me`, seeded defaults, and known workflow operations).
### 6) Workflow page
- Show `/api/workflow/requests` with filters
- `status` (`DRAFT`, `PENDING`, `APPROVED`, `REJECTED`)
- `resourceType`
- `makerUsername`
- `limit`
- Actions:
- Approve modal
- Reject modal
- show notes and optional checkerRole (if omitted, backend uses step role default `CHECKER`)
### 7) Audit page
- Admin-only
- `GET /api/audit?limit=50`
- render `action`, `resourceType`, `resourceId`, before/after snapshots, outcome, correlation id
- Keep pagination/infinite-load support for audit + workflow lists.
## DTO references for implementation
### Login
```ts
{ username: string; password: string }
```
### Create user management request
- Local mode:
```ts
{
username: string
password: string
enabled?: boolean
roleCodes: string[]
}
```
- LDAP mode:
```ts
{
username: string
ldapDn?: string
enabled?: boolean
roleCodes: string[]
}
```
### Update user roles
```ts
{ username: string; roleCodes: string[] }
```
### Create role request
```ts
{ code: string; name: string; permissionCodes: string[] }
```
### Update role permissions
```ts
{ code: string; permissionCodes: string[] }
```
### Workflow action
```ts
{ notes?: string; checkerRole?: string }
```
### Create approval request (generic)
```ts
{ resourceType: string; resourceId: string; payload?: string; requiredSteps: number }
```
### Response from `/api/users/me`
```ts
{ tenantId: string; username: string; roles: string[]; permissions: string[] }
```
## UI requirements
- Use Tabler-inspired components for
- tables
- forms
- modals
- badges
- alerts
- Keep navigation corporate and simple
- Add loading states, inline error states, and toast notifications
- Keep table columns configurable (search, sort, pagination)
## Error handling
Backend may return these patterns:
- Login failures with localized message
- Lockout message key in i18n when brute force threshold exceeded
- Standard `ApiResponse` with `success` false
Frontend should:
- show notification from `message`
- maintain tenant context in state across page refresh/login switch
- keep unauthorized navigation blocked by RBAC-derived route guards
## Delivery expectations
Please generate runnable code for:
- `app/` shell and route layout
- Axios client with interceptors
- Login/auth flow
- Tenant-aware request wrapper
- Users module screens + workflow request forms
- Roles module screens + workflow request forms
- Workflow list/detail with approve/reject action
- Audit list
- Reusable table/form/modal components
Please include a short setup checklist:
- env vars (`NEXT_PUBLIC_API_BASE_URL` etc)
- install commands
- run instructions

417
docs/sequence-diagrams.md Normal file
View File

@ -0,0 +1,417 @@
# Controller Sequence Diagrams
All diagrams are in Mermaid syntax (` ```mermaid `) and can be rendered by GitHub, IntelliJ, VS Code Mermaid extensions, and most markdown tools.
## 1) AuthController (`/api/auth`)
### 1.1 POST `/api/auth/login`
```mermaid
sequenceDiagram
autonumber
actor Client
participant AC as AuthController
participant AF as AuthService
participant TF as TenantFilter
participant TS as TenantService
participant LT as LoginThrottleService
participant AM as AuthenticationManager
participant JR as JwtService
participant UR as UserRepository
participant RTR as RefreshTokenRepository
Client->>AC: POST /api/auth/login {tenant, username, password}
AC->>AC: MessageResolver message key
AC-->>TF: tenant header (X-Tenant-Id)
TF->>TF: TenantContext.setTenantId(tenant)
AC->>AF: login(request)
AF->>TS: getActiveTenant(tenantId)
TS-->>AF: tenant entity
AF->>LT: ensureAllowed(tenantId, username)
alt account locked
LT-->>AF: AppException(auth.login.locked)
else allowed
AF->>AM: authenticate(UsernamePasswordAuthenticationToken)
alt invalid credential
AM-->>AF: AuthenticationException
AF->>LT: recordFailure(tenantId, username)
AF-->>AC: throw AppException(auth.invalid.credentials)
AC-->>Client: 400 Error via GlobalExceptionHandler
else success
AF->>LT: recordSuccess(tenantId, username)
AF->>UR: findByTenantIdAndUsername
UR-->>AF: User
AF->>AF: build UserPrincipal
AF->>JR: generateAccessToken(principal)
AF->>JR: generateRefreshToken(principal)
AF->>RTR: delete old refresh tokens
AF->>RTR: save RefreshToken
AF-->>AC: AuthTokenResponse(Bearer, access, refresh)
AC-->>Client: 200 {success:true, message, token}
end
end
```
### 1.2 POST `/api/auth/refresh`
```mermaid
sequenceDiagram
autonumber
actor Client
participant AF as AuthService
participant AC as AuthController
participant TF as TenantFilter
participant RTR as RefreshTokenRepository
participant JR as JwtService
participant UR as UserRepository
Client->>AC: POST /api/auth/refresh {tenant, refreshToken}
AC-->>TF: resolve tenant header
AC->>AF: refresh(request)
AF->>AF: TenantContext.getRequiredTenantId
AF->>RTR: findByTokenAndTenantId(refreshToken, tenantId)
alt token not found
RTR-->>AF: empty
AF-->>AC: AppException("Refresh token not found")
AC-->>Client: 400 via GlobalExceptionHandler
else token found
AF->>AF: validate revoked/expired
AF->>JR: parseClaims(refreshToken)
AF->>UR: findByTenantIdAndUsername(claims.sub)
AF->>JR: generateAccessToken(principal)
AF-->>AC: AuthTokenResponse(new access token)
AC-->>Client: 200 {success:true, message, token}
end
```
### 1.3 POST `/api/auth/logout`
```mermaid
sequenceDiagram
autonumber
actor Client
participant AC as AuthController
participant SE as Spring Security
participant AF as AuthService
participant TBS as TokenBlacklistService
participant JR as JwtService
Client->>AC: POST /api/auth/logout Authorization: Bearer <token>
AC->>SE: isAuthenticated() method security
alt unauthenticated
SE-->>Client: 401/403
else authenticated
AC->>AF: logout(bearer token)
alt token missing/blank
AF->>AF: return
else token present
AF->>JR: parseClaims(access token)
AF->>AF: compute ttl from exp
AF->>TBS: blacklist(token, ttl)
end
AF-->>AC: void
AC-->>Client: 200 {success:true, logout message}
end
```
## 2) WorkflowController (`/api/workflow`)
### 2.1 POST `/api/workflow/request`
```mermaid
sequenceDiagram
autonumber
actor Client
participant SC as Spring Security
participant WC as ApprovalWorkflowController
participant AFS as ApprovalWorkflowService
participant TS as TenantService
participant AR as ApprovalRequestRepository
participant ASR as ApprovalStepRepository
participant AH as ApprovalHistoryRepository
participant AT as AuditTrailService
Client->>WC: POST /api/workflow/request (workflow payload)
WC->>SC: hasAuthority('WORKFLOW_CREATE') OR hasRole('MAKER')
alt auth failed
SC-->>Client: 403
else authorized
WC->>AFS: createRequest(dto, servletRequest)
AFS->>TS: getActiveTenant(tenantId)
AFS->>AFS: resolve maker + checkerRole default
AFS->>AR: save ApprovalRequest(PENDING, status=0)
loop for each requiredSteps
AFS->>ASR: save ApprovalStep(stepOrder, CHECKER role)
end
AFS->>AH: addHistory(action=CREATE)
AFS->>AT: record(ACTION_CREATE, before=null, after=snapshot)
AFS-->>WC: ApprovalResponse
WC-->>Client: 200 workflow.request.created
end
```
### 2.2 POST `/api/workflow/{id}/approve`
```mermaid
sequenceDiagram
autonumber
actor Client
participant SC as Spring Security
participant WC as ApprovalWorkflowController
participant AFS as ApprovalWorkflowService
participant AR as ApprovalRequestRepository
participant ASR as ApprovalStepRepository
participant AH as ApprovalHistoryRepository
participant EVT as ApprovalEventProducer
participant AT as AuditTrailService
Client->>WC: POST /api/workflow/{id}/approve (action notes)
WC->>SC: hasAuthority('WORKFLOW_APPROVE') OR hasRole('CHECKER')
alt auth failed
SC-->>Client: 403
else authorized
WC->>AFS: approve(id, dto, auth, servletRequest)
AFS->>AR: findByIdAndTenantId(id, tenantId)
alt request not found or not pending
AFS-->>WC: AppException
WC-->>Client: 400 via handler
else valid
AFS->>ASR: find current step
AFS->>SC: validateCheckerRole(auth, expectedRole)
AFS->>ASR: save step status=APPROVED
AFS->>AR: update currentStep
alt all steps completed
AFS->>AR: set request status=APPROVED
AFS->>EVT: publishCompleted(ApprovalCompletedEvent)
end
AFS->>AH: addHistory(action=APPROVE)
AFS->>AT: record(ACTION_APPROVE, before/after states)
AFS-->>WC: ApprovalResponse
WC-->>Client: 200 workflow.request.approved
end
end
```
### 2.3 POST `/api/workflow/{id}/reject`
```mermaid
sequenceDiagram
autonumber
actor Client
participant SC as Spring Security
participant WC as ApprovalWorkflowController
participant AFS as ApprovalWorkflowService
participant AR as ApprovalRequestRepository
participant ASR as ApprovalStepRepository
participant AH as ApprovalHistoryRepository
participant AT as AuditTrailService
Client->>WC: POST /api/workflow/{id}/reject (action notes)
WC->>SC: hasAuthority('WORKFLOW_APPROVE') OR hasRole('CHECKER')
alt auth failed
SC-->>Client: 403
else authorized
WC->>AFS: reject(id, dto, auth, servletRequest)
AFS->>AR: findByIdAndTenantId(id, tenantId)
alt request not found or not pending
AFS-->>WC: AppException
WC-->>Client: 400 via handler
else valid
AFS->>ASR: find current step
AFS->>SC: validateCheckerRole(auth, expectedRole)
AFS->>ASR: save step status=REJECTED
AFS->>AR: set request status=REJECTED
AFS->>AH: addHistory(action=REJECT)
AFS->>AT: record(ACTION_REJECT, before/after states)
AFS-->>WC: ApprovalResponse
WC-->>Client: 200 workflow.request.rejected
end
end
```
## 3) UserController (`/api/users`)
### 3.1 GET `/api/users/me`
```mermaid
sequenceDiagram
autonumber
actor Client
participant SC as Security Filter + Method Security
participant UC as UserController
participant US as UserService
participant UR as UserRepository
Client->>UC: GET /api/users/me
UC->>SC: hasAuthority('USER_READ') OR hasRole('ADMIN')
alt unauthorized
SC-->>Client: 403
else authorized
UC->>US: me(authentication.username)
US->>UR: findByTenantIdAndUsername
UR-->>US: User
US-->>UC: CurrentUserResponse(roles, permissions)
UC-->>Client: 200 {tenantId, user details}
end
```
### 3.2 POST `/api/users/management/requests/create`
```mermaid
sequenceDiagram
autonumber
actor Client
participant SC as Spring Security
participant UC as UserController
participant URS as UserRoleManagementService
participant AS as ApprovalWorkflowService
participant AR as ApprovalRequestRepository
Client->>UC: POST /api/users/management/requests/create
UC->>SC: hasAuthority('USER_MANAGE') OR hasRole('USER_ROLE_ADMIN')
alt unauthorized
SC-->>Client: 403
else authorized
UC->>URS: submitCreateUserRequest(request, servletRequest)
URS->>AS: createRequest(resource=USER_MANAGEMENT, requiredSteps=1, checkerRole=USER_ROLE_ADMIN)
AS->>AR: persist pending approval request + steps
AS-->>URS: ApprovalResponse
URS-->>UC: ApprovalResponse
UC-->>Client: 200 user.management.request.created
end
```
### 3.3 POST `/api/users/management/requests/update-roles`
```mermaid
sequenceDiagram
autonumber
actor Client
participant SC as Spring Security
participant UC as UserController
participant URS as UserRoleManagementService
participant AR as ApprovalRequestRepository
Client->>UC: POST /api/users/management/requests/update-roles
UC->>SC: hasAuthority('USER_MANAGE') OR hasRole('USER_ROLE_ADMIN')
alt unauthorized
SC-->>Client: 403
else authorized
UC->>URS: submitUpdateUserRolesRequest(request)
URS->>AR: validate user + roles, build payload
URS->>AR: create approval request with step checker role
URS-->>UC: ApprovalResponse
UC-->>Client: 200 user.management.request.created
end
```
## 4) RoleController (`/api/roles`)
### 4.1 POST `/api/roles/management/requests/create`
```mermaid
sequenceDiagram
autonumber
actor Client
participant SC as Spring Security
participant RC as RoleController
participant URS as UserRoleManagementService
participant AS as ApprovalWorkflowService
Client->>RC: POST /api/roles/management/requests/create
RC->>SC: hasAuthority('ROLE_MANAGE') OR hasRole('USER_ROLE_ADMIN')
alt unauthorized
SC-->>Client: 403
else authorized
RC->>URS: submitCreateRoleRequest(request, servletRequest)
URS->>AS: createRequest(resource=ROLE_MANAGEMENT, requiredSteps=1)
AS-->>URS: ApprovalResponse
URS-->>RC: ApprovalResponse
RC-->>Client: 200 role.management.request.created
end
```
### 4.2 POST `/api/roles/management/requests/update-permissions`
```mermaid
sequenceDiagram
autonumber
actor Client
participant SC as Spring Security
participant RC as RoleController
participant URS as UserRoleManagementService
participant AS as ApprovalWorkflowService
Client->>RC: POST /api/roles/management/requests/update-permissions
RC->>SC: hasAuthority('ROLE_MANAGE') OR hasRole('USER_ROLE_ADMIN')
alt unauthorized
SC-->>Client: 403
else authorized
RC->>URS: submitUpdateRolePermissionsRequest(request, servletRequest)
URS->>AS: createRequest(resource=ROLE_MANAGEMENT, requiredSteps=1)
AS-->>URS: ApprovalResponse
URS-->>RC: ApprovalResponse
RC-->>Client: 200 role.management.request.created
end
```
## 5) AuditController (`/api/audit`)
### 5.1 GET `/api/audit?limit={n}`
```mermaid
sequenceDiagram
autonumber
actor Client
participant SC as Spring Security
participant AC as AuditController
participant TS as TenantContext
participant ATS as AuditTrailService
participant ARepo as AuditTrailRepository
Client->>AC: GET /api/audit?limit=50
AC->>SC: hasRole('ADMIN')
alt unauthorized
SC-->>Client: 403
else authorized
AC->>TS: getRequiredTenantId()
AC->>ATS: listRecent(tenantId, limit)
ATS->>ARepo: find top by tenant/order by createdAt desc
ARepo-->>ATS: list audit entities
ATS-->>AC: mapped list entities
AC-->>AC: map to AuditTrailResponse DTOs
AC-->>Client: 200 audit.list.success
end
```
## 6) TenantController (`/api/tenant`)
### 6.1 GET `/api/tenant/context`
```mermaid
sequenceDiagram
autonumber
actor Client
participant SC as Spring Security
participant TC as TenantController
participant TCX as TenantContext
Client->>TC: GET /api/tenant/context
TC->>SC: isAuthenticated()
alt unauthenticated
SC-->>Client: 401/403
else authenticated
TC->>TCX: getRequiredTenantId()
TC-->>Client: 200 {tenantId}
end
```
## Common Cross-Cutting Exception Flow
### Validation and Error handling for all controllers
```mermaid
sequenceDiagram
autonumber
actor Client
participant Controller
participant Handler as GlobalExceptionHandler
Client->>Controller: Invalid body / business rule violation
Controller-->>Handler: throws MethodArgumentNotValidException or AppException
alt AppException
Handler-->>Client: 400 ApiResponse.fail(message)
else AccessDenied
Handler-->>Client: 403 ApiResponse.fail("error.forbidden")
else General exception
Handler-->>Client: 500 ApiResponse.fail("error.internal")
end
```