initial commit
This commit is contained in:
335
docs/frontend-api-surface.md
Normal file
335
docs/frontend-api-surface.md
Normal 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
|
||||
Reference in New Issue
Block a user