> ## Documentation Index
> Fetch the complete documentation index at: https://docs.comforthub.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Environments and secrets

> The one production project, the local stack, where every key lives, and how code and schema reach production

There is one production: a hosted Supabase project. Every other copy of the engine is a local stack a developer runs on their own machine. No key is ever written in a page, a repo, a seed or a migration; this page says where each group lives, never what it is.

## Environments

| Environment     | What it is                                                                                                                                                                                                                                                                                                    | Who uses it                                |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
| Production      | The hosted Supabase project: the database, the ten functions, the queues and the scheduled jobs. The app, the pay page, Zoho, QuickBooks, Stripe, Twilio and Resend all talk to this one project                                                                                                              | Everyone                                   |
| The local stack | A copy of the database and the functions on a developer's machine, started with the Supabase command line from the backend repo. It replays every migration from the start and provisions its own Supabase keys. Vendor keys are faked in tests, so a developer only needs real ones to talk to a real vendor | Developers, and the gate before every push |

The [backend repo](/reference/repos-and-links) holds the migrations, the functions and the local stack's configuration.

## Where the secrets live

The secrets vault is one Infisical project. The backend's secrets sit in three of its folders, one per consumer. A secret is set in the vault first, then copied to the place its consumer reads from.

| Secret group                                                                                                             | Where it lives                                                                                                          | Who reads it                                                                                                                  |
| ------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| The functions' keys: Zoho, QuickBooks, Stripe, Resend, Google, Helcim, Sentry, the assistant's model and the map service | The functions folder in the vault, copied into the production project's function secrets with the Supabase command line | The ten functions, from their environment                                                                                     |
| The phone and push keys: the Twilio account and its API key, the Apple push keys, the app's calling certificate          | The database vault folder, copied into the database's own encrypted vault                                               | Database functions, which hand them to the phone function and the push sender                                                 |
| The deploy and audit keys: the Supabase access token, the database password, the Zoho sync login used by the workflows   | The GitHub folder in the vault, copied into the repository's secrets on GitHub                                          | The deploy workflow and the weekly field audit                                                                                |
| The workstation gate's tokens: a Supabase access token and a Sentry token                                                | A file in the developer's home directory, readable only by their own account, outside every checkout                    | The gate's first check, which refuses a push while production carries a dead letter, an open review item or an open condition |
| The app's Supabase address and publishable key                                                                           | In the app's source, visible in the bundle by design                                                                    | The app. These are not secrets                                                                                                |

The three folders' exact names are on [Names](/reference/names). The vault link file in the backend repo points at the production environment and the functions folder, so a developer's export lands the right group in the local functions' environment.

## Rotating a secret

A secret is one value set in two places, never typed or pasted. The backend README holds the one command that generates the value, sets it in the vault and sets it in the production project in the same line, then deletes the temporary file. A value that exists in only one of the two places is a broken rotation: the function reads the old value until the second set lands.

The QuickBooks connection is the exception to "one value": it is an app the owner authorises once, and its refresh token rotates itself and is kept in the engine's own token table; see [QuickBooks](/systems/quickbooks).

## Who may call a function

Every function has the platform's own token check switched off and checks authorization in its own code. A webhook receiver checks the vendor's signature over the raw body; a route the app calls checks the signed-in user; a route a scheduled job calls checks the job's shared secret. This is a rule of the repo, held by review, and the local stack's configuration says so beside every function.

## How code and schema reach production

Nothing reaches production from a laptop. A merge to the main branch runs the gate; a green gate deploys. The deploy workflow has two jobs, and their order is the safety.

| Order  | Job        | What it does                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| ------ | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| First  | Migrations | The workflow links to the production project, rehearses the push and keeps the output in the run summary, then pushes every migration production lacks                                                                                                                                                                                                                                                                                                                                                                                                      |
| Second | Functions  | One function at a time, in a fixed order. No function may read a column that is not live yet, which is why migrations go first. Among the functions the rule is consumer before producer: the calendar function before the action worker, because the worker mints appointment links the calendar function has to be able to verify; the phone function before the worker, because the worker sends texts whose delivery receipts land on the phone function. The action worker goes before everything that fills its queue, and the ops function goes last |

The order guarantees nothing the other way. Between a migration landing and the function deploy finishing, the previously deployed code runs against the new schema. A migration that drops or renames something the live code still reads takes production down for that window. The gate refuses such a migration; the fix is two steps in two merges: stop reading the column first, drop it next.

A manual run of the deploy workflow exists for a re-deploy, or for one half on its own. Direct SQL against production is allowed for operational work and is never a schema change: a schema change is always a migration.

## Related

* [The Supabase backend](/systems/supabase-backend)
* [Repos and links](/reference/repos-and-links)
* [How the monitor works](/handbook/running/how-the-monitor-works)
