@proj-airi/api-server
Project AIRI's resource API. Authentication is a separate workspace app at
server/apps/auth; this package does not instantiate Better Auth or expose
auth/OIDC routes.
Responsibilities
- Hono business APIs and WebSocket endpoints.
- Characters, chats, providers, Flux, Stripe, model routing, and billing.
- PostgreSQL migration ownership for the currently shared database. Drizzle reads the checked-in
drizzle/journal and SQL files at startup. - Redis cache, configuration KV, and cross-instance Pub/Sub.
- Local verification of Auth-issued OIDC JWTs through public JWKS.
Redis cache
src/libs/redis/cache.ts provides stateless functions for string snapshots.
writeCache requires a positive TTL and writes the value and expiry atomically.
readCache accepts only expiring entries and never renews their expiry.
Redis errors propagate to the caller. These functions do not manage locks,
queues, Pub/Sub, connections, or database transactions.
src/services/domain/flux-cache.ts owns balance validation and the 60-second
Flux TTL. Flux services use its read, write, and invalidation functions.
ConfigKV shares the write function while retaining its existing read policy.
Keys use domain names: config:{key}, stripe:prices, and user:{userId}:flux.
The cache functions do not add a key prefix.
Payment
src/services/domain/payment owns pack grant and payment_order rows.
Checkout and package list live in the Stripe adapter on /api/v1/stripe/*.
ConfigKV stores STRIPE_FLUX_PRODUCT_ID. The adapter lists that product's
Prices from Stripe. GET /packages returns stripePriceId. Checkout accepts
stripePriceId. Label, flux amount, and display prices come from Price
metadata and Stripe amounts.
The adapter maps a verified session onto a ClaimReceipt, then calls settle.
Run locally
pnpm -F @proj-airi/api-server dev
pnpm -F @proj-airi/api-server typecheck
pnpm -F @proj-airi/api-server exec vitest run
pnpm -F @proj-airi/api-server build
Run the complete local backend from the repository root:
pnpm dev:backend
For source-level debugging, start @proj-airi/api-server and
@proj-airi/auth-server separately instead.
server/docker-compose.yaml exposes the local Caddy gateway at http://localhost:6112 and keeps
the API and Auth container ports private.
Service boundaries
AUTH_SERVER_URLis Auth's canonical public issuer origin used for JWKS, issuer, and audience validation. It must exactly equal Auth'sPUBLIC_URL./internal/auth/*is reachable only on the deployment's trusted private network. The public edge must reject/internal/*and the API service must not have its own public ingress.AUTH_SERVER_INTERNAL_URLoptionally sends JWKS fetches directly to Auth on the private network while issuer and audience remainAUTH_SERVER_URL.- Auth tables and principal types come from
@proj-airi/auth-shared; no module underserver/apps/authis imported.
Railway
Deploy this as the Resource API Railway service with Config File Path
/server/apps/api/railway.toml; keep the service Root Directory at the
repository root because the Dockerfile copies shared workspace packages. The
config owns its Dockerfile, start command, /readyz healthcheck, and the
watch patterns for every copied build input.
Set AUTH_SERVER_INTERNAL_URL from Auth's Railway private domain. It is only
the private JWKS route; AUTH_SERVER_URL remains the public Auth issuer URL.
See server/README.md for the complete
cross-service variable and migration contract.