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.

HNU-TimeLetter is a live-data application: every story, map pin, creation-board card, and contributor credit is pulled from Feishu Bitable at sync time and served from typed JSON files at runtime. This guide walks you from a fresh clone to a fully running local development server in four steps, assuming you already have valid Feishu app credentials and an Aliyun OSS bucket available.
HNU-TimeLetter ships without mock data. The src/data/ directory will contain empty or missing JSON files until npm run sync completes successfully against a real Feishu Bitable instance. Skipping or failing the sync step means the homepage, map, and creation board will all render empty. Configure your .env.local fully before starting the dev server.
1

Clone the repository and install dependencies

Ensure you are running Node.js 20 or later before proceeding. The project uses tsx to execute TypeScript scripts directly, and Turbopack for the dev server — both require a modern Node runtime.
node --version   # must print v20.x.x or higher
Clone the repository and install all dependencies with a single command:
git clone https://github.com/HNU-himematsu/HNU-TimeLetter.git
cd HNU-TimeLetter
npm install
npm install resolves both production dependencies (Next.js, Framer Motion, Zustand, Lenis, @waaark/luge, node-schedule, dotenv) and dev dependencies (TypeScript, Tailwind CSS v4, ESLint, tsx).
After install completes, run the two quality checks to verify your toolchain is wired up correctly before you add any credentials:
npm run typecheck   # tsc --noEmit  — zero TypeScript errors expected on a clean clone
npm run lint        # eslint         — zero lint errors expected on a clean clone
If either command fails on a fresh clone, check that your Node.js version is ≥ 20 and that npm install completed without errors.
2

Copy .env.example and fill in your credentials

The repository ships an .env.example that lists every variable the application reads. Copy it to .env.local — Next.js loads .env.local automatically and it is excluded from version control by .gitignore.
cp .env.example .env.local
Open .env.local in your editor and fill in the following key groups. All variables are documented in detail on the Environment Variables page.Feishu app credentials (required for all sync operations):
FEISHU_APP_ID=cli_xxxxxxxxxxxxxxxx
FEISHU_APP_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Feishu Bitable table identifiers (obtained from each table’s URL in Feishu):
# Homepage stories
FEISHU_APP_TOKEN=xxxxxxxxxxxxxxxxxxxxxx
FEISHU_TABLE_ID=tblxxxxxxxxxxxxxxxx
FEISHU_VIEW_ID=vewxxxxxxxxxxxxxxxx
FEISHU_LOCATIONS_TABLE_ID=tblxxxxxxxxxxxxxxxx

# Creation board
FEISHU_CREATION_TABLE_ID=tblxxxxxxxxxxxxxxxx
FEISHU_CREATION_VIEW_ID=vewxxxxxxxxxxxxxxxx
FEISHU_CREATION_HEADER_TABLE_ID=tblxxxxxxxxxxxxxxxx

# Contributors / credits
FEISHU_CONTRIBUTORS_TABLE_ID=tblxxxxxxxxxxxxxxxx
Aliyun OSS (image attachment storage):
ALIYUN_OSS_REGION=oss-cn-hangzhou
ALIYUN_OSS_BUCKET=your-bucket-name
ALIYUN_OSS_ACCESS_KEY_ID=LTAI5txxxxxxxxxxxxxxxx
ALIYUN_OSS_ACCESS_KEY_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Admin authentication (required to access /admin):
ADMIN_PASSWORD=your-admin-password
ADMIN_SESSION_SECRET=a-random-string-of-at-least-32-bytes
SYNC_WEBHOOK_SECRET=another-independent-random-secret
The default values for sync runtime variables are already pre-filled in .env.example and are safe to keep as-is for local development:
SYNC_RUNTIME_DIR=runtime
SYNC_LOG_DIR=logs/sync
SYNC_LOCK_TIMEOUT_MS=1800000
The frontend activity-notice Feishu document popup calls /api/feishu-jsapi-signature. For that specific feature to work in a local browser session you need FEISHU_APP_ID and FEISHU_APP_SECRET set, and the target Feishu document must grant read access to your app.
3

Run the Feishu sync to populate src/data/

With credentials in place, pull all content from Feishu Bitable and write it to the local JSON artifacts:
npm run sync
Under the hood this executes tsx src/scripts/sync-feishu.ts, which:
  1. Authenticates with the Feishu Open API using FEISHU_APP_ID and FEISHU_APP_SECRET to obtain a tenant access token.
  2. Fetches all records from the homepage stories table (FEISHU_TABLE_ID / FEISHU_VIEW_ID), the creation board tables, and the contributors table.
  3. Downloads image attachments referenced in Feishu records.
  4. Uploads each image to your Aliyun OSS bucket and rewrites the attachment field with the public OSS URL.
  5. Shapes the fetched data into the domain types defined in src/lib/types.ts and writes three JSON files:
src/data/content.json          ← homepage stories (Story[])
src/data/creation-board.json   ← community creation board (CreationCard[])
src/data/contributors.json     ← credits / acknowledgements
A successful sync prints a summary of records fetched and assets uploaded. If any Feishu or OSS credential is missing or incorrect, the script will exit with a non-zero code and print the offending variable name.
You can re-run npm run sync at any time to pull the latest Feishu content without restarting the dev server. The runtime API routes serve these files with no-store cache headers, so the browser will reflect updates on the next client poll cycle — no rebuild required.
4

Start the development server

npm run dev
Next.js starts with Turbopack on http://localhost:3000. The four application routes are immediately accessible:
URLWhat you will see
http://localhost:3000Envelope opening ritual → scroll through About, Credits, and Footer sections
http://localhost:3000/mapInteractive campus map (desktop) or stamp-collection waterfall (mobile)
http://localhost:3000/creationCommunity creation board — sticky-note masonry grid
http://localhost:3000/adminAdmin login — enter ADMIN_PASSWORD to access the sync dashboard
The dev server supports hot module replacement. Editing components in src/components/ or pages in src/app/ will trigger instant in-browser updates without a full page reload.

Production Build

When you are ready to verify a production-quality build locally, run:
npm run build
This executes next build, compiling and optimising the application for production. For a workflow that mirrors the CI pipeline — sync first, then build — use the combined script:
npm run build:with-sync   # equivalent to: npm run sync && npm run build
Start the production server locally after a successful build:
npm run start   # serves the .next/ output on http://localhost:3000
Additional quality gates that run in CI and are worth running locally before opening a pull request:
npm run lint        # ESLint — check for code style violations
npm run typecheck   # tsc --noEmit — catch type errors without emitting output
npm audit --omit=dev  # Check production dependencies for known vulnerabilities
In a self-hosted production environment, GitHub Actions on the release branch runs the full quality gate → sync → build → deploy pipeline automatically. Environment variables (FEISHU_*, ALIYUN_*, ADMIN_*) must be configured as repository or environment secrets in GitHub Actions settings.

Build docs developers (and LLMs) love