Files
inkreach-official-website/docs/dev/database-table-design.md
T
yeuimu 6c61a4e871 feat(deploy): production deployment setup and fixes
- Debian-based api image (bookworm-slim), docker/debian mirrors, prisma
  binaryTargets for openssl 3.0
- nginx: admin SPA under /admin, TLS via acme.sh (ZeroSSL) + auto-renewal
  cron, http->https redirect
- prisma: add origin_goods.delisted migration, sync missing schema
  (good_image/tag_font_color/good_tags), fix users.createdAt Timestamptz
- api: CORS wildcard reflection, helmet CORP cross-origin, price
  backfill in persistProductDetail, categoryIcon ancestor fallback,
  mediaByColor per-color gallery in public goods detail
- admin: /admin base path (vite + router)
- import-data.mjs: udt_name casting, serial sequence advance fix
2026-08-26 14:23:09 +08:00

173 lines
8.0 KiB
Markdown
Raw 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.
-- 1. 原商品表(外部来源商品)
CREATE TABLE origin_goods (
origin_good_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
sds_good_id TEXT NOT NULL, -- SDS商品ID,假设为外部系统标识
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
COMMENT ON TABLE origin_goods IS '原商品表,记录外部来源商品';
COMMENT ON COLUMN origin_goods.origin_good_id IS '原商品ID(主键)';
COMMENT ON COLUMN origin_goods.sds_good_id IS 'SDS商品ID';
-- 2. 国家表
CREATE TABLE countries (
country_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
country_name TEXT NOT NULL UNIQUE, -- 国家名称唯一
country_icon TEXT, -- 图标URL或路径
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
COMMENT ON TABLE countries IS '国家表';
COMMENT ON COLUMN countries.country_id IS '国家ID(主键)';
COMMENT ON COLUMN countries.country_name IS '国家名称';
COMMENT ON COLUMN countries.country_icon IS '国家图标';
-- 3. 品类表(支持层级)
CREATE TABLE categories (
category_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
parent_category_id BIGINT REFERENCES categories(category_id) ON DELETE RESTRICT,
category_name TEXT NOT NULL,
category_icon TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
COMMENT ON TABLE categories IS '品类表,支持自关联层级';
COMMENT ON COLUMN categories.category_id IS '品类ID(主键)';
COMMENT ON COLUMN categories.parent_category_id IS '父品类IDNULL表示顶级品类';
COMMENT ON COLUMN categories.category_name IS '品类名称';
COMMENT ON COLUMN categories.category_icon IS '品类图标';
-- 索引:外键列
CREATE INDEX idx_categories_parent_id ON categories(parent_category_id);
-- 4. 标签表
CREATE TABLE tags (
tag_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
tag_name TEXT NOT NULL UNIQUE,
tag_color TEXT, -- 十六进制颜色码,如 '#FF0000'
timing TEXT, -- 时机(如促销时段)
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
COMMENT ON TABLE tags IS '标签表';
COMMENT ON COLUMN tags.tag_id IS '标签ID(主键)';
COMMENT ON COLUMN tags.tag_name IS '标签名';
COMMENT ON COLUMN tags.tag_color IS '标签颜色(前端展示用)';
COMMENT ON COLUMN tags.timing IS '时机(例如节日促销、季节限定)';
-- 5. 位置表(展示位置定义)
-- 原设计中的 Indexes 表,为避免与数据库索引关键字混淆,重命名为 positions
CREATE TABLE positions (
position_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
index_val INTEGER NOT NULL, -- 位置排序值或权重
country_id BIGINT REFERENCES countries(country_id) ON DELETE CASCADE,
category_id BIGINT REFERENCES categories(category_id) ON DELETE CASCADE,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
COMMENT ON TABLE positions IS '展示位置表,定义商品在特定国家/品类下的展示排序';
COMMENT ON COLUMN positions.position_id IS '位置ID(主键)';
COMMENT ON COLUMN positions.index_val IS '位置值(如排序序号、优先级权重)';
COMMENT ON COLUMN positions.country_id IS '关联的国家IDNULL表示不限国家';
COMMENT ON COLUMN positions.category_id IS '关联的品类IDNULL表示不限品类';
-- 索引:外键列
CREATE INDEX idx_positions_country_id ON positions(country_id);
CREATE INDEX idx_positions_category_id ON positions(category_id);
-- 复合索引用于快速查询某个国家+品类下的位置列表
CREATE INDEX idx_positions_country_category ON positions(country_id, category_id);
-- 6. 商品表(核心表)
CREATE TABLE goods (
good_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
origin_good_id BIGINT REFERENCES origin_goods(origin_good_id) ON DELETE RESTRICT,
country_id BIGINT NOT NULL REFERENCES countries(country_id) ON DELETE RESTRICT,
category_id BIGINT NOT NULL REFERENCES categories(category_id) ON DELETE RESTRICT,
tag_id BIGINT REFERENCES tags(tag_id) ON DELETE SET NULL,
position_id BIGINT REFERENCES positions(position_id) ON DELETE SET NULL,
good_name TEXT NOT NULL,
good_priority INTEGER NOT NULL DEFAULT 0 CHECK (good_priority >= 0), -- 优先级,数值越高越靠前
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
COMMENT ON TABLE goods IS '商品主表';
COMMENT ON COLUMN goods.good_id IS '商品ID(主键)';
COMMENT ON COLUMN goods.origin_good_id IS '原商品ID(关联外部来源)';
COMMENT ON COLUMN goods.country_id IS '国家ID(必填)';
COMMENT ON COLUMN goods.category_id IS '品类ID(必填)';
COMMENT ON COLUMN goods.tag_id IS '标签ID(可为空)';
COMMENT ON COLUMN goods.position_id IS '展示位置ID(可为空)';
COMMENT ON COLUMN goods.good_name IS '商品名称';
COMMENT ON COLUMN goods.good_priority IS '商品优先级(全局排序,越大越靠前)';
-- 外键索引(必须手动创建)
CREATE INDEX idx_goods_origin_good_id ON goods(origin_good_id);
CREATE INDEX idx_goods_country_id ON goods(country_id);
CREATE INDEX idx_goods_category_id ON goods(category_id);
CREATE INDEX idx_goods_tag_id ON goods(tag_id);
CREATE INDEX idx_goods_position_id ON goods(position_id);
-- 常用查询索引
CREATE INDEX idx_goods_priority ON goods(good_priority DESC); -- 按优先级排序
CREATE INDEX idx_goods_country_priority ON goods(country_id, good_priority DESC); -- 按国家+优先级
CREATE INDEX idx_goods_category_country ON goods(category_id, country_id); -- 品类+国家过滤
-- 可选:部分索引,仅索引活跃商品(如果有软删除或状态字段)
-- 当前设计无状态字段,暂不添加
-- 7. (可选)商品与标签的多对多关联表
-- 原设计中 goods 表仅有单一 tag_id,限制了多标签场景。
-- 若业务需要多标签,建议增加关联表,并移除 goods.tag_id 字段。
-- 以下为扩展设计(可根据实际需求决定是否启用):
/*
CREATE TABLE goods_tags (
goods_id BIGINT NOT NULL REFERENCES goods(good_id) ON DELETE CASCADE,
tag_id BIGINT NOT NULL REFERENCES tags(tag_id) ON DELETE CASCADE,
PRIMARY KEY (goods_id, tag_id)
);
CREATE INDEX idx_goods_tags_tag_id ON goods_tags(tag_id);
*/
-- 注意:若使用 goods_tags 关联表,则应删除 goods 表中的 tag_id 列。
-- 保留原单标签设计还是采用多标签,请根据业务需求选择。
-- 8. 自动更新 updated_at 的触发器函数(可选)
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = now();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- 为每个表应用自动更新 updated_at 的触发器
CREATE TRIGGER trigger_origin_goods_updated_at
BEFORE UPDATE ON origin_goods
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER trigger_countries_updated_at
BEFORE UPDATE ON countries
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER trigger_categories_updated_at
BEFORE UPDATE ON categories
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER trigger_tags_updated_at
BEFORE UPDATE ON tags
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER trigger_positions_updated_at
BEFORE UPDATE ON positions
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER trigger_goods_updated_at
BEFORE UPDATE ON goods
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();