-- 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;