Files
Arkie-Library-Frontend/.unipi/docs/specs/2026-05-25-frontend-backend-api-requirements.md
2026-05-25 05:25:57 +08:00

582 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.
---
title: "ARK Library Frontend — Backend API Requirements"
type: api-requirements
date: 2026-05-25
audience: backend
status: draft
---
# ARK Library Frontend — Backend API Requirements
这份文档列出前端接下来需要后端提供的**全部接口**。重点是新的 Telegram-style 资料流;旧 `resources` 接口可作为过渡,但最终建议统一到 `posts` 模型。
## 0. 通用约定
- API base前端通过 `VITE_API_URL` 指向后端;本地可同源 `/api`
- 上传文件可通过 `/uploads/...` 或完整 URL 返回;前端会用 `assetUrl()` 处理相对路径。
- 所有时间字段使用 ISO 8601 字符串,例如 `2026-05-24T14:42:00.000Z`
- 语言字段:`zh-TW` / `zh-CN` / `en`
- 错误格式:非 2xx + text/plain 或 JSON 均可;前端会显示错误文本。
- Admin 接口需要 `Authorization: Bearer <token>`
## 1. 核心数据模型
### 1.1 Category
```ts
type Category = {
id: number;
slug: string; // 用于 /category/:slug 和 GET /api/posts?category=<slug>
name: string; // 已按 lang 返回本地化名称
description?: string;
iconKey: string; // folder/calendar/megaphone/video/image 等,前端已有 icon map
sortOrder: number;
};
```
### 1.2 Post新资料流核心
```ts
type AttachmentKind = "image" | "video" | "document";
type Attachment = {
id: string;
kind: AttachmentKind;
url: string; // 原始文件或可访问文件 URL
mime: string; // image/jpeg, application/pdf, video/mp4, ...
filename: string;
sizeBytes: number;
width?: number; // image/video 建议提供
height?: number;
durationSec?: number; // video 建议提供
posterUrl?: string; // video preview
thumbnailUrl?: string; // image/document preview
};
type Post = {
id: string;
categoryId: number;
categorySlug: string;
language: "zh-TW" | "zh-CN" | "en";
text?: string;
attachments: Attachment[];
isRecommended: boolean;
publishedAt: string;
updatedAt: string;
};
type PostListResponse = {
items: Post[];
nextCursor?: string;
};
```
### 1.3 Post 显示规则(后端必须按这个模型返回)
- 纯文字/链接:`attachments: []``text` 非空。
- 单张图片:`attachments.length === 1``kind: "image"`
- 图片 + 文字:`kind: "image"` + `text`
- 视频:`kind: "video"`,建议提供 `posterUrl` / `durationSec`
- 文件:`kind: "document"`,前端显示下载卡。
- 图片当文件上传:`kind: "document"``mime` 是 image前端会显示缩略图 + 下载按钮。
- 多图:
- 2 / 3 / 4 张图:前端会独立纵向显示每张图,同一个 Post 只显示一次时间。
- 超过 4 张图:前端显示 2×2 合并格,第 4 格模糊并显示 `+N`
## 2. Public API前台用户
### 2.1 分类列表
```http
GET /api/categories?lang=zh-CN
```
Response:
```ts
Category[]
```
用途Home 资料分类、CategoryPage 标题、Admin 表单分类选择。
---
### 2.2 全部资料 / 分类资料流
```http
GET /api/posts?lang=zh-CN&limit=20&cursor=<cursor>&type=all&language=&category=<slug>
```
Query:
| 参数 | 必填 | 说明 |
|---|---:|---|
| `lang` | 是 | UI 语言 |
| `limit` | 否 | 默认 20最大建议 50 |
| `cursor` | 否 | 后端返回的不透明 cursor |
| `category` | 否 | 不传 = 全部资料;传 slug = 单分类 |
| `type` | 否 | `all/image/video/ppt/pdf/text/link/archive` |
| `language` | 否 | 资料语言:`zh-TW/zh-CN/en` |
Response:
```ts
PostListResponse
```
排序:`publishedAt DESC`
用途:
- `/browse`:不传 `category`
- `/category/:slug`:传 `category=<slug>`
---
### 2.3 Home 推荐资料
```http
GET /api/posts/recommended?lang=zh-CN&limit=12
```
Response:
```ts
{ items: Post[] }
```
用途Home「官方推荐」section。按 `sortOrder ASC` + `publishedAt DESC` 或后端自定义推荐顺序。
> 过渡期:当前前端 Home 仍可接受旧 `/api/resources/recommended`,但建议后端新做 `posts/recommended` 后前端再切换。
---
### 2.4 Home 最新资料
```http
GET /api/posts/latest?lang=zh-CN&limit=8
```
Response:
```ts
{ items: Post[] }
```
用途Home「最新更新」section。按 `publishedAt DESC`
> 过渡期:当前前端 Home 仍可接受旧 `/api/resources/latest`。
---
### 2.5 单条 Post旧链接落地
```http
GET /api/posts/:id
```
Response:
```ts
Post
```
用途:旧 `/resource/:id` 前端重定向:拿 `categorySlug` 后跳到 `/category/<slug>#post-<id>`
---
### 2.6 搜索
建议新接口:
```http
GET /api/posts/search?q=<keyword>&lang=zh-CN&type=all&language=&cursor=&limit=20
```
Response:
```ts
PostListResponse
```
搜索范围建议:`text``filename``categoryName`、tags。
过渡期当前前端仍使用:
```http
GET /api/resources?q=<keyword>&lang=&type=&language=&limit=50
```
Response:
```ts
{ items: Resource[] }
```
---
### 2.7 搜索日志
```http
POST /api/search-log
Content-Type: application/json
{ "query": "ARK" }
```
Response204 或 `{ ok: true }`
用途:记录用户搜索词;失败不阻断用户体验。
---
### 2.8 下载统计(可选)
文件下载目前前端可直接打开 `Attachment.url`。如果后端需要统计下载,提供:
```http
POST /api/posts/:postId/attachments/:attachmentId/download
```
Response204 或 `{ ok: true }`
> 过渡期旧 Home 推荐卡还可能调用 `POST /api/resources/:id/download`。
## 3. Filter 语义
`GET /api/posts``type` 参数建议按以下规则命中:
| type | 命中条件 |
|---|---|
| `all` | 全部 |
| `image` | 任一 attachment `kind === "image"` |
| `video` | 任一 attachment `kind === "video"``mime.startsWith("video/")` |
| `pdf` | 任一 attachment 扩展名 `pdf``mime === "application/pdf"` |
| `ppt` | 任一 attachment 扩展名 `ppt/pptx/key` 或 mime 含 `presentation` |
| `archive` | 任一 attachment 扩展名 `zip/rar/7z/tar/gz` |
| `text` | `text` 非空 |
| `link` | `text` 中包含 `https?://` |
## 4. Wallet Auth API
### 4.1 取得签名 nonce/message
```http
POST /api/auth/wallet/nonce
Content-Type: application/json
{ "address": "0x..." }
```
Response:
```ts
{ message: string }
```
### 4.2 验证签名并签发 token
```http
POST /api/auth/wallet/verify
Content-Type: application/json
{
"address": "0x...",
"message": "...",
"signature": "0x..."
}
```
Response:
```ts
{ token: string }
```
### 4.3 验证当前 wallet session
```http
GET /api/auth/wallet/me
Authorization: Bearer <wallet-token>
```
Response:
```ts
{ wallet: string }
```
## 5. Admin API
### 5.1 Admin 登录
```http
POST /api/admin/login
Content-Type: application/json
{ "username": "...", "password": "..." }
```
Response:
```ts
{ token: string }
```
---
### 5.2 Admin dashboard
```http
GET /api/admin/dashboard
Authorization: Bearer <admin-token>
```
Response:
```ts
type AdminDashboard = {
totalResources: number; // 若迁移到 Post可理解为 totalPosts
published: number;
todayNew: number;
totalViews: number;
totalDownloads: number;
totalFavorites: number; // 收藏下线后可返回 0避免旧 admin UI 崩
totalShares: number;
hotResources: {
id: string;
title: string;
downloads: number;
favorites: number; // 可返回 0
views: number;
}[];
};
```
---
### 5.3 文件上传
```http
POST /api/admin/upload
Authorization: Bearer <admin-token>
Content-Type: multipart/form-data
file=<File>
```
最低 Response:
```ts
{ url: string }
```
建议 Response更方便前端自动建 Attachment
```ts
{
url: string;
mime: string;
filename: string;
sizeBytes: number;
width?: number;
height?: number;
durationSec?: number;
thumbnailUrl?: string;
posterUrl?: string;
}
```
---
### 5.4 Admin Post 列表
```http
GET /api/admin/posts?limit=25&page=1&status=&category=&type=&q=
Authorization: Bearer <admin-token>
```
Response:
```ts
{
items: AdminPost[];
total: number;
}
type AdminPost = Post & {
isPublic: boolean;
sortOrder: number;
status: "draft" | "published" | "archived";
viewCount?: number;
downloadCount?: number;
};
```
---
### 5.5 Admin Post 详情
```http
GET /api/admin/posts/:id
Authorization: Bearer <admin-token>
```
Response`AdminPost`
---
### 5.6 创建 Post
```http
POST /api/admin/posts
Authorization: Bearer <admin-token>
Content-Type: application/json
```
Request:
```ts
type UpsertPostPayload = {
categoryId: number;
language: "zh-TW" | "zh-CN" | "en";
text?: string;
attachments: Attachment[];
isPublic: boolean;
isRecommended: boolean;
sortOrder: number;
status: "draft" | "published" | "archived";
publishedAt?: string;
tags?: string[];
};
```
Response`AdminPost`
---
### 5.7 更新 Post
```http
PUT /api/admin/posts/:id
Authorization: Bearer <admin-token>
Content-Type: application/json
```
Request`UpsertPostPayload`
Response`AdminPost`
---
### 5.8 删除 Post
```http
DELETE /api/admin/posts/:id
Authorization: Bearer <admin-token>
```
Response204 或 `{ ok: true }`
---
### 5.9 Admin 搜索日志
```http
GET /api/admin/search-logs?limit=300
Authorization: Bearer <admin-token>
```
Response:
```ts
{
items: {
id: string;
query: string;
createdAt: string;
count?: number;
}[];
}
```
## 6. 过渡期旧 Resource API如果 admin 尚未迁移)
当前部分前端/admin 代码仍可能使用旧接口。后端可以短期保留,或前端后续再统一切到 Post
```http
GET /api/resources?lang=&limit=&page=&sort=&q=&type=&language=&tag=
GET /api/resources/recommended?lang=&limit=
GET /api/resources/latest?lang=&limit=
POST /api/resources/:id/download
GET /api/admin/resources?limit=&page=
GET /api/admin/resources/:id
POST /api/admin/resources
PUT /api/admin/resources/:id
```
`Resource` shape
```ts
type Resource = {
id: string;
title: string;
description?: string;
type: string;
language: string;
categoryId: number;
categorySlug: string;
categoryName: string;
coverImage?: string;
fileUrl?: string;
previewUrl?: string;
externalUrl?: string;
bodyText?: string;
badgeLabel?: string;
isDownloadable: boolean;
isRecommended: boolean;
publishedAt?: string;
updatedAt: string;
tags?: string[];
};
```
## 7. 已下线 / 不需要实现
- 用户收藏:`/favorites` 页面已移除。
- `POST /api/resources/:id/favorite` 不需要。
- Reaction / 点赞 / 评论不需要。
- Telegram 管理员标签、头像、群组名不需要。
## 8. 前后端切换计划
1. 后端先实现 `/api/posts``/api/posts/:id``/api/categories`
2. 前端 staging 设置:`VITE_USE_MOCK_POSTS=false`
3. 确认 `/browse``/category/:slug` 正常拉真数据。
4. 再实现 `/api/posts/recommended``/api/posts/latest`,前端把 Home 从旧 resources 切到 posts。
5. 最后迁移 Admin 从 `/api/admin/resources``/api/admin/posts`
## 9. 最小可上线优先级
### P0前台资料流必需
- `GET /api/categories`
- `GET /api/posts`
- `GET /api/posts/:id`
- `POST /api/admin/upload`
- `POST /api/admin/posts`
- `PUT /api/admin/posts/:id`
- `GET /api/admin/posts`
- `GET /api/admin/posts/:id`
### P1首页/搜索/统计)
- `GET /api/posts/recommended`
- `GET /api/posts/latest`
- `GET /api/posts/search`
- `POST /api/search-log`
- `GET /api/admin/dashboard`
- `GET /api/admin/search-logs`
### P2账户
- Wallet nonce / verify / me