docs: rebuild architecture and taskplans for role-site model
This commit is contained in:
@@ -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 指派。
|
||||
|
||||
Reference in New Issue
Block a user