Files
UTMS-NG-BE/docs/frontend-api-surface.md
2026-04-21 06:25:33 +07:00

336 lines
7.8 KiB
Markdown

# 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