chore: v1 整理 — 清理历史文件、DDL 合并、文档归档

- 清理 1155 个已删除的历史文件(废弃 prompt_logs、tmp、旧 ops 脚本)
- export/ 数据文件从 git 移除(已在 .gitignore)
- demo-miniprogram 从 tmp/ 移入 apps/,添加 CLAUDE.md 注解
- DDL 合并:完整 schema 定义填充到 db/*/schemas/(从 docs/database/ddl/ 复制)
- 39 个 v1 迁移脚本归档到 db/_archived/migrations_v1_merged/
- 4 个迁移变更类 BD_Manual 文档归档到 docs/database/_archived/
- .gitignore 补充 .vite/ 和 apps/*.zip
- settings.json 添加 effortLevel 默认配置
- scripts/ops/ 新增运维脚本入库

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Neo
2026-04-06 00:39:27 +08:00
parent 6f8f12314f
commit 779b2f6d52
1340 changed files with 9124 additions and 132087 deletions

View File

@@ -1,26 +1,23 @@
# db/ — 数据库资产目录
## 当前状态2026-04-05 更新)
## 当前状态2026-04-06 更新)
完整 DDL 基线在 `docs/database/ddl/`(按 schema 分文件,从测试库自动导出)。
本目录保留运行时资产迁移脚本、FDW 配置、建库脚本
DDL 基线最近一次刷新:**2026-04-05**(合并了截至 2026-03-31 的全部迁移)。
项目 v1DDL 不存在迭代更新。完整 schema 定义在 `schemas/` 目录(按 schema 分文件,从测试库导出)。
同一份 DDL 也保留在 `docs/database/ddl/`(文档视角)
## 目录结构
```
db/
├── etl_feiqiu/
│ ├── schemas/ — 已清空DDL 基线见 docs/database/ddl/etl_feiqiu__*.sql
│ ├── migrations/ — 11 个活跃迁移2026-03-19 ~ 2026-03-31
│ ├── seeds/ — 已清空(合并进对应 DDL 文件末尾)
│ ├── schemas/ — 六层完整 DDLmeta/ods/dwd/core/dws/app
│ ├── migrations/ — 未来增量迁移v1 已全部归档
│ ├── ods/ — ODS 补充脚本
│ └── scripts/
│ └── create_test_db.sql
├── zqyy_app/
│ ├── schemas/ — 已清空
│ ├── migrations/ — 8 个活跃迁移2026-03-20 ~ 2026-03-31+ _archived/
│ ├── seeds/ — 已清空
│ ├── schemas/ — 三层完整 DDLpublic/auth/biz
│ ├── migrations/ — 未来增量迁移v1 已全部归档)
│ └── scripts/
│ └── create_test_db.sql
├── fdw/ — FDW 跨库映射配置
@@ -28,42 +25,43 @@ db/
│ ├── setup_fdw_test.sql — 正向(测试环境)
│ ├── setup_fdw_reverse.sql — 反向etl_feiqiu → zqyy_app.member_retention_clue
│ └── setup_fdw_reverse_test.sql — 反向(测试环境)
└── _archived/ — 归档2026-02-22 基线重置前的旧迁移,仅供历史参考)
── ddl_baseline_2026-02-22/
└── _archived/ — 归档
── ddl_baseline_2026-02-22/ — 旧基线
└── migrations_v1_merged/ — v1 全部迁移39 个,已合并进 schemas/
├── etl_feiqiu/ — 11 个迁移
└── zqyy_app/ — 28 个迁移
```
## DDL 基线
## Schema 文件
新建库或 schema diff 请使用 `docs/database/ddl/` 下的文件:
`db/etl_feiqiu/schemas/``db/zqyy_app/schemas/` 是权威的完整 DDL包含建表、索引、约束、种子数据。
| 文件 | 数据库 | Schema | 对象数 |
|------|--------|--------|--------|
| `etl_feiqiu__meta.sql` | etl_feiqiu | meta | 3 表 |
| `etl_feiqiu__ods.sql` | etl_feiqiu | ods | 23 表 |
| `etl_feiqiu__dwd.sql` | etl_feiqiu | dwd | 42 表 |
| `etl_feiqiu__core.sql` | etl_feiqiu | core | 7 表 |
| `etl_feiqiu__dws.sql` | etl_feiqiu | dws | 38 表 |
| `etl_feiqiu__app.sql` | etl_feiqiu | app | 仅视图 |
| `zqyy_app__public.sql` | zqyy_app | public | 12 表 |
| `zqyy_app__auth.sql` | zqyy_app | auth | 9 表 |
| `zqyy_app__biz.sql` | zqyy_app | biz | 21 表 |
| `fdw.sql` | — | — | 正向 FDW 映射 |
| `fdw_reverse.sql` | — | — | 反向 FDW 映射 |
| `etl_feiqiu/schemas/meta.sql` | etl_feiqiu | meta | 3 表 |
| `etl_feiqiu/schemas/ods.sql` | etl_feiqiu | ods | 23 表 |
| `etl_feiqiu/schemas/dwd.sql` | etl_feiqiu | dwd | 42 表 |
| `etl_feiqiu/schemas/core.sql` | etl_feiqiu | core | 7 表 |
| `etl_feiqiu/schemas/dws.sql` | etl_feiqiu | dws | 38 表 |
| `etl_feiqiu/schemas/app.sql` | etl_feiqiu | app | 仅视图 |
| `zqyy_app/schemas/public.sql` | zqyy_app | public | 12 表 |
| `zqyy_app/schemas/auth.sql` | zqyy_app | auth | 9 表 |
| `zqyy_app/schemas/biz.sql` | zqyy_app | biz | 21 表 |
重新生成:`PYTHONUTF8=1 python tools/db/gen_consolidated_ddl.py`
## 迁移管理
项目 1.0 尚未上线DDL 基线已统一到 `docs/database/ddl/`(含种子数据)
后续新增迁移脚本放 `migrations/`,文件名格式 `YYYY-MM-DD__描述.sql`
每次迁移执行后,重新运行 DDL 生成脚本刷新基线
种子数据已合并进对应 DDL 文件末尾,不再单独维护 `seeds/` 目录
v1 阶段的 39 个迁移已全部合并进 `schemas/` 完整 DDL原文件归档在 `_archived/migrations_v1_merged/`
后续新增迁移放 `migrations/`,文件名格式 `YYYY-MM-DD__描述.sql`
执行后重新运行 DDL 生成脚本刷新 `schemas/` 基线
## 文档分工
| 位置 | 管辖范围 |
|------|---------|
| `docs/database/` | 业务库(zqyy_app) BD_Manual + 跨模块(FDW/RLS) + DDL 基线 |
| `docs/database/` | 业务库(zqyy_app) BD_Manual + 跨模块(FDW/RLS) + DDL 基线副本 |
| `apps/etl/connectors/feiqiu/docs/database/` | ETL 专属(ODS/DWD/DWS 表级文档) |
| `db/`(本目录) | 运行时资产(迁移脚本/FDW 配置/建库脚本) |
| `db/`(本目录) | 权威 DDL + 运行时资产(迁移/FDW/建库脚本) |
| `tools/db/` | 数据库工具(DDL 生成/验证/一致性检查) |

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,99 @@
-- =============================================================================
-- etl_feiqiu / core跨门店标准化维度/事实)
-- 生成日期2026-04-05
-- 来源:测试库(通过脚本自动导出)
-- =============================================================================
CREATE SCHEMA IF NOT EXISTS core;
-- 表
CREATE TABLE core.dim_assistant (
assistant_id bigint NOT NULL,
tenant_id bigint NOT NULL,
site_id bigint NOT NULL,
real_name text NOT NULL,
nickname text,
mobile text,
level integer,
assistant_status integer,
leave_status integer
);
CREATE TABLE core.dim_goods_category (
category_id bigint NOT NULL,
tenant_id bigint NOT NULL,
category_name text NOT NULL,
parent_id bigint,
level integer
);
CREATE TABLE core.dim_member (
member_id bigint NOT NULL,
system_member_id bigint,
tenant_id bigint NOT NULL,
register_site_id bigint NOT NULL,
mobile text,
nickname text,
member_card_grade_name text,
status integer
);
CREATE TABLE core.dim_site (
site_id bigint NOT NULL,
tenant_id bigint NOT NULL,
shop_name text NOT NULL,
site_label text,
shop_status integer,
site_id_alias bigint
);
CREATE TABLE core.dim_table (
table_id bigint NOT NULL,
site_id bigint NOT NULL,
table_name text NOT NULL,
site_table_area_name text,
table_price numeric(18,2)
);
CREATE TABLE core.fact_payment (
payment_id bigint NOT NULL,
site_id bigint NOT NULL,
order_settle_id bigint,
pay_type integer,
pay_amount numeric(18,2),
pay_time timestamp with time zone,
status integer
);
CREATE TABLE core.fact_settlement (
order_settle_id bigint NOT NULL,
site_id bigint NOT NULL,
tenant_id bigint NOT NULL,
order_trade_no bigint,
member_id bigint,
total_amount numeric(18,2),
actual_amount numeric(18,2),
discount_amount numeric(18,2),
pay_status integer,
settle_time timestamp with time zone,
created_at timestamp with time zone,
updated_at timestamp with time zone
);
-- 约束(主键 / 唯一 / 外键)
ALTER TABLE core.dim_assistant ADD CONSTRAINT dim_assistant_pkey PRIMARY KEY (assistant_id);
ALTER TABLE core.dim_goods_category ADD CONSTRAINT dim_goods_category_pkey PRIMARY KEY (category_id);
ALTER TABLE core.dim_member ADD CONSTRAINT dim_member_pkey PRIMARY KEY (member_id);
ALTER TABLE core.dim_site ADD CONSTRAINT dim_site_pkey PRIMARY KEY (site_id);
ALTER TABLE core.dim_table ADD CONSTRAINT dim_table_pkey PRIMARY KEY (table_id);
ALTER TABLE core.fact_payment ADD CONSTRAINT fact_payment_pkey PRIMARY KEY (payment_id);
ALTER TABLE core.fact_settlement ADD CONSTRAINT fact_settlement_pkey PRIMARY KEY (order_settle_id);
-- 索引
CREATE INDEX idx_core_assistant_site ON core.dim_assistant USING btree (site_id);
CREATE INDEX idx_core_member_site ON core.dim_member USING btree (register_site_id);
CREATE INDEX idx_core_table_site ON core.dim_table USING btree (site_id);
CREATE INDEX idx_core_payment_site ON core.fact_payment USING btree (site_id);
CREATE INDEX idx_core_settlement_site ON core.fact_settlement USING btree (site_id);
CREATE INDEX idx_core_settlement_time ON core.fact_settlement USING btree (settle_time);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,77 @@
-- =============================================================================
-- etl_feiqiu / metaETL 调度元数据)
-- 生成日期2026-04-05
-- 来源:测试库(通过脚本自动导出)
-- =============================================================================
CREATE SCHEMA IF NOT EXISTS meta;
-- 序列
CREATE SEQUENCE IF NOT EXISTS meta.etl_cursor_cursor_id_seq AS bigint;
CREATE SEQUENCE IF NOT EXISTS meta.etl_run_run_id_seq AS bigint;
CREATE SEQUENCE IF NOT EXISTS meta.etl_task_task_id_seq AS bigint;
-- 表
CREATE TABLE meta.etl_cursor (
cursor_id bigint DEFAULT nextval('meta.etl_cursor_cursor_id_seq'::regclass) NOT NULL,
task_id bigint NOT NULL,
store_id bigint NOT NULL,
last_start timestamp with time zone,
last_end timestamp with time zone,
last_id bigint,
last_run_id bigint,
extra jsonb DEFAULT '{}'::jsonb,
created_at timestamp with time zone DEFAULT now(),
updated_at timestamp with time zone DEFAULT now()
);
CREATE TABLE meta.etl_run (
run_id bigint DEFAULT nextval('meta.etl_run_run_id_seq'::regclass) NOT NULL,
run_uuid text NOT NULL,
task_id bigint NOT NULL,
store_id bigint NOT NULL,
status text NOT NULL,
started_at timestamp with time zone DEFAULT now(),
ended_at timestamp with time zone,
window_start timestamp with time zone,
window_end timestamp with time zone,
window_minutes integer,
overlap_seconds integer,
fetched_count integer DEFAULT 0,
loaded_count integer DEFAULT 0,
updated_count integer DEFAULT 0,
skipped_count integer DEFAULT 0,
error_count integer DEFAULT 0,
unknown_fields integer DEFAULT 0,
export_dir text,
log_path text,
request_params jsonb DEFAULT '{}'::jsonb,
manifest jsonb DEFAULT '{}'::jsonb,
error_message text,
extra jsonb DEFAULT '{}'::jsonb
);
CREATE TABLE meta.etl_task (
task_id bigint DEFAULT nextval('meta.etl_task_task_id_seq'::regclass) NOT NULL,
task_code text NOT NULL,
store_id bigint NOT NULL,
enabled boolean DEFAULT true,
cursor_field text,
window_minutes_default integer DEFAULT 30,
overlap_seconds integer DEFAULT 600,
page_size integer DEFAULT 200,
retry_max integer DEFAULT 3,
params jsonb DEFAULT '{}'::jsonb,
created_at timestamp with time zone DEFAULT now(),
updated_at timestamp with time zone DEFAULT now()
);
-- 约束(主键 / 唯一 / 外键)
ALTER TABLE meta.etl_cursor ADD CONSTRAINT etl_cursor_task_id_fkey FOREIGN KEY (task_id) REFERENCES meta.etl_task(task_id) ON DELETE CASCADE;
ALTER TABLE meta.etl_cursor ADD CONSTRAINT etl_cursor_pkey PRIMARY KEY (cursor_id);
ALTER TABLE meta.etl_cursor ADD CONSTRAINT etl_cursor_task_id_store_id_key UNIQUE (task_id, store_id);
ALTER TABLE meta.etl_run ADD CONSTRAINT etl_run_task_id_fkey FOREIGN KEY (task_id) REFERENCES meta.etl_task(task_id) ON DELETE CASCADE;
ALTER TABLE meta.etl_run ADD CONSTRAINT etl_run_pkey PRIMARY KEY (run_id);
ALTER TABLE meta.etl_task ADD CONSTRAINT etl_task_pkey PRIMARY KEY (task_id);
ALTER TABLE meta.etl_task ADD CONSTRAINT etl_task_task_code_store_id_key UNIQUE (task_code, store_id);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,163 @@
-- =============================================================================
-- zqyy_app / auth用户认证与权限
-- 生成日期2026-04-05
-- 来源:测试库(通过脚本自动导出)
-- =============================================================================
CREATE SCHEMA IF NOT EXISTS auth;
-- 序列
CREATE SEQUENCE IF NOT EXISTS auth.permissions_id_seq AS integer;
CREATE SEQUENCE IF NOT EXISTS auth.roles_id_seq AS integer;
CREATE SEQUENCE IF NOT EXISTS auth.site_code_mapping_id_seq AS integer;
CREATE SEQUENCE IF NOT EXISTS auth.tenant_admins_id_seq AS bigint;
CREATE SEQUENCE IF NOT EXISTS auth.user_applications_id_seq AS integer;
CREATE SEQUENCE IF NOT EXISTS auth.user_assistant_binding_id_seq AS integer;
CREATE SEQUENCE IF NOT EXISTS auth.user_site_roles_id_seq AS integer;
CREATE SEQUENCE IF NOT EXISTS auth.users_id_seq AS integer;
-- 表
CREATE TABLE auth._archived_site_code_mapping (
id integer DEFAULT nextval('auth.site_code_mapping_id_seq'::regclass) NOT NULL,
site_code character varying(10) NOT NULL,
site_id bigint NOT NULL,
site_name character varying(200),
tenant_id bigint,
created_at timestamp with time zone DEFAULT now() NOT NULL
);
CREATE TABLE auth.permissions (
id integer DEFAULT nextval('auth.permissions_id_seq'::regclass) NOT NULL,
code character varying(100) NOT NULL,
name character varying(200) NOT NULL,
description text,
created_at timestamp with time zone DEFAULT now() NOT NULL
);
CREATE TABLE auth.role_permissions (
role_id integer NOT NULL,
permission_id integer NOT NULL
);
CREATE TABLE auth.roles (
id integer DEFAULT nextval('auth.roles_id_seq'::regclass) NOT NULL,
code character varying(50) NOT NULL,
name character varying(100) NOT NULL,
description text,
created_at timestamp with time zone DEFAULT now() NOT NULL
);
CREATE TABLE auth.tenant_admins (
id bigint DEFAULT nextval('auth.tenant_admins_id_seq'::regclass) NOT NULL,
username character varying(50) NOT NULL,
password_hash character varying(255) NOT NULL,
display_name character varying(100),
tenant_id bigint NOT NULL,
managed_site_ids _int8 NOT NULL,
is_active boolean DEFAULT true,
created_by bigint,
created_at timestamp with time zone DEFAULT now(),
last_login_at timestamp with time zone,
deleted_at timestamp with time zone,
admin_type character varying(20) DEFAULT 'tenant_admin'::character varying NOT NULL
);
CREATE TABLE auth.user_applications (
id integer DEFAULT nextval('auth.user_applications_id_seq'::regclass) NOT NULL,
user_id integer NOT NULL,
site_code character varying(10) NOT NULL,
site_id bigint,
applied_role_text character varying(100) NOT NULL,
employee_number character varying(50),
phone character varying(20) NOT NULL,
status character varying(20) DEFAULT 'pending'::character varying NOT NULL,
reviewer_id integer,
review_note text,
created_at timestamp with time zone DEFAULT now() NOT NULL,
reviewed_at timestamp with time zone
);
CREATE TABLE auth.user_assistant_binding (
id integer DEFAULT nextval('auth.user_assistant_binding_id_seq'::regclass) NOT NULL,
user_id integer NOT NULL,
site_id bigint NOT NULL,
assistant_id bigint,
staff_id bigint,
binding_type character varying(20) NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
is_removed boolean DEFAULT false NOT NULL,
removed_at timestamp with time zone
);
CREATE TABLE auth.user_site_roles (
id integer DEFAULT nextval('auth.user_site_roles_id_seq'::regclass) NOT NULL,
user_id integer NOT NULL,
site_id bigint NOT NULL,
role_id integer NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
is_removed boolean DEFAULT false NOT NULL,
removed_at timestamp with time zone
);
CREATE TABLE auth.users (
id integer DEFAULT nextval('auth.users_id_seq'::regclass) NOT NULL,
wx_openid character varying(100),
wx_union_id character varying(100),
wx_avatar_url text,
nickname character varying(100),
phone character varying(20),
status character varying(20) DEFAULT 'new'::character varying NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
updated_at timestamp with time zone DEFAULT now() NOT NULL,
rejection_count integer DEFAULT 0 NOT NULL,
avatar_url character varying(500)
);
-- 约束(主键 / 唯一 / 外键)
ALTER TABLE auth._archived_site_code_mapping ADD CONSTRAINT site_code_mapping_pkey PRIMARY KEY (id);
ALTER TABLE auth._archived_site_code_mapping ADD CONSTRAINT site_code_mapping_site_code_key UNIQUE (site_code);
ALTER TABLE auth._archived_site_code_mapping ADD CONSTRAINT site_code_mapping_site_id_key UNIQUE (site_id);
ALTER TABLE auth._archived_site_code_mapping ADD CONSTRAINT uq_site_code_mapping_site_code UNIQUE (site_code);
ALTER TABLE auth._archived_site_code_mapping ADD CONSTRAINT uq_site_code_mapping_site_id UNIQUE (site_id);
ALTER TABLE auth.permissions ADD CONSTRAINT permissions_pkey PRIMARY KEY (id);
ALTER TABLE auth.permissions ADD CONSTRAINT permissions_code_key UNIQUE (code);
ALTER TABLE auth.permissions ADD CONSTRAINT uq_permissions_code UNIQUE (code);
ALTER TABLE auth.role_permissions ADD CONSTRAINT fk_role_permissions_permission_id FOREIGN KEY (permission_id) REFERENCES auth.permissions(id) ON DELETE CASCADE;
ALTER TABLE auth.role_permissions ADD CONSTRAINT fk_role_permissions_role_id FOREIGN KEY (role_id) REFERENCES auth.roles(id) ON DELETE CASCADE;
ALTER TABLE auth.role_permissions ADD CONSTRAINT role_permissions_permission_id_fkey FOREIGN KEY (permission_id) REFERENCES auth.permissions(id) ON DELETE CASCADE;
ALTER TABLE auth.role_permissions ADD CONSTRAINT role_permissions_role_id_fkey FOREIGN KEY (role_id) REFERENCES auth.roles(id) ON DELETE CASCADE;
ALTER TABLE auth.role_permissions ADD CONSTRAINT role_permissions_pkey PRIMARY KEY (role_id, permission_id);
ALTER TABLE auth.roles ADD CONSTRAINT roles_pkey PRIMARY KEY (id);
ALTER TABLE auth.roles ADD CONSTRAINT roles_code_key UNIQUE (code);
ALTER TABLE auth.roles ADD CONSTRAINT uq_roles_code UNIQUE (code);
ALTER TABLE auth.tenant_admins ADD CONSTRAINT tenant_admins_pkey PRIMARY KEY (id);
ALTER TABLE auth.tenant_admins ADD CONSTRAINT tenant_admins_username_key UNIQUE (username);
ALTER TABLE auth.user_applications ADD CONSTRAINT fk_user_applications_user_id FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE CASCADE;
ALTER TABLE auth.user_applications ADD CONSTRAINT user_applications_user_id_fkey FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE CASCADE;
ALTER TABLE auth.user_applications ADD CONSTRAINT user_applications_pkey PRIMARY KEY (id);
ALTER TABLE auth.user_assistant_binding ADD CONSTRAINT fk_user_assistant_binding_user_id FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE CASCADE;
ALTER TABLE auth.user_assistant_binding ADD CONSTRAINT user_assistant_binding_user_id_fkey FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE CASCADE;
ALTER TABLE auth.user_assistant_binding ADD CONSTRAINT user_assistant_binding_pkey PRIMARY KEY (id);
ALTER TABLE auth.user_site_roles ADD CONSTRAINT fk_user_site_roles_role_id FOREIGN KEY (role_id) REFERENCES auth.roles(id) ON DELETE CASCADE;
ALTER TABLE auth.user_site_roles ADD CONSTRAINT fk_user_site_roles_user_id FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE CASCADE;
ALTER TABLE auth.user_site_roles ADD CONSTRAINT user_site_roles_role_id_fkey FOREIGN KEY (role_id) REFERENCES auth.roles(id) ON DELETE CASCADE;
ALTER TABLE auth.user_site_roles ADD CONSTRAINT user_site_roles_user_id_fkey FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE CASCADE;
ALTER TABLE auth.user_site_roles ADD CONSTRAINT user_site_roles_pkey PRIMARY KEY (id);
ALTER TABLE auth.user_site_roles ADD CONSTRAINT uq_user_site_roles_user_site_role UNIQUE (user_id, site_id, role_id);
ALTER TABLE auth.user_site_roles ADD CONSTRAINT user_site_roles_user_id_site_id_role_id_key UNIQUE (user_id, site_id, role_id);
ALTER TABLE auth.users ADD CONSTRAINT users_pkey PRIMARY KEY (id);
ALTER TABLE auth.users ADD CONSTRAINT uq_users_wx_openid UNIQUE (wx_openid);
ALTER TABLE auth.users ADD CONSTRAINT users_wx_openid_key UNIQUE (wx_openid);
-- 索引
CREATE INDEX ix_site_code_mapping_site_code ON auth._archived_site_code_mapping USING btree (site_code);
CREATE INDEX idx_tenant_admin_tenant ON auth.tenant_admins USING btree (tenant_id);
CREATE INDEX idx_tenant_admins_active_not_deleted ON auth.tenant_admins USING btree (is_active) WHERE (deleted_at IS NULL);
CREATE INDEX ix_user_applications_status ON auth.user_applications USING btree (status);
CREATE INDEX ix_user_applications_user_id ON auth.user_applications USING btree (user_id);
CREATE INDEX idx_user_assistant_binding_active ON auth.user_assistant_binding USING btree (user_id, site_id) WHERE (is_removed = false);
CREATE INDEX idx_user_site_roles_active ON auth.user_site_roles USING btree (user_id, site_id) WHERE (is_removed = false);
CREATE INDEX ix_user_site_roles_user_site ON auth.user_site_roles USING btree (user_id, site_id);
CREATE INDEX ix_users_status ON auth.users USING btree (status);
CREATE INDEX ix_users_wx_openid ON auth.users USING btree (wx_openid);

390
db/zqyy_app/schemas/biz.sql Normal file
View File

@@ -0,0 +1,390 @@
-- =============================================================================
-- zqyy_app / biz核心业务表任务/备注/触发器))
-- 生成日期2026-04-05
-- 来源:测试库(通过脚本自动导出)
-- =============================================================================
CREATE SCHEMA IF NOT EXISTS biz;
-- 序列
CREATE SEQUENCE IF NOT EXISTS biz.ai_cache_id_seq AS bigint;
CREATE SEQUENCE IF NOT EXISTS biz.ai_conversations_id_seq AS bigint;
CREATE SEQUENCE IF NOT EXISTS biz.ai_messages_id_seq AS bigint;
CREATE SEQUENCE IF NOT EXISTS biz.ai_run_logs_id_seq AS bigint;
CREATE SEQUENCE IF NOT EXISTS biz.ai_trigger_jobs_id_seq AS bigint;
CREATE SEQUENCE IF NOT EXISTS biz.cfg_task_generator_params_id_seq AS bigint;
CREATE SEQUENCE IF NOT EXISTS biz.coach_task_history_id_seq AS bigint;
CREATE SEQUENCE IF NOT EXISTS biz.coach_task_transfer_log_id_seq AS bigint;
CREATE SEQUENCE IF NOT EXISTS biz.coach_tasks_id_seq AS bigint;
CREATE SEQUENCE IF NOT EXISTS biz.connectors_id_seq AS integer;
CREATE SEQUENCE IF NOT EXISTS biz.dws_assistant_task_monthly_id_seq AS bigint;
CREATE SEQUENCE IF NOT EXISTS biz.excel_upload_log_id_seq AS bigint;
CREATE SEQUENCE IF NOT EXISTS biz.notes_id_seq AS bigint;
CREATE SEQUENCE IF NOT EXISTS biz.salary_adjustments_id_seq AS bigint;
CREATE SEQUENCE IF NOT EXISTS biz.site_code_history_id_seq AS integer;
CREATE SEQUENCE IF NOT EXISTS biz.sites_id_seq AS integer;
CREATE SEQUENCE IF NOT EXISTS biz.stg_finance_expense_id_seq AS bigint;
CREATE SEQUENCE IF NOT EXISTS biz.stg_platform_income_id_seq AS bigint;
CREATE SEQUENCE IF NOT EXISTS biz.stg_recharge_commission_id_seq AS bigint;
CREATE SEQUENCE IF NOT EXISTS biz.tenants_id_seq AS integer;
CREATE SEQUENCE IF NOT EXISTS biz.trigger_jobs_id_seq AS integer;
-- 表
CREATE TABLE biz.ai_cache (
id bigint DEFAULT nextval('biz.ai_cache_id_seq'::regclass) NOT NULL,
cache_type character varying(30) NOT NULL,
site_id bigint NOT NULL,
target_id character varying(100) NOT NULL,
result_json jsonb NOT NULL,
score integer,
triggered_by character varying(100),
created_at timestamp with time zone DEFAULT now() NOT NULL,
expires_at timestamp with time zone,
status character varying(20) DEFAULT 'valid'::character varying
);
CREATE TABLE biz.ai_conversations (
id bigint DEFAULT nextval('biz.ai_conversations_id_seq'::regclass) NOT NULL,
user_id character varying(50) NOT NULL,
nickname character varying(100) DEFAULT ''::character varying NOT NULL,
app_id character varying(30) NOT NULL,
site_id bigint NOT NULL,
source_page character varying(100),
source_context jsonb,
created_at timestamp with time zone DEFAULT now() NOT NULL,
context_type character varying(20),
context_id character varying(50),
title character varying(200),
last_message text,
last_message_at timestamp with time zone,
session_id character varying(100)
);
CREATE TABLE biz.ai_messages (
id bigint DEFAULT nextval('biz.ai_messages_id_seq'::regclass) NOT NULL,
conversation_id bigint NOT NULL,
role character varying(10) NOT NULL,
content text NOT NULL,
tokens_used integer,
created_at timestamp with time zone DEFAULT now() NOT NULL,
reference_card jsonb
);
CREATE TABLE biz.ai_run_logs (
id bigint DEFAULT nextval('biz.ai_run_logs_id_seq'::regclass) NOT NULL,
site_id bigint NOT NULL,
app_type character varying(30) NOT NULL,
trigger_type character varying(20) NOT NULL,
member_id bigint,
request_prompt text,
response_text text,
tokens_used integer DEFAULT 0,
latency_ms integer,
status character varying(20) DEFAULT 'pending'::character varying NOT NULL,
error_message text,
session_id character varying(100),
created_at timestamp with time zone DEFAULT now() NOT NULL,
finished_at timestamp with time zone,
alert_status character varying(20) DEFAULT NULL::character varying
);
CREATE TABLE biz.ai_trigger_jobs (
id bigint DEFAULT nextval('biz.ai_trigger_jobs_id_seq'::regclass) NOT NULL,
site_id bigint NOT NULL,
event_type character varying(30) NOT NULL,
connector_type character varying(30) DEFAULT 'feiqiu'::character varying,
member_id bigint,
payload jsonb,
status character varying(20) DEFAULT 'pending'::character varying NOT NULL,
is_forced boolean DEFAULT false,
app_chain character varying(100),
started_at timestamp with time zone,
finished_at timestamp with time zone,
error_message text,
created_at timestamp with time zone DEFAULT now() NOT NULL
);
CREATE TABLE biz.cfg_task_generator_params (
id bigint DEFAULT nextval('biz.cfg_task_generator_params_id_seq'::regclass) NOT NULL,
site_id bigint,
param_key character varying(64) NOT NULL,
param_value numeric NOT NULL,
description text,
updated_at timestamp with time zone DEFAULT now() NOT NULL,
updated_by bigint
);
CREATE TABLE biz.coach_task_history (
id bigint DEFAULT nextval('biz.coach_task_history_id_seq'::regclass) NOT NULL,
task_id bigint NOT NULL,
action character varying(50) NOT NULL,
old_status character varying(20),
new_status character varying(20),
old_task_type character varying(50),
new_task_type character varying(50),
detail jsonb,
created_at timestamp with time zone DEFAULT now()
);
CREATE TABLE biz.coach_task_transfer_log (
id bigint DEFAULT nextval('biz.coach_task_transfer_log_id_seq'::regclass) NOT NULL,
site_id bigint NOT NULL,
member_id bigint NOT NULL,
from_assistant_id bigint NOT NULL,
to_assistant_id bigint NOT NULL,
from_task_id bigint NOT NULL,
to_task_id bigint,
transfer_reason text,
guard_checks jsonb,
transfer_score numeric,
created_at timestamp with time zone DEFAULT now() NOT NULL
);
CREATE TABLE biz.coach_tasks (
id bigint DEFAULT nextval('biz.coach_tasks_id_seq'::regclass) NOT NULL,
site_id bigint NOT NULL,
assistant_id bigint NOT NULL,
member_id bigint NOT NULL,
task_type character varying(50) NOT NULL,
status character varying(20) DEFAULT 'active'::character varying NOT NULL,
priority_score numeric(5,2),
expires_at timestamp with time zone,
is_pinned boolean DEFAULT false,
abandon_reason text,
completed_at timestamp with time zone,
completed_task_type character varying(50),
parent_task_id bigint,
created_at timestamp with time zone DEFAULT now(),
updated_at timestamp with time zone DEFAULT now(),
transfer_count integer DEFAULT 0 NOT NULL,
transferred_from bigint,
transferred_at timestamp with time zone
);
CREATE TABLE biz.connectors (
id integer DEFAULT nextval('biz.connectors_id_seq'::regclass) NOT NULL,
connector_key character varying(50) NOT NULL,
display_name character varying(100) NOT NULL,
is_active boolean DEFAULT true NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL
);
CREATE TABLE biz.dws_assistant_task_monthly (
id bigint DEFAULT nextval('biz.dws_assistant_task_monthly_id_seq'::regclass) NOT NULL,
site_id bigint NOT NULL,
assistant_id bigint NOT NULL,
stat_month date NOT NULL,
recall_created integer DEFAULT 0 NOT NULL,
follow_up_created integer DEFAULT 0 NOT NULL,
relationship_created integer DEFAULT 0 NOT NULL,
total_created integer DEFAULT 0 NOT NULL,
recall_completed integer DEFAULT 0 NOT NULL,
follow_up_completed integer DEFAULT 0 NOT NULL,
total_completed integer DEFAULT 0 NOT NULL,
abandoned_count integer DEFAULT 0 NOT NULL,
transferred_count integer DEFAULT 0 NOT NULL,
updated_at timestamp with time zone DEFAULT now() NOT NULL
);
CREATE TABLE biz.excel_upload_log (
id bigint DEFAULT nextval('biz.excel_upload_log_id_seq'::regclass) NOT NULL,
site_id bigint NOT NULL,
upload_type character varying(30) NOT NULL,
file_name character varying(255) NOT NULL,
uploaded_by bigint NOT NULL,
row_count integer DEFAULT 0,
conflict_count integer DEFAULT 0,
resolved_count integer DEFAULT 0,
status character varying(20) NOT NULL,
error_detail jsonb,
created_at timestamp with time zone DEFAULT now(),
confirmed_at timestamp with time zone
);
CREATE TABLE biz.notes (
id bigint DEFAULT nextval('biz.notes_id_seq'::regclass) NOT NULL,
site_id bigint NOT NULL,
user_id integer NOT NULL,
target_type character varying(50) NOT NULL,
target_id bigint NOT NULL,
type character varying(20) DEFAULT 'normal'::character varying NOT NULL,
content text NOT NULL,
rating_service_willingness smallint,
rating_revisit_likelihood smallint,
task_id bigint,
ai_score smallint,
ai_analysis text,
created_at timestamp with time zone DEFAULT now(),
updated_at timestamp with time zone DEFAULT now(),
score smallint
);
CREATE TABLE biz.salary_adjustments (
id bigint DEFAULT nextval('biz.salary_adjustments_id_seq'::regclass) NOT NULL,
site_id bigint NOT NULL,
assistant_id bigint,
assistant_name character varying(100) NOT NULL,
assistant_number character varying(50) NOT NULL,
salary_month character varying(7) NOT NULL,
adjustment_type character varying(20) NOT NULL,
amount numeric(12,2) NOT NULL,
reason character varying(200) NOT NULL,
upload_batch_id bigint,
created_at timestamp with time zone DEFAULT now(),
created_by bigint
);
CREATE TABLE biz.site_code_history (
id integer DEFAULT nextval('biz.site_code_history_id_seq'::regclass) NOT NULL,
site_id bigint NOT NULL,
site_code character varying(6) NOT NULL,
is_current boolean DEFAULT false NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
retired_at timestamp with time zone
);
CREATE TABLE biz.sites (
id integer DEFAULT nextval('biz.sites_id_seq'::regclass) NOT NULL,
tenant_id integer NOT NULL,
site_id bigint NOT NULL,
site_name character varying(200),
site_code character varying(6),
site_label character varying(50),
is_active boolean DEFAULT true NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
updated_at timestamp with time zone DEFAULT now() NOT NULL
);
CREATE TABLE biz.stg_finance_expense (
id bigint DEFAULT nextval('biz.stg_finance_expense_id_seq'::regclass) NOT NULL,
site_id bigint NOT NULL,
expense_month character varying(7) NOT NULL,
category character varying(50) NOT NULL,
amount numeric(12,2) NOT NULL,
remark text,
upload_batch_id bigint,
synced_at timestamp with time zone,
created_at timestamp with time zone DEFAULT now()
);
CREATE TABLE biz.stg_platform_income (
id bigint DEFAULT nextval('biz.stg_platform_income_id_seq'::regclass) NOT NULL,
site_id bigint NOT NULL,
income_month character varying(7) NOT NULL,
platform_name character varying(100) NOT NULL,
amount numeric(12,2) NOT NULL,
remark text,
upload_batch_id bigint,
synced_at timestamp with time zone,
created_at timestamp with time zone DEFAULT now()
);
CREATE TABLE biz.stg_recharge_commission (
id bigint DEFAULT nextval('biz.stg_recharge_commission_id_seq'::regclass) NOT NULL,
site_id bigint NOT NULL,
recharge_date date NOT NULL,
member_name character varying(100) NOT NULL,
recharge_amount numeric(12,2) NOT NULL,
assigned_assistant character varying(100) NOT NULL,
reward_amount numeric(12,2) NOT NULL,
upload_batch_id bigint,
synced_at timestamp with time zone,
created_at timestamp with time zone DEFAULT now()
);
CREATE TABLE biz.tenants (
id integer DEFAULT nextval('biz.tenants_id_seq'::regclass) NOT NULL,
connector_id integer NOT NULL,
tenant_id bigint NOT NULL,
tenant_name character varying(200),
is_active boolean DEFAULT true NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
updated_at timestamp with time zone DEFAULT now() NOT NULL
);
CREATE TABLE biz.trigger_jobs (
id integer DEFAULT nextval('biz.trigger_jobs_id_seq'::regclass) NOT NULL,
job_type character varying(100) NOT NULL,
job_name character varying(100) NOT NULL,
trigger_condition character varying(20) NOT NULL,
trigger_config jsonb NOT NULL,
last_run_at timestamp with time zone,
next_run_at timestamp with time zone,
status character varying(20) DEFAULT 'enabled'::character varying NOT NULL,
created_at timestamp with time zone DEFAULT now(),
last_error text,
description text,
last_stats jsonb
);
-- 约束(主键 / 唯一 / 外键)
ALTER TABLE biz.ai_cache ADD CONSTRAINT ai_cache_pkey PRIMARY KEY (id);
ALTER TABLE biz.ai_conversations ADD CONSTRAINT ai_conversations_pkey PRIMARY KEY (id);
ALTER TABLE biz.ai_messages ADD CONSTRAINT ai_messages_conversation_id_fkey FOREIGN KEY (conversation_id) REFERENCES biz.ai_conversations(id) ON DELETE CASCADE;
ALTER TABLE biz.ai_messages ADD CONSTRAINT ai_messages_pkey PRIMARY KEY (id);
ALTER TABLE biz.ai_run_logs ADD CONSTRAINT ai_run_logs_pkey PRIMARY KEY (id);
ALTER TABLE biz.ai_trigger_jobs ADD CONSTRAINT ai_trigger_jobs_pkey PRIMARY KEY (id);
ALTER TABLE biz.cfg_task_generator_params ADD CONSTRAINT cfg_task_generator_params_pkey PRIMARY KEY (id);
ALTER TABLE biz.cfg_task_generator_params ADD CONSTRAINT cfg_task_generator_params_site_id_param_key_key UNIQUE (site_id, param_key);
ALTER TABLE biz.coach_task_history ADD CONSTRAINT coach_task_history_task_id_fkey FOREIGN KEY (task_id) REFERENCES biz.coach_tasks(id);
ALTER TABLE biz.coach_task_history ADD CONSTRAINT coach_task_history_pkey PRIMARY KEY (id);
ALTER TABLE biz.coach_task_transfer_log ADD CONSTRAINT coach_task_transfer_log_from_task_id_fkey FOREIGN KEY (from_task_id) REFERENCES biz.coach_tasks(id);
ALTER TABLE biz.coach_task_transfer_log ADD CONSTRAINT coach_task_transfer_log_to_task_id_fkey FOREIGN KEY (to_task_id) REFERENCES biz.coach_tasks(id);
ALTER TABLE biz.coach_task_transfer_log ADD CONSTRAINT coach_task_transfer_log_pkey PRIMARY KEY (id);
ALTER TABLE biz.coach_tasks ADD CONSTRAINT coach_tasks_parent_task_id_fkey FOREIGN KEY (parent_task_id) REFERENCES biz.coach_tasks(id);
ALTER TABLE biz.coach_tasks ADD CONSTRAINT fk_coach_tasks_transferred_from FOREIGN KEY (transferred_from) REFERENCES biz.coach_tasks(id);
ALTER TABLE biz.coach_tasks ADD CONSTRAINT coach_tasks_pkey PRIMARY KEY (id);
ALTER TABLE biz.connectors ADD CONSTRAINT connectors_pkey PRIMARY KEY (id);
ALTER TABLE biz.connectors ADD CONSTRAINT connectors_connector_key_key UNIQUE (connector_key);
ALTER TABLE biz.dws_assistant_task_monthly ADD CONSTRAINT dws_assistant_task_monthly_pkey PRIMARY KEY (id);
ALTER TABLE biz.dws_assistant_task_monthly ADD CONSTRAINT dws_assistant_task_monthly_site_id_assistant_id_stat_month_key UNIQUE (site_id, assistant_id, stat_month);
ALTER TABLE biz.excel_upload_log ADD CONSTRAINT excel_upload_log_pkey PRIMARY KEY (id);
ALTER TABLE biz.notes ADD CONSTRAINT notes_task_id_fkey FOREIGN KEY (task_id) REFERENCES biz.coach_tasks(id);
ALTER TABLE biz.notes ADD CONSTRAINT notes_pkey PRIMARY KEY (id);
ALTER TABLE biz.salary_adjustments ADD CONSTRAINT salary_adjustments_upload_batch_id_fkey FOREIGN KEY (upload_batch_id) REFERENCES biz.excel_upload_log(id);
ALTER TABLE biz.salary_adjustments ADD CONSTRAINT salary_adjustments_pkey PRIMARY KEY (id);
ALTER TABLE biz.site_code_history ADD CONSTRAINT site_code_history_pkey PRIMARY KEY (id);
ALTER TABLE biz.site_code_history ADD CONSTRAINT site_code_history_site_code_key UNIQUE (site_code);
ALTER TABLE biz.sites ADD CONSTRAINT sites_tenant_id_fkey FOREIGN KEY (tenant_id) REFERENCES biz.tenants(id);
ALTER TABLE biz.sites ADD CONSTRAINT sites_pkey PRIMARY KEY (id);
ALTER TABLE biz.sites ADD CONSTRAINT sites_site_code_key UNIQUE (site_code);
ALTER TABLE biz.sites ADD CONSTRAINT sites_site_id_key UNIQUE (site_id);
ALTER TABLE biz.stg_finance_expense ADD CONSTRAINT stg_finance_expense_upload_batch_id_fkey FOREIGN KEY (upload_batch_id) REFERENCES biz.excel_upload_log(id);
ALTER TABLE biz.stg_finance_expense ADD CONSTRAINT stg_finance_expense_pkey PRIMARY KEY (id);
ALTER TABLE biz.stg_platform_income ADD CONSTRAINT stg_platform_income_upload_batch_id_fkey FOREIGN KEY (upload_batch_id) REFERENCES biz.excel_upload_log(id);
ALTER TABLE biz.stg_platform_income ADD CONSTRAINT stg_platform_income_pkey PRIMARY KEY (id);
ALTER TABLE biz.stg_recharge_commission ADD CONSTRAINT stg_recharge_commission_upload_batch_id_fkey FOREIGN KEY (upload_batch_id) REFERENCES biz.excel_upload_log(id);
ALTER TABLE biz.stg_recharge_commission ADD CONSTRAINT stg_recharge_commission_pkey PRIMARY KEY (id);
ALTER TABLE biz.tenants ADD CONSTRAINT tenants_connector_id_fkey FOREIGN KEY (connector_id) REFERENCES biz.connectors(id);
ALTER TABLE biz.tenants ADD CONSTRAINT tenants_pkey PRIMARY KEY (id);
ALTER TABLE biz.tenants ADD CONSTRAINT tenants_connector_id_tenant_id_key UNIQUE (connector_id, tenant_id);
ALTER TABLE biz.trigger_jobs ADD CONSTRAINT trigger_jobs_pkey PRIMARY KEY (id);
ALTER TABLE biz.trigger_jobs ADD CONSTRAINT trigger_jobs_job_name_key UNIQUE (job_name);
-- 索引
CREATE INDEX idx_ai_cache_cleanup ON biz.ai_cache USING btree (cache_type, site_id, target_id, created_at);
CREATE INDEX idx_ai_cache_lookup ON biz.ai_cache USING btree (cache_type, site_id, target_id, created_at DESC);
CREATE INDEX idx_ai_conv_app_site ON biz.ai_conversations USING btree (app_id, site_id, created_at DESC);
CREATE INDEX idx_ai_conv_context ON biz.ai_conversations USING btree (user_id, site_id, context_type, context_id, last_message_at DESC NULLS LAST) WHERE (context_type IS NOT NULL);
CREATE INDEX idx_ai_conv_last_msg ON biz.ai_conversations USING btree (user_id, site_id, last_message_at DESC NULLS LAST);
CREATE INDEX idx_ai_conv_user_site ON biz.ai_conversations USING btree (user_id, site_id, created_at DESC);
CREATE INDEX idx_ai_msg_conv ON biz.ai_messages USING btree (conversation_id, created_at);
CREATE INDEX idx_ai_run_logs_alert ON biz.ai_run_logs USING btree (alert_status, created_at DESC) WHERE ((status)::text = ANY ((ARRAY['failed'::character varying, 'timeout'::character varying, 'circuit_open'::character varying])::text[]));
CREATE INDEX idx_ai_run_logs_created ON biz.ai_run_logs USING btree (created_at);
CREATE INDEX idx_ai_run_logs_created_brin ON biz.ai_run_logs USING brin (created_at) WITH (pages_per_range='32');
CREATE INDEX idx_ai_run_logs_site_app ON biz.ai_run_logs USING btree (site_id, app_type);
CREATE INDEX idx_ai_run_logs_status ON biz.ai_run_logs USING btree (status);
CREATE INDEX idx_ai_trigger_jobs_dedup ON biz.ai_trigger_jobs USING btree (event_type, member_id, site_id, created_at) WHERE ((status)::text <> 'skipped_duplicate'::text);
CREATE INDEX idx_ai_trigger_jobs_site ON biz.ai_trigger_jobs USING btree (site_id, event_type);
CREATE INDEX idx_ai_trigger_jobs_status ON biz.ai_trigger_jobs USING btree (status);
CREATE INDEX idx_transfer_log_member ON biz.coach_task_transfer_log USING btree (member_id, created_at DESC);
CREATE INDEX idx_transfer_log_site_created ON biz.coach_task_transfer_log USING btree (site_id, created_at DESC);
CREATE INDEX idx_coach_tasks_assistant_status ON biz.coach_tasks USING btree (site_id, assistant_id, status);
CREATE UNIQUE INDEX idx_coach_tasks_site_assistant_member_type ON biz.coach_tasks USING btree (site_id, assistant_id, member_id, task_type) WHERE ((status)::text = 'active'::text);
CREATE INDEX idx_task_monthly_assistant ON biz.dws_assistant_task_monthly USING btree (assistant_id, stat_month DESC);
CREATE INDEX idx_task_monthly_site_month ON biz.dws_assistant_task_monthly USING btree (site_id, stat_month DESC);
CREATE INDEX idx_excel_log_site ON biz.excel_upload_log USING btree (site_id, created_at DESC);
CREATE INDEX idx_notes_target ON biz.notes USING btree (site_id, target_type, target_id);
CREATE INDEX idx_salary_adj_assistant_month ON biz.salary_adjustments USING btree (assistant_id, salary_month);
CREATE INDEX idx_salary_adj_site_month ON biz.salary_adjustments USING btree (site_id, salary_month);

View File

@@ -0,0 +1,207 @@
-- =============================================================================
-- zqyy_app / public小程序业务表
-- 生成日期2026-04-05
-- 来源:测试库(通过脚本自动导出)
-- =============================================================================
CREATE SCHEMA IF NOT EXISTS public;
-- 序列
CREATE SEQUENCE IF NOT EXISTS public.admin_users_id_seq AS integer;
CREATE SEQUENCE IF NOT EXISTS public.approvals_id_seq AS bigint;
CREATE SEQUENCE IF NOT EXISTS public.member_retention_clue_id_seq AS bigint;
CREATE SEQUENCE IF NOT EXISTS public.permissions_id_seq AS integer;
CREATE SEQUENCE IF NOT EXISTS public.roles_id_seq AS integer;
CREATE SEQUENCE IF NOT EXISTS public.tasks_id_seq AS bigint;
CREATE SEQUENCE IF NOT EXISTS public.users_id_seq AS bigint;
-- 表
CREATE TABLE public.admin_users (
id integer DEFAULT nextval('admin_users_id_seq'::regclass) NOT NULL,
username character varying(64) NOT NULL,
password_hash character varying(256) NOT NULL,
display_name character varying(128),
site_id bigint NOT NULL,
is_active boolean DEFAULT true,
created_at timestamp with time zone DEFAULT now(),
updated_at timestamp with time zone DEFAULT now(),
roles _text DEFAULT '{site_admin}'::text[] NOT NULL
);
CREATE TABLE public.approvals (
id bigint DEFAULT nextval('approvals_id_seq'::regclass) NOT NULL,
task_id bigint,
approver_id bigint,
status text DEFAULT 'pending'::text,
comment text,
site_id bigint NOT NULL,
created_at timestamp with time zone DEFAULT now()
);
CREATE TABLE public.member_retention_clue (
id bigint DEFAULT nextval('member_retention_clue_id_seq'::regclass) NOT NULL,
member_id bigint NOT NULL,
category character varying(20) NOT NULL,
summary character varying(200) NOT NULL,
detail text,
recorded_by_assistant_id bigint,
recorded_by_name character varying(50),
recorded_at timestamp with time zone DEFAULT now() NOT NULL,
site_id bigint NOT NULL,
source character varying(20) DEFAULT 'manual'::character varying NOT NULL,
is_hidden boolean DEFAULT false NOT NULL
);
CREATE TABLE public.permissions (
id integer DEFAULT nextval('permissions_id_seq'::regclass) NOT NULL,
resource text NOT NULL,
action text NOT NULL,
description text
);
CREATE TABLE public.role_permissions (
role_id integer NOT NULL,
permission_id integer NOT NULL
);
CREATE TABLE public.roles (
id integer DEFAULT nextval('roles_id_seq'::regclass) NOT NULL,
name text NOT NULL,
description text,
site_id bigint NOT NULL,
created_at timestamp with time zone DEFAULT now()
);
CREATE TABLE public.scheduled_tasks (
id uuid DEFAULT gen_random_uuid() NOT NULL,
site_id bigint NOT NULL,
name character varying(256) NOT NULL,
task_codes _text NOT NULL,
task_config jsonb NOT NULL,
schedule_config jsonb NOT NULL,
enabled boolean DEFAULT true,
last_run_at timestamp with time zone,
next_run_at timestamp with time zone,
run_count integer DEFAULT 0,
last_status character varying(20),
created_at timestamp with time zone DEFAULT now(),
updated_at timestamp with time zone DEFAULT now(),
min_run_interval_value integer DEFAULT 0 NOT NULL,
min_run_interval_unit character varying(20) DEFAULT 'minutes'::character varying NOT NULL,
last_success_at timestamp with time zone,
min_run_intervals jsonb DEFAULT '{}'::jsonb NOT NULL
);
CREATE TABLE public.task_execution_log (
id uuid DEFAULT gen_random_uuid() NOT NULL,
queue_id uuid,
site_id bigint NOT NULL,
task_codes _text NOT NULL,
status character varying(20) NOT NULL,
started_at timestamp with time zone NOT NULL,
finished_at timestamp with time zone,
exit_code integer,
duration_ms bigint,
command text,
output_log text,
error_log text,
summary jsonb,
created_at timestamp with time zone DEFAULT now(),
schedule_id uuid,
config jsonb
);
CREATE TABLE public.task_queue (
id uuid DEFAULT gen_random_uuid() NOT NULL,
site_id bigint NOT NULL,
config jsonb NOT NULL,
status character varying(20) DEFAULT 'pending'::character varying NOT NULL,
"position" integer DEFAULT 0 NOT NULL,
created_at timestamp with time zone DEFAULT now(),
started_at timestamp with time zone,
finished_at timestamp with time zone,
exit_code integer,
error_message text,
schedule_id uuid,
enqueued_by character varying(255) DEFAULT NULL::character varying
);
CREATE TABLE public.tasks (
id bigint DEFAULT nextval('tasks_id_seq'::regclass) NOT NULL,
title text NOT NULL,
description text,
status text DEFAULT 'pending'::text,
assignee_id bigint,
creator_id bigint,
site_id bigint NOT NULL,
created_at timestamp with time zone DEFAULT now(),
updated_at timestamp with time zone DEFAULT now()
);
CREATE TABLE public.user_roles (
user_id bigint NOT NULL,
role_id integer NOT NULL,
site_id bigint NOT NULL
);
CREATE TABLE public.users (
id bigint DEFAULT nextval('users_id_seq'::regclass) NOT NULL,
wx_openid text,
mobile text,
nickname text,
status integer DEFAULT 1,
site_id bigint NOT NULL,
created_at timestamp with time zone DEFAULT now(),
updated_at timestamp with time zone DEFAULT now()
);
-- 约束(主键 / 唯一 / 外键)
ALTER TABLE admin_users ADD CONSTRAINT admin_users_pkey PRIMARY KEY (id);
ALTER TABLE admin_users ADD CONSTRAINT admin_users_username_key UNIQUE (username);
ALTER TABLE approvals ADD CONSTRAINT approvals_approver_id_fkey FOREIGN KEY (approver_id) REFERENCES users(id);
ALTER TABLE approvals ADD CONSTRAINT approvals_task_id_fkey FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE;
ALTER TABLE approvals ADD CONSTRAINT approvals_pkey PRIMARY KEY (id);
ALTER TABLE member_retention_clue ADD CONSTRAINT member_retention_clue_pkey PRIMARY KEY (id);
ALTER TABLE permissions ADD CONSTRAINT permissions_pkey PRIMARY KEY (id);
ALTER TABLE permissions ADD CONSTRAINT permissions_resource_action_key UNIQUE (resource, action);
ALTER TABLE role_permissions ADD CONSTRAINT role_permissions_permission_id_fkey FOREIGN KEY (permission_id) REFERENCES permissions(id) ON DELETE CASCADE;
ALTER TABLE role_permissions ADD CONSTRAINT role_permissions_role_id_fkey FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE;
ALTER TABLE role_permissions ADD CONSTRAINT role_permissions_pkey PRIMARY KEY (role_id, permission_id);
ALTER TABLE roles ADD CONSTRAINT roles_pkey PRIMARY KEY (id);
ALTER TABLE roles ADD CONSTRAINT roles_name_key UNIQUE (name);
ALTER TABLE scheduled_tasks ADD CONSTRAINT scheduled_tasks_pkey PRIMARY KEY (id);
ALTER TABLE task_execution_log ADD CONSTRAINT task_execution_log_queue_id_fkey FOREIGN KEY (queue_id) REFERENCES task_queue(id);
ALTER TABLE task_execution_log ADD CONSTRAINT task_execution_log_schedule_id_fkey FOREIGN KEY (schedule_id) REFERENCES scheduled_tasks(id) ON DELETE SET NULL;
ALTER TABLE task_execution_log ADD CONSTRAINT task_execution_log_pkey PRIMARY KEY (id);
ALTER TABLE task_queue ADD CONSTRAINT task_queue_schedule_id_fkey FOREIGN KEY (schedule_id) REFERENCES scheduled_tasks(id) ON DELETE SET NULL;
ALTER TABLE task_queue ADD CONSTRAINT task_queue_pkey PRIMARY KEY (id);
ALTER TABLE tasks ADD CONSTRAINT tasks_assignee_id_fkey FOREIGN KEY (assignee_id) REFERENCES users(id);
ALTER TABLE tasks ADD CONSTRAINT tasks_creator_id_fkey FOREIGN KEY (creator_id) REFERENCES users(id);
ALTER TABLE tasks ADD CONSTRAINT tasks_pkey PRIMARY KEY (id);
ALTER TABLE user_roles ADD CONSTRAINT user_roles_role_id_fkey FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE;
ALTER TABLE user_roles ADD CONSTRAINT user_roles_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
ALTER TABLE user_roles ADD CONSTRAINT user_roles_pkey PRIMARY KEY (user_id, role_id);
ALTER TABLE users ADD CONSTRAINT users_pkey PRIMARY KEY (id);
ALTER TABLE users ADD CONSTRAINT users_wx_openid_key UNIQUE (wx_openid);
-- 索引
CREATE INDEX idx_admin_users_site ON public.admin_users USING btree (site_id);
CREATE INDEX idx_approvals_site_id ON public.approvals USING btree (site_id);
CREATE INDEX idx_approvals_task_id ON public.approvals USING btree (task_id);
CREATE INDEX idx_retention_clue_category ON public.member_retention_clue USING btree (member_id, category);
CREATE INDEX idx_retention_clue_member ON public.member_retention_clue USING btree (member_id);
CREATE INDEX idx_retention_clue_site ON public.member_retention_clue USING btree (site_id);
CREATE INDEX idx_roles_site_id ON public.roles USING btree (site_id);
CREATE INDEX idx_scheduled_tasks_next_run ON public.scheduled_tasks USING btree (next_run_at) WHERE (enabled = true);
CREATE INDEX idx_scheduled_tasks_site ON public.scheduled_tasks USING btree (site_id);
CREATE INDEX idx_execution_log_schedule_id ON public.task_execution_log USING btree (schedule_id) WHERE (schedule_id IS NOT NULL);
CREATE INDEX idx_execution_log_site_started ON public.task_execution_log USING btree (site_id, started_at DESC);
CREATE INDEX idx_task_queue_site_position ON public.task_queue USING btree (site_id, "position") WHERE ((status)::text = 'pending'::text);
CREATE INDEX idx_task_queue_status ON public.task_queue USING btree (status);
CREATE INDEX idx_tasks_assignee_id ON public.tasks USING btree (assignee_id);
CREATE INDEX idx_tasks_site_id ON public.tasks USING btree (site_id);
CREATE INDEX idx_tasks_status ON public.tasks USING btree (status);
CREATE INDEX idx_user_roles_site_id ON public.user_roles USING btree (site_id);
CREATE INDEX idx_users_mobile ON public.users USING btree (mobile);
CREATE INDEX idx_users_site_id ON public.users USING btree (site_id);