Configuration

ATS has two kinds of configuration, on purpose. Deployment settings (secrets, URLs, mail transport) come from the environment and are set by whoever runs it. Workspace settings (stages, sites, templates, retention, modules) live in the database and HR edits them in the app, without a redeploy.

Node.js and Docker#

Environment variables, validated at startup. Every problem is listed by name and the process exits before opening a port. The kit's apps/node/.env.example has the same list.

VariableDefaultNotes
PUBLIC_URLrequiredPublic origin, e.g. https://ats.example.com. Used for links in emails and the CSRF origin check.
INGEST_SECRETrequiredAt least 32 characters. Shared with the website that posts applications.
PROXY_SECRETrequired with AUTH_MODE=proxyAt least 16 characters. Your auth proxy must send it on every request it forwards.
BASE_PATH/atsUI at ${BASE_PATH}/, API at ${BASE_PATH}/api, intake at ${BASE_PATH}/ingest.
PORT / HOST3000 / 0.0.0.0Use HOST=127.0.0.1 when the proxy runs on the same machine.
DATA_DIR./dataHolds ats.db (SQLite, WAL mode) and files/. The Docker image sets /data.
BOOTSTRAP_ADMINSemptyComma-separated emails that are always admins, even on an empty database.
AUTH_MODEproxyproxy, or dev for local development (requires NODE_ENV=development; signs everyone in as DEV_USER_EMAIL).
PROXY_EMAIL_HEADERx-forwarded-emailHeader with the signed-in user's email. Authelia: remote-email.
PROXY_NAME_HEADERnoneOptional display-name header, e.g. remote-name.
PROXY_SECRET_HEADERx-ats-proxy-secretHeader that carries PROXY_SECRET.
TRUST_PROXYfalsetrue: audit-log IP from the right-most X-Forwarded-For entry.
MAIL_FROM + SMTP_URLnoneSMTP mail, e.g. smtps://user:pass@smtp.example.com:465. MAIL_FROM is required with SMTP_URL.
GRAPH_TENANT_ID, GRAPH_CLIENT_ID, GRAPH_CLIENT_SECRET, GRAPH_MAILBOXnoneMicrosoft Graph instead of SMTP: set all four or none, and not together with SMTP_URL.
MAX_FILE_BYTES10485760Maximum size per uploaded file (10 MiB).
UI_DISTpackages/ui/distWhere the built web app lives.
NODE_ENVnoneAnything other than development gives JSON-line logs. The Docker image sets production.
DEV_USER_EMAILadmin@example.comOnly with AUTH_MODE=dev.
SEED_ADMIN_EMAILnoneAdmin created by npm run seed in proxy mode (demo data only).

Without SMTP_URL or the Graph variables, ATS runs without sending mail.

Cloudflare#

Bindings and [vars] go in apps/cloudflare/wrangler.toml; secrets go in with npx wrangler secret put NAME. Invalid configuration is reported by variable name (never by value) in the Worker logs, and every request gets a generic 500 until it is fixed.

NameKindNotes
DBD1 bindingThe database (wrangler d1 create ats).
FILESR2 bindingUploaded files (bucket ats-files).
ASSETSassets bindingThe prebuilt web app, ../../packages/ui/dist.
PUBLIC_URLvarPublic origin for links and the CSRF origin check.
BASE_PATHvar/ats; must match the route.
ACCESS_TEAM_DOMAIN, ACCESS_AUDvarYour Zero Trust team domain and the Access application's AUD tag. Required outside local dev.
BOOTSTRAP_ADMINSvarComma-separated emails that are always admins.
MAIL_FROM, GRAPH_TENANT_ID, GRAPH_CLIENT_ID, GRAPH_MAILBOXvarOptional Microsoft Graph mail: an app registration with Mail.Send, ideally restricted with an application access policy.
MAX_FILE_BYTESvarOptional; default 10 MiB per file.
INGEST_SECRETsecretAt least 32 characters.
GRAPH_CLIENT_SECRETsecretOnly with Graph mail.
ENVIRONMENT, DEV_USER_EMAIL.dev.vars onlyLocal development identity instead of Access. Never set ENVIRONMENT in production.

The Worker also needs a routes entry for your hostname and a Cron Trigger (crons = ["0 * * * *"], hourly), both already in the shipped wrangler.toml.

In the app: Settings#

Admins change these in Settings; they apply immediately and are stored in the database. A fresh install starts with sensible defaults, so nothing here is required before the first application arrives.

TabWhat it controls
GeneralCompany name (used in email templates) and theme.
Pipeline stagesStage names, colors and kind (open, hired, rejected). Defaults: New, Screening, Interview, Offer, Hired, Not moving forward.
SitesYour locations or brands. New site ids from submissions are added automatically.
Email templatesSubject and body with {{firstName}}, {{lastName}}, {{position}}, {{siteName}}, {{companyName}} placeholders.
ModulesTurn optional features on or off and tune them (below).
Sensitive fieldsAnswer keys to mask, exact or prefix*. Default: convicted*, work_auth*.
Users & accessPeople, their role (viewer, recruiter, admin) and the sites they may see.
Audit logBrowse the compliance trail.

Modules#

ModuleDefaultSettings
auditonKeep entries for keepDays (default 730, minimum 30), then prune.
retentiononDelete candidates with no activity for months (24), or talentPoolMonths (36) if they joined the talent pool; keepHired (on) never auto-deletes people who were hired.
talentPoolonrequireConsent (on): only recommend people who opted in. maxAgeMonths (24): ignore older applicants.
candidateEmailoffTemplate sent automatically on receipt (default: "Application received"), and templates sent when an application enters a stage. Needs mail configured.
hrNotifyoffEmail HR about new applications: default recipients plus per-site overrides. Needs mail configured.

Per-person preferences, such as row density and last-used inbox filters, are saved for each user. Light or dark is chosen per browser.