# BD 手册:public Schema — RBAC 与工作流(8 表) > 目标库:`zqyy_app`(通过 `APP_DB_DSN` 连接) > DDL 位置:`docs/database/ddl/zqyy_app__public.sql` > 关联文档:`BD_manual_scheduled_tasks.md`(调度相关 3 表)、`BD_manual_member_retention_clue.md`(维客线索表) --- ## 1. 概述 `public` Schema 共 12 张表,本文档覆盖其中 RBAC(角色权限)+ 工作流(任务审批)共 8 张表。其余 4 张表已有独立文档: | 表 | 文档 | |----|------| | `scheduled_tasks`、`task_queue`、`task_execution_log` | `BD_manual_scheduled_tasks.md` | | `member_retention_clue` | `BD_manual_member_retention_clue.md` | ### 表关系 ``` admin_users(管理后台登录账户,roles 数组字段) users ──┬── user_roles ── roles ── role_permissions ── permissions │ (用户-角色映射) (角色) (角色-权限映射) (权限) │ ├── tasks(任务指派,creator_id / assignee_id → users) │ │ └── approvals(审批记录,approver_id → users,task_id → tasks) ``` --- ## 2. 表结构 ### public.admin_users(9 字段) 管理后台(admin-web / tenant-admin)登录账户。通过 JWT `aud=admin` 或 `aud=tenant-admin` 认证。 | 字段 | 类型 | 约束 | 说明 | |------|------|------|------| | `id` | SERIAL | PK | 自增主键 | | `username` | VARCHAR(64) | NOT NULL, UNIQUE | 登录用户名 | | `password_hash` | VARCHAR(256) | NOT NULL | bcrypt 密码哈希 | | `display_name` | VARCHAR(128) | 可空 | 显示名称 | | `site_id` | BIGINT | NOT NULL | 所属门店 ID | | `is_active` | BOOLEAN | DEFAULT true | 是否启用 | | `roles` | TEXT[] | NOT NULL, DEFAULT '{site_admin}' | 角色数组(`site_admin` / `tenant_admin` 等) | | `created_at` | TIMESTAMPTZ | DEFAULT NOW() | 创建时间 | | `updated_at` | TIMESTAMPTZ | DEFAULT NOW() | 更新时间 | > 注意:`admin_users.roles` 是 TEXT 数组字段(快捷权限标记),与 `roles` 表的 RBAC 体系并行使用。admin-web 当前主要依赖此数组字段做权限判断。 ### public.users(8 字段) 小程序端用户(C 端会员),通过微信 code → JWT `aud=miniapp` 认证。 | 字段 | 类型 | 约束 | 说明 | |------|------|------|------| | `id` | BIGSERIAL | PK | 自增主键 | | `wx_openid` | TEXT | UNIQUE,可空 | 微信 OpenID(登录唯一标识) | | `mobile` | TEXT | 可空 | 手机号 | | `nickname` | TEXT | 可空 | 用户昵称 | | `status` | INTEGER | DEFAULT 1 | 状态(1=正常) | | `site_id` | BIGINT | NOT NULL | 所属门店 ID | | `created_at` | TIMESTAMPTZ | DEFAULT NOW() | 创建时间 | | `updated_at` | TIMESTAMPTZ | DEFAULT NOW() | 更新时间 | ### public.roles(5 字段) 角色定义表,按门店隔离。 | 字段 | 类型 | 约束 | 说明 | |------|------|------|------| | `id` | SERIAL | PK | 自增主键 | | `name` | TEXT | NOT NULL, UNIQUE | 角色名称(全局唯一) | | `description` | TEXT | 可空 | 角色描述 | | `site_id` | BIGINT | NOT NULL | 所属门店 ID | | `created_at` | TIMESTAMPTZ | DEFAULT NOW() | 创建时间 | ### public.permissions(4 字段) 权限定义表(资源+动作组合)。 | 字段 | 类型 | 约束 | 说明 | |------|------|------|------| | `id` | SERIAL | PK | 自增主键 | | `resource` | TEXT | NOT NULL | 资源标识(如 `etl`、`users`) | | `action` | TEXT | NOT NULL | 操作标识(如 `read`、`write`、`execute`) | | `description` | TEXT | 可空 | 权限描述 | ### public.role_permissions(2 字段) 角色-权限关联表(多对多)。 | 字段 | 类型 | 约束 | 说明 | |------|------|------|------| | `role_id` | INTEGER | PK, FK → roles(id) ON DELETE CASCADE | 角色 ID | | `permission_id` | INTEGER | PK, FK → permissions(id) ON DELETE CASCADE | 权限 ID | ### public.user_roles(3 字段) 用户-角色关联表(多对多),按门店隔离。 | 字段 | 类型 | 约束 | 说明 | |------|------|------|------| | `user_id` | BIGINT | PK, FK → users(id) ON DELETE CASCADE | 用户 ID | | `role_id` | INTEGER | PK, FK → roles(id) ON DELETE CASCADE | 角色 ID | | `site_id` | BIGINT | NOT NULL | 门店 ID | ### public.tasks(9 字段) 任务指派表,用于门店内任务管理。 | 字段 | 类型 | 约束 | 说明 | |------|------|------|------| | `id` | BIGSERIAL | PK | 自增主键 | | `title` | TEXT | NOT NULL | 任务标题 | | `description` | TEXT | 可空 | 任务描述 | | `status` | TEXT | DEFAULT 'pending' | 状态:`pending` / `in_progress` / `completed` | | `assignee_id` | BIGINT | FK → users(id),可空 | 负责人 ID | | `creator_id` | BIGINT | FK → users(id),可空 | 创建人 ID | | `site_id` | BIGINT | NOT NULL | 门店 ID | | `created_at` | TIMESTAMPTZ | DEFAULT NOW() | 创建时间 | | `updated_at` | TIMESTAMPTZ | DEFAULT NOW() | 更新时间 | ### public.approvals(7 字段) 审批记录表,关联到任务。 | 字段 | 类型 | 约束 | 说明 | |------|------|------|------| | `id` | BIGSERIAL | PK | 自增主键 | | `task_id` | BIGINT | FK → tasks(id) ON DELETE CASCADE,可空 | 关联任务 ID | | `approver_id` | BIGINT | FK → users(id),可空 | 审批人 ID | | `status` | TEXT | DEFAULT 'pending' | 状态:`pending` / `approved` / `rejected` | | `comment` | TEXT | 可空 | 审批意见 | | `site_id` | BIGINT | NOT NULL | 门店 ID | | `created_at` | TIMESTAMPTZ | DEFAULT NOW() | 创建时间 | --- ## 3. 约束与索引 | 表 | 约束/索引名 | 类型 | 说明 | |----|-----------|------|------| | `admin_users` | `admin_users_pkey` | PK | `(id)` | | `admin_users` | `admin_users_username_key` | UNIQUE | `(username)` | | `admin_users` | `idx_admin_users_site` | INDEX | `(site_id)` | | `users` | `users_pkey` | PK | `(id)` | | `users` | `users_wx_openid_key` | UNIQUE | `(wx_openid)` | | `users` | `idx_users_site_id` | INDEX | `(site_id)` | | `users` | `idx_users_mobile` | INDEX | `(mobile)` | | `roles` | `roles_pkey` | PK | `(id)` | | `roles` | `roles_name_key` | UNIQUE | `(name)` | | `roles` | `idx_roles_site_id` | INDEX | `(site_id)` | | `permissions` | `permissions_pkey` | PK | `(id)` | | `permissions` | `permissions_resource_action_key` | UNIQUE | `(resource, action)` | | `role_permissions` | `role_permissions_pkey` | PK | `(role_id, permission_id)` | | `role_permissions` | FK `role_id` | FK | → roles(id) ON DELETE CASCADE | | `role_permissions` | FK `permission_id` | FK | → permissions(id) ON DELETE CASCADE | | `user_roles` | `user_roles_pkey` | PK | `(user_id, role_id)` | | `user_roles` | FK `user_id` | FK | → users(id) ON DELETE CASCADE | | `user_roles` | FK `role_id` | FK | → roles(id) ON DELETE CASCADE | | `user_roles` | `idx_user_roles_site_id` | INDEX | `(site_id)` | | `tasks` | `tasks_pkey` | PK | `(id)` | | `tasks` | FK `assignee_id` | FK | → users(id) | | `tasks` | FK `creator_id` | FK | → users(id) | | `tasks` | `idx_tasks_site_id` | INDEX | `(site_id)` | | `tasks` | `idx_tasks_status` | INDEX | `(status)` | | `tasks` | `idx_tasks_assignee_id` | INDEX | `(assignee_id)` | | `approvals` | `approvals_pkey` | PK | `(id)` | | `approvals` | FK `task_id` | FK | → tasks(id) ON DELETE CASCADE | | `approvals` | FK `approver_id` | FK | → users(id) | | `approvals` | `idx_approvals_site_id` | INDEX | `(site_id)` | | `approvals` | `idx_approvals_task_id` | INDEX | `(task_id)` | --- ## 4. 兼容性影响 | 组件 | 影响 | |------|------| | admin-web | 直接依赖。登录用 `admin_users`,权限判断用 `admin_users.roles` 数组 | | tenant-admin | 直接依赖。登录也用 `admin_users`(`aud=tenant-admin`),按 `site_id` 隔离 | | 后端 API | `admin_users` 用于 JWT 签发和验证;RBAC 表(roles/permissions/user_roles)用于细粒度权限控制 | | 小程序 | 通过 `users` 表完成微信登录注册和用户信息管理 | | ETL | 无直接影响 | --- ## 5. 验证 SQL ```sql -- 1. 验证 8 张表存在 SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_name IN ('admin_users', 'users', 'roles', 'permissions', 'role_permissions', 'user_roles', 'tasks', 'approvals') ORDER BY table_name; -- 预期:8 行 -- 2. 验证 admin_users 字段数量 SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'admin_users'; -- 预期:9 -- 3. 验证 admin_users.roles 默认值 SELECT column_default FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'admin_users' AND column_name = 'roles'; -- 预期:'{site_admin}'::text[] -- 4. 验证外键关系 SELECT tc.table_name, tc.constraint_name, ccu.table_name AS references_table FROM information_schema.table_constraints tc JOIN information_schema.constraint_column_usage ccu ON tc.constraint_name = ccu.constraint_name WHERE tc.table_schema = 'public' AND tc.constraint_type = 'FOREIGN KEY' AND tc.table_name IN ('approvals', 'tasks', 'role_permissions', 'user_roles') ORDER BY tc.table_name; -- 预期:7 行外键 -- 5. 验证 permissions 唯一约束 SELECT constraint_name FROM information_schema.table_constraints WHERE table_schema = 'public' AND table_name = 'permissions' AND constraint_type = 'UNIQUE'; -- 预期:permissions_resource_action_key ```