feat(skill): 产线设计师数据库设计规范 database-design
- 字段语义→类型/长度/精度映射(金额double 18/2、外键str 32、日期date等) - 系统不加外键,codes段逻辑关联 - 编码字典 appcodes/appcodes_kv 初始化数据设计 - 种子数据在应用模块自身build.sh落库(非平台代码) - 运行时环境变量 init/.模块名 文件约定
This commit is contained in:
parent
289a4a4cae
commit
0579609d19
@ -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 约束**
|
||||
- 关联方式 = 字段存目标表 id(str 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),部署时按实际环境填写
|
||||
Loading…
x
Reference in New Issue
Block a user