docs: rebuild architecture and taskplans for role-site model

This commit is contained in:
Chris
2026-04-02 23:35:05 +08:00
parent 7cdf2b5a51
commit 16bbfdba24
8 changed files with 263 additions and 286 deletions

View File

@@ -1,43 +1,105 @@
# DB Schema現行
# DB Schema新架構目標版
## 真實來源
- `backend/scripts/init_schema.sql`
- 線上增量:`backend/scripts/migrate_add_users_username.sql`
- 欄位重命名增量:`backend/scripts/migrate_rename_identity_columns.sql`
> 本文件是新架構的目標資料模型,供後端 schema 重建與 migration 依據。
> DB 真實來源仍以 `backend/scripts/init_schema.sql` 為準。
## 主要表
- `users`
- `user_sub` UNIQUE
- `idp_user_id` VARCHAR(128)
- `username` UNIQUE
- `email` UNIQUE
- `display_name`
- `is_active`, `status`, timestamps
- `companies`
- `sites``company_id -> companies.id`
- `systems`
- `modules``system_key -> systems.system_key`
- `permission_groups`
- `permission_group_members`group + user_sub
- `permission_group_permissions`group + site/system/module/action
- `user_scope_permissions`(相容保留)
- `api_clients`(保留給機器對機器用途)
## 1) companies
- `id` UUID PK default `gen_random_uuid()`
- `company_key` TEXT NOT NULL UNIQUE
- `display_name` TEXT NOT NULL
- `legal_name` TEXT
- `idp_group_id` TEXT
- `status` VARCHAR(16) NOT NULL default `'active'`
- `created_at` TIMESTAMPTZ NOT NULL default `now()`
- `updated_at` TIMESTAMPTZ NOT NULL default `now()`
## 權限規則
- `scope_type='site'`
- `action in ('view','edit')`
## 2) sites
- `id` UUID PK default `gen_random_uuid()`
- `site_key` TEXT NOT NULL UNIQUE
- `company_id` UUID NOT NULL FK -> `companies(id)` ON DELETE CASCADE
- `display_name` TEXT NOT NULL
- `domain` TEXT
- `idp_group_id` TEXT
- `status` VARCHAR(16) NOT NULL default `'active'`
- `created_at` TIMESTAMPTZ NOT NULL default `now()`
- `updated_at` TIMESTAMPTZ NOT NULL default `now()`
## 會員與 IdP 對齊Keycloak 優先)
- `users.user_sub` 對應 IdP 主體識別
- `users.username` 對應 IdP `username`
- `users.display_name` 對應 IdP 顯示名稱
## 3) systems
- `id` UUID PK default `gen_random_uuid()`
- `system_key` TEXT NOT NULL UNIQUE
- `name` TEXT NOT NULL
- `idp_client_id` TEXT NOT NULL UNIQUE
- `status` VARCHAR(16) NOT NULL default `'active'`
- `created_at` TIMESTAMPTZ NOT NULL default `now()`
- `updated_at` TIMESTAMPTZ NOT NULL default `now()`
## 快速檢查 SQL
```sql
SELECT column_name, data_type
FROM information_schema.columns
WHERE table_name='users'
ORDER BY ordinal_position;
## 4) roles
- `id` UUID PK default `gen_random_uuid()`
- `role_key` TEXT NOT NULL UNIQUE
- `system_id` UUID NOT NULL FK -> `systems(id)` ON DELETE CASCADE
- `name` TEXT NOT NULL
- `description` TEXT
- `idp_role_name` TEXT NOT NULL
- `status` VARCHAR(16) NOT NULL default `'active'`
- `created_at` TIMESTAMPTZ NOT NULL default `now()`
- `updated_at` TIMESTAMPTZ NOT NULL default `now()`
- UNIQUE(`system_id`, `idp_role_name`)
SELECT COUNT(*) FROM users WHERE username IS NULL;
```
## 5) site_roles
- `id` UUID PK default `gen_random_uuid()`
- `site_id` UUID NOT NULL FK -> `sites(id)` ON DELETE CASCADE
- `role_id` UUID NOT NULL FK -> `roles(id)` ON DELETE CASCADE
- `created_at` TIMESTAMPTZ NOT NULL default `now()`
- UNIQUE(`site_id`, `role_id`)
## 6) users
- `id` UUID PK default `gen_random_uuid()`
- `user_sub` TEXT NOT NULL UNIQUE
- `idp_user_id` TEXT UNIQUE
- `username` TEXT UNIQUE
- `email` TEXT UNIQUE
- `display_name` TEXT
- `status` VARCHAR(16) NOT NULL default `'active'`
- `is_active` BOOLEAN NOT NULL default `true`
- `created_at` TIMESTAMPTZ NOT NULL default `now()`
- `updated_at` TIMESTAMPTZ NOT NULL default `now()`
## 7) user_sites
- `id` UUID PK default `gen_random_uuid()`
- `user_id` UUID NOT NULL FK -> `users(id)` ON DELETE CASCADE
- `site_id` UUID NOT NULL FK -> `sites(id)` ON DELETE CASCADE
- `created_at` TIMESTAMPTZ NOT NULL default `now()`
- `updated_at` TIMESTAMPTZ NOT NULL default `now()`
- UNIQUE(`user_id`, `site_id`)
## 8) auth_sync_state
- `id` UUID PK default `gen_random_uuid()`
- `entity_type` VARCHAR(32) NOT NULL
- `entity_id` UUID NOT NULL
- `last_synced_at` TIMESTAMPTZ
- `source_version` TEXT
- `last_error` TEXT
- `updated_at` TIMESTAMPTZ NOT NULL default `now()`
- UNIQUE(`entity_type`, `entity_id`)
## 9) api_clients
- `id` UUID PK default `gen_random_uuid()`
- `client_key` TEXT NOT NULL UNIQUE
- `name` TEXT NOT NULL
- `status` VARCHAR(16) NOT NULL default `'active'`
- `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()`
## 關聯總結
- Company 1:N Site
- System 1:N Role
- Site M:N Role`site_roles`
- User M:N Site`user_sites`
- User 最終角色由 Site 推導,不做 user direct role 指派。