This commit is contained in:
2025-12-15 17:55:32 +08:00
commit 28ab17324d
170 changed files with 18373 additions and 0 deletions

151
specs/DB.sql Normal file
View File

@@ -0,0 +1,151 @@
-- 新项目数据库 DDLPostgreSQL
-- 目标多租户tenant_id 全表隔离)+ tenant_uuid 用于 OSS Keyquyun/<tenant_uuid>/<md5>.<ext>
-- 注意tenant_uuid 由业务代码生成写入(不使用 DB 扩展默认值)
BEGIN;
-- 1) 租户
CREATE TABLE IF NOT EXISTS tenants (
id BIGSERIAL PRIMARY KEY,
tenant_code VARCHAR(64) NOT NULL,
tenant_uuid UUID NOT NULL,
name VARCHAR(128) NOT NULL DEFAULT '',
status INT2 NOT NULL DEFAULT 0,
config JSONB NOT NULL DEFAULT '{}'::jsonb,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- tenant_code不区分大小写写入/查询均 lower并限制字符集 a-z0-9_-
ALTER TABLE tenants
ADD CONSTRAINT tenants_tenant_code_format
CHECK (tenant_code ~ '^[A-Za-z0-9_-]+$');
CREATE UNIQUE INDEX IF NOT EXISTS ux_tenants_tenant_code_lower
ON tenants (lower(tenant_code));
CREATE UNIQUE INDEX IF NOT EXISTS ux_tenants_tenant_uuid
ON tenants (tenant_uuid);
-- 2) 租户后台账号
CREATE TABLE IF NOT EXISTS admin_users (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
username VARCHAR(64) NOT NULL,
password_hash TEXT NOT NULL,
role VARCHAR(32) NOT NULL DEFAULT 'admin',
status INT2 NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE UNIQUE INDEX IF NOT EXISTS ux_admin_users_tenant_username
ON admin_users (tenant_id, lower(username));
-- 3) 用户(微信 openid 用户)
CREATE TABLE IF NOT EXISTS users (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
deleted_at TIMESTAMPTZ,
status INT2 NOT NULL DEFAULT 0,
open_id VARCHAR(128) NOT NULL,
username VARCHAR(128) NOT NULL DEFAULT '',
avatar TEXT,
metas JSONB NOT NULL DEFAULT '{}'::jsonb,
auth_token JSONB NOT NULL DEFAULT '{}'::jsonb,
balance BIGINT NOT NULL DEFAULT 0
);
CREATE UNIQUE INDEX IF NOT EXISTS ux_users_tenant_openid
ON users (tenant_id, open_id);
CREATE INDEX IF NOT EXISTS ix_users_tenant_id
ON users (tenant_id, id);
-- 4) 媒体
CREATE TABLE IF NOT EXISTS medias (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
name VARCHAR(255) NOT NULL DEFAULT '',
mime_type VARCHAR(128) NOT NULL DEFAULT '',
size BIGINT NOT NULL DEFAULT 0,
path VARCHAR(512) NOT NULL DEFAULT '',
metas JSONB NOT NULL DEFAULT '{}'::jsonb,
hash VARCHAR(64) NOT NULL DEFAULT ''
);
-- 租户内按 md5 去重
CREATE UNIQUE INDEX IF NOT EXISTS ux_medias_tenant_hash
ON medias (tenant_id, hash);
CREATE INDEX IF NOT EXISTS ix_medias_tenant_id
ON medias (tenant_id, id);
-- 5) 曲谱/内容
CREATE TABLE IF NOT EXISTS posts (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
deleted_at TIMESTAMPTZ,
status INT2 NOT NULL DEFAULT 0,
title VARCHAR(128) NOT NULL,
head_images JSONB NOT NULL DEFAULT '[]'::jsonb,
description VARCHAR(256) NOT NULL DEFAULT '',
content TEXT NOT NULL DEFAULT '',
price BIGINT NOT NULL DEFAULT 0,
discount INT2 NOT NULL DEFAULT 100,
views BIGINT NOT NULL DEFAULT 0,
likes BIGINT NOT NULL DEFAULT 0,
tags JSONB NOT NULL DEFAULT '[]'::jsonb,
assets JSONB NOT NULL DEFAULT '[]'::jsonb
);
CREATE INDEX IF NOT EXISTS ix_posts_tenant_status_deleted
ON posts (tenant_id, status, deleted_at);
-- 6) 授权关系(购买/赠送)
CREATE TABLE IF NOT EXISTS user_posts (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
post_id BIGINT NOT NULL REFERENCES posts(id) ON DELETE CASCADE,
price BIGINT NOT NULL DEFAULT 0
);
CREATE UNIQUE INDEX IF NOT EXISTS ux_user_posts_tenant_user_post
ON user_posts (tenant_id, user_id, post_id);
CREATE INDEX IF NOT EXISTS ix_user_posts_tenant_user
ON user_posts (tenant_id, user_id, id);
-- 7) 订单(仅余额)
CREATE TABLE IF NOT EXISTS orders (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
order_no VARCHAR(64) NOT NULL,
price BIGINT NOT NULL DEFAULT 0,
discount INT2 NOT NULL DEFAULT 100,
currency VARCHAR(10) NOT NULL DEFAULT 'CNY',
payment_method VARCHAR(50) NOT NULL DEFAULT 'balance',
post_id BIGINT NOT NULL REFERENCES posts(id) ON DELETE CASCADE,
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
status INT2 NOT NULL DEFAULT 0,
meta JSONB NOT NULL DEFAULT '{}'::jsonb
);
CREATE UNIQUE INDEX IF NOT EXISTS ux_orders_tenant_order_no
ON orders (tenant_id, order_no);
CREATE INDEX IF NOT EXISTS ix_orders_tenant_user
ON orders (tenant_id, user_id, id);
COMMIT;