8.0 KiB
8.0 KiB
项目开发规范(AI必读)
数据库
1. 表命名
格式:b_{模块}_{实体}
所有业务表以 b_ 前缀开头,使用 snake_case。例如:b_clothing_clothes、b_meal_dish、b_chat_file。
2. 关联表命名
M:N 关联表直接用「主实体 + 子实体」拼接:
格式:b_{模块}_{主实体}_{子实体}
例如:b_clothing_outfit_clothes、b_meal_dish_ingredient。
禁止:多态关联(target_type + target_id),应拆分为独立表。
3. 标签表
标签表统一用 _tag 后缀:
| 表名 | 用途 |
|---|---|
b_clothing_tag |
衣物标签(父子结构) |
b_meal_tag |
餐食标签(父子结构) |
b_clothing_clothes_tag |
衣服 ↔ 标签关联 |
b_meal_dish_tag |
菜品 ↔ 标签关联 |
- 父子结构:
parent_id BIGINT,NULL表示顶层,不要用0 - 颜色字段:
color varchar(7),存储 hex 色值如#EF4444
4. 字段命名
审计字段(所有业务表必须包含):
id BIGINT PRIMARY KEY, -- 雪花 ID
create_time TIMESTAMPTZ DEFAULT now(),
update_time TIMESTAMPTZ DEFAULT now(),
create_by BIGINT,
update_by BIGINT
审计字段由
pkg/db/meta_field.go自动注入,仅有b_user和b_user_oauth豁免。
通用业务字段:
family_id BIGINT NOT NULL, -- 家庭 ID(多租户隔离)
status SMALLINT NOT NULL DEFAULT 1, -- 0=停用, 1=启用
sort_number INT NOT NULL DEFAULT 0, -- 排序序号
命名约定:
- 全部
snake_case - 外键:
{实体}_id,如family_id、category_id、dish_id - 图片:
image_file_key或{用途}_file_key,如cover_file_key - 数值金额:
amount numeric(12,2) - 金额:
amount numeric(12,2)
4. 索引命名
格式:idx_{表名}_{用途}
- 主键约束:
{表名}_pkey - 唯一约束:
{表名}_{字段}_key
-- 按业务查询
idx_b_clothing_clothes_family_status_category
-- 关联表双向索引
idx_b_meal_dish_tag_dish -- 按主实体查
idx_b_meal_dish_tag_tag -- 按子实体反查
-- 唯一约束
idx_b_meal_plan_family_date_slot
6. 不允许的坏味道
- ❌ 时间戳用
timestamp without time zone→ 必须用TIMESTAMPTZ - ❌
parent_id用0表示顶层 → 必须用NULL - ❌
create_by/update_by设NOT NULL→ 可为空,由应用层注入 - ❌ 表名/索引名中包含过时模块名(如
b_space残留) - ❌ 一张表用多态字段关联多种实体
前端
1. 项目结构
app-rn/src/
app/ Expo Router 页面(文件即路由)
components/ 可复用组件
configs/ 配置定义
helpers/ 业务辅助函数
hooks/ 自定义 Hooks
layouts/ 布局组件
request/ API 封装
store/ Zustand 状态
types/ TypeScript 类型
utils/ 通用工具
2. 命名规范
| 成员 | 规范 | 示例 |
|---|---|---|
| 组件 | PascalCase |
PageLayout、Home |
| 普通函数 | camelCase |
formatMoney |
| Hooks | use 开头 |
useLoading、useFamilyStore |
| API 函数 | Api 结尾 |
loadDataApi、saveDataApi |
| 类型/接口 | PascalCase |
ClothingTag、FilterState |
| 文件名 | camelCase.ts(x) |
useLoading.ts、finance.tsx |
- 类型定义优先用
interface而非type - 领域类型按文件拆分:
auth.ts、finance.ts、clothing.ts
3. 数据访问
所有数据操作通过 src/request/api.ts 的 5 个封装函数:
loadDataApi({ view_name, search_condition, args, ... })
loadDataPageApi({ view_name, page, page_size, ... })
loadDataBySqlApi({ sql, args })
saveDataApi([{ table_name, key_field, inserts, updates, deletes }])
getUniqueIdApi(count)
- 必须传递
family_id:useFamilyStore((s) => s.getFamilyId()) - 响应通过
res.isSuccess判断结果
4. 操作记录
所有增/改/删操作完成后必须通过 useModuleChatNotifier 记录操作:
import { useModuleChatNotifier } from "@/hooks/useModuleChatNotifier";
const notifyOp = useModuleChatNotifier();
notifyOp({
module: "餐食", // 模块名
action: "创建菜单", // 操作描述
target: planDate, // 操作目标
sourceTable: "b_meal_plan",
sourceId: targetId,
});
5. 状态管理
- 全局持久化(用户/家庭):Zustand +
persist中间件 +AsyncStorage - 模块内部:Zustand 内存 store,不持久化
- Store 接口同时包含状态和方法
6. 样式与组件
- 样式用 NativeWind
className,禁止内联style={} - 尽量使用主题色:颜色统一用
useThemeColor()获取,不硬编码色值 - 图标用
lucide-react-native,颜色通过useThemeColor("accent")获取(className="text-accent"对图标不生效) - UI 组件优先用 HeroUI Native(
heroui-native) - 页面用
PageLayout/ModuleLayout/AppLayout包裹 - 页面布局尽量使用
LayoutView+LayoutView.ScrollView - 页面搜索/筛选参考:
app-rn/src/app/finance/(tabs)/home/index.tsx - 嵌套 BottomSheet 筛选参考:
app-rn/src/app/clothes/outfit/edit/index.tsx
7. BottomSheet 规范
- Title 必须居中:
<Text className="text-center text-lg font-semibold"> - 必须限制最大高度:内容区设置
maxHeight,防止弹出层过高 - 搜索/筛选过多时加独立筛选 BottomSheet:如果选择器内筛选条件过多(如选择衣服时按分类、标签、归属者筛选),筛选按钮触发第二个 BottomSheet,避免第一个 BottomSheet 内容过载
8. 异步操作
所有保存/更新/删除操作必须使用 useLoading + <LoadingOverlay>:
const { isLoading, startLoading, stopLoading } = useLoading();
startLoading("保存中...");
const res = await saveDataApi([...]);
if (res.isSuccess) {
stopLoading({ type: "success", message: "已保存" });
} else {
stopLoading({ type: "error", message: "操作失败" });
}
禁止手动管理多个 loading 布尔值。
后端
1. 项目结构
app-go/
internal/
config/ 配置加载
handle/ HTTP handler
httpx/ 请求/响应工具
middleware/ Fiber 中间件
router/ 路由注册
types/ DTO
ws/ WebSocket
pkg/
db/ PostgreSQL 客户端
jwtx/ JWT
logger/ 日志
s3store/ S3 存储
uniqueid/ 雪花 ID 生成
2. 命名规范
| 成员 | 规范 | 示例 |
|---|---|---|
| 导出函数/类型 | PascalCase |
LoadData、LoginQqReq |
| 非导出函数 | camelCase |
handleThirdLogin |
| 包名 | 单个小写单词 | package handle |
| 文件名 | snake_case.go |
meta_field.go |
| JSON 标签 | snake_case |
json:"family_id" |
3. API 设计
不允许创建专用 REST 端点。 所有数据操作复用 5 个通用 API:
| 端点 | 用途 |
|---|---|
POST /app/data/loadData |
条件查询 |
POST /app/data/loadDataPage |
分页查询 |
POST /app/data/loadDataBySql |
原生 SQL |
POST /app/data/saveData |
批量增/改/删 |
POST /app/data/getUniqueId |
获取雪花 ID |
非必要不新增接口。 新增任何接口前必须先询问并获得确认,且新增接口必须是通用型的,不能为某个业务功能单独定制。
4. 数据访问
- 所有业务数据关联
family_id,查询时必须按当前用户的family_id过滤 - 审计字段(
create_time、update_time、create_by、update_by)由pkg/db/meta_field.go自动注入,仅b_user和b_user_oauth豁免 - 事务使用闭包模式:
dbClient.WithTx(ctx, func(tx *db.Client) error { ... }) - 外部调用错误用
errors.WithStack(err)包装,业务错误用httpx.Fail(c, "消息")返回
5. 导入顺序
内部包(allapp-go/)在前,第三方包在后,两组之间空一行:
import (
"allapp-go/internal/httpx"
"allapp-go/internal/types"
"github.com/gofiber/fiber/v3"
)