feat(skill): 产线设计师数据库设计规范 database-design

- 字段语义→类型/长度/精度映射(金额double 18/2、外键str 32、日期date等)
- 系统不加外键,codes段逻辑关联
- 编码字典 appcodes/appcodes_kv 初始化数据设计
- 种子数据在应用模块自身build.sh落库(非平台代码)
- 运行时环境变量 init/.模块名 文件约定
This commit is contained in:
yumoqing 2026-08-20 11:29:45 +08:00
parent 289a4a4cae
commit 0579609d19

View File

@ -0,0 +1,154 @@
---
name: database-design
description: 产线设计师数据库设计规范——字段语义到类型/长度/精度的映射规则、系统不加外键的关联方式、编码字典(appcodes/appcodes_kv)初始化数据设计、build.sh种子数据落库、运行时环境变量约定。触发设计新模块的数据表、定义表字段、准备编码字典/初始化数据。
capability: task_capability
---
# 产线设计师数据库设计规范
本 skill 是产线设计师agent.design在设计阶段产出模块数据设计时必须遵守的规范。
表定义 JSON 的四段式格式、CRUD JSON 格式沿用 `database-table-definition-spec` / `crud-definition-spec`
本 skill 聚焦:**字段怎么定类型**、**表间怎么关联**、**编码字典怎么准备和落库**、**环境变量怎么放**。
## 一、字段语义 → 类型/长度/精度 映射
| 字段语义 | type | length | dec | 备注 |
|---|---|---|---|---|
| 主键 id | str | 32 | - | 铁律 |
| 外键引用 xxx_id | str | 32 | - | 存目标表 id不建 FK 约束 |
| 名称 name/title/*_name | str | 255 | - | 短名用 64/100/128 |
| 编码/编号 code/no | str | 64 | - | 合同编号、单据号 |
| 描述/备注 description/remark | text | - | - | 短备注用 str 500 |
| 内容 content | text | - | - | 富文本/大字段 |
| 金额 amount/balance/cost/total | double | 18 | 2 | 统一 18/2 |
| 单价 price | double | 18 | 4 | 保留 4 位 |
| 折扣/比例 discount/rate/ratio | double | 5 | 4 | 0.0000~1.0000 |
| 数量 count/qty | int | - | - | 整数 |
| 状态 status | str | 16 | - | 字符串码,配编码字典 |
| 开关/标志 flg/is_ | str | 1 | - | 0/1 |
| 创建/更新时间 created_at/updated_at | timestamp | - | - | |
| 业务日期 *_date | date | - | - | 只到天,不显示时分秒 |
**规则**
- 金额/单价/折扣必须带 `length` + `dec`,缺了 DDL 会生成不带精度的类型
- 金额统一 `double` + `18/2`**用 double 不用 decimal**sqlor DDL 模板无 decimal 分支,会丢失精度)
- 业务日期用 `date`,别用 `timestamp`(否则 UI 出现时分秒控件困扰用户)
- 禁用原生类型:`varchar``bigint``boolean``int(11)` —— 一律用抽象类型str/int/double/timestamp/date/text
## 二、系统不加外键
- 表之间**不建 FOREIGN KEY 约束**
- 关联方式 = 字段存目标表 idstr 32+ `codes` 段声明逻辑关联(下拉、显示名),不产生 DDL 约束
```json
"codes": [
{"field": "orgid", "table": "organization", "valuefield": "id", "textfield": "orgname"}
]
```
## 三、编码字典设计appcodes / appcodes_kv
所有枚举/下拉选项统一进 appbase 的 **appcodes + appcodes_kv 两张表**,不写死在字段 default 里。
### 1. 适用字段
状态、类型、开关、类别等取值有限且稳定的枚举字段。
### 2. 数据定义:模块 `init/data.json`
```json
{
"appcodes": [
{
"parentid": "order_status",
"parentname": "订单状态",
"items": [
{"k": "pending", "v": "待处理"},
{"k": "paid", "v": "已支付"},
{"k": "shipped", "v": "已发货"},
{"k": "closed", "v": "已关闭"}
]
}
]
}
```
- `parentid` 下划线小写、见名知义(<31 字符
- `k` 是存储值(写入业务表 status 字段),`v` 是显示文本
### 3. 表里引用models codes 段cond 必须 parentid=
```json
"codes": [
{"field": "status", "table": "appcodes_kv", "valuefield": "k", "textfield": "v", "cond": "parentid='order_status'"}
]
```
**cond 必须用 `parentid=`,绝不能用 `id=`**(用 id 会查空)。
### 4. 两张表结构(复用 appbase不自建
- `appcodes`父表id字典组名、name显示名、hierarchy_flg'0'平铺/'1'层级)
- `appcodes_kv`子表id、parentid=字典组名、k存储值、v显示文本
### 5. 数据落库:应用模块自身 build.sh 的「种子数据」步骤
在**应用模块自己的 build.sh**(不是产线平台代码)里加种子数据步骤,内联 Python 幂等导入:
```bash
# 应用模块 build.sh 的种子数据步骤
"${PYTHON}" - "${CDIR}" <<'PYEOF'
import sys, os, json, asyncio
CDIR = sys.argv[1]
sys.path[:0] = [os.path.join(CDIR, 'py3', 'lib', 'python3.10', 'site-packages')]
from appPublic.jsonConfig import getConfig
from sqlor.dbpools import DBPools
from appPublic.uniqueID import getID
data = json.load(open(os.path.join(CDIR, 'pkgs', '<模块名>', 'init', 'data.json')))
async def seed():
config = getConfig(CDIR)
db = DBPools(config.databases)
async with db.sqlorContext('<应用库名>') as sor:
for ac in data.get('appcodes', []):
pid = ac['parentid']
rows = await sor.R('appcodes', {'id': pid})
if not rows:
await sor.C('appcodes', {'id': pid, 'name': ac.get('parentname', pid), 'hierarchy_flg': '0'})
for item in ac.get('items', []):
chk = await sor.sqlExe(
"SELECT id FROM appcodes_kv WHERE parentid=${p}$ AND k=${k}$",
{'p': pid, 'k': item['k']})
if not chk:
await sor.C('appcodes_kv', {'id': getID(), 'parentid': pid, 'k': item['k'], 'v': item['v']})
print(f"seeded {len(data.get('appcodes', []))} code groups")
asyncio.run(seed())
PYEOF
```
**要点**
- 种子数据步骤在**应用模块自身 build.sh**(不是平台代码),一键部署时自动落库
- 幂等靠 `(parentid, k)` 判重,重复执行不报错、不重复插入
- 数据源是模块 `init/data.json`,改字典只改 data.json不碰 build.sh
## 四、其他初始化数据(同样写法)
模块若有其他数据需要初始化(组织、角色、默认配置等),**同样写在 `init/data.json`**,在 build.sh 的种子数据步骤里一起幂等导入,不另起一套机制。`init/data.json` 是模块初始化数据的唯一入口。
## 五、运行时环境变量
模块运行时需要的环境变量(密钥、端点等),放在模块 `init` 目录,文件命名 `.模块名`(如 `.smssend`
```
init/
├── data.json # 数据库初始化数据appcodes 等)
└── .smssend # 运行时环境变量export KEY=value
```
```bash
# init/.smssend 内容
export BAIDU_SMS_ACCESS_KEY=xxx
export BAIDU_SMS_HOST=yyy
```
- 部署时 build.sh 把 `init/.模块名` 复制到应用根目录,`start.sh``[ -f .模块名 ] && source .模块名` 加载
- 该文件含敏感信息,**不入库**.gitignore部署时按实际环境填写