Files
portal-mini-go/.codebuddy/docs/API.md
T

344 lines
10 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.
# portal-mini-go 接口文档
> 基于 Go + gin 的中后台/门户后端服务。本文档描述当前已实现的 HTTP 接口、鉴权方式、统一响应结构、错误码与数据模型。
## 1. 概述
- **基础路径**:`/`
- **服务地址**:由 `configs/config.yaml` 中 `server.port` 决定(默认 `8080`),例如 `http://localhost:8080`。
- **统一响应**:所有接口均返回 `HTTP 200`,业务结果通过响应体中的 `code` 字段判断(见 §3)。
- **路由分层**:
- `/api/ma`:小程序端接口,通过请求头 `X-App-ID` 鉴权(校验小程序是否被纳管且启用)。
- `/api/admin`:后台管理接口,通过 `Authorization: Bearer <JWT>` 鉴权。
- `/healthz`:健康检查,无需鉴权。
## 2. 公共约定
### 2.1 请求头
| Header | 必填 | 说明 |
| --- | --- | --- |
| `Content-Type` | 是(POST/PUT) | 固定为 `application/json`。 |
| `X-App-ID` | 是(小程序接口) | 微信小程序的 AppID,标识调用方小程序身份。 |
| `Authorization` | 是(后台接口) | 后台登录后下发的 JWT,格式 `Bearer <token>`。 |
### 2.2 统一响应结构
```json
{
"code": 0,
"msg": "ok",
"data": { }
}
```
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `code` | int | 业务码。`0` 表示成功;非 `0` 表示失败(见 §3 错误码)。 |
| `msg` | string | 结果描述。`0` 时为 `ok`,失败时为人可读信息。 |
| `data` | object/null | 业务数据,成功时有内容,失败时通常省略。 |
> 约定:错误统一由 `ErrorHandler` 中间件转换,handler 内不直接散落 `c.JSON` 处理错误。
### 2.3 鉴权中间件
| 分组 | 中间件 | 校验逻辑 |
| --- | --- | --- |
| `/api/ma` | `MiniAppAuth` | 校验请求头 `X-App-ID` 对应一个「已启用且未删除」的被纳管小程序;通过后将 `app_id` 与小程序主键 `mini_id` 注入上下文。 |
| `/api/admin` | `AdminAuth` | 校验 `Authorization: Bearer <JWT>`(HS256)。校验通过后将 `admin_id` 注入上下文。 |
| 全局 | `Recovery` / `Trace` / `ErrorHandler` | panic 恢复、trace_id 注入、错误统一转换。 |
## 3. 错误码
| 业务码 | 常量 | 含义 |
| --- | --- | --- |
| `0` | — | 成功 |
| `40000` | `ErrBadRequest` | 请求参数错误 / 非法输入(`ext` 非合法 JSON 等) |
| `40100` | `ErrUnauthorized` | 未认证 / 登录失败 / token 无效或过期 |
| `40300` | `ErrForbidden` | 禁止访问 |
| `40400` | `ErrNotFound` | 资源不存在 / 小程序未注册 |
| `50000` | `ErrServer` | 服务内部错误(含微信调用、会话写入、token 签发等) |
> 非 `BizError` 的未知错误一律归为 `50000`。
## 4. 接口列表
### 4.1 健康检查
#### `GET /healthz`
无需鉴权。
**响应示例**
```json
{ "code": 0, "msg": "ok", "data": { "status": "ok" } }
```
---
### 4.2 小程序接口(前缀 `/api/ma`)
所有接口需在请求头携带 `X-App-ID`(已启用且被纳管的小程序)。当前示例实现为 `app1`,后续小程序按相同结构扩展。
#### `POST /api/ma/login`
小程序登录:通过微信 `code2session` 换取 `openid`/`unionid`,落库用户并向客户端下发会话 token。
**请求头**
```
X-App-ID: <微信小程序 AppID>
```
**请求体**
```json
{
"code": "081abc..." // 必填,微信登录 code
}
```
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `code` | string | 是 | 小程序 `wx.login` 获取的临时登录 code。 |
**响应**
```json
{
"code": 0,
"msg": "ok",
"data": {
"token": "a1b2c3...48位hex字符串",
"user": {
"id": 1,
"mini_id": 3,
"openid": "oABC...",
"union_id": "oXYZ...",
"nickname": "",
"avatar": "",
"created_at": "2026-10-25T10:00:00Z",
"updated_at": "2026-10-25T10:00:00Z"
}
}
}
```
> `token` 为 `24` 字节随机值的 hex 编码(48 字符),对应会话在 Redis/内存存储中保留 `7` 天。后续小程序业务接口应携带该 token 完成用户身份识别。
**curl 示例**
```bash
curl -X POST http://localhost:8080/api/ma/login \
-H "Content-Type: application/json" \
-H "X-App-ID: wx1234567890" \
-d '{"code":"081abc..."}'
```
---
### 4.3 后台管理接口(前缀 `/api/admin`)
所有接口需在请求头携带 `Authorization: Bearer <JWT>`。
#### `POST /api/admin/login`
后台管理员登录,签发 JWT。
**请求体**
```json
{
"username": "admin",
"password": "admin123"
}
```
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `username` | string | 是 | 管理员账号(当前示例固定 `admin`)。 |
| `password` | string | 是 | 密码(当前示例固定 `admin123`;生产应接 DB + 密码哈希)。 |
**响应**
```json
{ "code": 0, "msg": "ok", "data": { "token": "<JWT>" } }
```
**curl 示例**
```bash
curl -X POST http://localhost:8080/api/admin/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin123"}'
```
#### `GET /api/admin/info`
受保护接口示例,需有效 JWT,返回当前管理员 ID。
**响应**
```json
{ "code": 0, "msg": "ok", "data": { "admin_id": "1" } }
```
#### `POST /api/admin/miniapps`
新建被纳管小程序。
**请求体**
```json
{
"name": "示例小程序",
"description": "用于演示",
"app_id": "wx1234567890",
"app_secret": "secret-xxxx",
"status": 1,
"ext": "{\"k\":\"v\"}"
}
```
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `name` | string | 是 | 小程序名称。 |
| `description` | string | 否 | 描述。 |
| `app_id` | string | 是 | 微信 AppID,全局唯一。 |
| `app_secret` | string | 是 | 微信 AppSecret(不会在响应中返回)。 |
| `status` | int8 | 否 | 状态:`0` 停用,`1` 启用。缺省为 `1`。 |
| `ext` | string | 否 | 扩展字段,必须为合法 JSON 字符串(允许空串)。 |
**响应**:返回创建后的 `MiniProgram` 对象(见 §5.1),`app_secret` 字段不返回。
#### `PUT /api/admin/miniapps/:id`
按 ID 局部更新小程序。
**路径参数**
| 参数 | 类型 | 说明 |
| --- | --- | --- |
| `id` | uint64 | 小程序主键。 |
**请求体**(所有字段均为可选,仅在提供时更新;`ext` 若提供需为合法 JSON)
```json
{
"name": "新名称",
"description": "新描述",
"app_secret": "new-secret",
"status": 0,
"ext": "{\"theme\":\"dark\"}"
}
```
> 字段以指针区分「未提供」与「置空」;若全部为空则不更新,直接返回原记录。
**响应**:返回更新后的 `MiniProgram` 对象。
#### `GET /api/admin/miniapps/:id`
查询单个小程序。
**路径参数**:`id`(uint64)。
**响应**:返回 `MiniProgram` 对象;不存在返回 `40400`。
#### `GET /api/admin/miniapps`
分页列表查询小程序。
**查询参数**
| 参数 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `status` | int8 | `-1`(全部) | 按状态筛选:`0` 停用,`1` 启用,`-1` 全部。 |
| `page` | int | `1` | 页码,从 1 开始。 |
| `size` | int | `20` | 每页条数。 |
**响应**
```json
{
"code": 0,
"msg": "ok",
"data": {
"list": [ { "id": 1, "name": "示例小程序", "app_id": "wx123...", "status": 1, "...": "..." } ],
"total": 1,
"page": 1,
"size": 20
}
}
```
#### `DELETE /api/admin/miniapps/:id`
软删除小程序(置 `deleted_at`)。
**路径参数**:`id`(uint64)。
**响应**
```json
{ "code": 0, "msg": "ok" }
```
**curl 示例(列表)**
```bash
curl "http://localhost:8080/api/admin/miniapps?status=1&page=1&size=20" \
-H "Authorization: Bearer <JWT>"
```
## 5. 数据模型
### 5.1 MiniProgram(被纳管小程序)
| 字段 | 类型 | JSON | 说明 |
| --- | --- | --- | --- |
| `ID` | uint64 | `id` | 主键,自增。 |
| `Name` | string | `name` | 名称。 |
| `Description` | string | `description` | 描述。 |
| `AppID` | string | `app_id` | 微信 AppID,全局唯一。 |
| `AppSecret` | string | `app_secret` | **不返回**(json `-`)。 |
| `Status` | int8 | `status` | `0` 停用,`1` 启用。 |
| `Ext` | string | `ext` | 扩展 JSON 文本。 |
| `CreatedAt` | time | `created_at` | 创建时间。 |
| `UpdatedAt` | time | `updated_at` | 更新时间。 |
### 5.2 User(小程序用户)
| 字段 | 类型 | JSON | 说明 |
| --- | --- | --- | --- |
| `ID` | uint64 | `id` | 主键,自增。 |
| `MiniID` | uint64 | `mini_id` | 所属小程序主键(关联 `mini_programs.id`)。 |
| `OpenID` | string | `openid` | 微信 openid。 |
| `UnionID` | string | `union_id` | 微信 unionid(可为空)。 |
| `Nickname` | string | `nickname` | 昵称。 |
| `Avatar` | string | `avatar` | 头像 URL。 |
| `CreatedAt` | time | `created_at` | 创建时间。 |
| `UpdatedAt` | time | `updated_at` | 更新时间。 |
> 用户由 `(mini_id, open_id)` 唯一标识。
## 6. 配置说明
配置由 `configs/config.yaml` + 环境变量(支持 `${ENV}` 占位符)加载。敏感信息(DB 密码、JWT Secret)应通过环境变量注入,禁止硬编码。
| 配置项 | 说明 |
| --- | --- |
| `server.port` / `server.mode` | 服务端口、运行模式(`release` 时 gin 进入 ReleaseMode)。 |
| `mysql.*` | MySQL 连接与连接池参数,拼装为 DSN。 |
| `logging.level` / `logging.format` | 日志级别与格式(text/json)。 |
| `admin.jwt_secret` | 后台 JWT 签名密钥。 |
| `admin.token_ttl` | 后台 JWT 有效期(如 `24h`)。 |
## 7. 备注与后续扩展
- **小程序会话**:`/api/ma/login` 返回的 token 为会话凭证,当前示例在 `/api/ma` 下仅实现 `login`;业务接口应在路由中增加基于该 token 的用户身份中间件后再登记。
- **后台账号**:`/api/admin/login` 当前为固定示例账号,生产环境需接入数据库与密码哈希校验。
- **会话存储**:默认 `MemoryStore`(单实例),多实例部署应替换为 Redis 实现(复用 `session.Store` 接口)。
- **多小程序**:新增 `app2`..`app10` 时,按 `internal/handler/miniapp/app1`、`internal/service/miniapp/app1` 的目录结构各自建包,在 `router.New` 中注册即可,互不耦合。