Skip to content

Backend configuration ​

The backend is a Hono + Drizzle service (@aw-chat/server). It runs TypeScript via tsx.

Copy apps/server/.env.example → apps/server/.env.

Required = process will not start without it (unless noted as prod-only guard). Full production checklist: Deployment · Security.

Environment variables ​

Core ​

VarRequiredDescription
DATABASE_URL✅PostgreSQL URL. Migrations apply on start.
JWT_SECRET✅HS256 client session secret (must match host minting). ≥32 chars in prod.
REQUIRE_JWT_EXPprod ✅1 rejects JWTs without exp.
JWT_AUDprod ✅Expected aud claim (e.g. aw-chat). When set, tokens without it are rejected.
JWT_ISSprod ✅Expected iss claim (minting service). When set, tokens without it are rejected.
INTERCOM_ACCESS_TOKEN✅Intercom server token (never expose to clients).
INTERCOM_CLIENT_SECRET✅Webhook HMAC (app Client Secret).
INTERCOM_TICKET_TYPE_ID—Ticket type id for POST /api/tickets. Unused while users cannot create tickets; the server starts without it.
INTERCOM_TIMEOUT_MS—Intercom HTTP timeout (default 10000).
INTERCOM_BASE_URL—Override API host (mocks only). Forbidden in production.
PORT—Listen port (default 3100).
NODE_ENV—production enables hard security asserts.
RATE_LIMIT_PER_MIN—Per-user /api limit (default 600).
RATE_LIMIT_IP_PER_MIN—Failed JWT attempts per IP/min (default 120).
RATE_LIMIT_WEBHOOK_PER_MIN—Per-IP /webhooks/* (default 120); HMAC still required.
RATE_LIMIT_FILES_PER_MIN—Per-IP /files/* signed downloads (default 300).
TRUST_PROXY_HOPS—Trusted X-Forwarded-For hops (set 1 behind nginx).
CORS_ORIGINSprod ✅Comma-separated browser origins (SDK hosts + admin). Empty = reflect any (non-prod only).

Admin sessions ​

VarRequiredDescription
ADMIN_SESSION_SECRETprod ✅HMAC secret for revocable admin cookies; ≠ JWT_SECRET; ≥32 chars.
ADMIN_SESSION_TTL_MS—Session TTL (default 1h; maximum 8h).

Admin passwords are not env vars — see Admin panel.

Auto-reply (optional) ​

VarDescription
INTERCOM_AUTOREPLY_ADMIN_IDTeammate id; empty = off.
INTERCOM_AUTOREPLY_TEXT_RU / _ENCanned first-message texts.
INTERCOM_REOPEN_WINDOW_DAYSDays after close during which a user reply reopens the same conversation (default 5; 0 = never). Mirror of Intercom Messenger; keep in sync when that setting changes.

Push (optional) ​

VarDescription
FCM_SERVICE_ACCOUNTPath to Firebase service-account JSON.
TELEGRAM_BOT_TOKENBot token (TMA + channel push).
TELEGRAM_BOT_USERNAMEFor t.me/<user>/app deep links.

Files / S3 ​

VarRequiredDescription
REQUIRE_S3prod ✅1 — refuse to run without S3.
S3_ENDPOINT / S3_BUCKET / S3_ACCESS_KEY / S3_SECRET_KEYfor durable filesS3-compatible storage.
S3_REGION—Default us-east-1.
FILE_URL_SECRETprod ✅HMAC for public /files/:id?t=; ≠ other secrets; ≥32 chars.
UPLOAD_DIR—Local fallback when S3 unset (use a volume).
MAX_FILE_MB / MAX_IMAGE_MB / MAX_VIDEO_MB / MAX_FILES_PER_MSG—Upload caps.
MEDIA_UPLOAD_MAX—Concurrent full-buffer uploads (default 4).
MEDIA_UPLOAD_MAX_QUEUED—Waiters beyond this get 503 (default 16).
MEDIA_PROCESS_MAX / MEDIA_PROCESS_MAX_QUEUED—Sharp/BlurHash concurrency.
MAX_PINNED_POSTS—Max pinned posts per channel (default 5).

Retention & analytics ​

VarDescription
DATA_RETENTION_DAYSIf set, daily prune of post_button_clicks + admin_logs older than N days. Empty = keep forever. Does not prune complaints / CSAT / moderation (business records — separate retention policy if needed).
STATS_TZIANA TZ for admin “activity by hour” (default UTC).

Devtools (keep empty in shared/prod) ​

VarDescription
ENABLE_DEVTOOLSMount /api/devtools (ignored when NODE_ENV=production).
ENABLE_DEVTOOLS_RESET_ALLAllow bulk contact wipe.

Tests ​

VarDescription
TEST_DATABASE_URLPostgres for Vitest (default postgresql://localhost/awchat_test).

Contact country / IP come from edge headers (CF-IPCountry, X-Forwarded-For), not env — configure your proxy accordingly.

Admin users (database-backed) ​

bash
pnpm --filter @aw-chat/server admin:create <username> <password> [email]

Permissions: manage_posts, manage_reasons, view_logs, view_feedback, manage_users, moderate_comments. Super-admins hold all. Details: Admin panel.

Database ​

bash
pnpm --filter @aw-chat/server db:generate
pnpm --filter @aw-chat/server db:migrate

Migrations also run automatically on server start.

Tables (overview) ​

Support-adjacent: user_contacts, devices, notification_settings, conversation_reads, conversation_durations, csat_ratings, complaints, reasons, processed_events.

AW Channel: channels, channel_posts, post_attachments, post_buttons, post_reaction_counts, post_user_reactions, post_views, post_button_clicks, channel_reads.

Comments: channel_comments, comment_attachments, comment_reports, comment_bans, comment_moderators, comment_moderation_events.

Admin: admin_users, admin_logs.

Canonical definitions: apps/server/src/db/schema.ts. Semantics: Data model.

Run ​

bash
pnpm --filter @aw-chat/server dev
pnpm --filter @aw-chat/server start

Intercom setup notes ​

  • Custom contact attributes (app_version, hardware_id, …) are created idempotently on first use.
  • Each userId ↔ Intercom contact is cached in user_contacts.
  • Each support request is an Intercom conversation; the topic becomes an internal note + tags on create.
  • Point the Intercom webhook at https://<your-api>/webhooks/intercom with the Client Secret — Webhooks.

AW Chat SDK — integration & platform handoff docs.