refactor: rebuild backend around role-site authorization model
This commit is contained in:
@@ -1,19 +1,20 @@
|
||||
# Backend TaskPlan
|
||||
|
||||
## 待辦
|
||||
- [ ] 重建 schema 與 migration:退場舊表(`modules` 舊權限流程、`permission_groups*`、`user_scope_permissions`),上線 `roles`、`site_roles`、`user_sites`。
|
||||
- [ ] 重做 Admin API:`Company/Site/System/Role/User` CRUD 與關聯管理 API。
|
||||
- [ ] 重做 Role API:只允許 Site 指派/解除,不提供 user direct role API。
|
||||
- [ ] 重做 `/me/permissions/snapshot`:改為 role 聚合格式(由 user_sites + site_roles 推導)。
|
||||
- [ ] Keycloak 同步器改版:Company/Site group 同步、System client role 同步、Site 角色套用同步。
|
||||
- [ ] Swagger response model 全面更新為 role-site 新模型。
|
||||
- [ ] 新增/補齊 API 測試(CRUD、關聯、同步、刪除、錯誤碼)。
|
||||
- [ ] 補齊 pytest API 測試(CRUD、關聯、同步、刪除、錯誤碼)。
|
||||
- [ ] 補一支「一鍵重建 schema」腳本(串 `init_schema.sql`)。
|
||||
|
||||
## 進行中
|
||||
- [ ] 文件與實際回應格式持續對齊(避免文件漂移)。
|
||||
- [ ] Swagger response model 與前端實際畫面持續對齊。
|
||||
|
||||
## 已完成
|
||||
- [x] Keycloak OIDC 登入主流程(authorize + callback + token)。
|
||||
- [x] `/admin/*` Bearer token + admin 群組白名單安全線。
|
||||
- [x] API 白名單基礎(`api_clients`)已存在並可管理。
|
||||
- [x] 前後端本地啟動流程已可分開運行(backend + frontend)。
|
||||
- [x] schema 重建:清除舊表,改為 `roles`、`site_roles`、`user_sites` 主流程。
|
||||
- [x] 移除舊後端程式:`module/permission_group/user_scope_permissions` 相關 model/repo/api。
|
||||
- [x] Admin API 改版:`Company/Site/System/Role/User` CRUD 與關聯 API。
|
||||
- [x] Role 指派只允許綁 Site,不提供 user direct role API。
|
||||
- [x] `/me/permissions/snapshot` 改為 role 聚合格式。
|
||||
- [x] Internal API 改版:可取 `users/{user_sub}/roles` 聚合結果。
|
||||
- [x] 保留 `api_clients` 白名單管理 API。
|
||||
- [x] Keycloak OIDC 登入主流程。
|
||||
- [x] `/admin/*` Bearer + admin 群組白名單安全線。
|
||||
|
||||
@@ -13,26 +13,38 @@
|
||||
{ "detail": "error_code" }
|
||||
```
|
||||
|
||||
## 資源模型(重點)
|
||||
- `company`: `id`, `company_key`, `display_name`, `legal_name`, `status`
|
||||
- `site`: `id`, `site_key`, `company_id`, `display_name`, `domain`, `status`
|
||||
- `system`: `id`, `system_key`, `name`, `idp_client_id`, `status`
|
||||
- `role`: `id`, `role_key`, `system_id`, `name`, `description`, `idp_role_name`, `status`
|
||||
- `user`: `id`, `user_sub`, `username`, `email`, `display_name`, `is_active`, `status`
|
||||
|
||||
## 主要端點(目標)
|
||||
## 已實作端點
|
||||
1. `GET /internal/companies`
|
||||
2. `GET /internal/sites`
|
||||
3. `GET /internal/systems`
|
||||
4. `GET /internal/roles`
|
||||
5. `GET /internal/users`
|
||||
6. `GET /internal/users/{user_sub}/roles`
|
||||
- 回傳該 user 透過 site 推導出的最終 roles。
|
||||
5. `GET /internal/members`
|
||||
6. `POST /internal/users/upsert-by-sub`
|
||||
7. `GET /internal/users/{user_sub}/roles`
|
||||
8. `GET /internal/permissions/{user_sub}/snapshot`(相容路徑,回 role 聚合資料)
|
||||
9. `POST /internal/idp/users/ensure`
|
||||
10. `POST /internal/keycloak/users/ensure`
|
||||
|
||||
## 關聯端點(目標)
|
||||
1. `POST /internal/site-roles` / `DELETE /internal/site-roles/{id}`
|
||||
2. `POST /internal/user-sites` / `DELETE /internal/user-sites/{id}`
|
||||
## 角色聚合回應(`GET /internal/users/{user_sub}/roles`)
|
||||
```json
|
||||
{
|
||||
"user_sub": "xxxxxxxx",
|
||||
"roles": [
|
||||
{
|
||||
"site_key": "ST20260402X1234",
|
||||
"site_display_name": "OSE Main",
|
||||
"company_key": "CP20260402X5678",
|
||||
"company_display_name": "OSE",
|
||||
"system_key": "SY20260402X0001",
|
||||
"system_name": "Marketing",
|
||||
"role_key": "RL20260402X0002",
|
||||
"role_name": "campaign_edit",
|
||||
"idp_role_name": "campaign_edit"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 注意事項
|
||||
- 不提供 user direct role 寫入 API。
|
||||
- 若其他系統需要判斷某 user 可否做某事,請吃 `users/{user_sub}/roles` 聚合結果。
|
||||
- User 最終角色由 `user_sites` + `site_roles` 推導。
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
# Local Dev Runbook(Keycloak)
|
||||
|
||||
## 1) 啟動後端
|
||||
## 1) 先重建 DB schema(本次改版必做)
|
||||
```bash
|
||||
cd backend
|
||||
psql "$DATABASE_URL" -f scripts/init_schema.sql
|
||||
```
|
||||
- DB schema 檔案:[backend/scripts/init_schema.sql](../backend/scripts/init_schema.sql)
|
||||
|
||||
## 2) 啟動後端
|
||||
```bash
|
||||
cd backend
|
||||
./scripts/start_dev.sh
|
||||
@@ -8,7 +15,7 @@ cd backend
|
||||
- 專案路徑:[backend](../backend)
|
||||
- 啟動腳本:[backend/scripts/start_dev.sh](../backend/scripts/start_dev.sh)
|
||||
|
||||
## 2) 啟動前端
|
||||
## 3) 啟動前端
|
||||
```bash
|
||||
cd frontend
|
||||
npm install
|
||||
@@ -16,7 +23,7 @@ npm run dev
|
||||
```
|
||||
- 專案路徑:[frontend](../frontend)
|
||||
|
||||
## 3) 必要環境變數([backend/.env.development](../backend/.env.development))
|
||||
## 4) 必要環境變數([backend/.env.development](../backend/.env.development))
|
||||
- `KEYCLOAK_BASE_URL`
|
||||
- `KEYCLOAK_REALM`
|
||||
- `KEYCLOAK_CLIENT_ID`
|
||||
@@ -25,20 +32,20 @@ npm run dev
|
||||
- `KEYCLOAK_ADMIN_CLIENT_SECRET`
|
||||
- `ADMIN_REQUIRED_GROUPS`
|
||||
|
||||
## 4) 基本檢查
|
||||
## 5) 基本檢查
|
||||
1. `GET http://127.0.0.1:8000/healthz` 應為 200。
|
||||
2. 前端按「前往 Keycloak 登入」應可成功導轉與回跳。
|
||||
3. `GET /me` 登入後應有資料。
|
||||
4. 非 admin 群組帳號打 `/admin/*` 應為 403。
|
||||
|
||||
## 5) 新模型驗收路徑
|
||||
## 6) 新模型驗收路徑
|
||||
1. 新增 Company、Site。
|
||||
2. 新增 System、Role。
|
||||
3. 對 Site 指派 Role。
|
||||
4. 新增 User,加入 Site。
|
||||
5. 驗證 User 的角色是由 Site 推導,不是 direct assign。
|
||||
|
||||
## 6) API 白名單驗收
|
||||
## 7) API 白名單驗收
|
||||
1. 建立 `api_client`。
|
||||
2. 用 `X-Client-Key` + `X-API-Key` 呼叫 `/internal/*`。
|
||||
3. 驗證未授權 key 會被拒絕。
|
||||
|
||||
Reference in New Issue
Block a user