更新项目文档,添加 AGENTS.md
- 删除旧的 prompt.md API 文档 - 添加 AGENTS.md 项目文档,包含技术栈、项目结构、API 接口、认证流程等
This commit is contained in:
191
AGENTS.md
Normal file
191
AGENTS.md
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
# Agent 文档 — rust-backend
|
||||||
|
|
||||||
|
## 项目概述
|
||||||
|
|
||||||
|
微信小程序天气数据采集后端。用户通过微信认证,上传天气观测数据,并通过 REST API 管理数据。
|
||||||
|
|
||||||
|
## 技术栈
|
||||||
|
|
||||||
|
- **语言**: Rust (edition 2024)
|
||||||
|
- **Web 框架**: actix-web 4.11
|
||||||
|
- **数据库**: PostgreSQL,通过 sqlx 0.8.6 连接
|
||||||
|
- **认证**: JWT (HS256),使用 jsonwebtoken 9.3
|
||||||
|
- **HTTP 客户端**: reqwest(用于调用微信 API)
|
||||||
|
- **序列化**: serde + serde_json
|
||||||
|
- **时间处理**: chrono
|
||||||
|
|
||||||
|
## 项目结构
|
||||||
|
|
||||||
|
```
|
||||||
|
src/
|
||||||
|
├── main.rs # 入口文件,所有路由处理器,服务器配置
|
||||||
|
├── auth.rs # JWT 中间件,令牌生成/验证
|
||||||
|
├── db.rs # 数据库操作(通过 sqlx 执行原始 SQL)
|
||||||
|
├── models.rs # 数据结构(Claims、User、WeatherData 等)
|
||||||
|
└── config.rs # 配置结构体(main.rs 中未使用 — 死代码)
|
||||||
|
|
||||||
|
migrations/
|
||||||
|
└── 001_add_payment_fields.sql # 用于添加支付字段的 ALTER TABLE
|
||||||
|
|
||||||
|
tests/
|
||||||
|
└── integration_test.rs # 基础测试框架
|
||||||
|
```
|
||||||
|
|
||||||
|
## 数据库表结构
|
||||||
|
|
||||||
|
### users 表
|
||||||
|
```sql
|
||||||
|
id INTEGER PRIMARY KEY
|
||||||
|
openid VARCHAR UNIQUE(微信用户 ID)
|
||||||
|
name VARCHAR(默认为 openid 前 8 个字符)
|
||||||
|
type INTEGER(硬编码为 2)
|
||||||
|
is_paid BOOLEAN DEFAULT false
|
||||||
|
is_admin BOOLEAN DEFAULT false
|
||||||
|
paid_expires_at TIMESTAMPTZ DEFAULT NULL
|
||||||
|
```
|
||||||
|
|
||||||
|
### weather_data 表
|
||||||
|
```sql
|
||||||
|
id INTEGER PRIMARY KEY
|
||||||
|
user_id INTEGER(外键,关联 users 表)
|
||||||
|
title, date, hour, min, longitude, latitude, ...
|
||||||
|
-- 30+ 个天气测量字段列
|
||||||
|
```
|
||||||
|
|
||||||
|
## 认证流程
|
||||||
|
|
||||||
|
1. **登录**: `POST /api/login` 传入微信 code → 调用微信 API → UPSERT 用户 → 返回 JWT
|
||||||
|
2. **JWT 声明**: `{exp, iat, user_id, openid, user_type}`(24 小时过期)
|
||||||
|
3. **中间件**: `jwt_middleware` 提取 Bearer 令牌,验证后将 Claims 插入请求扩展
|
||||||
|
4. **处理器访问**: 通过 `claims: web::ReqData<Claims>` 参数获取
|
||||||
|
|
||||||
|
## API 接口
|
||||||
|
|
||||||
|
### 公开接口(无需认证)
|
||||||
|
- `POST /api/login` — 微信登录
|
||||||
|
- `GET /weather/details?temp_token=...` — 通过临时令牌访问
|
||||||
|
- `GET /static/{tail:*}` — 静态文件
|
||||||
|
|
||||||
|
### 受保护接口(需要 JWT)
|
||||||
|
- `POST /api/post-weather-data` — 上传天气数据(带配额检查)
|
||||||
|
- `GET /weather` — 分页列出用户的天气数据
|
||||||
|
- `GET /weather/details?id=...` — 获取天气详情(JWT 认证)
|
||||||
|
- `POST /api/generate-temp-token/{resource_id}` — 生成 10 分钟分享令牌
|
||||||
|
- `DELETE /weather/delete/{id}` — 删除天气记录
|
||||||
|
|
||||||
|
### 管理员接口(需要 JWT + is_admin)
|
||||||
|
- `PUT /api/admin/users/{id}/payment` — 更新用户支付状态
|
||||||
|
- `GET /api/admin/users/{id}` — 获取用户信息
|
||||||
|
|
||||||
|
## 支付系统
|
||||||
|
|
||||||
|
### 支付状态逻辑
|
||||||
|
```rust
|
||||||
|
is_paid_active = is_paid && (paid_expires_at.is_none() || paid_expires_at > Utc::now())
|
||||||
|
```
|
||||||
|
|
||||||
|
### 配额限制
|
||||||
|
- 未付费用户限制为 `FREE_USER_DATA_LIMIT` 条记录(环境变量,默认 20)
|
||||||
|
- 付费用户(活跃状态)无限制
|
||||||
|
- 在 `insert_weather_data` 执行 INSERT 前进行检查
|
||||||
|
|
||||||
|
### 管理员 API
|
||||||
|
```json
|
||||||
|
PUT /api/admin/users/{id}/payment
|
||||||
|
{
|
||||||
|
"is_paid": true,
|
||||||
|
"paid_expires_at": "2026-12-31T23:59:59Z" // 可选,null 表示永久
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 代码模式
|
||||||
|
|
||||||
|
### 处理器模式
|
||||||
|
```rust
|
||||||
|
#[post("/api/endpoint")]
|
||||||
|
async fn handler(
|
||||||
|
pool: web::Data<PgPool>,
|
||||||
|
claims: web::ReqData<Claims>,
|
||||||
|
body: web::Json<RequestBody>,
|
||||||
|
) -> impl Responder {
|
||||||
|
match db::function(pool.get_ref(), claims.user_id).await {
|
||||||
|
Ok(data) => HttpResponse::Ok().json(serde_json::json!({"success": true, "data": data})),
|
||||||
|
Err(e) => HttpResponse::Ok().json(serde_json::json!({"success": false, "errcode": 500, "errmsg": e}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 数据库函数模式
|
||||||
|
```rust
|
||||||
|
pub async fn function_name(pool: &PgPool, param: i32) -> Result<Type, String> {
|
||||||
|
match sqlx::query_as::<_, Type>("SELECT ...")
|
||||||
|
.bind(param)
|
||||||
|
.fetch_optional(pool)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(Some(row)) => Ok(row),
|
||||||
|
Ok(None) => Err("Not found".to_string()),
|
||||||
|
Err(e) => Err(format!("Query failed: {}", e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 错误响应格式
|
||||||
|
```json
|
||||||
|
{"success": false, "errcode": 403, "errmsg": "Error message"}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 环境变量
|
||||||
|
|
||||||
|
```env
|
||||||
|
DATABASE_URL=postgres://user:pass@host:5432/dbname
|
||||||
|
WECHAT_APPID=wx...
|
||||||
|
WECHAT_SECRET=...
|
||||||
|
JWT_SECRET=your_secret_key
|
||||||
|
SSL_KEY_PATH=/path/to/key
|
||||||
|
SSL_CERT_PATH=/path/to/cert
|
||||||
|
RUST_LOG=info
|
||||||
|
APP_VERSION=0.2.0
|
||||||
|
FREE_USER_DATA_LIMIT=20
|
||||||
|
```
|
||||||
|
|
||||||
|
## 约束条件
|
||||||
|
|
||||||
|
### 禁止事项
|
||||||
|
- 在 JWT Claims 中添加 `is_admin`(必须查询数据库)
|
||||||
|
- 信任 JWT 中的 `is_paid` 来做配额决策(必须查询数据库)
|
||||||
|
- 使用 `as any`、`@ts-ignore` 或类型错误抑制
|
||||||
|
- 修改 config.rs(死代码)
|
||||||
|
- 添加支付网关集成
|
||||||
|
- 添加审计日志
|
||||||
|
|
||||||
|
### 必须事项
|
||||||
|
- 管理员接口必须通过数据库查询验证管理员身份
|
||||||
|
- 已认证处理器使用 `web::ReqData<Claims>`
|
||||||
|
- 遵循现有的错误响应格式
|
||||||
|
- 通过数据库查询检查 `is_paid_active`,而非 JWT
|
||||||
|
|
||||||
|
## 常见任务
|
||||||
|
|
||||||
|
### 添加新接口
|
||||||
|
1. 在 `main.rs` 中创建处理器函数
|
||||||
|
2. 如需要,在 `db.rs` 中添加数据库函数
|
||||||
|
3. 在 `create_server_config` 中注册(如果是受保护接口,放在 JWT 作用域内)
|
||||||
|
4. 如需要,在 `models.rs` 中添加请求/响应结构体
|
||||||
|
|
||||||
|
### 修改数据库
|
||||||
|
1. 在 `migrations/` 中创建迁移 SQL
|
||||||
|
2. 在 PostgreSQL 上手动执行迁移
|
||||||
|
3. 如果表结构变更,更新 `models.rs` 中的 `User` 结构体
|
||||||
|
4. 更新 `db.rs` 中的数据库函数
|
||||||
|
|
||||||
|
## 构建与运行
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo build # 编译
|
||||||
|
cargo run # 启动服务器
|
||||||
|
cargo test # 运行测试
|
||||||
|
cargo clippy # 代码检查
|
||||||
|
```
|
||||||
|
|
||||||
|
服务器尝试端口顺序:4433、8443、8080、3000、8000、8888
|
||||||
36
prompt.md
36
prompt.md
@@ -1,36 +0,0 @@
|
|||||||
# api
|
|
||||||
|
|
||||||
## login
|
|
||||||
|
|
||||||
- POST /api/wx/login - 微信小程序登录接口(接收 code 并返回令牌)
|
|
||||||
- GET /api/user/info - 获取当前登录用户信息
|
|
||||||
- POST /api/logout - 登出接口
|
|
||||||
|
|
||||||
## data
|
|
||||||
|
|
||||||
- GET /api/resources/data 获取个人全部数据的部分,或者指定数据的全部
|
|
||||||
- GET /api/permissions 用于后续用户管理
|
|
||||||
|
|
||||||
# backend
|
|
||||||
|
|
||||||
- rust
|
|
||||||
- actix-web
|
|
||||||
- serde
|
|
||||||
- jsonwebtoken
|
|
||||||
- sqlx
|
|
||||||
- dotenv
|
|
||||||
|
|
||||||
# routine
|
|
||||||
|
|
||||||
## /api/wx/login
|
|
||||||
|
|
||||||
1. 接收小程序发送的 code
|
|
||||||
2. 调用微信官方code2Session接口获取 openid
|
|
||||||
3. 生成 JWT 令牌返回给小程序
|
|
||||||
4. 实现令牌验证中间件保护需要登录的接口
|
|
||||||
|
|
||||||
# auth
|
|
||||||
|
|
||||||
1. 基于角色的访问控制 (RBAC) 模型
|
|
||||||
2. 在中间件中验证用户令牌和权限
|
|
||||||
3. 实现权限检查装饰器 / 宏简化代码
|
|
||||||
Reference in New Issue
Block a user