Skip to content

Latest commit

 

History

History
559 lines (379 loc) · 11 KB

File metadata and controls

559 lines (379 loc) · 11 KB

Runbook v0.2

Purpose

This runbook covers non-visual operation of the tri-model personality API.

The UI can be built separately against the API contract.

Local Run

Requirements:

Node.js 24 or newer

Install the locked dependency set:

npm install

Run tests:

npm test

Start API server:

npm start

Default base URL:

http://localhost:3000

Health check:

GET /health

API endpoint index:

GET /api

Environment Variables

Use .env.example as the reference list.

npm start loads .env when the file exists. Deployment-provided environment variables still take precedence.

Required for basic dry-run mode:

none

Required for live explanation mode:

OPENAI_API_KEY
OPENAI_MODEL

Optional:

PORT
HOST
CORS_ORIGINS
TRUST_PROXY
APP_ACCESS_TOKEN
APP_OWNER_ID
REQUEST_LOGGING_ENABLED
RATE_LIMIT_ENABLED
RATE_LIMIT_WINDOW_MS
RATE_LIMIT_MAX
PROFILE_DATABASE_FILE
PROFILE_STORE_FILE
OPENAI_RESPONSES_URL
OPENAI_TIMEOUT_MS
OPENAI_MAX_OUTPUT_TOKENS
OPENAI_MAX_RETRIES

HOST defaults to 127.0.0.1. If it is changed to a non-loopback address, startup fails unless APP_ACCESS_TOKEN is configured. Protected API calls then require:

Authorization: Bearer <APP_ACCESS_TOKEN>

CORS_ORIGINS is a comma-separated allowlist. Wildcard origins are rejected. Set TRUST_PROXY=true only behind a trusted reverse proxy that overwrites x-forwarded-for.

UI Integration Flow

  1. Check server capability:
GET /health
  1. Optionally discover available endpoints:
GET /api
  1. Start the complete frontend experience when the UI wants one aggregated payload:
POST /api/experience/start
  1. Inspect the public comparison rule summary:
POST /api/rules/summary
  1. Validate form input before generation:
POST /api/profile/validate
  1. Preview a profile without saving:
POST /api/profile/preview
  1. Generate a profile:
POST /api/profile/generate
  1. Store profile_id in the UI state.

  2. Rebuild derived models when rules or providers change:

POST /api/profile/rebuild
  1. Rebuild selected profiles when rules or providers change:
POST /api/profile/rebuild-batch
  1. List profile summaries for a management or restore view:
POST /api/profile/list
  1. Fetch profile stats for dashboards or empty-state decisions:
POST /api/profile/stats
  1. Fetch the public profile if needed:
POST /api/profile/get
  1. Fetch deterministic comparison:
POST /api/profile/compare
  1. Export a profile package for download, backup, or external handoff:
POST /api/profile/export
  1. Export multiple selected profiles:
POST /api/profile/export-batch
  1. Import a previously exported profile package when restoring data:
POST /api/profile/import
  1. Import a previously exported profile batch package:
POST /api/profile/import-batch
  1. Build or run explanation:
POST /api/profile/explain

Use mode: "dry_run" until the live provider is configured.

  1. Delete or clear explanation history:
POST /api/profile/explanation/delete
POST /api/profile/explanation/clear
  1. Delete local profile data when it is no longer needed:
POST /api/profile/delete
  1. Delete multiple selected profiles:
POST /api/profile/delete-batch

Persistence

Default storage is memory-only. SQLite is the recommended single-user persistent store:

PROFILE_DATABASE_FILE=./data/profiles.sqlite

SQLite uses write-ahead logging and owner-scoped profile keys. The database file still contains private data and should not be committed or served as a static asset.

Legacy JSON persistence remains available for migration and small local demos:

PROFILE_STORE_FILE=./data/profiles.json

Use a managed database and replace the bearer-token authenticator before a multi-user production deployment.

Frontend Experience Endpoint

POST /api/experience/start is the preferred frontend entry point. It validates input, creates or refreshes the owner-scoped profile, returns the complete public profile, and optionally prepares or runs an explanation.

{
  "birth_date": "1990-03-15",
  "birth_time": "10:30",
  "location": "Shanghai",
  "timezone": "Asia/Shanghai",
  "mbti": "INTJ",
  "explanation_mode": "dry_run",
  "user_question": "What is the main tension?"
}

explanation_mode may be none, dry_run, or live. The response always keeps the generated profile available; an explanation-provider failure is reported in explanation_error without discarding the profile.

Listing

Validate profile form input:

{
  "birth_date": "1990-03-15",
  "birth_time": "10:30",
  "location": "Shanghai",
  "mbti": "INTJ"
}

Validation returns normalized input and does not save profile data.

Preview profile output without saving:

{
  "birth_date": "1990-03-15",
  "birth_time": "10:30",
  "location": "Shanghai",
  "mbti": "INTJ"
}

Preview returns the same public profile shape used by POST /api/profile/get, including the deterministic comparison model, but it does not store the profile.

Generate is idempotent within the authenticated owner. A new profile receives a random UUID; repeating the same normalized input for the same owner reuses that UUID and preserves created_at and explanation history. Another owner receives a different profile.

Inspect public comparison rules:

{}

The rules summary includes model authority, model weights, trait axes, context explanation keys, and zodiac date boundaries. It does not include profile data, prompts, or debug traces.

Rebuild an existing profile from stored birth_info:

{
  "profile_id": "string"
}

Rebuild preserves profile_id, created_at, and explanation history while refreshing derived models.

Rebuild selected profiles in batch:

{
  "profile_ids": ["string"]
}

Batch rebuild supports up to 50 ids, skips duplicates, reports missing ids in missing_profile_ids, and preserves each profile's profile_id, created_at, and explanation history.

List stored profile summaries:

{
  "limit": 50,
  "offset": 0,
  "mbti_type": "INTJ",
  "zodiac_sign": "Pisces",
  "bazi_day_master": "water",
  "has_explanations": false
}

The list response is intended for management views and restore entry points. It includes identifiers and model summaries, but not full birth_info.

limit and offset are optional. limit defaults to 50 and cannot exceed 100.

The filter fields are optional. Use them to build management views by MBTI type, zodiac sign, Bazi day master, or explanation-history status.

Profile stats:

{}

Stats include counts and distributions only. They do not include full profile data, birth data, explanations, or prompts.

Live LLM Mode

Dry-run request:

{
  "profile_id": "string",
  "mode": "dry_run"
}

Live request:

{
  "profile_id": "string",
  "mode": "live",
  "user_question": "Explain the main contradictions.",
  "include_history": true,
  "history_limit": 3
}

If live mode is not configured, the API returns 503.

Successful live explanations are persisted on the profile and returned by:

POST /api/profile/get

Dry-run explanation requests are not persisted.

Follow-up explanation requests include recent saved explanations by default. Set include_history to false for a standalone answer, or set history_limit from 1 to 10 to control how much context is sent.

Delete one explanation record:

{
  "profile_id": "string",
  "explanation_id": "string"
}

Clear all explanation records on a profile:

{
  "profile_id": "string"
}

Deletion

Delete profile data:

{
  "profile_id": "string"
}

Deletion removes the profile from the active store. With file storage enabled, the JSON store is rewritten without that profile.

Delete selected profiles in batch:

{
  "profile_ids": ["string"]
}

Batch delete supports up to 50 ids, skips duplicates, and reports missing ids in missing_profile_ids.

Export

Export profile data:

{
  "profile_id": "string"
}

The export response includes:

  • export_version
  • exported_at
  • profile

The profile payload uses the same public shape as POST /api/profile/get and excludes internal debug data.

Batch export selected profiles:

{
  "profile_ids": ["string"]
}

Batch export supports up to 50 ids, skips duplicates, and reports missing ids in missing_profile_ids.

Import

Import a profile export package:

{
  "export_version": "profile_export.v0",
  "overwrite": false,
  "profile": {}
}

Import defaults to no overwrite. If a profile with the same profile_id already exists, pass:

{
  "overwrite": true
}

Imported birth input and explanation records are validated before save. Derived Bazi, Zodiac, MBTI status, and comparison fields are recomputed from birth_info, so edited export calculations cannot poison stored results.

Import a profile batch export package:

{
  "export_version": "profile_export_batch.v0",
  "overwrite": false,
  "profiles": []
}

Batch import supports up to 50 profiles, skips duplicate ids in the same request, and skips existing profiles unless overwrite is true.

Logging

Request logs are structured JSON.

Logged fields:

  • request_id
  • method
  • path
  • status
  • duration_ms

Not logged:

  • request body
  • birth data
  • MBTI values
  • LLM prompts
  • API keys

Each response includes:

x-request-id

Common Errors

validation_failed

The request body has invalid fields. Check error.details.fields.

profile_not_found

The profile id does not exist in the current store.

If using memory storage, restart clears all profiles.

profile_already_exists

Import found an existing profile with the same id. Retry with overwrite: true only when replacing that profile is intentional.

missing_openai_api_key

Live explanation mode requires OPENAI_API_KEY.

missing_openai_model

Live explanation mode requires OPENAI_MODEL.

invalid_llm_output

The provider returned JSON that did not match the required explanation shape.

explanation_not_found

The profile exists, but the requested explanation id does not.

rate_limit_exceeded

Too many requests were sent in the configured time window. Check retry-after and error.details.retry_after_ms.

Current Known Boundary

The default Bazi provider is lunar_javascript_cn. It uses computed Jie Qi boundaries through lunar-javascript and accepts Asia/Shanghai civil time. The response includes calendar_basis so the frontend can disclose the basis. Location is retained as metadata; true-solar-time longitude correction is not yet applied.

It is deterministic and useful for MVP product testing, but it is not a high-precision astronomical calendar implementation.

See bazi-provider-contract.md before replacing the provider.