docs: add backend onboarding guide
This commit is contained in:
360
docs/API.md
Normal file
360
docs/API.md
Normal 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.
|
||||
Reference in New Issue
Block a user