20260622214432
This commit is contained in:
1 parent
b5f6fafd74
commit
e9e3371be7
19 files changed
+1068
-121
No files matched your search
@@ -0,0 +1,251 @@
|
||||
---
|
||||
name: allapp-conventions
|
||||
description: >
|
||||
Allapp 项目开发规范和数据库配置指南。该 skill 应在以下场景使用:(1) 在 Allapp 项目中新增功能、
|
||||
创建数据库表、或调用后端 API 时;(2) 需要了解项目通用 API 接口用法、数据库连接信息、
|
||||
表结构约定时;(3) 需要遵循项目的代码规范时。触发词包括:allapp、记账、app-go、app-rn、
|
||||
数据库连接、API 接口、建表、收藏功能等。
|
||||
agent_created: true
|
||||
---
|
||||
|
||||
# Allapp 项目开发规范
|
||||
|
||||
## 项目概览
|
||||
|
||||
Allapp 是一个家庭/个人空间型 mini 程序平台:
|
||||
- **后端** `app-go/`:Go + Fiber v3 + PostgreSQL (pgx) + JWT
|
||||
- **前端** `app-rn/`:React Native + Expo 55 + Expo Router + Zustand + Alova
|
||||
- **数据库** PostgreSQL,库名 `allapp`,schema `public`
|
||||
|
||||
数据库连接信息见 `references/db-config.md`。
|
||||
|
||||
## 项目结构速查
|
||||
|
||||
```
|
||||
app-go/ # Go 后端
|
||||
├── configs/ # YAML 配置(config.yaml / config.dev.yaml)
|
||||
├── internal/
|
||||
│ ├── bootstrap/ # 启动入口
|
||||
│ ├── config/ # 配置加载
|
||||
│ ├── handle/ # 请求处理(auth / data / data_save / data_list / s3)
|
||||
│ ├── httpx/ # 请求/响应工具
|
||||
│ ├── middleware/ # 中间件(auth / logger)
|
||||
│ ├── router/ # 路由注册
|
||||
│ └── types/ # 请求/响应类型
|
||||
├── pkg/
|
||||
│ ├── db/ # 数据库操作(insert / update / meta_field)
|
||||
│ └── jwtx/ # JWT 工具
|
||||
└── main.go
|
||||
|
||||
app-rn/ # React Native 前端
|
||||
├── app.json
|
||||
├── package.json # ⚠️ 写页面必须先读这个
|
||||
├── tailwind.config.ts
|
||||
├── src/
|
||||
│ ├── app/ # Expo Router 页面
|
||||
│ │ ├── _layout.tsx # 根布局
|
||||
│ │ ├── (tabs)/ # 主 Tab(home / space / tools / chat / mine)
|
||||
│ │ ├── auth/ # 登录页
|
||||
│ │ ├── tools/ # 工具广场
|
||||
│ │ └── finance/ # 记账子模块
|
||||
│ ├── components/ # 通用组件(layout/view / AZIndex 等)
|
||||
│ ├── configs/ # pages.ts(子应用列表配置)
|
||||
│ ├── layouts/ # 布局(ModuleLayout 等)
|
||||
│ ├── request/ # API 封装(index.ts / api.ts)
|
||||
│ ├── store/ # Zustand 状态管理
|
||||
│ └── types/ # TypeScript 类型定义
|
||||
```
|
||||
|
||||
## 前端关键依赖库
|
||||
|
||||
写页面/组件时必须优先使用项目已安装的库,不要引入新包:
|
||||
|
||||
| 库 | 用途 | 导入方式 |
|
||||
|----|------|----------|
|
||||
| `heroui-native` | UI 组件库(PressableFeedback、SearchField、Button 等) | `import { PressableFeedback, SearchField } from "heroui-native"` |
|
||||
| `@legendapp/list` | 高性能长列表 | `import { LegendList } from "@legendapp/list"` |
|
||||
| `lucide-react-native` | 图标库 | `import { Star, ... } from "lucide-react-native"` |
|
||||
| `zustand` | 状态管理 | `import { create } from "zustand"` |
|
||||
| `alova` + `@alova/adapter-axios` | 请求库 | `import { createAlova } from "alova"` |
|
||||
| `dayjs` | 日期处理 | `import dayjs from "dayjs"` |
|
||||
| `expo-router` | 路由 | `import { useRouter } from "expo-router"` |
|
||||
| `react-native-reanimated` | 动画 | `import Animated from "react-native-reanimated"` |
|
||||
| `react-native-gesture-handler` | 手势 | 与 reanimated 配合 |
|
||||
| `react-native-safe-area-context` | 安全区域 | `import { useSafeAreaInsets } from "react-native-safe-area-context"` |
|
||||
| `tailwindcss` + `tailwind-merge` | 样式 | className 方式,`import { twMerge } from "tailwind-merge"` |
|
||||
| `sonner-native` | Toast 提示 | `import { toast } from "sonner-native"` |
|
||||
| `@gorhom/bottom-sheet` | 底部弹出面板 | |
|
||||
| `expo-image` | 图片组件 | `import { Image } from "expo-image"` |
|
||||
|
||||
**样式约定**:项目使用 NativeWind(Tailwind CSS),className 方式写样式,比如 `className="bg-white rounded-xl shadow-lg"`。不要写内联 `style={{}}` 除非必要。
|
||||
|
||||
## 核心开发规范
|
||||
|
||||
### 规则 0:写页面前必须先读 package.json
|
||||
|
||||
**每次写新页面或新组件之前**,必须先用 Read 工具读取 `app-rn/package.json`,了解项目已有的依赖库,确保:
|
||||
- 使用项目已有的组件库和工具库,不要引入未安装的包
|
||||
- 了解可用的第三方组件(如 heroui-native、@legendapp/list 等),优先复用
|
||||
|
||||
### 规则 1:禁止新增专用 API 接口
|
||||
|
||||
项目已有 4 个通用数据 API,所有 CRUD 操作必须复用它们,**不得再创建专用 REST 端点**:
|
||||
|
||||
| 接口 | 路径 | 用途 |
|
||||
|------|------|------|
|
||||
| loadData | `POST /data/loadData` | 查询:传入 `view_name`(表/视图名)、`search_condition`(WHERE)、`order_by`、`search_columns`、`args` |
|
||||
| saveData | `POST /data/saveData` | 增删改:传入 `[{table_name, key_field, inserts, updates, deletes}]` 数组 |
|
||||
| loadDataBySql | `POST /data/loadDataBySql` | 原生 SQL:传入 `sql` 和 `args` |
|
||||
| getUniqueId | `POST /data/getUniqueId` | 获取雪花 ID:传入 `count`(1-100) |
|
||||
|
||||
**新增接口必须满足两个条件:**
|
||||
1. 先向用户确认是否允许新增接口
|
||||
2. 新接口必须是**通用接口**(类似上面四种),不能专属于某个功能
|
||||
|
||||
前端调用示例:
|
||||
```ts
|
||||
// 查询
|
||||
import { loadDataApi, saveDataApi, getUniqueIdApi } from "@/request/api";
|
||||
|
||||
const res = await loadDataApi({
|
||||
view_name: "b_user",
|
||||
search_condition: "id = ?",
|
||||
search_columns: [],
|
||||
order_by: "",
|
||||
args: [userId],
|
||||
});
|
||||
|
||||
// 插入
|
||||
const idRes = await getUniqueIdApi(1);
|
||||
await saveDataApi([{
|
||||
table_name: "b_user",
|
||||
key_field: "id",
|
||||
inserts: [{ id: idRes.data[0], nickname: "test", ... }],
|
||||
updates: [],
|
||||
deletes: [],
|
||||
}]);
|
||||
```
|
||||
|
||||
### 规则 2:数据库表必须包含审计字段
|
||||
|
||||
所有业务表的**必需列**:
|
||||
|
||||
```sql
|
||||
id BIGINT PRIMARY KEY, -- 雪花 ID
|
||||
create_time TIMESTAMPTZ NOT NULL, -- 创建时间
|
||||
update_time TIMESTAMPTZ NOT NULL, -- 更新时间
|
||||
create_by BIGINT, -- 创建者 user_id
|
||||
update_by BIGINT -- 更新者 user_id
|
||||
```
|
||||
|
||||
后端 `pkg/db/meta_field.go` 中的 `applyMetaFields` 函数会为 insert/update 自动注入这些字段。
|
||||
只有 `b_user` 和 `b_user_oauth` 两类系统表在 `auditExcludeTables` 中豁免,**其他新表一律不要加豁免**。
|
||||
|
||||
ID 获取方式:
|
||||
- 前端:调用 `getUniqueIdApi(count)` 获取
|
||||
- 后端:调用 `uniqueid.NextId()` 获取
|
||||
|
||||
### 规则 3:不要重复造轮子
|
||||
|
||||
- **前端 API 请求**:统一使用 `@/request/api` 中已有的方法,不要创建新的 API 封装
|
||||
- **前端状态管理**:优先复用已有的 Zustand store(`@/store/`),新 Store 只用通用 API
|
||||
- **前端组件**:
|
||||
- UI 组件优先用 `heroui-native`(PressableFeedback、SearchField、Button、Spinner 等)
|
||||
- 长列表用 `@legendapp/list`(LegendList),不要用 FlatList/ScrollView 处理大量数据
|
||||
- 图标统一用 `lucide-react-native`
|
||||
- Toast 用 `sonner-native`
|
||||
- 底部面板用 `@gorhom/bottom-sheet`
|
||||
- 样式用 NativeWind className,避免内联 style
|
||||
- **后端**:不要创建新的 handler 和路由,除非是通用基础设施
|
||||
|
||||
### 规则 4:家庭/空间为中心的设计
|
||||
|
||||
系统以家庭(Family)为核心实体。所有业务数据(记账、收藏等)都跟 `family_id` 关联。
|
||||
用户通过 `family_member` 表关联到家庭。
|
||||
|
||||
## 关键文件索引
|
||||
|
||||
| 文件 | 说明 | 写页面必读 |
|
||||
|------|------|:---:|
|
||||
| `app-rn/package.json` | 前端依赖清单,了解可用库 | ⭐ |
|
||||
| `PROJECT_CONTEXT.md` | 完整项目文档 | |
|
||||
| `db.local.yml` | 本地数据库连接备忘 | |
|
||||
| `app-go/internal/router/router.go` | 后端路由定义 | |
|
||||
| `app-go/pkg/db/meta_field.go` | 审计字段自动注入逻辑 | |
|
||||
| `app-rn/src/request/api.ts` | 前端 API 方法 | |
|
||||
| `app-rn/src/store/` | Zustand 状态管理 | |
|
||||
| `app-rn/src/configs/pages.ts` | 子应用列表配置 | |
|
||||
| `app-rn/src/components/` | 通用组件 | |
|
||||
|
||||
## 当前数据库表
|
||||
|
||||
```
|
||||
b_user - 用户
|
||||
b_user_oauth - 第三方登录绑定
|
||||
b_family - 家庭/空间
|
||||
b_family_member - 家庭成员
|
||||
b_finance - 记账记录
|
||||
b_finance_category - 记账分类
|
||||
b_finance_category_default - 默认分类模板
|
||||
b_app_favorite - 子应用收藏
|
||||
```
|
||||
|
||||
视图:`v_family_member`(join b_family_member + b_user)
|
||||
|
||||
## 常见操作示例
|
||||
|
||||
### 前端:拉取数据
|
||||
```ts
|
||||
import { loadDataApi } from "@/request/api";
|
||||
|
||||
// 查当前家庭的收藏
|
||||
const res = await loadDataApi({
|
||||
view_name: "b_app_favorite",
|
||||
search_condition: "family_id = ?",
|
||||
order_by: "id ASC",
|
||||
search_columns: [],
|
||||
args: [familyId],
|
||||
});
|
||||
if (res.isSuccess) {
|
||||
const list = res.data; // any[]
|
||||
}
|
||||
```
|
||||
|
||||
### 前端:保存数据(新增)
|
||||
```ts
|
||||
import { saveDataApi, getUniqueIdApi } from "@/request/api";
|
||||
|
||||
const idRes = await getUniqueIdApi(1);
|
||||
await saveDataApi([{
|
||||
table_name: "b_app_favorite",
|
||||
key_field: "id",
|
||||
inserts: [{
|
||||
id: idRes.data[0],
|
||||
family_id: familyId,
|
||||
user_id: userId,
|
||||
app_id: "finance",
|
||||
}],
|
||||
updates: [],
|
||||
deletes: [],
|
||||
}]);
|
||||
```
|
||||
|
||||
### 前端:保存数据(删除)
|
||||
```ts
|
||||
await saveDataApi([{
|
||||
table_name: "b_app_favorite",
|
||||
key_field: "id",
|
||||
inserts: [],
|
||||
updates: [],
|
||||
deletes: [{ id: recordId }],
|
||||
}]);
|
||||
```
|
||||
|
||||
### Python:连接数据库
|
||||
```python
|
||||
import psycopg2
|
||||
conn = psycopg2.connect(
|
||||
'postgres://postgres:<password>@117.72.182.135:5432/allapp?sslmode=disable'
|
||||
)
|
||||
# 具体密码见 references/db-config.md
|
||||
```
|
||||
@@ -0,0 +1,109 @@
|
||||
# Allapp 数据库连接配置
|
||||
|
||||
## 连接信息
|
||||
|
||||
| 参数 | 值 |
|
||||
|------|-----|
|
||||
| Host | 117.72.182.135 |
|
||||
| Port | 5432 |
|
||||
| Database | allapp |
|
||||
| User | postgres |
|
||||
| Password | zhang520.. |
|
||||
| SSL | disable |
|
||||
|
||||
## 连接字符串
|
||||
|
||||
```
|
||||
postgres://postgres:zhang520..@117.72.182.135:5432/allapp?sslmode=disable
|
||||
```
|
||||
|
||||
## Python 连接示例
|
||||
|
||||
```python
|
||||
import psycopg2
|
||||
|
||||
conn = psycopg2.connect(
|
||||
host="117.72.182.135",
|
||||
port=5432,
|
||||
database="allapp",
|
||||
user="postgres",
|
||||
password="zhang520..",
|
||||
sslmode="disable",
|
||||
)
|
||||
```
|
||||
|
||||
## 相关配置文件
|
||||
|
||||
- `D:\workspace\code\app\db.local.yml` — 本地备忘
|
||||
- `D:\workspace\code\app\app-go\configs\config.dev.yaml` — 后端开发配置(base_url、端口等)
|
||||
- `D:\workspace\code\app\app-go\configs\config.yaml` — 后端主配置
|
||||
|
||||
## 表结构速查
|
||||
|
||||
所有表均在 `public` schema 下,无外键约束,关系由代码维护。
|
||||
|
||||
### b_user — 用户
|
||||
| 列 | 类型 | 说明 |
|
||||
|----|------|------|
|
||||
| id | BIGINT PK | 雪花 ID |
|
||||
| nickname | VARCHAR | 昵称 |
|
||||
| avatar | VARCHAR | 头像路径 |
|
||||
| name | VARCHAR | 真实姓名 |
|
||||
| phone | VARCHAR | 手机号 |
|
||||
| birth_date | DATE | 生日 |
|
||||
| last_login_time | TIMESTAMPTZ | 最后登录时间 |
|
||||
| create_time | TIMESTAMPTZ | 创建时间 |
|
||||
| update_time | TIMESTAMPTZ | 更新时间 |
|
||||
|
||||
### b_family — 家庭/空间
|
||||
| 列 | 类型 | 说明 |
|
||||
|----|------|------|
|
||||
| id | BIGINT PK | 雪花 ID |
|
||||
| name | VARCHAR | 家庭名称 |
|
||||
| code | VARCHAR | 邀请码 |
|
||||
| create_by | BIGINT | 创建者 |
|
||||
| create_time | TIMESTAMPTZ | 创建时间 |
|
||||
| update_time | TIMESTAMPTZ | 更新时间 |
|
||||
|
||||
### b_family_member — 家庭成员
|
||||
| 列 | 类型 | 说明 |
|
||||
|----|------|------|
|
||||
| id | BIGINT PK | 雪花 ID |
|
||||
| family_id | BIGINT | 家庭 ID |
|
||||
| user_id | BIGINT | 用户 ID |
|
||||
| role | INTEGER | 角色(0=成员) |
|
||||
| nickname | VARCHAR | 在家庭中的昵称 |
|
||||
|
||||
### b_finance — 记账记录
|
||||
| 列 | 类型 | 说明 |
|
||||
|----|------|------|
|
||||
| id | BIGINT PK | 雪花 ID |
|
||||
| family_id | BIGINT | 家庭 ID |
|
||||
| category_id | BIGINT | 分类 ID |
|
||||
| amount | NUMERIC | 金额 |
|
||||
| type | INTEGER | 0=支出, 1=收入 |
|
||||
| remark | TEXT | 备注 |
|
||||
| record_time | TIMESTAMPTZ | 记账时间 |
|
||||
|
||||
### b_finance_category — 记账分类
|
||||
| 列 | 类型 | 说明 |
|
||||
|----|------|------|
|
||||
| id | BIGINT PK | 雪花 ID |
|
||||
| family_id | BIGINT | 家庭 ID |
|
||||
| name | VARCHAR | 分类名称 |
|
||||
| icon | VARCHAR | 图标标识 |
|
||||
| type | INTEGER | 0=支出, 1=收入 |
|
||||
|
||||
### b_app_favorite — 子应用收藏
|
||||
| 列 | 类型 | 说明 |
|
||||
|----|------|------|
|
||||
| id | BIGINT PK | 雪花 ID |
|
||||
| family_id | BIGINT | 家庭 ID |
|
||||
| user_id | BIGINT | 用户 ID |
|
||||
| app_id | VARCHAR | 应用标识(对应 pages.ts 中 id) |
|
||||
| create_time | TIMESTAMPTZ | 创建时间 |
|
||||
| update_time | TIMESTAMPTZ | 更新时间 |
|
||||
| create_by | BIGINT | 创建者 |
|
||||
| update_by | BIGINT | 更新者 |
|
||||
|
||||
UNIQUE(family_id, app_id) — 同一家庭同一应用只能收藏一次
|
||||
Reference in new issue
Block a user