Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/HNU-himematsu/HNU-TimeLetter/llms.txt

Use this file to discover all available pages before exploring further.

The /api/content endpoint is the primary data feed for the HNU-TimeLetter interactive map. It returns every campus location pinned on the SVG campus overlay, together with all galgame-style character stories nested under each location. The data is produced by the Feishu sync pipeline and written to src/data/content.json; the endpoint reads that file at request time, so new stories appear immediately after a sync completes — no build or server restart is needed.

Endpoint

GET /api/content
Authentication: None — this is a fully public endpoint. Query parameters: None.

Response — 200 OK

Returns a JSON object with a single top-level key, locations, containing an array of LocationPoint objects. Each LocationPoint embeds its own stories array.
{
  "locations": [
    {
      "id": "lib-001",
      "name": "图书馆",
      "x": 25,
      "y": 60,
      "stories": [
        {
          "id": "story_001",
          "characterId": "char_001",
          "characterName": "姬松",
          "avatarUrl": "https://oss.himematsu.cn/avatars/himematsu-q.png",
          "mainImageUrl": "https://oss.himematsu.cn/images/story_001_main.png",
          "content": "那天在图书馆,我第一次遇见了她……",
          "author": "Aki",
          "locationId": "lib-001",
          "locationName": "图书馆"
        }
      ]
    },
    {
      "id": "canteen-002",
      "name": "学生食堂",
      "x": 52,
      "y": 38,
      "stories": []
    }
  ]
}

Schema

locations
LocationPoint[]
required
Array of campus location points displayed on the SVG map overlay. Each entry carries its own nested story list.

TypeScript example

interface Story {
  id: string;
  characterId: string;
  characterName: string;
  avatarUrl: string;
  mainImageUrl: string;
  content: string;
  author: string;
  locationId: string;
  locationName?: string;
}

interface LocationPoint {
  id: string;
  name: string;
  x: number;
  y: number;
  stories: Story[];
}

interface ContentResponse {
  locations: LocationPoint[];
}

async function fetchContent(): Promise<ContentResponse> {
  const res = await fetch("/api/content");
  if (!res.ok) {
    throw new Error(`Failed to fetch content: ${res.status}`);
  }
  return res.json() as Promise<ContentResponse>;
}

// Usage
const { locations } = await fetchContent();
const library = locations.find((loc) => loc.id === "lib-001");
console.log(`${library?.name} has ${library?.stories.length} stories`);

Data source

This endpoint reads src/data/content.json at runtime on every request. The file is generated by the Feishu sync pipeline, which pulls from the Feishu 地点表 (locations table) and 故事表 (stories table) and merges them into a single nested structure.Run npm run sync or trigger a sync from the admin dashboard to refresh the data. No build step and no server restart are required — the updated JSON is served immediately on the next request.
The sync pipeline writes two intermediate files during the locations+stories sync step:
FileContent
src/config/locations.jsonFlat array of location metadata (id, name, x, y)
src/data/content.jsonMerged LocationPoint[] with nested Story[] arrays
The /api/content endpoint serves exclusively from src/data/content.json.

Build docs developers (and LLMs) love