feat: bootstrap backend MVP and architecture docs
This commit is contained in:
106
docs/API_CLIENTS_SQL.sql
Normal file
106
docs/API_CLIENTS_SQL.sql
Normal file
@@ -0,0 +1,106 @@
|
||||
-- member_center: API 呼叫方白名單表
|
||||
-- 位置: public schema
|
||||
|
||||
BEGIN;
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'client_status') THEN
|
||||
CREATE TYPE client_status AS ENUM ('active', 'inactive');
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS api_clients (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
client_key TEXT NOT NULL UNIQUE,
|
||||
name TEXT NOT NULL,
|
||||
status client_status NOT NULL DEFAULT 'active',
|
||||
|
||||
-- 只存 hash,不存明文 key
|
||||
api_key_hash TEXT NOT NULL,
|
||||
|
||||
-- 可先留空,之後再嚴格化
|
||||
allowed_origins JSONB NOT NULL DEFAULT '[]'::jsonb,
|
||||
allowed_ips JSONB NOT NULL DEFAULT '[]'::jsonb,
|
||||
allowed_paths JSONB NOT NULL DEFAULT '[]'::jsonb,
|
||||
|
||||
rate_limit_per_min INTEGER,
|
||||
expires_at TIMESTAMPTZ,
|
||||
last_used_at TIMESTAMPTZ,
|
||||
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_api_clients_status ON api_clients(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_api_clients_expires_at ON api_clients(expires_at);
|
||||
|
||||
CREATE OR REPLACE FUNCTION set_updated_at_api_clients()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = NOW();
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_trigger WHERE tgname = 'trg_api_clients_set_updated_at'
|
||||
) THEN
|
||||
CREATE TRIGGER trg_api_clients_set_updated_at
|
||||
BEFORE UPDATE ON api_clients
|
||||
FOR EACH ROW EXECUTE FUNCTION set_updated_at_api_clients();
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- 建議初始化 2~3 個 client(api_key_hash 先放占位,後續再更新)
|
||||
INSERT INTO api_clients (
|
||||
client_key,
|
||||
name,
|
||||
status,
|
||||
api_key_hash,
|
||||
allowed_origins,
|
||||
allowed_ips,
|
||||
allowed_paths,
|
||||
rate_limit_per_min
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
'mkt-backend',
|
||||
'MKT Backend Service',
|
||||
'active',
|
||||
'REPLACE_WITH_BCRYPT_OR_ARGON2_HASH',
|
||||
'[]'::jsonb,
|
||||
'[]'::jsonb,
|
||||
'["/internal/users/upsert-by-sub", "/internal/permissions"]'::jsonb,
|
||||
600
|
||||
),
|
||||
(
|
||||
'admin-frontend',
|
||||
'Admin Frontend',
|
||||
'active',
|
||||
'REPLACE_WITH_BCRYPT_OR_ARGON2_HASH',
|
||||
'["https://admin.ose.tw", "https://member.ose.tw"]'::jsonb,
|
||||
'[]'::jsonb,
|
||||
'["/admin"]'::jsonb,
|
||||
300
|
||||
),
|
||||
(
|
||||
'ops-local',
|
||||
'Ops Local Tooling',
|
||||
'inactive',
|
||||
'REPLACE_WITH_BCRYPT_OR_ARGON2_HASH',
|
||||
'[]'::jsonb,
|
||||
'["127.0.0.1"]'::jsonb,
|
||||
'["/internal", "/admin"]'::jsonb,
|
||||
120
|
||||
)
|
||||
ON CONFLICT (client_key) DO NOTHING;
|
||||
|
||||
COMMIT;
|
||||
|
||||
-- 快速檢查
|
||||
-- SELECT client_key, status, expires_at, created_at FROM api_clients ORDER BY client_key;
|
||||
23
docs/ARCHITECTURE_AND_CONFIG.md
Normal file
23
docs/ARCHITECTURE_AND_CONFIG.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# member 系統文件入口(Architecture & Config)
|
||||
|
||||
## 入口說明
|
||||
這份文件是入口索引。若你只要快速開始,先看:
|
||||
1. `docs/BACKEND_BOOTSTRAP.md`
|
||||
2. `docs/BACKEND_ARCHITECTURE.md`
|
||||
3. `docs/FRONTEND_ARCHITECTURE.md`
|
||||
|
||||
## 文件地圖
|
||||
- `docs/BACKEND_BOOTSTRAP.md`
|
||||
- 後端啟動步驟(環境、安裝、建表、啟動)
|
||||
- `docs/BACKEND_ARCHITECTURE.md`
|
||||
- memberapi 後端模組、資料流、API、安全策略
|
||||
- `docs/FRONTEND_ARCHITECTURE.md`
|
||||
- member 前端架構(由前端 AI 接手)
|
||||
- `docs/API_CLIENTS_SQL.sql`
|
||||
- `api_clients` 白名單表與初始資料 SQL
|
||||
|
||||
## 目前狀態(2026-03-29)
|
||||
- 後端骨架:已建立(FastAPI + SQLAlchemy)
|
||||
- 核心 API:已建立(health/internal/admin)
|
||||
- API key 驗證:已建立(`X-Client-Key` + `X-API-Key`)
|
||||
- Authentik 深度整合:待補(目前先保留介接欄位與流程位置)
|
||||
82
docs/BACKEND_ARCHITECTURE.md
Normal file
82
docs/BACKEND_ARCHITECTURE.md
Normal file
@@ -0,0 +1,82 @@
|
||||
# memberapi.ose.tw 後端架構(FastAPI)
|
||||
|
||||
## 1. 目標與邊界
|
||||
- 網域:`memberapi.ose.tw`
|
||||
- 角色:會員中心後端真相來源(User + Permission)
|
||||
- 範圍:
|
||||
- user upsert(以 `authentik_sub` 為跨系統主鍵)
|
||||
- permission grant/revoke
|
||||
- permission snapshot 提供給其他系統
|
||||
- 不在本服務處理:
|
||||
- Authentik OIDC 流程頁與 UI
|
||||
- 前端互動邏輯
|
||||
|
||||
## 2. 技術棧
|
||||
- Python 3.12
|
||||
- FastAPI
|
||||
- SQLAlchemy 2.0
|
||||
- PostgreSQL(psycopg)
|
||||
- Pydantic Settings
|
||||
|
||||
## 3. 後端目錄(已建立)
|
||||
- `backend/app/main.py`
|
||||
- `backend/app/api/`
|
||||
- `internal.py`
|
||||
- `admin.py`
|
||||
- `backend/app/core/config.py`
|
||||
- `backend/app/db/session.py`
|
||||
- `backend/app/models/`
|
||||
- `user.py`
|
||||
- `permission.py`
|
||||
- `api_client.py`
|
||||
- `backend/app/repositories/`
|
||||
- `users_repo.py`
|
||||
- `permissions_repo.py`
|
||||
- `backend/app/security/api_client_auth.py`
|
||||
- `backend/scripts/init_schema.sql`
|
||||
- `backend/.env.example`
|
||||
- `backend/.env.production.example`
|
||||
|
||||
## 4. 資料模型
|
||||
- `users`
|
||||
- `id`, `authentik_sub`(unique), `email`, `display_name`, `is_active`, timestamps
|
||||
- `permissions`
|
||||
- `id`, `user_id`, `scope_type`, `scope_id`, `module`, `action`, `created_at`
|
||||
- unique constraint: `(user_id, scope_type, scope_id, module, action)`
|
||||
- `api_clients`(由 `docs/API_CLIENTS_SQL.sql` 建立)
|
||||
- `client_key`, `api_key_hash`, `status`, allowlist, expires/rate-limit 欄位
|
||||
|
||||
## 5. API 設計(MVP)
|
||||
- 健康檢查
|
||||
- `GET /healthz`
|
||||
- 內部路由(系統對系統)
|
||||
- `POST /internal/users/upsert-by-sub`
|
||||
- `GET /internal/permissions/{authentik_sub}/snapshot`
|
||||
- header: `X-Internal-Secret`
|
||||
- 管理路由(後台/API client)
|
||||
- `POST /admin/permissions/grant`
|
||||
- `POST /admin/permissions/revoke`
|
||||
- headers: `X-Client-Key`, `X-API-Key`
|
||||
|
||||
## 6. 安全策略
|
||||
- `admin` 路由強制 API client 驗證:
|
||||
- client 必須存在且 `status=active`
|
||||
- `expires_at` 未過期
|
||||
- `api_key_hash` 驗證(支援 `sha256:<hex>` 與 bcrypt/argon2)
|
||||
- allowlist 驗證(origin/ip/path)
|
||||
- `internal` 路由使用 `X-Internal-Secret` 做服務間驗證
|
||||
- 建議上線前:
|
||||
- 將 `.env` 範本中的明文密碼改為部署平台 secret
|
||||
- API key 全部改為 argon2/bcrypt hash
|
||||
|
||||
## 7. 與其他系統資料流
|
||||
1. mkt/admin 後端登入後,以 token `sub` 呼叫 `/internal/users/upsert-by-sub`
|
||||
2. 權限調整走 `/admin/permissions/grant|revoke`
|
||||
3. 需要授權判斷時,呼叫 `/internal/permissions/{sub}/snapshot`
|
||||
4. mkt 系統可本地快取 snapshot,並做定時補償
|
||||
|
||||
## 8. 下一階段(建議)
|
||||
- 加入 Alembic migration
|
||||
- 為 permission/action 加 enum 與驗證規則
|
||||
- 增加 audit log(誰在何時授權/撤銷)
|
||||
- 加入 rate-limit 與可觀測性(metrics + request id)
|
||||
26
docs/BACKEND_BOOTSTRAP.md
Normal file
26
docs/BACKEND_BOOTSTRAP.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Backend Bootstrap(memberapi)
|
||||
|
||||
## 1. 環境準備
|
||||
```bash
|
||||
cd member.ose.tw/backend
|
||||
python -m venv .venv
|
||||
source .venv/bin/activate
|
||||
pip install -e .
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
## 2. 建立資料表
|
||||
1. 先執行 `member.ose.tw/docs/API_CLIENTS_SQL.sql`
|
||||
2. 再執行 `member.ose.tw/backend/scripts/init_schema.sql`
|
||||
|
||||
## 3. 啟動服務
|
||||
```bash
|
||||
cd member.ose.tw/backend
|
||||
source .venv/bin/activate
|
||||
uvicorn app.main:app --host 127.0.0.1 --port 8000 --reload
|
||||
```
|
||||
|
||||
## 4. 快速驗證
|
||||
```bash
|
||||
curl -sS http://127.0.0.1:8000/healthz
|
||||
```
|
||||
55
docs/FRONTEND_ARCHITECTURE.md
Normal file
55
docs/FRONTEND_ARCHITECTURE.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# member.ose.tw 前端架構(Vue)
|
||||
|
||||
## 1. 角色定位
|
||||
- 網域:`member.ose.tw`
|
||||
- 功能:會員中心前台(管理 users/公司/站台/權限)
|
||||
- 注意:密碼流程不在這裡做,自動導 Authentik flow
|
||||
|
||||
## 2. 技術棧
|
||||
- `Vue 3 + Vite`
|
||||
- `Element Plus`
|
||||
- `Tailwind CSS`
|
||||
- `Vue Router`
|
||||
- `Pinia`(建議)
|
||||
|
||||
## 3. 建議目錄
|
||||
- `frontend/src/main.ts`
|
||||
- `frontend/src/router/`
|
||||
- `frontend/src/stores/`
|
||||
- `frontend/src/api/`(axios client + modules)
|
||||
- `frontend/src/pages/`
|
||||
- `users/`
|
||||
- `companies/`
|
||||
- `sites/`
|
||||
- `permissions/`
|
||||
- `frontend/src/components/`
|
||||
|
||||
## 4. 第一版頁面
|
||||
- 使用者列表/搜尋
|
||||
- 公司列表
|
||||
- 站台列表
|
||||
- 權限指派(user x scope x module x action)
|
||||
|
||||
## 5. 權限與登入
|
||||
- 透過 Authentik OIDC 登入
|
||||
- 前端持有 backend session/token,不直接操作 Authentik admin API
|
||||
- 「修改密碼 / 忘記密碼」按鈕導 Authentik 使用者流程頁
|
||||
|
||||
## 6. API 串接
|
||||
- `VITE_API_BASE_URL=https://memberapi.ose.tw`
|
||||
- 所有請求帶上必要 auth header
|
||||
- 管理操作走 `memberapi` 的 admin 路由
|
||||
|
||||
## 7. UI/互動規則
|
||||
- Element Plus 做表單/表格/對話框
|
||||
- Tailwind 做 spacing/layout/快速樣式
|
||||
- 權限編輯畫面要清楚顯示:
|
||||
- scope_type(company/site)
|
||||
- scope_id
|
||||
- module
|
||||
- action(view/edit)
|
||||
|
||||
## 8. 第一版不做項目
|
||||
- 不做密碼重設畫面
|
||||
- 不做複雜儀表板
|
||||
- 不做跨系統 SSO 管理 UI
|
||||
Reference in New Issue
Block a user