Skip to content

Backend configuration

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

Copy apps/server/.env.exampleapps/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_URLPostgreSQL URL. Migrations apply on start.
JWT_SECRETHS256 client session secret (must match host minting). ≥32 chars in prod.
REQUIRE_JWT_EXPprod ✅1 rejects JWTs without exp.
INTERCOM_ACCESS_TOKENIntercom server token (never expose to clients).
INTERCOM_CLIENT_SECRETWebhook HMAC (app Client Secret).
INTERCOM_TICKET_TYPE_IDTicket type id for creates.
INTERCOM_TIMEOUT_MSIntercom HTTP timeout (default 10000).
INTERCOM_BASE_URLOverride API host (mocks only). Forbidden in production.
PORTListen port (default 3100).
NODE_ENVproduction enables hard security asserts.
RATE_LIMIT_PER_MINPer-user /api limit (default 600).
TRUST_PROXY_HOPSTrusted 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 admin bearer tokens; ≠ JWT_SECRET; ≥32 chars.
ADMIN_SESSION_TTL_MSSession TTL (default 12h).

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.

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_REGIONDefault us-east-1.
FILE_URL_SECRETprod ✅HMAC for public /files/:id?t=; ≠ other secrets; ≥32 chars.
UPLOAD_DIRLocal fallback when S3 unset (use a volume).
MAX_FILE_MB / MAX_IMAGE_MB / MAX_VIDEO_MB / MAX_FILES_PER_MSGUpload caps.
MAX_PINNED_POSTSMax 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.
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.