---
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-CN` / `en` / `ja` / `ko` / `vi` / `id` / `ms`；默认语言为 `en`。中文只有简体 `zh-CN`，没有繁体中文。
- 错误格式：非 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-CN" | "en" | "ja" | "ko" | "vi" | "id" | "ms";
  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=en
```

Response:

```ts
Category[]
```

用途：Home 资料分类、CategoryPage 标题、Admin 表单分类选择。

---

### 2.2 全部资料 / 分类资料流

```http
GET /api/posts?lang=en&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/en/ja/ko/vi/id/ms`            |

Response:

```ts
PostListResponse;
```

排序：`publishedAt DESC`。

用途：

- `/browse`：不传 `category`
- `/category/:slug`：传 `category=<slug>`

---

### 2.3 Home 推荐资料

```http
GET /api/posts/recommended?lang=en&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=en&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=en&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" }
```

Response：204 或 `{ ok: true }`。

用途：记录用户搜索词；失败不阻断用户体验。

---

### 2.8 下载统计（可选）

文件下载目前前端可直接打开 `Attachment.url`。如果后端需要统计下载，提供：

```http
POST /api/posts/:postId/attachments/:attachmentId/download
```

Response：204 或 `{ 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-CN" | "en" | "ja" | "ko" | "vi" | "id" | "ms";
  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>
```

Response：204 或 `{ 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
