chore: 初始化仓库

中华文明全图鉴——文物全图系统(PC Web 地图 + NestJS API + 管理后台)。
含三大 IP(文物南迁北归 / 国宝海外回归 / 博物馆手艺人)、AI 文物对话、
文物地图与详情、以及 demo-video-kit 演示视频生成工具。
This commit is contained in:
selfrelease
2026-06-13 20:55:44 +08:00
commit 2d847e154f
161 changed files with 22629 additions and 0 deletions
+458
View File
@@ -0,0 +1,458 @@
# 中华文明全图鉴——数据模型文档
## 1. 数据模型目标
本数据模型服务于第一阶段 PC Web 地图站 MVP,覆盖文物、机构、位置、标签、数字资产、权限、操作日志和地图查询所需的核心数据结构。
## 2. 设计原则
- **PostgreSQL + PostGIS**:结构化业务数据与地理数据统一存储。
- **多位置记录**:一件文物可有多条位置记录,前台默认展示最新有效位置。
- **敏感坐标分级**:同一位置可保存精确坐标和公开展示坐标或模糊区域。
- **标签可扩展**:基础标签固定,扩展标签通过标签分类和标签类型支持动态扩展。
- **操作可追溯**:核心对象修改必须记录操作日志。
- **字段可演进**:对角色卡、故事、AI 推荐等中后期能力保留扩展空间。
## 3. 枚举定义
## 3.1 artifact_category
| 值 | 含义 |
|---|---|
| bronze | 青铜 |
| painting_calligraphy | 书画 |
| porcelain | 陶瓷 |
| jade | 玉器 |
| gold_silver | 金银器 |
| lacquer | 漆器 |
| textile | 织绣 |
| stone_carving | 石刻 |
| wood_carving | 木雕 |
| dunhuang | 敦煌 |
| ancient_book | 古籍 |
| other | 其他 |
## 3.2 artifact_level
| 值 | 含义 |
|---|---|
| level_1 | 一级 |
| level_2 | 二级 |
| level_3 | 三级 |
| general | 一般 |
| unknown | 未定级 |
## 3.3 artifact_status
| 值 | 含义 |
|---|---|
| at_home | 在家 |
| away | 离家 |
| in_transit | 在途 |
| unknown | 未知 |
## 3.4 location_type
| 值 | 含义 |
|---|---|
| domestic | 国内 |
| overseas | 海外 |
| unknown | 未知 |
| in_transit | 在途 |
## 3.5 location_precision
| 值 | 含义 |
|---|---|
| exact_room | 展厅 |
| exact_building | 建筑 |
| city | 城市 |
| country | 国家 |
| region | 区域 |
## 3.6 display_status
| 值 | 含义 |
|---|---|
| on_display | 在展 |
| in_storage | 库藏 |
| loaned | 外借 |
| repairing | 修复中 |
| touring | 巡展中 |
| unknown | 未知 |
## 3.7 source_type
| 值 | 含义 |
|---|---|
| institution_feed | 机构直供 |
| manual_entry | 后台录入 |
| user_report | 用户报告 |
| expert_verify | 专家验证 |
| public_source | 公开资料 |
## 3.8 publish_status
| 值 | 含义 |
|---|---|
| draft | 草稿 |
| pending | 待发布 |
| published | 已发布 |
| archived | 已归档 |
| rejected | 已驳回 |
## 3.9 tag_value_type
| 值 | 含义 |
|---|---|
| single | 单选 |
| multiple | 多选 |
| boolean | 布尔 |
| text | 文本 |
| number | 数字 |
## 4. 核心表设计
## 4.1 users
后台账号和前台用户统一存储,MVP 优先支持后台账号。
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | uuid | pk | 用户 ID |
| username | varchar(100) | unique | 登录名 |
| phone | varchar(30) | nullable | 手机号 |
| email | varchar(255) | nullable | 邮箱 |
| password_hash | varchar(255) | nullable | 密码 hash |
| nickname | varchar(100) | nullable | 昵称 |
| avatar_url | text | nullable | 头像 |
| user_type | varchar(30) | not null | admin、institution、public、expert、editor |
| institution_id | uuid | fk nullable | 绑定机构 |
| is_active | boolean | default true | 是否启用 |
| created_at | timestamptz | not null | 创建时间 |
| updated_at | timestamptz | not null | 更新时间 |
## 4.2 roles
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | uuid | pk | 角色 ID |
| code | varchar(50) | unique | 角色编码 |
| name | varchar(100) | not null | 角色名称 |
| description | text | nullable | 描述 |
| created_at | timestamptz | not null | 创建时间 |
## 4.3 permissions
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | uuid | pk | 权限 ID |
| code | varchar(100) | unique | 权限编码 |
| name | varchar(100) | not null | 权限名称 |
| module | varchar(50) | not null | 模块 |
| created_at | timestamptz | not null | 创建时间 |
## 4.4 user_roles
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| user_id | uuid | pk fk | 用户 ID |
| role_id | uuid | pk fk | 角色 ID |
| created_at | timestamptz | not null | 创建时间 |
## 4.5 institutions
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | uuid | pk | 机构 ID |
| name | varchar(255) | not null | 机构名称 |
| short_name | varchar(100) | nullable | 简称 |
| code | varchar(100) | unique nullable | 机构编码 |
| institution_type | varchar(50) | not null | museum、research、private、other |
| country | varchar(100) | not null | 国家 |
| province | varchar(100) | nullable | 省份 |
| city | varchar(100) | nullable | 城市 |
| address | text | nullable | 地址 |
| location | geography(Point, 4326) | nullable | 机构坐标 |
| official_website | text | nullable | 官网 |
| description | text | nullable | 简介 |
| is_verified | boolean | default false | 是否认证 |
| publish_status | publish_status | not null | 发布状态 |
| created_at | timestamptz | not null | 创建时间 |
| updated_at | timestamptz | not null | 更新时间 |
索引:
- `idx_institutions_location_gist``GIST(location)`
- `idx_institutions_name``name`
- `idx_institutions_country_city``country, city`
## 4.6 artifacts
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | uuid | pk | 文物 ID |
| unified_map_id | varchar(50) | unique | 全图唯一编码 |
| name | varchar(255) | not null | 文物名称 |
| alternative_names | text[] | nullable | 别名 |
| category | artifact_category | not null | 门类 |
| dynasty | varchar(100) | nullable | 年代 |
| level | artifact_level | default unknown | 文物级别 |
| material | varchar(255) | nullable | 材质 |
| dimensions | varchar(255) | nullable | 尺寸 |
| current_status | artifact_status | default unknown | 在家、离家、在途、未知 |
| home_institution_id | uuid | fk nullable | 原属或现属国内机构 |
| summary | text | nullable | 简介 |
| story_hook | varchar(255) | nullable | 一句话故事钩子 |
| persona_quote | varchar(255) | nullable | 趣味化角色短句 |
| publish_status | publish_status | not null | 发布状态 |
| created_by | uuid | fk nullable | 创建人 |
| updated_by | uuid | fk nullable | 更新人 |
| created_at | timestamptz | not null | 创建时间 |
| updated_at | timestamptz | not null | 更新时间 |
索引:
- `idx_artifacts_name``name`
- `idx_artifacts_category``category`
- `idx_artifacts_dynasty``dynasty`
- `idx_artifacts_status``current_status`
- `idx_artifacts_home_institution``home_institution_id`
## 4.7 artifact_locations
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | uuid | pk | 位置记录 ID |
| artifact_id | uuid | fk not null | 文物 ID |
| location_type | location_type | not null | 国内、海外、未知、在途 |
| institution_id | uuid | fk nullable | 关联机构 |
| precise_location | geography(Point, 4326) | nullable | 精确坐标 |
| public_location | geography(Point, 4326) | nullable | 前台可展示坐标 |
| fuzzy_area | geography(Polygon, 4326) | nullable | 模糊区域 |
| precision | location_precision | not null | 坐标精度 |
| floor_plan_ref | varchar(255) | nullable | 展厅平面图编号 |
| room_name | varchar(255) | nullable | 展厅名称 |
| cabinet_no | varchar(100) | nullable | 展柜编号 |
| display_status | display_status | default unknown | 展出状态 |
| source_type | source_type | not null | 来源类型 |
| source_description | text | nullable | 来源说明 |
| discoverer_user_id | uuid | fk nullable | 发现者 |
| is_current | boolean | default false | 是否当前有效位置 |
| verified_at | timestamptz | nullable | 审核通过时间 |
| valid_from | timestamptz | nullable | 有效开始 |
| valid_until | timestamptz | nullable | 有效截止 |
| created_by | uuid | fk nullable | 创建人 |
| created_at | timestamptz | not null | 创建时间 |
| updated_at | timestamptz | not null | 更新时间 |
索引:
- `idx_artifact_locations_artifact_id``artifact_id`
- `idx_artifact_locations_institution_id``institution_id`
- `idx_artifact_locations_public_location_gist``GIST(public_location)`
- `idx_artifact_locations_precise_location_gist``GIST(precise_location)`
- `idx_artifact_locations_fuzzy_area_gist``GIST(fuzzy_area)`
- `idx_artifact_locations_current``artifact_id, is_current`
当前位置规则:
1. 优先取 `is_current = true` 的位置记录。
2. 若存在多条,则取 `verified_at` 最新的一条。
3.`valid_until` 已过期,则不作为前台当前位置展示。
4. 无权限用户只能读取 `public_location``fuzzy_area`
## 4.8 tag_categories
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | uuid | pk | 标签分类 ID |
| code | varchar(100) | unique | 分类编码 |
| name | varchar(100) | not null | 分类名称 |
| description | text | nullable | 描述 |
| sort_order | int | default 0 | 排序 |
| is_system | boolean | default false | 是否系统内置 |
| created_at | timestamptz | not null | 创建时间 |
## 4.9 tags
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | uuid | pk | 标签 ID |
| category_id | uuid | fk not null | 分类 ID |
| code | varchar(100) | unique | 标签编码 |
| name | varchar(100) | not null | 展示名 |
| value_type | tag_value_type | not null | 值类型 |
| description | text | nullable | 描述 |
| color | varchar(20) | nullable | 展示颜色 |
| icon | varchar(100) | nullable | 图标 |
| is_system | boolean | default false | 是否系统标签 |
| is_active | boolean | default true | 是否启用 |
| sort_order | int | default 0 | 排序 |
| created_at | timestamptz | not null | 创建时间 |
| updated_at | timestamptz | not null | 更新时间 |
## 4.10 artifact_tags
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | uuid | pk | 关系 ID |
| artifact_id | uuid | fk not null | 文物 ID |
| tag_id | uuid | fk not null | 标签 ID |
| value_text | text | nullable | 文本值 |
| value_number | numeric | nullable | 数字值 |
| confidence | numeric(5,2) | nullable | 置信度 |
| source_type | source_type | not null | 来源 |
| review_status | varchar(30) | default approved | pending、approved、rejected |
| created_by | uuid | fk nullable | 创建人 |
| created_at | timestamptz | not null | 创建时间 |
唯一约束:
- `artifact_id, tag_id, value_text`
## 4.11 digital_assets
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | uuid | pk | 资产 ID |
| artifact_id | uuid | fk nullable | 文物 ID |
| institution_id | uuid | fk nullable | 机构 ID |
| asset_type | varchar(50) | not null | image、audio、video、model_3d、document |
| title | varchar(255) | nullable | 标题 |
| url | text | not null | 资源地址 |
| thumbnail_url | text | nullable | 缩略图 |
| mime_type | varchar(100) | nullable | MIME 类型 |
| size_bytes | bigint | nullable | 文件大小 |
| copyright_owner | varchar(255) | nullable | 版权方 |
| license_scope | text | nullable | 授权范围 |
| sort_order | int | default 0 | 排序 |
| created_by | uuid | fk nullable | 上传人 |
| created_at | timestamptz | not null | 创建时间 |
## 4.12 operation_logs
| 字段 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | uuid | pk | 日志 ID |
| operator_id | uuid | fk nullable | 操作人 |
| operator_role | varchar(50) | nullable | 操作角色 |
| action | varchar(100) | not null | 操作类型 |
| target_type | varchar(100) | not null | 目标类型 |
| target_id | uuid | nullable | 目标 ID |
| before_data | jsonb | nullable | 变更前 |
| after_data | jsonb | nullable | 变更后 |
| ip_address | varchar(50) | nullable | IP |
| user_agent | text | nullable | UA |
| created_at | timestamptz | not null | 创建时间 |
索引:
- `idx_operation_logs_operator_id`
- `idx_operation_logs_target`
- `idx_operation_logs_created_at`
## 5. 地图接口视图建议
## 5.1 artifact_current_locations_view
用途:地图点位与文物详情快速读取。
字段:
- artifact_id
- artifact_name
- category
- dynasty
- level
- current_status
- story_hook
- persona_quote
- institution_id
- institution_name
- public_location
- fuzzy_area
- precision
- display_status
- source_type
- verified_at
## 5.2 map_summary_view
用途:顶部统计栏。
字段:
- total_artifacts
- domestic_count
- overseas_count
- on_display_count
- in_storage_count
- loaned_count
- unknown_location_count
## 6. Seed 数据建议
## 6.1 系统角色
- admin
- institution_user
- editor
- expert
- public_user
## 6.2 标签分类
- basic_attribute
- circulation_experience
- emotional_attribute
- content_derivation
## 6.3 基础标签
- 门类
- 年代
- 级别
- 材质
- 功能
- 流失状态
- 回归状态
- 南迁北归
- 修复经历
- 数字化经历
- 情绪主调
- 适合年龄
## 7. 数据校验规则
## 7.1 文物校验
- `name` 必填。
- `category` 必须在枚举范围内。
- `unified_map_id` 必须唯一。
- `current_status` 必须在枚举范围内。
- 发布时至少需要一条当前有效位置或明确标记为未知位置。
## 7.2 位置校验
- `location_type = domestic` 时优先要求 `institution_id`
- `precision = exact_room` 时需要 `room_name``floor_plan_ref`
- 公开坐标必须符合经纬度范围。
- 存在敏感位置时,前台不得返回 `precise_location`
- `valid_until` 小于当前时间时不作为当前有效位置。
## 7.3 标签校验
- 系统标签不可随意删除。
- 禁用标签不允许新增绑定。
- AI 推荐标签必须人工确认后才能公开展示。
## 8. 测试要点
- migration 可从空库完整执行。
- PostGIS 扩展可启用。
- 空间索引创建成功。
- 1000 件文物点位范围查询响应时间符合要求。
- 敏感坐标在游客权限下不可见。
- 机构用户无法访问其他机构文物。
- 文物标签绑定、解绑和筛选结果正确。