Files
Arkie-Library-Backend/docs/API.md
2026-05-18 07:56:27 +08:00

6.0 KiB
Raw Blame History

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:

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:

[
  {
    "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:

{
  "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:

{ "items": [] }

Max limit is 50.

GET /api/resources/latest?limit=12

Returns latest resources:

{ "items": [] }

GET /api/resources/popular?limit=12

Returns resources ordered by download + favorite + share count:

{ "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:

{ "items": [] }

Public activity endpoints

POST /api/search-log

Request:

{ "query": "ark" }

Response:

{ "ok": true }

POST /api/resources/{id}/view

Increments view count.

Response:

{ "ok": true }

POST /api/resources/{id}/download

Increments download count.

POST /api/resources/{id}/share

Increments share count.

POST /api/resources/{id}/favorite

Request:

{ "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:

{ "address": "0x0000000000000000000000000000000000000000" }

Response:

{
  "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:

{
  "address": "0x0000000000000000000000000000000000000000",
  "message": "same message from nonce endpoint",
  "signature": "0x..."
}

Response:

{
  "token": "jwt",
  "wallet": "0xChecksumAddress"
}

GET /api/auth/wallet/me

Requires header:

Authorization: Bearer <wallet-jwt>

Response:

{ "wallet": "0xChecksumAddress", "role": "user" }

Admin auth

POST /api/admin/login

Request:

{ "email": "admin@ark.local", "password": "admin123" }

Response:

{ "token": "admin-jwt" }

Use this token for admin endpoints:

Authorization: Bearer <admin-jwt>

Admin endpoints

All endpoints below require admin JWT.

GET /api/admin/dashboard

Response includes counts and hot resources:

{
  "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:

{ "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:

{
  "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:

{ "ok": true }

POST /api/admin/upload

Multipart upload with field name file.

Response for local storage:

{ "url": "/uploads/generated-name.ext", "filename": "generated-name.ext", "storage": "local" }

Response for S3:

{ "url": "https://...", "filename": "generated-name.ext", "storage": "s3" }

GET /api/admin/categories

Same handler as public categories; returns visible categories.