docs: 基本完成初版数据库设计
This commit is contained in:
@@ -8,7 +8,6 @@ SET LOCAL search_path = public, pg_catalog;
|
||||
|
||||
CREATE TABLE public.users (
|
||||
id varchar(128) COLLATE "C" PRIMARY KEY,
|
||||
mini_app_id varchar(64) COLLATE "C" NOT NULL,
|
||||
openid varchar(128) COLLATE "C" NOT NULL,
|
||||
unionid varchar(128) COLLATE "C",
|
||||
nick_name varchar(100),
|
||||
@@ -20,7 +19,7 @@ CREATE TABLE public.users (
|
||||
created_at timestamptz(3) NOT NULL DEFAULT now(),
|
||||
last_active_at timestamptz(3) NOT NULL DEFAULT now(),
|
||||
updated_at timestamptz(3) NOT NULL DEFAULT now(),
|
||||
CONSTRAINT users_mini_app_openid_key UNIQUE (mini_app_id, openid),
|
||||
CONSTRAINT users_openid_key UNIQUE (openid),
|
||||
CONSTRAINT users_role_check CHECK (role IN ('user', 'admin')),
|
||||
CONSTRAINT users_status_check CHECK (status IN ('active', 'disabled')),
|
||||
CONSTRAINT users_total_downloads_check CHECK (total_downloads >= 0),
|
||||
@@ -54,7 +53,7 @@ CREATE TABLE public.assets (
|
||||
REFERENCES public.users (id) ON UPDATE RESTRICT ON DELETE SET NULL,
|
||||
CONSTRAINT assets_provider_check CHECK (provider IN ('qiniu', 'external')),
|
||||
CONSTRAINT assets_purpose_check CHECK (
|
||||
purpose IN ('avatar', 'preview', 'category_icon', 'font', 'share', 'page_config', 'other')
|
||||
purpose IN ('avatar', 'preview', 'category_icon', 'font', 'share', 'page_config', 'worksheet_source', 'other')
|
||||
),
|
||||
CONSTRAINT assets_visibility_check CHECK (visibility IN ('public', 'private')),
|
||||
CONSTRAINT assets_avatar_visibility_check CHECK (purpose <> 'avatar' OR visibility = 'private'),
|
||||
@@ -120,6 +119,9 @@ CREATE TABLE public.worksheets (
|
||||
category_id varchar(128) COLLATE "C" NOT NULL,
|
||||
subcategory varchar(100),
|
||||
path varchar(1024) NOT NULL,
|
||||
generation_mode varchar(16) NOT NULL DEFAULT 'procedural',
|
||||
renderer_key varchar(64) COLLATE "C",
|
||||
render_config jsonb NOT NULL DEFAULT '{}'::jsonb,
|
||||
age_min smallint NOT NULL,
|
||||
age_max smallint NOT NULL,
|
||||
grade smallint NOT NULL DEFAULT 0,
|
||||
@@ -134,6 +136,7 @@ CREATE TABLE public.worksheets (
|
||||
downloads_seed bigint NOT NULL DEFAULT 0,
|
||||
likes_seed bigint NOT NULL DEFAULT 0,
|
||||
status varchar(16) NOT NULL DEFAULT 'draft',
|
||||
first_published_at timestamptz(3),
|
||||
created_at timestamptz(3) NOT NULL DEFAULT now(),
|
||||
content_updated_at timestamptz(3),
|
||||
updated_at timestamptz(3) NOT NULL DEFAULT now(),
|
||||
@@ -141,6 +144,11 @@ CREATE TABLE public.worksheets (
|
||||
REFERENCES public.categories (id) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||||
CONSTRAINT worksheets_preview_asset_id_fkey FOREIGN KEY (preview_asset_id)
|
||||
REFERENCES public.assets (id) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||||
CONSTRAINT worksheets_generation_mode_check CHECK (generation_mode IN ('procedural', 'resource')),
|
||||
CONSTRAINT worksheets_renderer_key_check CHECK (
|
||||
renderer_key IS NULL OR length(btrim(renderer_key)) > 0
|
||||
),
|
||||
CONSTRAINT worksheets_render_config_object_check CHECK (jsonb_typeof(render_config) = 'object'),
|
||||
CONSTRAINT worksheets_age_check CHECK (age_min >= 0 AND age_max >= age_min),
|
||||
CONSTRAINT worksheets_difficulty_check CHECK (difficulty BETWEEN 1 AND 4),
|
||||
CONSTRAINT worksheets_status_check CHECK (status IN ('draft', 'active', 'hidden')),
|
||||
@@ -156,16 +164,92 @@ CREATE INDEX worksheets_status_sort_idx
|
||||
ON public.worksheets (status, sort_order, updated_at DESC, id);
|
||||
CREATE INDEX worksheets_status_age_idx ON public.worksheets (status, age_min, age_max);
|
||||
|
||||
-- 年级与内容分类独立;同一 worksheet 可适用于多个(含不连续)年级。
|
||||
-- 不从年龄或旧 grade 自动生成关系,避免把推算值当作已核实的适用范围。
|
||||
CREATE TABLE public.worksheet_grades (
|
||||
worksheet_id varchar(128) COLLATE "C" NOT NULL,
|
||||
grade smallint NOT NULL,
|
||||
CONSTRAINT worksheet_grades_pkey PRIMARY KEY (worksheet_id, grade),
|
||||
CONSTRAINT worksheet_grades_worksheet_id_fkey FOREIGN KEY (worksheet_id)
|
||||
REFERENCES public.worksheets (id) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||||
CONSTRAINT worksheet_grades_grade_check CHECK (grade BETWEEN -4 AND 6)
|
||||
);
|
||||
|
||||
-- 联合主键支持查询功能的适用年级;反向索引用于年级菜单及筛选。
|
||||
CREATE INDEX worksheet_grades_grade_worksheet_idx
|
||||
ON public.worksheet_grades (grade, worksheet_id);
|
||||
|
||||
-- 资源条目代表一份完整可选择内容,不等于单个文件,也不是独立模板引擎。
|
||||
CREATE TABLE public.worksheet_resources (
|
||||
id varchar(128) COLLATE "C" PRIMARY KEY,
|
||||
worksheet_id varchar(128) COLLATE "C" NOT NULL,
|
||||
title varchar(100) NOT NULL,
|
||||
preview_asset_id varchar(128) COLLATE "C" NOT NULL,
|
||||
config_override jsonb,
|
||||
status varchar(16) NOT NULL DEFAULT 'draft',
|
||||
sort_order integer NOT NULL DEFAULT 0,
|
||||
downloads bigint NOT NULL DEFAULT 0,
|
||||
first_published_at timestamptz(3),
|
||||
created_at timestamptz(3) NOT NULL DEFAULT now(),
|
||||
updated_at timestamptz(3) NOT NULL DEFAULT now(),
|
||||
CONSTRAINT worksheet_resources_worksheet_id_fkey FOREIGN KEY (worksheet_id)
|
||||
REFERENCES public.worksheets (id) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||||
CONSTRAINT worksheet_resources_preview_asset_id_fkey FOREIGN KEY (preview_asset_id)
|
||||
REFERENCES public.assets (id) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||||
CONSTRAINT worksheet_resources_downloads_check CHECK (downloads >= 0),
|
||||
CONSTRAINT worksheet_resources_status_check CHECK (status IN ('draft', 'active', 'hidden')),
|
||||
CONSTRAINT worksheet_resources_config_object_check CHECK (
|
||||
config_override IS NULL OR jsonb_typeof(config_override) = 'object'
|
||||
)
|
||||
);
|
||||
|
||||
CREATE INDEX worksheet_resources_worksheet_status_sort_idx
|
||||
ON public.worksheet_resources (worksheet_id, status, sort_order, id);
|
||||
CREATE INDEX worksheet_resources_preview_asset_idx ON public.worksheet_resources (preview_asset_id);
|
||||
|
||||
-- 首期仅支持线框和参考图;允许多个同用途文件,排序并列时按 id 确定顺序。
|
||||
-- 文件格式由 assets 描述;是否打印、如何排列由 renderer 决定。
|
||||
CREATE TABLE public.worksheet_resource_assets (
|
||||
id varchar(128) COLLATE "C" PRIMARY KEY,
|
||||
worksheet_resource_id varchar(128) COLLATE "C" NOT NULL,
|
||||
asset_id varchar(128) COLLATE "C" NOT NULL,
|
||||
role varchar(16) NOT NULL,
|
||||
sort_order integer NOT NULL DEFAULT 0,
|
||||
CONSTRAINT worksheet_resource_assets_resource_id_fkey FOREIGN KEY (worksheet_resource_id)
|
||||
REFERENCES public.worksheet_resources (id) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||||
CONSTRAINT worksheet_resource_assets_asset_id_fkey FOREIGN KEY (asset_id)
|
||||
REFERENCES public.assets (id) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||||
CONSTRAINT worksheet_resource_assets_role_check CHECK (role IN ('outline', 'reference')),
|
||||
CONSTRAINT worksheet_resource_assets_resource_role_asset_key
|
||||
UNIQUE (worksheet_resource_id, role, asset_id)
|
||||
);
|
||||
|
||||
CREATE INDEX worksheet_resource_assets_resource_role_sort_idx
|
||||
ON public.worksheet_resource_assets (worksheet_resource_id, role, sort_order, id);
|
||||
CREATE INDEX worksheet_resource_assets_asset_idx ON public.worksheet_resource_assets (asset_id);
|
||||
|
||||
CREATE TABLE public.favorites (
|
||||
id varchar(128) COLLATE "C" PRIMARY KEY,
|
||||
user_id varchar(128) COLLATE "C" NOT NULL,
|
||||
worksheet_id varchar(128) COLLATE "C" NOT NULL,
|
||||
worksheet_resource_id varchar(128) COLLATE "C",
|
||||
created_at timestamptz(3) NOT NULL DEFAULT now(),
|
||||
CONSTRAINT favorites_user_id_fkey FOREIGN KEY (user_id)
|
||||
REFERENCES public.users (id) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||||
CONSTRAINT favorites_user_worksheet_key UNIQUE (user_id, worksheet_id)
|
||||
CONSTRAINT favorites_resource_id_check CHECK (
|
||||
worksheet_resource_id IS NULL OR length(btrim(worksheet_resource_id)) > 0
|
||||
)
|
||||
);
|
||||
|
||||
-- NULL 表示功能收藏;非 NULL 表示完整内容收藏,不另加 type 字段。
|
||||
-- 部分唯一索引分别去重,允许同用户收藏一个功能及其中多个资源。
|
||||
CREATE UNIQUE INDEX favorites_user_worksheet_key
|
||||
ON public.favorites (user_id, worksheet_id)
|
||||
WHERE worksheet_resource_id IS NULL;
|
||||
CREATE UNIQUE INDEX favorites_user_resource_key
|
||||
ON public.favorites (user_id, worksheet_resource_id)
|
||||
WHERE worksheet_resource_id IS NOT NULL;
|
||||
|
||||
CREATE INDEX favorites_user_created_at_idx
|
||||
ON public.favorites (user_id, created_at DESC, id DESC);
|
||||
|
||||
@@ -173,6 +257,7 @@ CREATE TABLE public.download_logs (
|
||||
id varchar(128) COLLATE "C" PRIMARY KEY,
|
||||
user_id varchar(128) COLLATE "C" NOT NULL,
|
||||
worksheet_id varchar(128) COLLATE "C" NOT NULL,
|
||||
worksheet_resource_id varchar(128) COLLATE "C",
|
||||
export_id varchar(128) COLLATE "C",
|
||||
source varchar(16) NOT NULL DEFAULT 'mini',
|
||||
params jsonb,
|
||||
@@ -270,19 +355,17 @@ CREATE INDEX admin_audit_logs_actor_created_at_idx
|
||||
ON public.admin_audit_logs (actor_user_id, created_at DESC);
|
||||
CREATE INDEX admin_audit_logs_request_id_idx ON public.admin_audit_logs (request_id);
|
||||
|
||||
COMMENT ON TABLE public.users IS '微信用户;沿用 CloudBase 字符串 ID,按 AppID + OpenID 唯一';
|
||||
COMMENT ON TABLE public.users IS '微信用户;沿用 CloudBase 字符串 ID,按 OpenID 唯一;AppID 由服务端配置';
|
||||
COMMENT ON COLUMN public.users.total_downloads IS '旧字段迁移兼容值;个人下载数量以 download_logs 查询为准';
|
||||
COMMENT ON COLUMN public.users.auth_version IS '应用凭证版本;服务端鉴权校验,不由 SQL 自动递增';
|
||||
COMMENT ON TABLE public.assets IS '七牛文件引用与旧资源迁移映射;不保存临时签名 URL';
|
||||
COMMENT ON COLUMN public.assets.object_ref_hash IS '规范序列化 [provider,bucket,objectKey] 的 SHA-256;服务端生成并核对原引用';
|
||||
COMMENT ON COLUMN public.assets.checksum IS '文件内容 SHA-256,不是七牛 ETag;非唯一';
|
||||
COMMENT ON TABLE public.categories IS '分类树;多层循环需由服务端事务检查';
|
||||
|
||||
COMMENT ON TABLE public.worksheets IS '题型内容与真实/种子计数;资源通过 assets 引用';
|
||||
COMMENT ON COLUMN public.worksheets.content_updated_at IS '仅内容修改时更新;不随计数变化;历史缺失保留 NULL';
|
||||
COMMENT ON COLUMN public.worksheets.updated_at IS '由服务显式更新;包含计数、状态、内容变更';
|
||||
COMMENT ON COLUMN public.worksheets.tags IS '字符串数组;数据库限制顶层 array,服务端校验元素';
|
||||
COMMENT ON TABLE public.favorites IS '当前收藏关系;取消收藏删除关系并由业务事务扣减 likes';
|
||||
COMMENT ON COLUMN public.favorites.worksheet_id IS '题型逻辑关联,不建外键,允许保留缺失题型的历史收藏';
|
||||
COMMENT ON TABLE public.download_logs IS '成功保存历史;同用户 exportId 唯一,日志与计数由业务事务同步';
|
||||
COMMENT ON COLUMN public.download_logs.worksheet_id IS '题型逻辑关联,不建外键,历史查询使用 LEFT JOIN';
|
||||
COMMENT ON COLUMN public.download_logs.export_id IS '历史 import 可为 NULL;mini/legacy 必须提供非空事件 ID';
|
||||
@@ -291,4 +374,31 @@ COMMENT ON TABLE public.settings IS '运行配置;value 保留原文档业务
|
||||
COMMENT ON TABLE public.job_runs IS '任务逻辑去重、租约与执行结果;内容更新仍需业务行锁';
|
||||
COMMENT ON TABLE public.admin_audit_logs IS '管理变更审计;操作者为逻辑关联,注销需主动去关联';
|
||||
|
||||
COMMENT ON COLUMN public.worksheets.generation_mode IS 'procedural 算法生成;resource 完整内容资源驱动;旧数据默认 procedural,导入逐项核对';
|
||||
COMMENT ON COLUMN public.worksheets.renderer_key IS '客户端绘制实现标识;多题型可共用;NULL 仅供旧版 ID/path 映射兼容,新功能发布必须明确';
|
||||
COMMENT ON COLUMN public.worksheets.render_config IS '共用绘制参数;仅允许已定义参数,不存执行代码或密钥';
|
||||
COMMENT ON TABLE public.worksheet_resources IS 'worksheet 下可选择的完整内容;独立预览及轻量配置覆盖';
|
||||
COMMENT ON COLUMN public.worksheet_resources.preview_asset_id IS '内容列表预览图;与绘制参考图用途独立,允许引用同一资产';
|
||||
COMMENT ON COLUMN public.worksheet_resources.config_override IS '可选参数覆盖;应用按 renderer 白名单校验,不支持任意深度合并';
|
||||
COMMENT ON TABLE public.worksheet_resource_assets IS '完整内容的文件输入;outline 线框,reference 对照图;不保存文件级配置';
|
||||
COMMENT ON COLUMN public.worksheet_resource_assets.role IS '业务用途,不是文件格式;用途对应的文件数量、类型和是否打印由 renderer 校验';
|
||||
COMMENT ON COLUMN public.worksheet_resource_assets.sort_order IS '同用途文件的处理顺序,并列按 id 排序;不等于通用图层 z-index';
|
||||
COMMENT ON COLUMN public.download_logs.worksheet_resource_id IS '可空资源条目逻辑关联;历史和算法生成可空;新写入校验属于同一 worksheet';
|
||||
|
||||
COMMENT ON TABLE public.worksheet_grades IS '功能适用年级的唯一权威关系;与内容分类独立,不从年龄自动推算';
|
||||
COMMENT ON COLUMN public.worksheet_grades.grade IS '-4 托班、-3 小班、-2 中班、-1 大班、0 幼小衔接、1至6 小学年级;无关系表示未配置,不表示全年级';
|
||||
COMMENT ON COLUMN public.worksheets.grade IS '旧版单年级兼容值;可能由年龄推算;保留原值,新年级筛选使用 worksheet_grades';
|
||||
COMMENT ON TABLE public.categories IS '内容分类树,与适用年级独立;多层循环需由服务端事务检查';
|
||||
|
||||
COMMENT ON COLUMN public.worksheets.first_published_at IS '首次公开发布时间;新功能由发布事务写入,重发/新增资源不重置;旧时间未知保持 NULL';
|
||||
COMMENT ON COLUMN public.worksheets.is_new IS '旧版新品兼容标记;新功能新品由首次发布时间及时间窗口派生,不作为新业务权威值';
|
||||
COMMENT ON COLUMN public.worksheets.is_hot IS '功能级人工运营推荐标记,不是下载排行榜计算结果,不自动传递给资源';
|
||||
COMMENT ON COLUMN public.worksheets.downloads IS '功能累计成功保存次数;保留旧累计值,资源下载也计入,不等于资源计数总和';
|
||||
COMMENT ON COLUMN public.worksheet_resources.first_published_at IS '内容首次公开发布时间;用于资源新品判断,草稿/重发不重置,未知旧时间保持 NULL';
|
||||
COMMENT ON COLUMN public.worksheet_resources.downloads IS '内容累计成功保存次数;仅有可信资源归属的新事件递增,不分摊功能旧计数,不因个人日志删除回减';
|
||||
|
||||
COMMENT ON TABLE public.favorites IS '功能和完整内容的当前收藏;取消即删除;仅功能收藏增减 worksheets.likes';
|
||||
COMMENT ON COLUMN public.favorites.worksheet_id IS '稳定功能逻辑关联;内容收藏的功能归属由服务端查询确定,历史缺失时保留';
|
||||
COMMENT ON COLUMN public.favorites.worksheet_resource_id IS 'NULL 是功能收藏,非 NULL 是完整内容收藏;逻辑关联,缺失/下架不清空,不退化为功能收藏';
|
||||
|
||||
COMMIT;
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
-- 已执行旧版 002 的数据库使用本增量 SQL;新建库仅执行最新 002/003。
|
||||
-- 首期只有一个小程序,AppID 由服务端配置,OpenID 直接唯一。
|
||||
-- 先创建更严格的唯一约束;若存在跨应用重复 OpenID,则事务回滚,保留原数据。
|
||||
BEGIN;
|
||||
SET LOCAL lock_timeout = '5s';
|
||||
SET LOCAL search_path = public, pg_catalog;
|
||||
|
||||
ALTER TABLE public.users
|
||||
ADD CONSTRAINT users_openid_key UNIQUE (openid);
|
||||
ALTER TABLE public.users
|
||||
DROP CONSTRAINT users_mini_app_openid_key;
|
||||
ALTER TABLE public.users
|
||||
DROP COLUMN mini_app_id;
|
||||
|
||||
COMMENT ON TABLE public.users IS '微信用户;沿用 CloudBase 字符串 ID,按 OpenID 唯一;AppID 由服务端配置';
|
||||
COMMIT;
|
||||
@@ -0,0 +1,84 @@
|
||||
-- 已执行旧版 002 的库在完成 004 后执行;最新空库基线不执行 004/005。
|
||||
-- 保留旧 ID/path、计数、配置和历史;不伪造资源条目或自动推断绘制方法。
|
||||
BEGIN;
|
||||
SET LOCAL TIME ZONE 'UTC';
|
||||
SET LOCAL lock_timeout = '5s';
|
||||
SET LOCAL search_path = public, pg_catalog;
|
||||
|
||||
ALTER TABLE public.worksheets
|
||||
ADD COLUMN generation_mode varchar(16) NOT NULL DEFAULT 'procedural',
|
||||
ADD COLUMN renderer_key varchar(64) COLLATE "C",
|
||||
ADD COLUMN render_config jsonb NOT NULL DEFAULT '{}'::jsonb,
|
||||
ADD CONSTRAINT worksheets_generation_mode_check CHECK (generation_mode IN ('procedural', 'resource')),
|
||||
ADD CONSTRAINT worksheets_renderer_key_check CHECK (
|
||||
renderer_key IS NULL OR length(btrim(renderer_key)) > 0
|
||||
),
|
||||
ADD CONSTRAINT worksheets_render_config_object_check CHECK (jsonb_typeof(render_config) = 'object');
|
||||
|
||||
ALTER TABLE public.assets DROP CONSTRAINT assets_purpose_check;
|
||||
ALTER TABLE public.assets ADD CONSTRAINT assets_purpose_check CHECK (
|
||||
purpose IN ('avatar', 'preview', 'category_icon', 'font', 'share', 'page_config', 'worksheet_source', 'other')
|
||||
);
|
||||
|
||||
-- 资源条目代表一份完整可选择内容,不等于单个文件,也不是独立模板引擎。
|
||||
CREATE TABLE public.worksheet_resources (
|
||||
id varchar(128) COLLATE "C" PRIMARY KEY,
|
||||
worksheet_id varchar(128) COLLATE "C" NOT NULL,
|
||||
title varchar(100) NOT NULL,
|
||||
preview_asset_id varchar(128) COLLATE "C" NOT NULL,
|
||||
config_override jsonb,
|
||||
status varchar(16) NOT NULL DEFAULT 'draft',
|
||||
sort_order integer NOT NULL DEFAULT 0,
|
||||
created_at timestamptz(3) NOT NULL DEFAULT now(),
|
||||
updated_at timestamptz(3) NOT NULL DEFAULT now(),
|
||||
CONSTRAINT worksheet_resources_worksheet_id_fkey FOREIGN KEY (worksheet_id)
|
||||
REFERENCES public.worksheets (id) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||||
CONSTRAINT worksheet_resources_preview_asset_id_fkey FOREIGN KEY (preview_asset_id)
|
||||
REFERENCES public.assets (id) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||||
CONSTRAINT worksheet_resources_status_check CHECK (status IN ('draft', 'active', 'hidden')),
|
||||
CONSTRAINT worksheet_resources_config_object_check CHECK (
|
||||
config_override IS NULL OR jsonb_typeof(config_override) = 'object'
|
||||
)
|
||||
);
|
||||
|
||||
CREATE INDEX worksheet_resources_worksheet_status_sort_idx
|
||||
ON public.worksheet_resources (worksheet_id, status, sort_order, id);
|
||||
CREATE INDEX worksheet_resources_preview_asset_idx ON public.worksheet_resources (preview_asset_id);
|
||||
|
||||
-- 首期仅支持线框和参考图;允许多个同用途文件,排序并列时按 id 确定顺序。
|
||||
-- 文件格式由 assets 描述;是否打印、如何排列由 renderer 决定。
|
||||
CREATE TABLE public.worksheet_resource_assets (
|
||||
id varchar(128) COLLATE "C" PRIMARY KEY,
|
||||
worksheet_resource_id varchar(128) COLLATE "C" NOT NULL,
|
||||
asset_id varchar(128) COLLATE "C" NOT NULL,
|
||||
role varchar(16) NOT NULL,
|
||||
sort_order integer NOT NULL DEFAULT 0,
|
||||
CONSTRAINT worksheet_resource_assets_resource_id_fkey FOREIGN KEY (worksheet_resource_id)
|
||||
REFERENCES public.worksheet_resources (id) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||||
CONSTRAINT worksheet_resource_assets_asset_id_fkey FOREIGN KEY (asset_id)
|
||||
REFERENCES public.assets (id) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||||
CONSTRAINT worksheet_resource_assets_role_check CHECK (role IN ('outline', 'reference')),
|
||||
CONSTRAINT worksheet_resource_assets_resource_role_asset_key
|
||||
UNIQUE (worksheet_resource_id, role, asset_id)
|
||||
);
|
||||
|
||||
CREATE INDEX worksheet_resource_assets_resource_role_sort_idx
|
||||
ON public.worksheet_resource_assets (worksheet_resource_id, role, sort_order, id);
|
||||
CREATE INDEX worksheet_resource_assets_asset_idx ON public.worksheet_resource_assets (asset_id);
|
||||
|
||||
-- 与 worksheet_id 一样保留逻辑关联,允许缺失内容的历史仍可读取。
|
||||
ALTER TABLE public.download_logs
|
||||
ADD COLUMN worksheet_resource_id varchar(128) COLLATE "C";
|
||||
|
||||
COMMENT ON COLUMN public.worksheets.generation_mode IS 'procedural 算法生成;resource 完整内容资源驱动;旧数据默认 procedural,导入逐项核对';
|
||||
COMMENT ON COLUMN public.worksheets.renderer_key IS '客户端绘制实现标识;多题型可共用;NULL 仅供旧版 ID/path 映射兼容,新功能发布必须明确';
|
||||
COMMENT ON COLUMN public.worksheets.render_config IS '共用绘制参数;仅允许已定义参数,不存执行代码或密钥';
|
||||
COMMENT ON TABLE public.worksheet_resources IS 'worksheet 下可选择的完整内容;独立预览及轻量配置覆盖';
|
||||
COMMENT ON COLUMN public.worksheet_resources.preview_asset_id IS '内容列表预览图;与绘制参考图用途独立,允许引用同一资产';
|
||||
COMMENT ON COLUMN public.worksheet_resources.config_override IS '可选参数覆盖;应用按 renderer 白名单校验,不支持任意深度合并';
|
||||
COMMENT ON TABLE public.worksheet_resource_assets IS '完整内容的文件输入;outline 线框,reference 对照图;不保存文件级配置';
|
||||
COMMENT ON COLUMN public.worksheet_resource_assets.role IS '业务用途,不是文件格式;用途对应的文件数量、类型和是否打印由 renderer 校验';
|
||||
COMMENT ON COLUMN public.worksheet_resource_assets.sort_order IS '同用途文件的处理顺序,并列按 id 排序;不等于通用图层 z-index';
|
||||
COMMENT ON COLUMN public.download_logs.worksheet_resource_id IS '可空资源条目逻辑关联;历史和算法生成可空;新写入校验属于同一 worksheet';
|
||||
|
||||
COMMIT;
|
||||
@@ -0,0 +1,28 @@
|
||||
-- 已有库完成 004/005 后执行;最新空库基线已经包含此结构,不执行本文件。
|
||||
-- 保留旧 worksheets.grade,不自动回填;经审核的年级映射由导入/管理业务显式写入。
|
||||
BEGIN;
|
||||
SET LOCAL TIME ZONE 'UTC';
|
||||
SET LOCAL lock_timeout = '5s';
|
||||
SET LOCAL search_path = public, pg_catalog;
|
||||
|
||||
-- 年级与内容分类独立;同一 worksheet 可适用于多个(含不连续)年级。
|
||||
-- 不从年龄或旧 grade 自动生成关系,避免把推算值当作已核实的适用范围。
|
||||
CREATE TABLE public.worksheet_grades (
|
||||
worksheet_id varchar(128) COLLATE "C" NOT NULL,
|
||||
grade smallint NOT NULL,
|
||||
CONSTRAINT worksheet_grades_pkey PRIMARY KEY (worksheet_id, grade),
|
||||
CONSTRAINT worksheet_grades_worksheet_id_fkey FOREIGN KEY (worksheet_id)
|
||||
REFERENCES public.worksheets (id) ON UPDATE RESTRICT ON DELETE RESTRICT,
|
||||
CONSTRAINT worksheet_grades_grade_check CHECK (grade BETWEEN -4 AND 6)
|
||||
);
|
||||
|
||||
-- 联合主键支持查询功能的适用年级;反向索引用于年级菜单及筛选。
|
||||
CREATE INDEX worksheet_grades_grade_worksheet_idx
|
||||
ON public.worksheet_grades (grade, worksheet_id);
|
||||
|
||||
COMMENT ON TABLE public.worksheet_grades IS '功能适用年级的唯一权威关系;与内容分类独立,不从年龄自动推算';
|
||||
COMMENT ON COLUMN public.worksheet_grades.grade IS '-4 托班、-3 小班、-2 中班、-1 大班、0 幼小衔接、1至6 小学年级;无关系表示未配置,不表示全年级';
|
||||
COMMENT ON COLUMN public.worksheets.grade IS '旧版单年级兼容值;可能由年龄推算;保留原值,新年级筛选使用 worksheet_grades';
|
||||
COMMENT ON TABLE public.categories IS '内容分类树,与适用年级独立;多层循环需由服务端事务检查';
|
||||
|
||||
COMMIT;
|
||||
@@ -0,0 +1,22 @@
|
||||
-- 已有库完成 004/005/006 后执行;最新空库基线包含此结构,不执行本文件。
|
||||
-- 不用创建时间/升级时间冒充首次发布,不将功能历史计数分摊到资源。
|
||||
BEGIN;
|
||||
SET LOCAL TIME ZONE 'UTC';
|
||||
SET LOCAL lock_timeout = '5s';
|
||||
SET LOCAL search_path = public, pg_catalog;
|
||||
|
||||
ALTER TABLE public.worksheets
|
||||
ADD COLUMN first_published_at timestamptz(3);
|
||||
ALTER TABLE public.worksheet_resources
|
||||
ADD COLUMN first_published_at timestamptz(3),
|
||||
ADD COLUMN downloads bigint NOT NULL DEFAULT 0,
|
||||
ADD CONSTRAINT worksheet_resources_downloads_check CHECK (downloads >= 0);
|
||||
|
||||
COMMENT ON COLUMN public.worksheets.first_published_at IS '首次公开发布时间;新功能由发布事务写入,重发/新增资源不重置;旧时间未知保持 NULL';
|
||||
COMMENT ON COLUMN public.worksheets.is_new IS '旧版新品兼容标记;新功能新品由首次发布时间及时间窗口派生,不作为新业务权威值';
|
||||
COMMENT ON COLUMN public.worksheets.is_hot IS '功能级人工运营推荐标记,不是下载排行榜计算结果,不自动传递给资源';
|
||||
COMMENT ON COLUMN public.worksheets.downloads IS '功能累计成功保存次数;保留旧累计值,资源下载也计入,不等于资源计数总和';
|
||||
COMMENT ON COLUMN public.worksheet_resources.first_published_at IS '内容首次公开发布时间;用于资源新品判断,草稿/重发不重置,未知旧时间保持 NULL';
|
||||
COMMENT ON COLUMN public.worksheet_resources.downloads IS '内容累计成功保存次数;仅有可信资源归属的新事件递增,不分摊功能旧计数,不因个人日志删除回减';
|
||||
|
||||
COMMIT;
|
||||
@@ -0,0 +1,29 @@
|
||||
-- 已有库完成 004/005/006/007 后执行;最新空库基线包含此结构,不执行本文件。
|
||||
-- 旧收藏全部保持功能收藏(新列 NULL),不猜测具体底图,不改旧 likes。
|
||||
-- 删除旧唯一约束并创建两种部分唯一索引均在同一事务内完成。
|
||||
BEGIN;
|
||||
SET LOCAL TIME ZONE 'UTC';
|
||||
SET LOCAL lock_timeout = '5s';
|
||||
SET LOCAL search_path = public, pg_catalog;
|
||||
|
||||
ALTER TABLE public.favorites
|
||||
ADD COLUMN worksheet_resource_id varchar(128) COLLATE "C",
|
||||
ADD CONSTRAINT favorites_resource_id_check CHECK (
|
||||
worksheet_resource_id IS NULL OR length(btrim(worksheet_resource_id)) > 0
|
||||
);
|
||||
ALTER TABLE public.favorites DROP CONSTRAINT favorites_user_worksheet_key;
|
||||
|
||||
-- NULL 表示功能收藏;非 NULL 表示完整内容收藏,不另加 type 字段。
|
||||
-- 部分唯一索引分别去重,允许同用户收藏一个功能及其中多个资源。
|
||||
CREATE UNIQUE INDEX favorites_user_worksheet_key
|
||||
ON public.favorites (user_id, worksheet_id)
|
||||
WHERE worksheet_resource_id IS NULL;
|
||||
CREATE UNIQUE INDEX favorites_user_resource_key
|
||||
ON public.favorites (user_id, worksheet_resource_id)
|
||||
WHERE worksheet_resource_id IS NOT NULL;
|
||||
|
||||
COMMENT ON TABLE public.favorites IS '功能和完整内容的当前收藏;取消即删除;仅功能收藏增减 worksheets.likes';
|
||||
COMMENT ON COLUMN public.favorites.worksheet_id IS '稳定功能逻辑关联;内容收藏的功能归属由服务端查询确定,历史缺失时保留';
|
||||
COMMENT ON COLUMN public.favorites.worksheet_resource_id IS 'NULL 是功能收藏,非 NULL 是完整内容收藏;逻辑关联,缺失/下架不清空,不退化为功能收藏';
|
||||
|
||||
COMMIT;
|
||||
@@ -4,17 +4,35 @@
|
||||
|
||||
2026-10-12 已在本地 PostgreSQL 18.6 临时数据库执行 001/002/003,并重复执行 003 验证不覆盖 enabled=false;10 张表与 19 项关键约束检查通过,历史 NULL 事件、标识大小写及资产所有者删除行为符合设计。验证库已删除;随后已在用户授权下正式初始化 doodle_dev,10 张表与两条配置记录核对通过。
|
||||
|
||||
| 文件 | 作用 | 执行位置 |
|
||||
| ------------------------------------------------------------ | ---------------------------------------------- | ---------------------------------------------------------- |
|
||||
| [001-create-database.sql](./001-create-database.sql) | 创建 UTF-8 / C locale / UTC 的 doodle_dev | 连接 postgres 管理数据库,有 CREATEDB 权限;不能包在事务里 |
|
||||
| [002-create-tables.sql](./002-create-tables.sql) | 创建 10 张表、约束、索引与注释 | 连接目标空数据库;单事务执行 |
|
||||
| [003-initialize-settings.sql](./003-initialize-settings.sql) | 初始化 current 页面配置及 homeAutoRefresh 开关 | 连接已建表数据库;可重复执行且不覆盖旧值 |
|
||||
| 文件 | 作用 | 执行位置 |
|
||||
| -------------------------------------------------------------------------------------------------- | ---------------------------------------------- | ---------------------------------------------------------- |
|
||||
| [001-create-database.sql](./001-create-database.sql) | 创建 UTF-8 / C locale / UTC 的 doodle_dev | 连接 postgres 管理数据库,有 CREATEDB 权限;不能包在事务里 |
|
||||
| [002-create-tables.sql](./002-create-tables.sql) | 创建 13 张表、约束、索引与注释 | 连接目标空数据库;单事务执行 |
|
||||
| [003-initialize-settings.sql](./003-initialize-settings.sql) | 初始化 current 页面配置及 homeAutoRefresh 开关 | 连接已建表数据库;可重复执行且不覆盖旧值 |
|
||||
| [004-remove-users-mini-app-id.sql](./004-remove-users-mini-app-id.sql) | 单小程序身份简化,OpenID 唯一 | 仅旧版基线库,成功后不重复执行 |
|
||||
| [005-add-worksheet-resources.sql](./005-add-worksheet-resources.sql) | 增加绘制配置、多文件内容及下载内容标识 | 仅未执行此升级的既有库,单事务执行 |
|
||||
| [006-add-worksheet-grades.sql](./006-add-worksheet-grades.sql) | 增加功能适用年级关系 | 已完成 004/005 的既有库;不自动回填旧 grade |
|
||||
| [007-add-publication-and-resource-downloads.sql](./007-add-publication-and-resource-downloads.sql) | 功能/资源首次发布时间及资源下载量 | 已完成 004/005/006 的既有库;旧时间不推算、旧计数不分摊 |
|
||||
| [008-add-resource-favorites.sql](./008-add-resource-favorites.sql) | 统一收藏功能与具体内容、两种部分唯一索引 | 已完成 004~007 的既有库,旧收藏保持功能目标 |
|
||||
|
||||
Docker 已在首次启动时创建 doodle_dev,**当前本地跳过 001**。其他环境显式修改 001 的数据库名并用对应角色执行;本次不自动创建云端数据库、生产账号或测试库,不在 SQL 中硬编码密码。生产角色和权限在部署时落实。
|
||||
|
||||
## 本地执行
|
||||
## 最新执行路径
|
||||
|
||||
从 `doodle-store` 根目录执行,使用根 `.env` 指定的本地数据库:
|
||||
当前本地 doodle_dev 已执行至 008,使用最新 13 张表;不重跑 002 或任何已成功的增量 SQL。
|
||||
|
||||
| 数据库当前状态 | 升级至最新的执行顺序 |
|
||||
| ---------------------- | ------------------------------------------------------ |
|
||||
| 空库 | 002 → 003;未建库时先执行 001,Docker 已建库则跳过 001 |
|
||||
| 最初 10 张表的旧基线库 | 004 → 005 → 006 → 007 → 008 |
|
||||
| 已执行部分增量的库 | 按编号顺序执行尚未应用的后续文件 |
|
||||
| 已执行 008 的库 | 无需再次执行 DDL |
|
||||
|
||||
004~008 是历史结构的升级文件,不能用于已执行最新 002 的空库基线。下文各阶段记录解释该次变更,不表示只完成其中某一步就已到最新结构。Prisma 迁移历史尚未接入,执行前依据实际结构及执行记录确认当前版本。
|
||||
|
||||
## 空库初始化示例
|
||||
|
||||
从 `doodle-store` 根目录执行,以下仅适用于尚未建表的目标库。根 `.env` 当前指向已初始化的 doodle_dev,不在现有库再次运行 002。
|
||||
|
||||
```bash
|
||||
pnpm infra:up
|
||||
@@ -36,7 +54,7 @@ SELECT id, version FROM public.page_configs;
|
||||
SELECT id, value FROM public.settings;
|
||||
```
|
||||
|
||||
预期业务表共 10 张,页面配置有 current,设置有 homeAutoRefresh。2026-10-12 已在本地 doodle_dev 执行 002/003 并核对通过,当前已有 10 张表;不要再次执行 002。独立临时库验证与正式本地初始化分别记录,未连接云服务器。
|
||||
最新基线预期业务表共 13 张,页面配置有 current,设置有 homeAutoRefresh。2026-10-12 已在本地 doodle_dev 执行 002/003 并核对通过,当时已有 10 张表;不要再次执行 002。独立临时库验证与正式本地初始化分别记录,未连接云服务器。
|
||||
|
||||
## 实施边界
|
||||
|
||||
@@ -47,3 +65,118 @@ SELECT id, value FROM public.settings;
|
||||
- tags 元素类型、分类多层循环、任务租约/锁、JWT 失效与管理员权限由后续业务实现;SQL 不代表业务 API 已完成。
|
||||
- updatedAt 和 contentUpdatedAt 由服务显式维护,不添加把两者混为一谈的更新时间触发器。
|
||||
- Prisma 尚未安装,Schema 和迁移历史尚未接入。后续接入时将本 SQL 纳入正式基线;已有表的库须采用基线登记流程,不能直接再次执行同一 DDL。
|
||||
|
||||
## 单小程序身份简化(2026-10-14)
|
||||
|
||||
最新 002 已移除 users.mini_app_id,改为 users.openid 唯一,AppID 由服务端配置。
|
||||
已执行旧版 002 的库使用 `004-remove-users-mini-app-id.sql` 增量升级;不要重跑 002。
|
||||
新建库执行最新 002/003 即可,不执行 004。004 会先建立 OpenID 唯一约束,
|
||||
如存在重复则全部回滚,不自动合并或删除用户;成功执行后不可重复执行。
|
||||
|
||||
2026-10-14 已在本地 doodle_dev 执行 004 并核对:mini_app_id 已移除,users_openid_key 为 UNIQUE (openid);执行时用户表为空。
|
||||
|
||||
## Worksheet 多资源扩展(2026-10-14)
|
||||
|
||||
设计原因见 [Worksheet 数据库设计说明](../../../../docs/v3.5/Worksheet数据库设计说明.md)。
|
||||
最新 002 新建 13 张表;worksheet 增加 generation_mode、renderer_key、render_config,新增
|
||||
worksheet_resources、worksheet_resource_assets,assets 支持 worksheet_source 用途,
|
||||
download_logs 增加可空 worksheet_resource_id。文件关联首期只有 outline/reference,无文件级配置。
|
||||
|
||||
- 新空库:执行最新 002 → 003;不要执行 004/005/006/007/008,它们的结果已经包含在基线里。
|
||||
- 2026-10-12 旧基线库:先执行 004(若尚未执行),再执行 005。
|
||||
- 已执行 004 的本地库:只执行 005;不要重跑 002 或 004。
|
||||
- 005 为单事务增量升级,成功后不可重复执行;不使用 IF NOT EXISTS 隐藏结构差异。
|
||||
|
||||
```bash
|
||||
docker compose --env-file .env -f infra/compose.yaml exec -T postgres \
|
||||
sh -c 'exec psql -X -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -d "$POSTGRES_DB"' \
|
||||
< apps/server/prisma/sql/005-add-worksheet-resources.sql
|
||||
```
|
||||
|
||||
旧 worksheet 的 ID/path、计数、预览及历史不变;新列默认 procedural、NULL renderer_key 和 {}。
|
||||
导入时按实际功能核对,NULL renderer_key 仅供已登记的旧版映射兼容;新功能发布必须明确实现。
|
||||
不把旧题型预览自动转为线框或参考资源,资源新表默认空。下载资源 ID 为逻辑关联,服务端需校验归属。
|
||||
|
||||
2026-10-14 验证记录:在两个隔离临时库分别执行最新 002/003 与旧版 002/003 + 005,
|
||||
列定义、约束、索引及注释一致(忽略新增列的物理顺序)。两条路径均通过多线框、共享资产、
|
||||
双用途引用、独立预览、JSON/状态/唯一性/外键/删除限制、旧数据保留与历史逻辑关联检查。
|
||||
临时库均已删除;本地 doodle_dev 已执行 005,核对为 12 张表,current/homeAutoRefresh 保留,
|
||||
两张资源新表为空,未导入测试内容或连接生产库。
|
||||
|
||||
## 多适用年级(2026-10-14)
|
||||
|
||||
categories 结构保持不变,新增 worksheet_grades(worksheet_id、grade),联合主键防重复,
|
||||
反向索引供年级菜单筛选。固定编码 -4~6,0 为幼小衔接;不新增年级字典或菜单表。
|
||||
旧 worksheets.grade 保留原值,关系表作为新适用年级筛选的唯一权威来源。
|
||||
|
||||
最新空库执行 002/003,跳过 004/005/006/007/008;已执行 005 的库仅执行 006。
|
||||
更早的库先按版本补齐未执行的增量文件,不重复执行成功的 SQL。006 单事务、非重复执行脚本,
|
||||
不自动从旧 grade 或年龄回填关系;经审核的 worksheetId → grades 映射另行导入。
|
||||
无关系表示未配置,不表示全年级;年级筛选上线前完成对应题型的映射审核。
|
||||
|
||||
```bash
|
||||
docker compose --env-file .env -f infra/compose.yaml exec -T postgres \
|
||||
sh -c 'exec psql -X -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -d "$POSTGRES_DB"' \
|
||||
< apps/server/prisma/sql/006-add-worksheet-grades.sql
|
||||
```
|
||||
|
||||
2026-10-14 验证:最新 002/003 与旧版基线 + 006 在两个隔离库中生成相同的列、约束、
|
||||
索引及注释;多/不连续年级、合法编码边界、联合主键、外键、删除限制、旧值保留、
|
||||
不自动回填及分类/年级组合查询不重复检查通过。临时库已删除。
|
||||
本地 doodle_dev 已执行 006,共 13 张表;worksheet_grades 为空,初始配置保留。
|
||||
|
||||
## 首次发布与资源下载统计(2026-10-14)
|
||||
|
||||
最新空库只执行 002/003;已执行 006 的既有库执行 007,不重跑旧迁移。
|
||||
007 在功能及内容上增加可空 first_published_at(无默认值),内容增加非负 downloads(默认 0)。
|
||||
旧 is_new 保留为兼容值,is_hot 保留为功能运营推荐;不新增资源新品/热门布尔值、收藏计数或 seed。
|
||||
未知旧发布时间保持 NULL,首次发布/新品派生及下载幂等事务由后续服务端业务实现。
|
||||
文件访问、日志数量、创建时间和升级时间都不能冒充真实历史依据。
|
||||
|
||||
```bash
|
||||
docker compose --env-file .env -f infra/compose.yaml exec -T postgres \
|
||||
sh -c 'exec psql -X -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -d "$POSTGRES_DB"' \
|
||||
< apps/server/prisma/sql/007-add-publication-and-resource-downloads.sql
|
||||
```
|
||||
|
||||
新结构仍为 13 张表。正常资源下载的日志及两层 downloads 由同一事务维护,不使用触发器自动加数。
|
||||
功能原累计值不覆盖或分摊,资源默认 0;旧单独保存的 is_new 不变,不能据此伪造时间。
|
||||
|
||||
2026-10-14 验证:最新 002/003 与旧版基线 + 007 在两个临时库生成相同列、约束、索引及注释。
|
||||
旧标记/计数/未知发布时间保留、资源默认 0、非负约束和独立发布时间检查通过;
|
||||
SQL 事务示例通过重复事件不加数、任一步失败全回滚、删除日志不扣累计的验证。
|
||||
这些验证不代表真实下载 API 已实现。临时库已清理;本地 doodle_dev 已执行 007,仍为 13 张表,
|
||||
新时间列可空且无默认值,资源 downloads 默认 0、NOT NULL 且非负,原初始配置保留。
|
||||
|
||||
## 统一功能与内容收藏(2026-10-14)
|
||||
|
||||
最新空库执行 002/003,跳过 004~008;已执行 007 的既有库仅执行 008,不重复已成功 SQL。
|
||||
008 新增 favorites.worksheet_resource_id,旧记录为 NULL;撤销旧全局唯一约束,
|
||||
创建功能和内容两个部分唯一索引。不新增资源收藏表/type 字段或资源 likes,仍为 13 张表。
|
||||
旧收藏 ID、时间、归属和功能 likes 不变。新内容 ID 为逻辑关联,归属由服务校验,缺失不 SET NULL。
|
||||
|
||||
```bash
|
||||
docker compose --env-file .env -f infra/compose.yaml exec -T postgres \
|
||||
sh -c 'exec psql -X -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -d "$POSTGRES_DB"' \
|
||||
< apps/server/prisma/sql/008-add-resource-favorites.sql
|
||||
```
|
||||
|
||||
后续收藏 INSERT 的 ON CONFLICT 需带对应部分索引谓词,Prisma 接入时保留原生索引。
|
||||
旧查询/数量/取消加 IS NULL;新资源关系不增减功能 likes,注销清理两类但仅扣功能贡献。
|
||||
本次仅修改数据库与接口契约,资源收藏 API 及小程序页面尚待实现。
|
||||
|
||||
2026-10-14 验证:最新基线与旧版基线 + 008 的列、约束、索引、注释一致;
|
||||
旧收藏保留、功能和同功能多资源共存、两种部分唯一索引/ON CONFLICT、用户隔离、
|
||||
旧功能取消范围、资源取消不扣 likes、下架/失联目标保留及注销 SQL 示例通过。
|
||||
临时验证库已删除;本地 doodle_dev 已执行 008,仍为 13 张表,两种部分索引生效,
|
||||
原配置保留,未导入测试收藏。验证不代表业务 API 或小程序资源收藏页面已经实现。
|
||||
|
||||
## 最终对齐核查(2026-10-14)
|
||||
|
||||
- 设计文档与最新 002 的 13 张表、135 个字段名称/类型/可空/默认值一致。
|
||||
- 实测 001 建隔离库;最新 002/003、原始旧基线 + 004~008 全链路、本地 doodle_dev 的列、约束、索引和注释一致,忽略物理列顺序。
|
||||
- 完整升级保留旧身份、功能、收藏、历史及计数;003 重复执行不覆盖关闭开关、页面内容及版本。
|
||||
- 最新基线下的资源、年级、发布/下载、两种收藏约束与 SQL 事务示例回归通过,标识列 C 排序规则核对通过。
|
||||
- 所有临时核查库已清理;开发库只读比对,无样本写入。本次只修正文档说明,无需新增 DDL 或再次升级开发库。
|
||||
|
||||
业务归属/权限、首次发布、计数和审计事务、任务调度等仍需服务端接入;SQL 验证不代替业务 API 验收。
|
||||
|
||||
Reference in New Issue
Block a user