HNU-TimeLetter reads all external service credentials and runtime tuning parameters from environment variables. In local development these live inDocumentation 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.
.env.local (copied from .env.example); in production they are injected by the host as repository or environment secrets. This page documents every variable in .env.example, explains how to obtain the required values, and highlights the security constraints that must be met before going to production.
Creating Your .env.local
Start by copying the example file that ships with the repository:.env.local is listed in .gitignore and will never be committed to version control. Never commit credentials directly to the repository.
Feishu Credentials
These two variables authenticate every call to the Feishu Open API and are required for both the sync script and the admin-triggered sync endpoint.| Variable | Required | Description |
|---|---|---|
FEISHU_APP_ID | ✅ Required | The App ID of your Feishu enterprise application, e.g. cli_a1b2c3d4e5f6g7h8. |
FEISHU_APP_SECRET | ✅ Required | The App Secret paired with FEISHU_APP_ID. Keep this value confidential. |
How to obtain Feishu app credentials
Create an enterprise application
Open the Feishu Developer Console and click Create Application → Enterprise Self-built App. Give the app a name (e.g. “HNU-TimeLetter Sync”) and confirm creation. The App ID and App Secret are shown on the application’s Credentials & Basic Info page.
Enable Bitable permissions
Navigate to Permissions & Scopes in the left sidebar. Search for and enable the following permission scopes:
bitable:app— read Bitable application databitable:app:readonly— read records and attachments from Bitable tables
Add the application to your Bitable document
Open the Feishu Bitable document that contains your content tables. Click ··· (more options) → Add application and search for the app you just created. Grant it Viewer or higher access. The sync script will not be able to read table records unless this step is completed.
Homepage Stories (Feishu Table Identifiers)
These variables identify the specific Bitable tables and views that hold homepage story content and campus location data. All values can be read directly from the URL of each table when viewed in a browser.| Variable | Required | Description | Example |
|---|---|---|---|
FEISHU_APP_TOKEN | ✅ Required | The Bitable application token — the long alphanumeric ID in the Bitable document URL after /base/. | xxxxxxxxxxxxxxxxxxxxxx |
FEISHU_TABLE_ID | ✅ Required | The table ID of the homepage stories table, found in the URL after ?table=. | tblxxxxxxxxxxxxxxxx |
FEISHU_VIEW_ID | ✅ Required | The view ID of the homepage stories view, found in the URL after &view=. | vewxxxxxxxxxxxxxxxx |
FEISHU_LOCATIONS_TABLE_ID | ✅ Required | The table ID of the campus locations / map-pin reference table. | tblxxxxxxxxxxxxxxxx |
The Bitable document URL typically looks like:
https://your-company.feishu.cn/base/{APP_TOKEN}?table={TABLE_ID}&view={VIEW_ID}
Copy the three highlighted segments directly into the corresponding environment variables.Creation Board
The Creation Board (/creation) is powered by its own set of Feishu tables, separate from the homepage stories, allowing the community submission workflow to be managed independently.
| Variable | Required | Description | Example |
|---|---|---|---|
FEISHU_CREATION_TABLE_ID | ✅ Required | Table ID of the main creation-idea records table. | tblxxxxxxxxxxxxxxxx |
FEISHU_CREATION_VIEW_ID | ✅ Required | View ID within the creation table used for the public board display. | vewxxxxxxxxxxxxxxxx |
FEISHU_CREATION_HEADER_TABLE_ID | ✅ Required | Table ID of the board header/banner configuration table. Controls the announcement or title card shown at the top of the creation board. | tblxxxxxxxxxxxxxxxx |
Contributors
The Credits section on the homepage and the contributors list are sourced from a dedicated Bitable table.| Variable | Required | Description | Example |
|---|---|---|---|
FEISHU_CONTRIBUTORS_TABLE_ID | ✅ Required | Table ID of the contributors / credits table. Records from this table are written to src/data/contributors.json during sync. | tblxxxxxxxxxxxxxxxx |
Aliyun OSS
During sync, the script downloads image attachments from Feishu and re-uploads them to Aliyun OSS. The resulting public OSS URLs are written into the JSON artifacts and rendered directly in the frontend — the browser never fetches images from Feishu.| Variable | Required | Description | Example |
|---|---|---|---|
ALIYUN_OSS_REGION | ✅ Required | The OSS region endpoint identifier where your bucket resides. | oss-cn-hangzhou |
ALIYUN_OSS_BUCKET | ✅ Required | The name of the OSS bucket to store uploaded images. | hnu-timeletter-assets |
ALIYUN_OSS_ACCESS_KEY_ID | ✅ Required | Aliyun RAM user Access Key ID with oss:PutObject permission. | LTAI5txxxxxxxxxxxxxxxx |
ALIYUN_OSS_ACCESS_KEY_SECRET | ✅ Required | The secret paired with ALIYUN_OSS_ACCESS_KEY_ID. Keep this value confidential. | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
OSS bucket setup checklist
- Create a bucket in the Aliyun OSS Console. Choose the same region as your deployment server for lowest latency.
- Set the bucket’s Access Control to Public Read (
public-read). This allows the Next.js frontend to render images via their direct OSS URLs without signed tokens. - Under Bucket Settings → CORS, add a rule that allows
*for Allowed Origins,GET, HEADfor Allowed Methods, and*for Allowed Headers. This ensures browsers can load images cross-origin if your domain differs from the OSS endpoint. - Create a dedicated RAM sub-user with only the
oss:PutObjectandoss:GetObjectpolicies scoped to your specific bucket. Do not use your root account Access Key.
Admin Authentication
The/admin route and all api/admin/ endpoints are protected by session-based authentication. Three secrets govern this subsystem.
| Variable | Required | Description | Example |
|---|---|---|---|
ADMIN_PASSWORD | ✅ Required | The plaintext password for the admin login form at /admin. Only one admin account exists; there is no user database. | a-strong-passphrase-here |
ADMIN_SESSION_SECRET | ✅ Required | A random string used to sign the admin session cookie. Must be at least 32 bytes (characters) long in production. | s3cr3t-r4nd0m-str1ng-min-32-ch4rs!! |
SYNC_WEBHOOK_SECRET | ✅ Required | A separate random secret used to authenticate webhook-triggered sync requests. Must differ from ADMIN_PASSWORD. | wh-secr3t-independent-v4lue-here |
Keep
SYNC_WEBHOOK_SECRET separate from ADMIN_PASSWORD. The webhook secret may appear in server access logs as a query parameter or request header, depending on how the sync trigger is integrated with external CI/CD systems. If it were the same value as ADMIN_PASSWORD, a leaked webhook log entry would also compromise admin access. Use independently generated random values for both.Sync Runtime
These variables control the behaviour of the sync process itself — where it writes lock files and logs, and how long it waits before considering a sync run stalled.| Variable | Required | Default | Description |
|---|---|---|---|
SYNC_RUNTIME_DIR | Optional | runtime | Directory (relative to the project root) where the sync lock file is written. The lock file prevents two concurrent sync processes from running simultaneously. |
SYNC_LOG_DIR | Optional | logs/sync | Directory (relative to the project root) where per-run sync log files are written. The admin panel reads these logs to display the sync history. |
SYNC_LOCK_TIMEOUT_MS | Optional | 1800000 | Maximum time in milliseconds a sync lock is considered valid before it is forcibly released. Defaults to 30 minutes (1 800 000 ms). Increase this value if your Feishu table has a very large number of image attachments. |
The default values (
runtime, logs/sync, 1800000) are pre-filled in .env.example and are safe for both local development and production use. You only need to override them if your deployment environment restricts writes to specific directories or imposes stricter concurrency constraints.Image Optimisation
| Variable | Required | Default | Description |
|---|---|---|---|
NEXT_PUBLIC_DISABLE_IMAGE_OPTIMIZATION | Optional | false | Set to true to bypass Next.js <Image> optimisation entirely. Useful on constrained self-hosted environments without a compatible sharp binary, or when all images are already optimised before upload to OSS. Setting this to true means images are served at their original OSS dimensions with no resizing or format conversion. |
Complete .env.example Reference
For quick copy-paste, here is the full.env.example as it ships in the repository:
.env.example