# 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 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 ```