Files
asset_helper/backend/CLAUDE.md

304 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Backend — Claude Code 项目指南
本文件为 Claude Code及其它 AI Agent提供后端项目的背景、结构说明和开发规范。
## 项目概述
这是一个基于 **Rust** 的微服务后端项目,采用 **Axum + Tokio** 技术栈,使用 **Nginx** 作为 API 网关,**PostgreSQL** 作为数据库,**Redis** 作为缓存。服务以 Docker 容器形式部署,按 **DDD 限界上下文Bounded Context** 划分服务边界——一个领域对外是一个微服务,内部由 Rust 模块组织。
## 技术栈
| 层级 | 技术 |
|------|------|
| 语言 | Rust 2024 Edition |
| Web 框架 | axum 0.8, tokio 1.x, tower 0.5 |
| 数据库 | PostgreSQL 18.3 (sqlx 0.8) |
| 缓存 | Redis 8.6.2 (redis 0.29) |
| 网关 | Nginx 1.25 (Alpine) |
| 部署 | Docker, Docker Compose |
| 其他 | bcrypt, jsonwebtoken, uuid v7, chrono, tracing, validator |
## 项目结构
```
backend/
├── services/ # 微服务目录
│ └── user-service/ # 用户服务DDD 用户限界上下文,单一服务对外)
│ ├── Cargo.toml # 单 crate
│ ├── Dockerfile # 单镜像
│ ├── migrations/ # 数据库初始化 SQL
│ │ └── 001_init.sql
│ └── src/
│ ├── main.rs # 装配 Router、连接池、AppState
│ ├── state.rs # AppState { db, jwt_secret }
│ ├── api.rs # 通用 ApiRequest<T> / ApiResponse<T>
│ ├── jwt.rs # JWT Claims + generate_token
│ ├── auth/ # 认证模块
│ │ ├── mod.rs
│ │ ├── login_account.rs
│ │ └── login_email.rs
│ └── register/ # 注册模块
│ ├── mod.rs
│ ├── account.rs
│ └── email.rs
├── gateway/ # API 网关
│ ├── Dockerfile
│ └── nginx/
│ ├── nginx.conf
│ ├── conf.d/default.conf
│ └── conf.d/services/ # 各服务路由配置
├── shared/ # 共享代码库(当前为空,待扩展)
├── deploy/
│ └── local/redis.conf # 本地 Redis 配置
├── scripts/
│ ├── gateway.sh # 网关管理脚本(测试/重载/日志/证书)
│ └── init-multiple-databases.sh # Postgres 多库初始化
└── README.md
```
> 编排已统一上移到项目根目录的 `docker-compose.yml` / `docker-compose.dev.yml`,本目录不再存放 compose 文件。
## 微服务架构说明
### 服务拆分原则
**DDD 限界上下文Bounded Context** 划分:每个独立的业务域对外暴露为单一微服务,内部细分通过 Rust 模块和 axum Router 组合实现,**不再按操作粒度(登录/注册)拆 crate**。
**user-service**(用户域,单一服务)对外提供:
| 方法 | 网关路径 | 下游路径 | 用途 |
|------|---------|---------|------|
| POST | `/api/v1/auth/login/account` | `/auth/login/account` | 账号密码登录,签发 JWT |
| POST | `/api/v1/auth/login/email` | `/auth/login/email` | 邮箱密码登录,签发 JWT |
| POST | `/api/v1/users/register/account` | `/users/register/account` | 账号注册(写 user_main / user_login_account / user_login_password |
| POST | `/api/v1/users/register/email` | `/users/register/email` | 邮箱注册(写 user_main / user_login_email / user_login_password |
| GET | `/health` | `/health` | 健康检查 |
> 网关 nginx 通过 `rewrite ^/api/v1(/.*)$ $1 break;` 统一去除 `/api/v1` 前缀。
服务内部模块化布局见 [项目结构](#项目结构)`auth/` 子模块负责登录认证,`register/` 子模块负责账号注册,共享 `state.rs` / `api.rs` / `jwt.rs`
### 数据库模型
核心表结构(见 `services/user-service/migrations/001_init.sql`
- `user_main(id UUID PK, deleted BOOLEAN, create_date, modify_date)`
- `user_login_account(id UUID PK, user_id FK, account VARCHAR)`
- `user_login_email(id UUID PK, user_id FK, email VARCHAR)`
- `user_login_password(id UUID PK, user_id FK, password VARCHAR)`
采用**软删除**设计(`deleted` 字段),账号/邮箱通过部分索引保证唯一性:
```sql
CREATE UNIQUE INDEX ... ON user_login_account(account) WHERE deleted = FALSE;
```
## 开发规范
### 1. API 公共约定
项目中存在两类接口风格,新增服务时请遵循对应场景的约定:
#### 注册/业务类接口(使用统一包装)
**请求包装格式:**
```json
{
"device": 1,
"language": 1,
"data": {
// 业务字段
}
}
```
- `device`: 设备类型标识(`i32`
- `1` = iOS
- `2` = Android
- `3` = Web
- `4` = iPad
- `5` = macOS
- `6` = Windows
- `7` = Linux
- `language`: 语言标识(`i32`
- `1` = 简体中文
- `2` = 繁体中文
- `3` = 英文
- `data`: 实际业务请求体
**响应包装格式:**
```json
{
"success": true,
"message": "User registered successfully",
"data": {
// 业务返回数据,失败时为 null
}
}
```
- `success`: 布尔值,表示业务是否成功
- `message`: 可读的状态描述或错误信息
- `data`: 业务数据,`Option<T>`,失败时返回 `null`
#### 登录/认证类接口(扁平响应)
**请求格式:** 直接携带凭证字段(如 `username`/`email` + `password`)。
**响应格式:**
```json
{
"success": true,
"token": "eyJhbGciOiJIUzI1NiIs...",
"message": "Login successful"
}
```
- `success`: 布尔值
- `token`: JWT Token认证失败或错误时为 `null`
- `message`: 状态描述
#### 健康检查
所有服务必须暴露 `GET /health`,成功时返回 HTTP 200
```text
OK
```
#### 错误响应HTTP 非 200
网关层返回统一 JSON 错误:
```json
{
"error": "Not Found",
"message": "The requested resource was not found",
"code": 404
}
```
### 2. 代码风格
- 使用 **Rust 2024 Edition**
- 注释使用**中文**。
- 服务状态通过 `Arc<AppState>` 注入到 Axum Handler 中。
- 注册类接口统一使用包装请求/响应格式:
```rust
struct ApiRequest<T> { device: i32, language: i32, data: T }
struct ApiResponse<T> { success: bool, message: String, data: Option<T> }
```
### 3. 时间字段约定
所有表中的 `create_date` 和 `modify_date` **必须由业务层生成并传入**数据库Schema中**不设置** `DEFAULT CURRENT_TIMESTAMP`,也不使用触发器自动更新。
- 建表时:
```sql
create_date TIMESTAMP WITH TIME ZONE NOT NULL,
modify_date TIMESTAMP WITH TIME ZONE NOT NULL
```
- Rust 代码中使用 `chrono::Utc::now()` 生成时间戳,统一在事务开始前创建 `let now = Utc::now();`,确保同一笔业务中各表时间一致。
- `modify_date` 更新时同样需要在业务代码中显式传入 `Utc::now()`。
#### 时区策略
项目采用**数据库存 UTC、查询按东八区显示**的策略:
- 业务层始终使用 `chrono::Utc::now()` 生成 UTC 时间写入数据库。
- 每个服务在建立数据库连接池后,执行 `SET TIME ZONE 'Asia/Shanghai';`,确保 `TIMESTAMP WITH TIME ZONE` 字段在查询时以东八区格式返回。
- 如需在 Rust 代码中做东八区展示转换,使用 `chrono::FixedOffset::east_opt(8 * 3600)` 处理。
### 4. 环境变量
所有服务通过环境变量读取配置:
- `DATABASE_URL` — PostgreSQL 连接串(必需)
- `REDIS_URL` — Redis 连接串
- `SERVICE_PORT` — 服务监听端口(默认 8080
- `JWT_SECRET` — JWT 签名密钥
- `RUST_LOG` — 日志级别
### 5. Docker 构建
- 各微服务 Dockerfile 的构建上下文为 **`backend/` 目录**(根目录 `docker-compose.yml` 中使用 `context: ./backend`)。
- 构建采用多阶段builder + runtime基于 `rust:1.94.1-alpine3.23` 编译,最终运行在 `alpine:3.23`。
- 共享代码更新时,需确保 `shared/` 目录在 Dockerfile 中被正确复制。
### 6. 网关与路由
- Nginx 监听 80/443开发环境使用自签名证书。
- 路由前缀约定:
- `/api/v1/users` → 用户服务通用接口
- `/api/v1/auth` → 认证接口(更严格限流)
- 新增服务时,需在 `gateway/nginx/conf.d/services/` 下创建对应 `.conf` 文件,并在 `nginx.conf` 中添加上游 `upstream`。
## 常用命令
### 启动整套后端(含网关 + 数据库 + 缓存)
后端不再单独编排,由项目根目录的 docker compose 一并启动。详见 [根目录 CLAUDE.md](../CLAUDE.md#部署)。
```bash
# 在项目根目录
docker compose -f docker-compose.dev.yml up -d --build # 测试
docker compose up -d --build # 正式
```
如需仅启动后端栈(不含前端)做联调:
```bash
docker compose -f docker-compose.dev.yml up -d --build \
user-db user-redis user-service gateway
```
### 网关管理
```bash
# 测试配置
./scripts/gateway.sh test
# 生成开发证书
./scripts/gateway.sh certs
# 查看状态
./scripts/gateway.sh status
# 热重载(容器运行中)
./scripts/gateway.sh reload
```
### 本地编译运行 user-service
```bash
cd services/user-service
cargo run
```
## 扩展指南
### 在已有领域内新增功能(推荐)
属于同一限界上下文(如新增"用户资料修改"接口)时,**不要**新建 crate 或服务,而是在现有 `user-service` 下新增模块:
1. 在 `services/user-service/src/` 下新增模块文件,或扩展现有 `auth/` / `register/` 子模块。
2. 在子模块的 `mod.rs` 中通过 `Router::new().route(...)` 注册新路由。
3. 在 `gateway/nginx/conf.d/services/user-service.conf` 中追加对应 `location` 块(路径仍以 `/api/v1/...` 起始)。
4. 如需新数据库表或字段,在 `services/user-service/migrations/` 下追加 SQL 文件。
### 新增服务域(新限界上下文)
当业务边界明显独立(如订单 `order-service`、支付 `payment-service`)时再新建独立服务:
1. 在 `services/<service-domain>/` 下创建独立 crate参考 `services/user-service/` 的目录布局:单 `Cargo.toml` + 单 `Dockerfile` + 模块化的 `src/`)。
2. 在 `gateway/nginx/conf.d/services/` 添加路由配置文件。
3. 在 `gateway/nginx/nginx.conf` 添加对应 `upstream`。
4. 在根目录 `docker-compose.yml` / `docker-compose.dev.yml` 中追加服务定义。
5. 在 [PORT_ALLOCATION.md](PORT_ALLOCATION.md) 申请新的百位段端口并更新分配表。
### 共享代码提取
当前 `shared/` 目录为空。当多个服务域需要共用模型、中间件或工具函数时:
1. 在 `shared/` 下创建子模块(如 `shared/models`、`shared/middleware`)。
2. 将共享 crate 以 path dependency 引入各微服务:
```toml
[dependencies]
shared = { path = "../../shared" }
```
3. 更新各 Dockerfile确保 `COPY shared /app/shared` 在依赖缓存步骤之前执行。
## 注意事项
- 当前 `shared/` 为空Agent 在修改代码时若发现跨服务域重复逻辑,可提议提取到 `shared/`;同一服务内部的重复逻辑直接抽到模块即可,无需走 `shared/`。
- 网关配置文件中的 `api.example.com` 为占位域名,本地开发需配置 hosts 或使用 `localhost`。