All domain types for HNU-TimeLetter are defined in a single file —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.
src/lib/types.ts — which serves as the project’s Single Source of Truth (SSOT) for data shapes. This page describes every entity, its Feishu field mapping, the JSON artifact it ends up in, and the Zustand store slice that coordinates UI state at runtime. Reading this document alongside the Sync System architecture gives a complete picture of the journey data takes from Feishu spreadsheet to rendered page.
Data Flow Overview
src/data/*.json and src/config/locations.json are committed to the repository. They act as build-time fallback data for Vercel Preview deployments where no sync process runs, and as hot-swappable runtime data on the self-hosted production server.Entity Reference
1. Character
ACharacter represents a single Galgame-style avatar character. It corresponds to one row in the Feishu characters table. During sync, if 头像OSS_URL is empty the pipeline automatically downloads the 角色头像 attachment, uploads it to Aliyun OSS, and back-fills the resulting URL.
src/data/characters.json — array of Character.
2. Story
AStory is one exhibition record on the /map route. It pairs a high-resolution scene image with a character avatar and narrative text, pinned to a campus location. Character metadata (characterName, avatarUrl) is injected by the sync layer from the characters table rather than stored redundantly in Feishu; locationName is resolved at runtime from the LocationPoint list.
src/data/content.json — a LocationPoint[] where every point embeds its matched Story[].
3. LocationPoint
LocationPoint is a frontend aggregation struct, not a flat Feishu record. It combines the coordinate data from src/config/locations.json with all stories whose locationId matches, producing the pin objects rendered on the SVG campus map.
src/data/content.json — LocationPoint[] (stories nested inside each point).
4. CreationIdea
CreationIdea is the raw sync-layer record for one submission in the Feishu “揭示板” (creation board) table, view “收集结果”. It preserves the original field semantics exactly, including the submitter identity field that is stripped out before the data reaches the frontend.
Multiple
CreationIdea records may share the same cardId — this is intentional. The table is designed for repeated submission by different users contributing to the same card. Do not deduplicate by cardId at the sync stage.src/data/creation-board.json — CreationIdea[].
5. CreationEntry
CreationEntry is a frontend projection of CreationIdea. It is produced at page-render time by src/components/creation/utils.ts and is never written to disk. The only structural difference from CreationIdea is the omission of submitter — no Feishu identity is exposed client-side.
creation-board.json at render time.
6. CreationCard
CreationCard is the top-level unit rendered in the /creation waterfall. It does not exist in Feishu as a single record; it is assembled by grouping all CreationIdea entries sharing the same cardId, projecting each to a CreationEntry, and attaching the addIdeaUrl deep-link.
CreationCard. Assembled from creation-board.json and creation-board-headers.json.
7. Contributor
Contributor maps one row in the Feishu credits / contributors table. Field extraction uses broad Feishu field-name compatibility so the table can be renamed without breaking the sync.
src/data/contributors.json — Contributor[]. Consumed by the Credits section on the home page.
Artifact Summary
| Artifact path | TypeScript type | Updated by |
|---|---|---|
src/config/locations.json | LocationCoords (coordinate map) | locations sync module |
src/data/characters.json | Character[] | characters sync module |
src/data/content.json | LocationPoint[] | stories sync module |
src/data/creation-board-headers.json | CardHeaderInfo[] | creation_headers sync module |
src/data/creation-board.json | CreationIdea[] | creation_board sync module |
src/data/contributors.json | Contributor[] | contributors sync module |
Zustand Store State
Global UI state lives insrc/lib/store.ts. All four slices are flat — no nested objects — to keep cross-slice transitions atomic.
| Key | Type | Description |
|---|---|---|
isEnvelopeOpened | boolean | true once the user completes the envelope-open gesture. Controls Lenis activation and scroll-section visibility. |
isTransitioning | boolean | true during the full-screen wax-seal overlay that bridges the home route to /map. Pauses all scroll and interaction. |
selectedLocationId | string | null | ID of the active map pin. null means no pin is selected; the story panel is hidden. |
currentStoryIndex | number | Zero-based index of the story currently shown within the selected location’s card stack. Resets to 0 when selectedLocationId changes. |