# 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 = { 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 ` - `X-Tenant-Id: ` - 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