Files

@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_URL is Auth's canonical public issuer origin used for JWKS, issuer, and audience validation. It must exactly equal Auth's PUBLIC_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_URL optionally sends JWKS fetches directly to Auth on the private network while issuer and audience remain AUTH_SERVER_URL.
  • Auth tables and principal types come from @proj-airi/auth-shared; no module under server/apps/auth is 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.