From c37a7a5f364f6655d5f7397d75991262cc97809d Mon Sep 17 00:00:00 2001 From: Milky0217 Date: Wed, 25 Mar 2026 13:18:09 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E9=A1=B9=E7=9B=AE=E6=96=87?= =?UTF-8?q?=E6=A1=A3=EF=BC=8C=E6=B7=BB=E5=8A=A0=20AGENTS.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 删除旧的 prompt.md API 文档 - 添加 AGENTS.md 项目文档,包含技术栈、项目结构、API 接口、认证流程等 --- AGENTS.md | 191 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ prompt.md | 36 ---------- 2 files changed, 191 insertions(+), 36 deletions(-) create mode 100644 AGENTS.md delete mode 100644 prompt.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..b986770 --- /dev/null +++ b/AGENTS.md @@ -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` 参数获取 + +## 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, + claims: web::ReqData, + body: web::Json, +) -> 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 { + 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` +- 遵循现有的错误响应格式 +- 通过数据库查询检查 `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 diff --git a/prompt.md b/prompt.md deleted file mode 100644 index 1b4e5ce..0000000 --- a/prompt.md +++ /dev/null @@ -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. 实现权限检查装饰器 / 宏简化代码 \ No newline at end of file