docs: add backend onboarding guide

This commit is contained in:
TerryM
2026-05-18 07:56:27 +08:00
parent 141d92dc15
commit 00540fbb73
6 changed files with 1067 additions and 0 deletions

360
docs/API.md Normal file
View File

@@ -0,0 +1,360 @@
# API Reference
Base URL in local development: `http://localhost:8080`.
Frontend usually calls paths like `/api/resources`; uploaded files are available under `/uploads/...`.
## Response style
Most responses are JSON. Errors use plain text via `http.Error`, for example `unauthorized` or `bad json`.
## Health
### `GET /healthz`
Returns plain text:
```text
ok
```
### `GET /health`
Same as `/healthz`.
## Public categories/resources
### `GET /api/categories`
Query/header language behavior:
- `?lang=zh-CN` returns Simplified Chinese name when available.
- `?lang=en` returns English name when available.
- otherwise Traditional Chinese is preferred.
Response:
```json
[
{
"id": 1,
"slug": "project-ppt",
"name": "項目資料PPT",
"description": "ARK 項目介紹、簡報與對外展示資料",
"iconKey": "folder",
"sortOrder": 1,
"updatedAt": "2026-01-01T00:00:00Z"
}
]
```
### `GET /api/resources`
Returns paginated public resources.
Query params:
| Param | Meaning |
| --- | --- |
| `page` | page number, default 1 |
| `limit` | page size, default 20, max 100 |
| `q` | search title/description/tag name |
| `type` | resource type; `all` means no filter |
| `language` | exact resource language filter |
| `category` | category slug |
| `tag` | tag slug or tag name, case-insensitive |
| `sort` | `latest` default, `published`, `recommended`, `popular` |
| `lang` | category display language, e.g. `en`, `zh-CN` |
Response:
```json
{
"items": [
{
"id": "uuid",
"title": "ARK 項目介紹簡報(示例)",
"description": "適合線下宣講與新人培訓。",
"type": "ppt",
"language": "zh-TW",
"categoryId": 1,
"categorySlug": "project-ppt",
"categoryName": "項目資料PPT",
"coverImage": "/uploads/placeholder-cover.svg",
"fileUrl": "/uploads/placeholder-cover.svg",
"isDownloadable": true,
"isRecommended": true,
"publishedAt": "2026-01-01T00:00:00Z",
"updatedAt": "2026-01-01T00:00:00Z",
"tags": ["官方推薦"]
}
],
"page": 1,
"limit": 20,
"total": 1
}
```
### `GET /api/resources/recommended?limit=12`
Returns recommended resources:
```json
{ "items": [] }
```
Max limit is 50.
### `GET /api/resources/latest?limit=12`
Returns latest resources:
```json
{ "items": [] }
```
### `GET /api/resources/popular?limit=12`
Returns resources ordered by download + favorite + share count:
```json
{ "items": [] }
```
### `GET /api/resources/{id}`
Returns one published public resource. `{id}` must be a UUID.
### `GET /api/resources/{id}/related`
Returns up to 8 resources from the same category:
```json
{ "items": [] }
```
## Public activity endpoints
### `POST /api/search-log`
Request:
```json
{ "query": "ark" }
```
Response:
```json
{ "ok": true }
```
### `POST /api/resources/{id}/view`
Increments view count.
Response:
```json
{ "ok": true }
```
### `POST /api/resources/{id}/download`
Increments download count.
### `POST /api/resources/{id}/share`
Increments share count.
### `POST /api/resources/{id}/favorite`
Request:
```json
{ "add": true }
```
- `add: true` increments favorite count.
- `add: false` decrements favorite count but not below zero.
## Wallet auth
Wallet auth is for normal users, not admin users.
### `POST /api/auth/wallet/nonce`
Request:
```json
{ "address": "0x0000000000000000000000000000000000000000" }
```
Response:
```json
{
"nonce": "hex-code",
"message": "ARK Database — wallet sign-in\n\nWallet: 0x...\nOne-time code: ..."
}
```
The frontend asks the wallet to sign `message`.
### `POST /api/auth/wallet/verify`
Request:
```json
{
"address": "0x0000000000000000000000000000000000000000",
"message": "same message from nonce endpoint",
"signature": "0x..."
}
```
Response:
```json
{
"token": "jwt",
"wallet": "0xChecksumAddress"
}
```
### `GET /api/auth/wallet/me`
Requires header:
```http
Authorization: Bearer <wallet-jwt>
```
Response:
```json
{ "wallet": "0xChecksumAddress", "role": "user" }
```
## Admin auth
### `POST /api/admin/login`
Request:
```json
{ "email": "admin@ark.local", "password": "admin123" }
```
Response:
```json
{ "token": "admin-jwt" }
```
Use this token for admin endpoints:
```http
Authorization: Bearer <admin-jwt>
```
## Admin endpoints
All endpoints below require admin JWT.
### `GET /api/admin/dashboard`
Response includes counts and hot resources:
```json
{
"totalResources": 10,
"published": 8,
"todayNew": 1,
"totalViews": 100,
"totalDownloads": 20,
"totalFavorites": 5,
"totalShares": 3,
"hotResources": []
}
```
### `GET /api/admin/search-logs?limit=200`
Max limit is 500.
Response:
```json
{ "items": [{ "id": 1, "query": "ark", "createdAt": "2026-01-01T00:00:00Z" }] }
```
### `GET /api/admin/resources?page=1&limit=20`
Lists all resources, including drafts/private resources.
### `GET /api/admin/resources/{id}`
Gets one resource by UUID.
### `POST /api/admin/resources`
Creates a resource.
Example request body:
```json
{
"title": "Example",
"description": "Short text",
"type": "ppt",
"language": "zh-TW",
"categoryId": 1,
"coverImage": "/uploads/example.svg",
"fileUrl": "/uploads/example.pdf",
"previewUrl": "",
"externalUrl": "",
"bodyText": "",
"badgeLabel": "新人必看",
"isPublic": true,
"isDownloadable": true,
"isRecommended": false,
"sortOrder": 0,
"status": "draft",
"tags": ["教程"]
}
```
### `PUT /api/admin/resources/{id}`
Updates a resource. Body shape is the same as create.
### `DELETE /api/admin/resources/{id}`
Deletes a resource.
Response:
```json
{ "ok": true }
```
### `POST /api/admin/upload`
Multipart upload with field name `file`.
Response for local storage:
```json
{ "url": "/uploads/generated-name.ext", "filename": "generated-name.ext", "storage": "local" }
```
Response for S3:
```json
{ "url": "https://...", "filename": "generated-name.ext", "storage": "s3" }
```
### `GET /api/admin/categories`
Same handler as public categories; returns visible categories.