Auth
GET /api/auth/login
Request example:
GET /api/auth/login HTTP/1.1
Host: localhost:8080
Response example (redirect to Auth Service):
HTTP/1.1 307 Temporary Redirect
X-Request-Id: f0b458f3-cf0e-4252-b118-bf601917bf90
X-RateLimit-Remaining: 9
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Location: http://localhost:8082/authorize?response_type=code&client_id=bff-user&redirect_uri=http://localhost:8083/api/auth/callback/testbed&scope=openid%20email%20profile&state=DBDGLhHLc3UGhiBIqqUL39n3bKZsabk_uQH92-eM8g0&nonce=j2vlztQDqdl1AOJnDVyqZPZoCPO4llwzuonNDRnS0Z4&code_challenge=-pLu2U_Dns0ulfkTiFIyHQA2-nthW3PzdjaJA0Y4P40&code_challenge_method=S256
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Strict-Transport-Security: max-age=31536000; includeSubDomains
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-XSS-Protection: 0
Set-Cookie: pkce_data=c8YF_CRB_y3h7-YWSR0X0UlY_8BlyZPS9Y9nxav3CQbwtPUpy-jnZJWXYgxtFS3UFTCHhv6ht9IykzMZ6wukWe63NQ25eg4fCak04y6HY_R9QtknP-_fRwNtBc8tfX5UV5KOFpcJWR3cd1XwS4wmJeFA1GHVF1HKetTLltdi28TJS8ckAFUjBr0Y0COwGv7sYQnHo4BJavOmkCrqZz78uhw-IXWoQmAukga0dc-Cws_MvjgLc6eHxNkChu_gMtsQzKm6zNiV; Path=/api/auth; Max-Age=300; Expires=Sun, 29 Mar 2026 13:14:59 GMT; HttpOnly; SameSite=Lax
POST /api/auth/logout
Request example:
POST /api/auth/logout HTTP/1.1
Host: localhost:8080
Content-Type: application/x-www-form-urlencoded
Response example:
HTTP/1.1 200 OK
X-Request-Id: 6aed29a1-c381-407d-abec-f25b9e02a37a
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json
Content-Length: 134
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Strict-Transport-Security: max-age=31536000; includeSubDomains
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-XSS-Protection: 0
Set-Cookie: access_token=; Path=/; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly; SameSite=Lax
Set-Cookie: refresh_token=; Path=/; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly; SameSite=Lax
Set-Cookie: id_token=; Path=/; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly; SameSite=Lax
{"success":true,"endSessionUrl":"http://localhost:8082/end_session?client_id=bff-user&post_logout_redirect_uri=http://localhost:5173"}
Response fields:
| Path | Type | Description |
|---|---|---|
|
|
是否成功登出 |
|
|
RP-Initiated Logout URL(Auth Service /end_session) |
GET /api/auth/me
Request example:
GET /api/auth/me HTTP/1.1
Authorization: Bearer eyJraWQiOiJ0ZXN0LWtleS0xIiwiYWxnIjoiRVMyNTYifQ.eyJzdWIiOiJleHRlcm5hbC11c2VyLTEyMyIsImlzcyI6Imh0dHBzOi8vYXV0aC51Zm90ZWMuY29tIiwiYXVkIjpbImh0dHBzOi8vYXBpLnVmb3RlYy5jb20iXSwiZW1haWwiOiJ0ZXN0QGV4YW1wbGUuY29tIiwicm9sZXMiOlsiVVNFUiJdLCJzdGF0dXMiOiJBQ1RJVkUiLCJpYXQiOjE3NzQ3ODk3OTksImV4cCI6MTc3NDc4OTg1OX0.h3CGKgHVOaopAOb8DEGAYL-3sCiXPtOjZ0NBlDPMQb1ym3S4Ar7gRlGNqvKNBkY37TptiVyw6SzFfP1sFldQDA
Host: localhost:8080
Response example:
HTTP/1.1 200 OK
X-Request-Id: e0e4c56b-b7a8-465d-8923-0e2ea706f47a
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json
Content-Length: 95
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Strict-Transport-Security: max-age=31536000; includeSubDomains
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-XSS-Protection: 0
{"accountId":"external-user-123","email":"test@example.com","roles":["USER"],"status":"ACTIVE"}
Response fields:
| Path | Type | Description |
|---|---|---|
|
|
帳號 ID |
|
|
Email 地址 |
|
|
角色列表 |
|
|
帳號狀態(如 ACTIVE / PENDING) |
User
PUT /api/users/me
Request example:
PUT /api/users/me HTTP/1.1
Content-Type: application/json
Authorization: Bearer eyJraWQiOiJ0ZXN0LWtleS0xIiwiYWxnIjoiRVMyNTYifQ.eyJzdWIiOiJleHRlcm5hbC11c2VyLTEyMyIsImlzcyI6Imh0dHBzOi8vYXV0aC51Zm90ZWMuY29tIiwiYXVkIjpbImh0dHBzOi8vYXBpLnVmb3RlYy5jb20iXSwiZW1haWwiOiJ0ZXN0QGV4YW1wbGUuY29tIiwicm9sZXMiOlsiVVNFUiJdLCJzdGF0dXMiOiJBQ1RJVkUiLCJpYXQiOjE3NzQ3ODk4MDAsImV4cCI6MTc3NDc4OTg2MH0.GyUlLQlSwwPz0jqPMJwoA2wla1Edzt9BVgdwzjhNbxwgZvw73S7AGCfi5Yjf9ExDbGQIyEES71vOlCoa2ldNCg
Content-Length: 82
Host: localhost:8080
{"displayName":"NewName","avatarUrl":"https://example.com/avatar.png","version":0}
Request fields:
| Path | Type | Description |
|---|---|---|
|
|
顯示名稱 |
|
|
頭像 URL |
|
|
Optimistic Lock 版本號 |
Response example:
HTTP/1.1 200 OK
X-Request-Id: c30e8837-1ae5-400f-9150-e2e1223bdac0
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json
Content-Length: 114
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Strict-Transport-Security: max-age=31536000; includeSubDomains
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-XSS-Protection: 0
{"accountId":"external-user-123","displayName":"NewName","avatarUrl":"https://example.com/avatar.png","version":1}
Response fields:
| Path | Type | Description |
|---|---|---|
|
|
帳號 ID |
|
|
更新後的顯示名稱 |
|
|
更新後的頭像 URL |
|
|
更新後的版本號 |
Notifications
GET /api/notifications
Request example:
GET /api/notifications?pageSize=20&unreadOnly=false HTTP/1.1
Authorization: Bearer eyJraWQiOiJ0ZXN0LWtleS0xIiwiYWxnIjoiRVMyNTYifQ.eyJzdWIiOiJleHRlcm5hbC11c2VyLTEyMyIsImlzcyI6Imh0dHBzOi8vYXV0aC51Zm90ZWMuY29tIiwiYXVkIjpbImh0dHBzOi8vYXBpLnVmb3RlYy5jb20iXSwiZW1haWwiOiJ0ZXN0QGV4YW1wbGUuY29tIiwicm9sZXMiOlsiVVNFUiJdLCJzdGF0dXMiOiJBQ1RJVkUiLCJpYXQiOjE3NzQ3ODk3OTgsImV4cCI6MTc3NDc4OTg1OH0.AH5fV7K-ClKXKqjLPh7CeKFNCl82lMFYNOHq-E-9jA9s6pIcAHX0Wqh_9SYjBNuqy9myR3oB4Eyh0h7YZIpasA
Host: localhost:8080
Query parameters:
| Parameter | Description |
|---|---|
|
每頁筆數(1~100) |
|
是否只回傳未讀通知(true/false) |
Response example:
HTTP/1.1 200 OK
X-Request-Id: 43f4ba00-962e-4881-8805-4ec247e9db9f
X-RateLimit-Remaining: 57
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json
Content-Length: 312
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Strict-Transport-Security: max-age=31536000; includeSubDomains
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-XSS-Protection: 0
{"notifications":[{"id":"ntf-initial","accountId":"external-user-123","type":"SYSTEM_ANNOUNCEMENT","title":"Welcome","body":"Welcome to the notification center","metadata":{},"read":true,"createdAt":"2026-03-29T13:09:51.487676060Z","readAt":"2026-03-29T13:09:57.890217160Z"}],"nextPageToken":null,"totalCount":1}
Response fields:
| Path | Type | Description |
|---|---|---|
|
|
通知列表 |
|
|
通知 ID |
|
|
帳號 ID |
|
|
通知類型 |
|
|
通知標題 |
|
|
通知內容 |
|
|
額外資訊 |
|
|
是否已讀 |
|
|
建立時間(ISO-8601) |
|
|
已讀時間(ISO-8601) |
|
|
下一頁游標 |
|
|
符合條件的總筆數 |
GET /api/notifications/unread-count
Request example:
GET /api/notifications/unread-count HTTP/1.1
Authorization: Bearer eyJraWQiOiJ0ZXN0LWtleS0xIiwiYWxnIjoiRVMyNTYifQ.eyJzdWIiOiJleHRlcm5hbC11c2VyLTEyMyIsImlzcyI6Imh0dHBzOi8vYXV0aC51Zm90ZWMuY29tIiwiYXVkIjpbImh0dHBzOi8vYXBpLnVmb3RlYy5jb20iXSwiZW1haWwiOiJ0ZXN0QGV4YW1wbGUuY29tIiwicm9sZXMiOlsiVVNFUiJdLCJzdGF0dXMiOiJBQ1RJVkUiLCJpYXQiOjE3NzQ3ODk3OTgsImV4cCI6MTc3NDc4OTg1OH0.686l2UOhZQZijFvYeUopNg8RaoLaPSqUAfIw-kJJpALWvD2XFAofMLHTfjoo0kauoAcGYb9kFdYvPWEKXOHVrg
Host: localhost:8080
Response example:
HTTP/1.1 200 OK
X-Request-Id: 1cef5ac7-be4b-4508-b527-ac20cd9c20ae
X-RateLimit-Remaining: 58
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json
Content-Length: 11
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Strict-Transport-Security: max-age=31536000; includeSubDomains
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-XSS-Protection: 0
{"count":0}
Response fields:
| Path | Type | Description |
|---|---|---|
|
|
未讀通知數 |
PATCH /api/notifications/{id}/read
Request example:
PATCH /api/notifications/ntf-initial/read HTTP/1.1
Authorization: Bearer eyJraWQiOiJ0ZXN0LWtleS0xIiwiYWxnIjoiRVMyNTYifQ.eyJzdWIiOiJleHRlcm5hbC11c2VyLTEyMyIsImlzcyI6Imh0dHBzOi8vYXV0aC51Zm90ZWMuY29tIiwiYXVkIjpbImh0dHBzOi8vYXBpLnVmb3RlYy5jb20iXSwiZW1haWwiOiJ0ZXN0QGV4YW1wbGUuY29tIiwicm9sZXMiOlsiVVNFUiJdLCJzdGF0dXMiOiJBQ1RJVkUiLCJpYXQiOjE3NzQ3ODk3OTgsImV4cCI6MTc3NDc4OTg1OH0.dpLHPRZ14PXsGAu6YqBYs1_HumR3-w_b5HUowKEX9fPDS5Q2ZjaCOVZqlaRCR8GNodpOfk5eTFvaU7BLCZB4nw
Host: localhost:8080
Content-Type: application/x-www-form-urlencoded
Path parameters: ./api/notifications/{id}/read
| Parameter | Description |
|---|---|
|
通知 ID |
Response example:
HTTP/1.1 204 No Content
X-Request-Id: 04163af7-9e85-4cc4-89c5-78a1e1dd14b3
X-RateLimit-Remaining: 56
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Strict-Transport-Security: max-age=31536000; includeSubDomains
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-XSS-Protection: 0
PATCH /api/notifications/read-all
Request example:
PATCH /api/notifications/read-all HTTP/1.1
Authorization: Bearer eyJraWQiOiJ0ZXN0LWtleS0xIiwiYWxnIjoiRVMyNTYifQ.eyJzdWIiOiJleHRlcm5hbC11c2VyLTEyMyIsImlzcyI6Imh0dHBzOi8vYXV0aC51Zm90ZWMuY29tIiwiYXVkIjpbImh0dHBzOi8vYXBpLnVmb3RlYy5jb20iXSwiZW1haWwiOiJ0ZXN0QGV4YW1wbGUuY29tIiwicm9sZXMiOlsiVVNFUiJdLCJzdGF0dXMiOiJBQ1RJVkUiLCJpYXQiOjE3NzQ3ODk3OTcsImV4cCI6MTc3NDc4OTg1N30.Y--gWpYkm9hqATv3CwaODA_3t1SESxGyomGPWmJK-ur8yumVwPdndq3nbctLmNcrpLLlqfuKjsvJA9_jjvwDpQ
Host: localhost:8080
Content-Type: application/x-www-form-urlencoded
Response example:
HTTP/1.1 200 OK
X-Request-Id: 95d0cada-739e-4431-b52b-a8537b460fe2
X-RateLimit-Remaining: 59
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json
Content-Length: 17
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Strict-Transport-Security: max-age=31536000; includeSubDomains
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-XSS-Protection: 0
{"markedCount":1}
Response fields:
| Path | Type | Description |
|---|---|---|
|
|
本次標記為已讀的通知數 |
POST /api/admin/notifications/broadcast
Request example:
POST /api/admin/notifications/broadcast HTTP/1.1
Content-Type: application/json
Authorization: Bearer eyJraWQiOiJ0ZXN0LWtleS0xIiwiYWxnIjoiRVMyNTYifQ.eyJzdWIiOiJleHRlcm5hbC11c2VyLTEyMyIsImlzcyI6Imh0dHBzOi8vYXV0aC51Zm90ZWMuY29tIiwiYXVkIjpbImh0dHBzOi8vYXBpLnVmb3RlYy5jb20iXSwiZW1haWwiOiJ0ZXN0QGV4YW1wbGUuY29tIiwicm9sZXMiOlsiQURNSU4iXSwic3RhdHVzIjoiQUNUSVZFIiwiaWF0IjoxNzc0Nzg5Nzk4LCJleHAiOjE3NzQ3ODk4NTh9.hZx4YPRjR4MR9MBuOCeXoRUiJw8hiwK8K8DjNR0_b21_XH_4JHN45HsDUi4LtpkGuyju5nvuJGCva4qcC7p7aQ
Content-Length: 143
Host: localhost:8080
{"type":"SYSTEM_ANNOUNCEMENT","title":"Maintenance","body":"Planned maintenance","metadata":{"scope":"all"},"accountIds":["external-user-123"]}
Request fields:
| Path | Type | Description |
|---|---|---|
|
|
通知類型 |
|
|
通知標題 |
|
|
通知內容 |
|
|
額外資訊(可自由擴充 key/value) |
|
|
目標帳號清單,不可為空(broadcast-to-all 尚未支援) |
Response example:
HTTP/1.1 200 OK
X-Request-Id: c4d57814-3073-4ebb-99e9-756b416f3086
X-RateLimit-Remaining: 8
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json
Content-Length: 18
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Strict-Transport-Security: max-age=31536000; includeSubDomains
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-XSS-Protection: 0
{"createdCount":1}
Response fields:
| Path | Type | Description |
|---|---|---|
|
|
建立的通知筆數 |