Files
doodle-store/deploy/postgres/initialize-doodle-prod.sql
2026-10-20 17:29:10 +08:00

1186 lines
42 KiB
PL/PgSQL
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- Doodle 生产空库初始化快照(2026-10-20)
-- 来源:独立空库实际执行仓库三次正式 Prisma 迁移后的完整导出;不包含 doodle_dev 业务数据。
-- 适用 PostgreSQL 18;仅第一次初始化空 doodle_prod。保留迁移校验和供后续 migrate deploy 接续。
-- 以目标数据库所有者执行;包含 13 张业务表、Prisma 历史和两条初始配置。
BEGIN;
SET LOCAL lock_timeout = '5s';
SET LOCAL statement_timeout = '120s';
DO $doodle_empty_guard$
BEGIN
IF current_database() <> 'doodle_prod' AND current_database() !~ '^doodle_schema_check_[a-z0-9]+$' THEN
RAISE EXCEPTION '只允许初始化 doodle_prod 空库;请核对当前数据库';
END IF;
IF EXISTS (
SELECT 1 FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
AND n.nspname NOT LIKE 'pg_toast%'
AND c.relkind IN ('r', 'p', 'v', 'm', 'f', 'S')
) THEN
RAISE EXCEPTION '目标已有用户表/视图/序列,停止初始化;不清空或覆盖已有结构';
END IF;
END
$doodle_empty_guard$;
--
-- PostgreSQL database dump
--
-- Dumped from database version 18.6
-- Dumped by pg_dump version 18.6
SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET transaction_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;
--
-- Name: public; Type: SCHEMA; Schema: -; Owner: -
--
--
-- Name: SCHEMA public; Type: COMMENT; Schema: -; Owner: -
--
COMMENT ON SCHEMA public IS 'standard public schema';
SET default_tablespace = '';
SET default_table_access_method = heap;
--
-- Name: _prisma_migrations; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public._prisma_migrations (
id character varying(36) NOT NULL,
checksum character varying(64) NOT NULL,
finished_at timestamp with time zone,
migration_name character varying(255) NOT NULL,
logs text,
rolled_back_at timestamp with time zone,
started_at timestamp with time zone DEFAULT now() NOT NULL,
applied_steps_count integer DEFAULT 0 NOT NULL
);
--
-- Name: admin_audit_logs; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.admin_audit_logs (
id character varying(128) NOT NULL COLLATE pg_catalog."C",
actor_user_id character varying(128) COLLATE pg_catalog."C",
actor_type character varying(16) NOT NULL,
action character varying(64) NOT NULL,
resource_type character varying(64) NOT NULL,
resource_id character varying(128) COLLATE pg_catalog."C",
request_id character varying(128) NOT NULL COLLATE pg_catalog."C",
before_data jsonb,
after_data jsonb,
reason text,
created_at timestamp(3) with time zone DEFAULT now() NOT NULL,
CONSTRAINT admin_audit_logs_actor_type_check CHECK (((actor_type)::text = ANY ((ARRAY['admin'::character varying, 'system'::character varying, 'migration'::character varying, 'user'::character varying])::text[])))
);
--
-- Name: TABLE admin_audit_logs; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON TABLE public.admin_audit_logs IS '管理变更审计;操作者为逻辑关联,注销需主动去关联';
--
-- Name: assets; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.assets (
id character varying(128) NOT NULL COLLATE pg_catalog."C",
source_ref text COLLATE pg_catalog."C",
source_ref_hash character(64) COLLATE pg_catalog."C",
provider character varying(16) DEFAULT 'qiniu'::character varying NOT NULL,
bucket character varying(128) COLLATE pg_catalog."C",
object_key text COLLATE pg_catalog."C",
object_ref_hash character(64) COLLATE pg_catalog."C",
external_url text COLLATE pg_catalog."C",
purpose character varying(32) NOT NULL,
owner_user_id character varying(128) COLLATE pg_catalog."C",
visibility character varying(16) NOT NULL,
mime_type character varying(128),
size_bytes bigint,
checksum character(64) COLLATE pg_catalog."C",
status character varying(16) DEFAULT 'pending'::character varying NOT NULL,
last_error text,
created_at timestamp(3) with time zone DEFAULT now() NOT NULL,
updated_at timestamp(3) with time zone DEFAULT now() NOT NULL,
CONSTRAINT assets_checksum_check CHECK (((checksum IS NULL) OR (checksum ~ '^[0-9a-f]{64}$'::text))),
CONSTRAINT assets_object_ref_hash_check CHECK (((object_ref_hash IS NULL) OR (object_ref_hash ~ '^[0-9a-f]{64}$'::text))),
CONSTRAINT assets_provider_check CHECK (((provider)::text = ANY ((ARRAY['qiniu'::character varying, 'external'::character varying])::text[]))),
CONSTRAINT assets_purpose_check CHECK (((purpose)::text = ANY ((ARRAY['avatar'::character varying, 'preview'::character varying, 'category_icon'::character varying, 'font'::character varying, 'share'::character varying, 'page_config'::character varying, 'worksheet_source'::character varying, 'other'::character varying])::text[]))),
CONSTRAINT assets_ready_reference_check CHECK ((((status)::text <> 'ready'::text) OR (((provider)::text = 'qiniu'::text) AND (bucket IS NOT NULL) AND (length((bucket)::text) > 0) AND (object_key IS NOT NULL) AND (length(object_key) > 0) AND (object_ref_hash IS NOT NULL) AND (mime_type IS NOT NULL) AND (length((mime_type)::text) > 0) AND (size_bytes IS NOT NULL) AND (checksum IS NOT NULL)) OR (((provider)::text = 'external'::text) AND (external_url IS NOT NULL) AND (external_url ~ '^https://[^/[:space:]]+'::text)))),
CONSTRAINT assets_size_bytes_check CHECK (((size_bytes IS NULL) OR (size_bytes >= 0))),
CONSTRAINT assets_source_ref_hash_check CHECK (((source_ref_hash IS NULL) OR (source_ref_hash ~ '^[0-9a-f]{64}$'::text))),
CONSTRAINT assets_status_check CHECK (((status)::text = ANY ((ARRAY['pending'::character varying, 'ready'::character varying, 'failed'::character varying, 'deleting'::character varying, 'deleted'::character varying])::text[]))),
CONSTRAINT assets_visibility_check CHECK (((visibility)::text = ANY ((ARRAY['public'::character varying, 'private'::character varying])::text[])))
);
--
-- Name: TABLE assets; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON TABLE public.assets IS '七牛文件引用与旧资源迁移映射;不保存临时签名 URL';
--
-- Name: COLUMN assets.object_ref_hash; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON COLUMN public.assets.object_ref_hash IS '规范序列化 [provider,bucket,objectKey] 的 SHA-256;服务端生成并核对原引用';
--
-- Name: COLUMN assets.checksum; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON COLUMN public.assets.checksum IS '文件内容 SHA-256,不是七牛 ETag;非唯一';
--
-- Name: categories; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.categories (
id character varying(128) NOT NULL COLLATE pg_catalog."C",
name character varying(100) NOT NULL,
icon character varying(1024) NOT NULL,
icon_asset_id character varying(128) COLLATE pg_catalog."C",
color character varying(32) NOT NULL,
sort_order integer DEFAULT 0 NOT NULL,
parent_id character varying(128) COLLATE pg_catalog."C",
created_at timestamp(3) with time zone DEFAULT now() NOT NULL,
updated_at timestamp(3) with time zone DEFAULT now() NOT NULL,
status character varying(16) DEFAULT 'draft'::character varying NOT NULL,
CONSTRAINT categories_parent_not_self_check CHECK (((parent_id IS NULL) OR ((parent_id)::text <> (id)::text))),
CONSTRAINT categories_status_check CHECK (((status)::text = ANY ((ARRAY['draft'::character varying, 'active'::character varying, 'hidden'::character varying])::text[])))
);
--
-- Name: TABLE categories; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON TABLE public.categories IS '内容分类树,与适用年级独立;多层循环需由服务端事务检查';
--
-- Name: COLUMN categories.status; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON COLUMN public.categories.status IS '发布状态:draft 开发测试,active 上线,hidden 下架;公开访问还需所有上级分类 active';
--
-- Name: download_logs; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.download_logs (
id character varying(128) NOT NULL COLLATE pg_catalog."C",
user_id character varying(128) NOT NULL COLLATE pg_catalog."C",
worksheet_id character varying(128) NOT NULL COLLATE pg_catalog."C",
worksheet_resource_id character varying(128) COLLATE pg_catalog."C",
export_id character varying(128) COLLATE pg_catalog."C",
source character varying(16) DEFAULT 'mini'::character varying NOT NULL,
params jsonb,
created_at timestamp(3) with time zone DEFAULT now() NOT NULL,
CONSTRAINT download_logs_export_id_check CHECK (((((source)::text = 'import'::text) AND (export_id IS NULL)) OR ((export_id IS NOT NULL) AND (length(btrim((export_id)::text)) > 0)))),
CONSTRAINT download_logs_source_check CHECK (((source)::text = ANY ((ARRAY['mini'::character varying, 'legacy'::character varying, 'import'::character varying])::text[])))
);
--
-- Name: TABLE download_logs; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON TABLE public.download_logs IS '成功保存历史;同用户 exportId 唯一,日志与计数由业务事务同步';
--
-- Name: COLUMN download_logs.worksheet_id; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON COLUMN public.download_logs.worksheet_id IS '题型逻辑关联,不建外键,历史查询使用 LEFT JOIN';
--
-- Name: COLUMN download_logs.worksheet_resource_id; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON COLUMN public.download_logs.worksheet_resource_id IS '可空资源条目逻辑关联;历史和算法生成可空;新写入校验属于同一 worksheet';
--
-- Name: COLUMN download_logs.export_id; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON COLUMN public.download_logs.export_id IS '历史 import 可为 NULL;mini/legacy 必须提供非空事件 ID';
--
-- Name: favorites; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.favorites (
id character varying(128) NOT NULL COLLATE pg_catalog."C",
user_id character varying(128) NOT NULL COLLATE pg_catalog."C",
worksheet_id character varying(128) NOT NULL COLLATE pg_catalog."C",
worksheet_resource_id character varying(128) COLLATE pg_catalog."C",
created_at timestamp(3) with time zone DEFAULT now() NOT NULL,
CONSTRAINT favorites_resource_id_check CHECK (((worksheet_resource_id IS NULL) OR (length(btrim((worksheet_resource_id)::text)) > 0)))
);
--
-- Name: TABLE favorites; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON TABLE public.favorites IS '功能和完整内容的当前收藏;取消即删除;仅功能收藏增减 worksheets.likes';
--
-- Name: COLUMN favorites.worksheet_id; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON COLUMN public.favorites.worksheet_id IS '稳定功能逻辑关联;内容收藏的功能归属由服务端查询确定,历史缺失时保留';
--
-- Name: COLUMN favorites.worksheet_resource_id; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON COLUMN public.favorites.worksheet_resource_id IS 'NULL 是功能收藏,非 NULL 是完整内容收藏;逻辑关联,缺失/下架不清空,不退化为功能收藏';
--
-- Name: job_runs; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.job_runs (
id character varying(128) NOT NULL COLLATE pg_catalog."C",
job_name character varying(64) NOT NULL COLLATE pg_catalog."C",
run_key character varying(128) NOT NULL COLLATE pg_catalog."C",
trigger_type character varying(16) NOT NULL,
status character varying(16) DEFAULT 'pending'::character varying NOT NULL,
scheduled_at timestamp(3) with time zone,
started_at timestamp(3) with time zone,
finished_at timestamp(3) with time zone,
attempt integer DEFAULT 0 NOT NULL,
lock_token character varying(128) COLLATE pg_catalog."C",
locked_until timestamp(3) with time zone,
result jsonb,
error_message text,
created_at timestamp(3) with time zone DEFAULT now() NOT NULL,
updated_at timestamp(3) with time zone DEFAULT now() NOT NULL,
CONSTRAINT job_runs_attempt_check CHECK ((attempt >= 0)),
CONSTRAINT job_runs_status_check CHECK (((status)::text = ANY ((ARRAY['pending'::character varying, 'running'::character varying, 'succeeded'::character varying, 'failed'::character varying, 'skipped'::character varying])::text[]))),
CONSTRAINT job_runs_trigger_type_check CHECK (((trigger_type)::text = ANY ((ARRAY['scheduled'::character varying, 'manual'::character varying, 'recovery'::character varying])::text[])))
);
--
-- Name: TABLE job_runs; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON TABLE public.job_runs IS '任务逻辑去重、租约与执行结果;内容更新仍需业务行锁';
--
-- Name: page_configs; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.page_configs (
id character varying(128) NOT NULL COLLATE pg_catalog."C",
home jsonb,
category jsonb,
age jsonb,
version bigint DEFAULT 0 NOT NULL,
updated_at timestamp(3) with time zone DEFAULT now() NOT NULL,
published_version bigint,
published_at timestamp(3) with time zone,
CONSTRAINT page_configs_age_object_check CHECK (((age IS NULL) OR (jsonb_typeof(age) = 'object'::text))),
CONSTRAINT page_configs_category_object_check CHECK (((category IS NULL) OR (jsonb_typeof(category) = 'object'::text))),
CONSTRAINT page_configs_home_object_check CHECK (((home IS NULL) OR (jsonb_typeof(home) = 'object'::text))),
CONSTRAINT page_configs_published_version_check CHECK (((published_version IS NULL) OR ((published_version >= 0) AND (published_version <= version)))),
CONSTRAINT page_configs_version_check CHECK ((version >= 0))
);
--
-- Name: TABLE page_configs; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON TABLE public.page_configs IS '页面配置权威源;JSON 内持久化 assetId,DTO 解析资源地址';
--
-- Name: settings; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.settings (
id character varying(128) NOT NULL COLLATE pg_catalog."C",
value jsonb NOT NULL,
version bigint DEFAULT 0 NOT NULL,
updated_at timestamp(3) with time zone DEFAULT now() NOT NULL,
CONSTRAINT settings_value_object_check CHECK ((jsonb_typeof(value) = 'object'::text)),
CONSTRAINT settings_version_check CHECK ((version >= 0))
);
--
-- Name: TABLE settings; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON TABLE public.settings IS '运行配置;value 保留原文档业务字段';
--
-- Name: users; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.users (
id character varying(128) NOT NULL COLLATE pg_catalog."C",
openid character varying(128) NOT NULL COLLATE pg_catalog."C",
unionid character varying(128) COLLATE pg_catalog."C",
nick_name character varying(100),
avatar_asset_id character varying(128) COLLATE pg_catalog."C",
total_downloads bigint DEFAULT 0 NOT NULL,
role character varying(16) DEFAULT 'user'::character varying NOT NULL,
status character varying(16) DEFAULT 'active'::character varying NOT NULL,
auth_version integer DEFAULT 1 NOT NULL,
created_at timestamp(3) with time zone DEFAULT now() NOT NULL,
last_active_at timestamp(3) with time zone DEFAULT now() NOT NULL,
updated_at timestamp(3) with time zone DEFAULT now() NOT NULL,
CONSTRAINT users_auth_version_check CHECK ((auth_version >= 0)),
CONSTRAINT users_role_check CHECK (((role)::text = ANY ((ARRAY['user'::character varying, 'admin'::character varying])::text[]))),
CONSTRAINT users_status_check CHECK (((status)::text = ANY ((ARRAY['active'::character varying, 'disabled'::character varying])::text[]))),
CONSTRAINT users_total_downloads_check CHECK ((total_downloads >= 0))
);
--
-- Name: TABLE users; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON TABLE public.users IS '微信用户;沿用 CloudBase 字符串 ID,按 OpenID 唯一;AppID 由服务端配置';
--
-- Name: COLUMN users.total_downloads; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON COLUMN public.users.total_downloads IS '旧字段迁移兼容值;个人下载数量以 download_logs 查询为准';
--
-- Name: COLUMN users.auth_version; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON COLUMN public.users.auth_version IS '应用凭证版本;服务端鉴权校验,不由 SQL 自动递增';
--
-- Name: worksheet_grades; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.worksheet_grades (
worksheet_id character varying(128) NOT NULL COLLATE pg_catalog."C",
grade smallint NOT NULL,
CONSTRAINT worksheet_grades_grade_check CHECK (((grade >= '-4'::integer) AND (grade <= 6)))
);
--
-- Name: TABLE worksheet_grades; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON TABLE public.worksheet_grades IS '功能适用年级的唯一权威关系;与内容分类独立,不从年龄自动推算';
--
-- Name: COLUMN worksheet_grades.grade; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON COLUMN public.worksheet_grades.grade IS '-4 托班、-3 小班、-2 中班、-1 大班、0 幼小衔接、1至6 小学年级;无关系表示未配置,不表示全年级';
--
-- Name: worksheet_resource_assets; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.worksheet_resource_assets (
id character varying(128) NOT NULL COLLATE pg_catalog."C",
worksheet_resource_id character varying(128) NOT NULL COLLATE pg_catalog."C",
asset_id character varying(128) NOT NULL COLLATE pg_catalog."C",
role character varying(16) NOT NULL,
sort_order integer DEFAULT 0 NOT NULL,
CONSTRAINT worksheet_resource_assets_role_check CHECK (((role)::text = ANY ((ARRAY['outline'::character varying, 'reference'::character varying])::text[])))
);
--
-- Name: TABLE worksheet_resource_assets; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON TABLE public.worksheet_resource_assets IS '完整内容的文件输入;outline 线框,reference 对照图;不保存文件级配置';
--
-- Name: COLUMN worksheet_resource_assets.role; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON COLUMN public.worksheet_resource_assets.role IS '业务用途,不是文件格式;用途对应的文件数量、类型和是否打印由 renderer 校验';
--
-- Name: COLUMN worksheet_resource_assets.sort_order; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON COLUMN public.worksheet_resource_assets.sort_order IS '同用途文件的处理顺序,并列按 id 排序;不等于通用图层 z-index';
--
-- Name: worksheet_resources; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.worksheet_resources (
id character varying(128) NOT NULL COLLATE pg_catalog."C",
worksheet_id character varying(128) NOT NULL COLLATE pg_catalog."C",
title character varying(100) NOT NULL,
preview_asset_id character varying(128) NOT NULL COLLATE pg_catalog."C",
config_override jsonb,
status character varying(16) DEFAULT 'draft'::character varying NOT NULL,
sort_order integer DEFAULT 0 NOT NULL,
downloads bigint DEFAULT 0 NOT NULL,
first_published_at timestamp(3) with time zone,
created_at timestamp(3) with time zone DEFAULT now() NOT NULL,
updated_at timestamp(3) with time zone DEFAULT now() NOT NULL,
CONSTRAINT worksheet_resources_config_object_check CHECK (((config_override IS NULL) OR (jsonb_typeof(config_override) = 'object'::text))),
CONSTRAINT worksheet_resources_downloads_check CHECK ((downloads >= 0)),
CONSTRAINT worksheet_resources_status_check CHECK (((status)::text = ANY ((ARRAY['draft'::character varying, 'active'::character varying, 'hidden'::character varying])::text[])))
);
--
-- Name: TABLE worksheet_resources; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON TABLE public.worksheet_resources IS 'worksheet 下可选择的完整内容;独立预览及轻量配置覆盖';
--
-- Name: COLUMN worksheet_resources.preview_asset_id; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON COLUMN public.worksheet_resources.preview_asset_id IS '内容列表预览图;与绘制参考图用途独立,允许引用同一资产';
--
-- Name: COLUMN worksheet_resources.config_override; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON COLUMN public.worksheet_resources.config_override IS '可选参数覆盖;应用按 renderer 白名单校验,不支持任意深度合并';
--
-- Name: COLUMN worksheet_resources.downloads; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON COLUMN public.worksheet_resources.downloads IS '内容累计成功保存次数;仅有可信资源归属的新事件递增,不分摊功能旧计数,不因个人日志删除回减';
--
-- Name: COLUMN worksheet_resources.first_published_at; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON COLUMN public.worksheet_resources.first_published_at IS '内容首次公开发布时间;用于资源新品判断,草稿/重发不重置,未知旧时间保持 NULL';
--
-- Name: worksheets; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.worksheets (
id character varying(128) NOT NULL COLLATE pg_catalog."C",
title character varying(100) NOT NULL,
subtitle character varying(500) NOT NULL,
category_id character varying(128) NOT NULL COLLATE pg_catalog."C",
subcategory character varying(100),
path character varying(1024) NOT NULL,
generation_mode character varying(16) DEFAULT 'procedural'::character varying NOT NULL,
renderer_key character varying(64) COLLATE pg_catalog."C",
render_config jsonb DEFAULT '{}'::jsonb NOT NULL,
age_min smallint NOT NULL,
age_max smallint NOT NULL,
grade smallint DEFAULT 0 NOT NULL,
difficulty smallint NOT NULL,
preview_asset_id character varying(128) NOT NULL COLLATE pg_catalog."C",
tags jsonb DEFAULT '[]'::jsonb NOT NULL,
is_new boolean DEFAULT false NOT NULL,
is_hot boolean DEFAULT false NOT NULL,
sort_order integer DEFAULT 0 NOT NULL,
downloads bigint DEFAULT 0 NOT NULL,
likes bigint DEFAULT 0 NOT NULL,
downloads_seed bigint DEFAULT 0 NOT NULL,
likes_seed bigint DEFAULT 0 NOT NULL,
status character varying(16) DEFAULT 'draft'::character varying NOT NULL,
first_published_at timestamp(3) with time zone,
created_at timestamp(3) with time zone DEFAULT now() NOT NULL,
content_updated_at timestamp(3) with time zone,
updated_at timestamp(3) with time zone DEFAULT now() NOT NULL,
CONSTRAINT worksheets_age_check CHECK (((age_min >= 0) AND (age_max >= age_min))),
CONSTRAINT worksheets_counts_check CHECK (((downloads >= 0) AND (likes >= 0) AND (downloads_seed >= 0) AND (likes_seed >= 0))),
CONSTRAINT worksheets_difficulty_check CHECK (((difficulty >= 1) AND (difficulty <= 4))),
CONSTRAINT worksheets_generation_mode_check CHECK (((generation_mode)::text = ANY ((ARRAY['procedural'::character varying, 'resource'::character varying])::text[]))),
CONSTRAINT worksheets_render_config_object_check CHECK ((jsonb_typeof(render_config) = 'object'::text)),
CONSTRAINT worksheets_renderer_key_check CHECK (((renderer_key IS NULL) OR (length(btrim((renderer_key)::text)) > 0))),
CONSTRAINT worksheets_status_check CHECK (((status)::text = ANY ((ARRAY['draft'::character varying, 'active'::character varying, 'hidden'::character varying])::text[]))),
CONSTRAINT worksheets_tags_array_check CHECK ((jsonb_typeof(tags) = 'array'::text))
);
--
-- Name: TABLE worksheets; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON TABLE public.worksheets IS '题型内容与真实/种子计数;资源通过 assets 引用';
--
-- Name: COLUMN worksheets.generation_mode; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON COLUMN public.worksheets.generation_mode IS 'procedural 算法生成;resource 完整内容资源驱动;旧数据默认 procedural,导入逐项核对';
--
-- Name: COLUMN worksheets.renderer_key; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON COLUMN public.worksheets.renderer_key IS '客户端绘制实现标识;多题型可共用;NULL 仅供旧版 ID/path 映射兼容,新功能发布必须明确';
--
-- Name: COLUMN worksheets.render_config; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON COLUMN public.worksheets.render_config IS '共用绘制参数;仅允许已定义参数,不存执行代码或密钥';
--
-- Name: COLUMN worksheets.grade; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON COLUMN public.worksheets.grade IS '旧版单年级兼容值;可能由年龄推算;保留原值,新年级筛选使用 worksheet_grades';
--
-- Name: COLUMN worksheets.tags; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON COLUMN public.worksheets.tags IS '字符串数组;数据库限制顶层 array,服务端校验元素';
--
-- Name: COLUMN worksheets.is_new; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON COLUMN public.worksheets.is_new IS '旧版新品兼容标记;新功能新品由首次发布时间及时间窗口派生,不作为新业务权威值';
--
-- Name: COLUMN worksheets.is_hot; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON COLUMN public.worksheets.is_hot IS '功能级人工运营推荐标记,不是下载排行榜计算结果,不自动传递给资源';
--
-- Name: COLUMN worksheets.downloads; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON COLUMN public.worksheets.downloads IS '功能累计成功保存次数;保留旧累计值,资源下载也计入,不等于资源计数总和';
--
-- Name: COLUMN worksheets.first_published_at; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON COLUMN public.worksheets.first_published_at IS '首次公开发布时间;新功能由发布事务写入,重发/新增资源不重置;旧时间未知保持 NULL';
--
-- Name: COLUMN worksheets.content_updated_at; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON COLUMN public.worksheets.content_updated_at IS '仅内容修改时更新;不随计数变化;历史缺失保留 NULL';
--
-- Name: COLUMN worksheets.updated_at; Type: COMMENT; Schema: public; Owner: -
--
COMMENT ON COLUMN public.worksheets.updated_at IS '由服务显式更新;包含计数、状态、内容变更';
--
-- Data for Name: _prisma_migrations; Type: TABLE DATA; Schema: public; Owner: -
--
INSERT INTO public._prisma_migrations (id, checksum, finished_at, migration_name, logs, rolled_back_at, started_at, applied_steps_count) VALUES ('6f0befd4-3285-40fd-94e3-cb0318b0f99a', 'fcf767720f78a156fff6a04a52c4a78ba85b7a6682ba5714e05f133b943da03e', '2026-10-20 07:24:00.506413+00', '0_v35_baseline', NULL, NULL, '2026-10-20 07:24:00.44403+00', 1);
INSERT INTO public._prisma_migrations (id, checksum, finished_at, migration_name, logs, rolled_back_at, started_at, applied_steps_count) VALUES ('dd0264b5-8640-4c87-802c-1de176a5a894', 'efb27c3d6ffc8b65c91c358c95549bb5bc74e035478dfa59da372c1771d74658', '2026-10-20 07:24:00.510581+00', '20261016000000_category_publication', NULL, NULL, '2026-10-20 07:24:00.506902+00', 1);
INSERT INTO public._prisma_migrations (id, checksum, finished_at, migration_name, logs, rolled_back_at, started_at, applied_steps_count) VALUES ('2b2a3931-3463-4a24-8cba-65d7675c9833', '22d2859a798a3b4502f27da521d7b4d9dd5438c5bf4fc18e5d52011201605158', '2026-10-20 07:24:00.513999+00', '20261019000000_member_assets', NULL, NULL, '2026-10-20 07:24:00.511081+00', 1);
--
-- Data for Name: admin_audit_logs; Type: TABLE DATA; Schema: public; Owner: -
--
--
-- Data for Name: assets; Type: TABLE DATA; Schema: public; Owner: -
--
--
-- Data for Name: categories; Type: TABLE DATA; Schema: public; Owner: -
--
--
-- Data for Name: download_logs; Type: TABLE DATA; Schema: public; Owner: -
--
--
-- Data for Name: favorites; Type: TABLE DATA; Schema: public; Owner: -
--
--
-- Data for Name: job_runs; Type: TABLE DATA; Schema: public; Owner: -
--
--
-- Data for Name: page_configs; Type: TABLE DATA; Schema: public; Owner: -
--
INSERT INTO public.page_configs (id, home, category, age, version, updated_at, published_version, published_at) VALUES ('current', NULL, NULL, NULL, 0, '2026-10-20 07:24:00.446+00', NULL, NULL);
--
-- Data for Name: settings; Type: TABLE DATA; Schema: public; Owner: -
--
INSERT INTO public.settings (id, value, version, updated_at) VALUES ('homeAutoRefresh', '{"enabled": true}', 0, '2026-10-20 07:24:00.446+00');
--
-- Data for Name: users; Type: TABLE DATA; Schema: public; Owner: -
--
--
-- Data for Name: worksheet_grades; Type: TABLE DATA; Schema: public; Owner: -
--
--
-- Data for Name: worksheet_resource_assets; Type: TABLE DATA; Schema: public; Owner: -
--
--
-- Data for Name: worksheet_resources; Type: TABLE DATA; Schema: public; Owner: -
--
--
-- Data for Name: worksheets; Type: TABLE DATA; Schema: public; Owner: -
--
--
-- Name: _prisma_migrations _prisma_migrations_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public._prisma_migrations
ADD CONSTRAINT _prisma_migrations_pkey PRIMARY KEY (id);
--
-- Name: admin_audit_logs admin_audit_logs_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.admin_audit_logs
ADD CONSTRAINT admin_audit_logs_pkey PRIMARY KEY (id);
--
-- Name: assets assets_object_ref_hash_key; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.assets
ADD CONSTRAINT assets_object_ref_hash_key UNIQUE (object_ref_hash);
--
-- Name: assets assets_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.assets
ADD CONSTRAINT assets_pkey PRIMARY KEY (id);
--
-- Name: assets assets_source_ref_hash_key; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.assets
ADD CONSTRAINT assets_source_ref_hash_key UNIQUE (source_ref_hash);
--
-- Name: categories categories_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.categories
ADD CONSTRAINT categories_pkey PRIMARY KEY (id);
--
-- Name: download_logs download_logs_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.download_logs
ADD CONSTRAINT download_logs_pkey PRIMARY KEY (id);
--
-- Name: download_logs download_logs_user_export_key; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.download_logs
ADD CONSTRAINT download_logs_user_export_key UNIQUE (user_id, export_id);
--
-- Name: favorites favorites_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.favorites
ADD CONSTRAINT favorites_pkey PRIMARY KEY (id);
--
-- Name: job_runs job_runs_job_run_key; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.job_runs
ADD CONSTRAINT job_runs_job_run_key UNIQUE (job_name, run_key);
--
-- Name: job_runs job_runs_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.job_runs
ADD CONSTRAINT job_runs_pkey PRIMARY KEY (id);
--
-- Name: page_configs page_configs_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.page_configs
ADD CONSTRAINT page_configs_pkey PRIMARY KEY (id);
--
-- Name: settings settings_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.settings
ADD CONSTRAINT settings_pkey PRIMARY KEY (id);
--
-- Name: users users_openid_key; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.users
ADD CONSTRAINT users_openid_key UNIQUE (openid);
--
-- Name: users users_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.users
ADD CONSTRAINT users_pkey PRIMARY KEY (id);
--
-- Name: worksheet_grades worksheet_grades_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.worksheet_grades
ADD CONSTRAINT worksheet_grades_pkey PRIMARY KEY (worksheet_id, grade);
--
-- Name: worksheet_resource_assets worksheet_resource_assets_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.worksheet_resource_assets
ADD CONSTRAINT worksheet_resource_assets_pkey PRIMARY KEY (id);
--
-- Name: worksheet_resource_assets worksheet_resource_assets_resource_role_asset_key; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.worksheet_resource_assets
ADD CONSTRAINT worksheet_resource_assets_resource_role_asset_key UNIQUE (worksheet_resource_id, role, asset_id);
--
-- Name: worksheet_resources worksheet_resources_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.worksheet_resources
ADD CONSTRAINT worksheet_resources_pkey PRIMARY KEY (id);
--
-- Name: worksheets worksheets_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.worksheets
ADD CONSTRAINT worksheets_pkey PRIMARY KEY (id);
--
-- Name: admin_audit_logs_actor_created_at_idx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX admin_audit_logs_actor_created_at_idx ON public.admin_audit_logs USING btree (actor_user_id, created_at DESC);
--
-- Name: admin_audit_logs_request_id_idx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX admin_audit_logs_request_id_idx ON public.admin_audit_logs USING btree (request_id);
--
-- Name: admin_audit_logs_resource_created_at_idx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX admin_audit_logs_resource_created_at_idx ON public.admin_audit_logs USING btree (resource_type, resource_id, created_at DESC);
--
-- Name: assets_owner_purpose_status_idx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX assets_owner_purpose_status_idx ON public.assets USING btree (owner_user_id, purpose, status);
--
-- Name: assets_status_updated_at_idx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX assets_status_updated_at_idx ON public.assets USING btree (status, updated_at);
--
-- Name: categories_parent_sort_idx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX categories_parent_sort_idx ON public.categories USING btree (parent_id, sort_order, id);
--
-- Name: categories_status_parent_sort_idx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX categories_status_parent_sort_idx ON public.categories USING btree (status, parent_id, sort_order, id);
--
-- Name: download_logs_user_created_at_idx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX download_logs_user_created_at_idx ON public.download_logs USING btree (user_id, created_at DESC, id DESC);
--
-- Name: download_logs_worksheet_created_at_idx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX download_logs_worksheet_created_at_idx ON public.download_logs USING btree (worksheet_id, created_at DESC, id DESC);
--
-- Name: favorites_user_created_at_idx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX favorites_user_created_at_idx ON public.favorites USING btree (user_id, created_at DESC, id DESC);
--
-- Name: favorites_user_resource_key; Type: INDEX; Schema: public; Owner: -
--
CREATE UNIQUE INDEX favorites_user_resource_key ON public.favorites USING btree (user_id, worksheet_resource_id) WHERE (worksheet_resource_id IS NOT NULL);
--
-- Name: favorites_user_worksheet_key; Type: INDEX; Schema: public; Owner: -
--
CREATE UNIQUE INDEX favorites_user_worksheet_key ON public.favorites USING btree (user_id, worksheet_id) WHERE (worksheet_resource_id IS NULL);
--
-- Name: job_runs_job_created_at_idx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX job_runs_job_created_at_idx ON public.job_runs USING btree (job_name, created_at DESC);
--
-- Name: job_runs_status_locked_until_idx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX job_runs_status_locked_until_idx ON public.job_runs USING btree (status, locked_until);
--
-- Name: users_unionid_idx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX users_unionid_idx ON public.users USING btree (unionid);
--
-- Name: worksheet_grades_grade_worksheet_idx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX worksheet_grades_grade_worksheet_idx ON public.worksheet_grades USING btree (grade, worksheet_id);
--
-- Name: worksheet_resource_assets_asset_idx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX worksheet_resource_assets_asset_idx ON public.worksheet_resource_assets USING btree (asset_id);
--
-- Name: worksheet_resource_assets_resource_role_sort_idx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX worksheet_resource_assets_resource_role_sort_idx ON public.worksheet_resource_assets USING btree (worksheet_resource_id, role, sort_order, id);
--
-- Name: worksheet_resources_preview_asset_idx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX worksheet_resources_preview_asset_idx ON public.worksheet_resources USING btree (preview_asset_id);
--
-- Name: worksheet_resources_worksheet_status_sort_idx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX worksheet_resources_worksheet_status_sort_idx ON public.worksheet_resources USING btree (worksheet_id, status, sort_order, id);
--
-- Name: worksheets_category_status_sort_idx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX worksheets_category_status_sort_idx ON public.worksheets USING btree (category_id, status, sort_order, updated_at DESC, id);
--
-- Name: worksheets_status_age_idx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX worksheets_status_age_idx ON public.worksheets USING btree (status, age_min, age_max);
--
-- Name: worksheets_status_sort_idx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX worksheets_status_sort_idx ON public.worksheets USING btree (status, sort_order, updated_at DESC, id);
--
-- Name: assets assets_owner_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.assets
ADD CONSTRAINT assets_owner_user_id_fkey FOREIGN KEY (owner_user_id) REFERENCES public.users(id) ON UPDATE RESTRICT ON DELETE SET NULL;
--
-- Name: categories categories_icon_asset_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.categories
ADD CONSTRAINT categories_icon_asset_id_fkey FOREIGN KEY (icon_asset_id) REFERENCES public.assets(id) ON UPDATE RESTRICT ON DELETE RESTRICT;
--
-- Name: categories categories_parent_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.categories
ADD CONSTRAINT categories_parent_id_fkey FOREIGN KEY (parent_id) REFERENCES public.categories(id) ON UPDATE RESTRICT ON DELETE RESTRICT;
--
-- Name: download_logs download_logs_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.download_logs
ADD CONSTRAINT download_logs_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON UPDATE RESTRICT ON DELETE RESTRICT;
--
-- Name: favorites favorites_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.favorites
ADD CONSTRAINT favorites_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON UPDATE RESTRICT ON DELETE RESTRICT;
--
-- Name: users users_avatar_asset_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.users
ADD CONSTRAINT users_avatar_asset_id_fkey FOREIGN KEY (avatar_asset_id) REFERENCES public.assets(id) ON UPDATE RESTRICT ON DELETE RESTRICT;
--
-- Name: worksheet_grades worksheet_grades_worksheet_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.worksheet_grades
ADD CONSTRAINT worksheet_grades_worksheet_id_fkey FOREIGN KEY (worksheet_id) REFERENCES public.worksheets(id) ON UPDATE RESTRICT ON DELETE RESTRICT;
--
-- Name: worksheet_resource_assets worksheet_resource_assets_asset_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.worksheet_resource_assets
ADD CONSTRAINT worksheet_resource_assets_asset_id_fkey FOREIGN KEY (asset_id) REFERENCES public.assets(id) ON UPDATE RESTRICT ON DELETE RESTRICT;
--
-- Name: worksheet_resource_assets worksheet_resource_assets_resource_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.worksheet_resource_assets
ADD CONSTRAINT worksheet_resource_assets_resource_id_fkey FOREIGN KEY (worksheet_resource_id) REFERENCES public.worksheet_resources(id) ON UPDATE RESTRICT ON DELETE RESTRICT;
--
-- Name: worksheet_resources worksheet_resources_preview_asset_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.worksheet_resources
ADD CONSTRAINT worksheet_resources_preview_asset_id_fkey FOREIGN KEY (preview_asset_id) REFERENCES public.assets(id) ON UPDATE RESTRICT ON DELETE RESTRICT;
--
-- Name: worksheet_resources worksheet_resources_worksheet_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.worksheet_resources
ADD CONSTRAINT worksheet_resources_worksheet_id_fkey FOREIGN KEY (worksheet_id) REFERENCES public.worksheets(id) ON UPDATE RESTRICT ON DELETE RESTRICT;
--
-- Name: worksheets worksheets_category_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.worksheets
ADD CONSTRAINT worksheets_category_id_fkey FOREIGN KEY (category_id) REFERENCES public.categories(id) ON UPDATE RESTRICT ON DELETE RESTRICT;
--
-- Name: worksheets worksheets_preview_asset_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.worksheets
ADD CONSTRAINT worksheets_preview_asset_id_fkey FOREIGN KEY (preview_asset_id) REFERENCES public.assets(id) ON UPDATE RESTRICT ON DELETE RESTRICT;
--
-- PostgreSQL database dump complete
--
-- 提交前检查迁移历史和默认配置;任何错误与建表操作在同一事务内回滚。
DO $doodle_schema_verify$
BEGIN
IF (SELECT count(*) FROM public._prisma_migrations WHERE finished_at IS NOT NULL AND rolled_back_at IS NULL) <> 3
OR EXISTS (
SELECT 1 FROM (VALUES ('0_v35_baseline','fcf767720f78a156fff6a04a52c4a78ba85b7a6682ba5714e05f133b943da03e'),
('20261016000000_category_publication','efb27c3d6ffc8b65c91c358c95549bb5bc74e035478dfa59da372c1771d74658'),
('20261019000000_member_assets','22d2859a798a3b4502f27da521d7b4d9dd5438c5bf4fc18e5d52011201605158')) AS expected(name, checksum)
WHERE NOT EXISTS (SELECT 1 FROM public._prisma_migrations m
WHERE m.migration_name = expected.name AND m.checksum = expected.checksum
AND m.finished_at IS NOT NULL AND m.rolled_back_at IS NULL)
) THEN
RAISE EXCEPTION 'Prisma 迁移历史不完整或校验和不匹配,回滚';
END IF;
IF NOT EXISTS (SELECT 1 FROM public.page_configs WHERE id = 'current')
OR NOT EXISTS (SELECT 1 FROM public.settings WHERE id = 'homeAutoRefresh') THEN
RAISE EXCEPTION '必要默认配置缺失,回滚';
END IF;
END
$doodle_schema_verify$;
COMMIT;