--- 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 `。 ## 1. 核心数据模型 ### 1.1 Category ```ts type Category = { id: number; slug: string; // 用于 /category/:slug 和 GET /api/posts?category= 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=&type=all&language=&category= ``` 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=` --- ### 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/#post-`。 --- ### 2.6 搜索 建议新接口: ```http GET /api/posts/search?q=&lang=zh-CN&type=all&language=&cursor=&limit=20 ``` Response: ```ts PostListResponse ``` 搜索范围建议:`text`、`filename`、`categoryName`、tags。 过渡期当前前端仍使用: ```http GET /api/resources?q=&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 ``` 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 ``` 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 Content-Type: multipart/form-data 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 ``` 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 ``` Response:`AdminPost`。 --- ### 5.6 创建 Post ```http POST /api/admin/posts Authorization: Bearer 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 Content-Type: application/json ``` Request:`UpsertPostPayload`。 Response:`AdminPost`。 --- ### 5.8 删除 Post ```http DELETE /api/admin/posts/:id Authorization: Bearer ``` Response:204 或 `{ ok: true }`。 --- ### 5.9 Admin 搜索日志 ```http GET /api/admin/search-logs?limit=300 Authorization: Bearer ``` 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