# Local development Run the Kortix stack on your machine and work with the encrypted API secrets. Canonical page: https://kortix.com/docs/development For contributors running this repository locally. Requires Docker, Node 22, and pnpm 8. ```sh pnpm install pnpm dev # full LOCAL stack (web + API + local Supabase + tunnel) ``` ## Environments There are **four environments for local development**, each a separate set of API secrets. They differ only in *which backend the API talks to* — same code, different DB / Stripe / keys: | Command | Env | API talks to | | --- | --- | --- | | `pnpm dev` | **local** | 100% local stack — local Supabase/Postgres in Docker, test Stripe. Also runs the web + tunnel. | | `pnpm dev:dev-env` | **dev** | the **dev** stack — dev Supabase DB, **test** Stripe, dev keys (mirrors `dev-api.kortix.com`). | | `pnpm dev:staging-env` | **staging** | the **staging** stack — staging Supabase DB and staging keys (mirrors `staging-api.kortix.com`). | | `pnpm dev:prod-env` | **prod** | the **prod** stack — prod Supabase DB, **LIVE** Stripe, prod keys (mirrors `api.kortix.com`). | `pnpm dev` is the full local stack you'll use day-to-day. `dev:dev-env` / `dev:staging-env` / `dev:prod-env` run the **API** locally against the remote dev/staging/prod backend (for debugging DB/billing/account flows) — they don't start local Supabase. > **Warn** > `pnpm dev:prod-env` connects your local API to **production** — DB writes, Stripe calls, etc. are **real**. Use it deliberately. Verify all profiles decrypt and point at the right stack: ```sh pnpm test:envs ``` ## How secrets work Each environment is a [dotenvx](https://dotenvx.com)-encrypted file, committed to the repo: | Env | File | Key (in `apps/api/.env.keys`) | | --- | --- | --- | | local | `apps/api/.env` | `DOTENV_PRIVATE_KEY` | | dev | `apps/api/.env.dev` | `DOTENV_PRIVATE_KEY_DEV` | | staging | `apps/api/.env.staging` | `DOTENV_PRIVATE_KEY_STAGING` | | prod | `apps/api/.env.prod` | `DOTENV_PRIVATE_KEY_PROD` | Every value is AES-encrypted (`KEY=encrypted:…`). The **public key** that encrypts sits in the file and is safe to commit; the **private key** that decrypts never touches git — it lives off your machine in [Dotenv Armor](https://dotenvx.com/armor). At runtime `dotenvx run --overload -f ` decrypts **in memory** and injects the vars — nothing plaintext is ever written to disk. `--overload` is intentional for env-specific runs so exported local cloud credentials cannot override the selected profile. > **Info** > These encrypted files are **only for local development**. The actual deployed **production** environment does **not** read them — the prod infra loads its env from **AWS Secrets Manager** at runtime. So `apps/api/.env.prod` is just for running locally against the prod backend; changing it does not change what production runs. **`apps/web` uses the same encrypted profiles** (`apps/web/.env` / `.env.dev` / `.env.staging` / `.env.prod`, own keys in `apps/web/.env.keys`). Most of it is public (`NEXT_PUBLIC_*`); only a few Vercel keys are secret. It's decrypted the same way — `pnpm dev` or `pnpm dev:web`. ## First time on a new machine ### Install the key manager and log in ```sh curl -sfS https://dotenvx.sh/armor | sh dotenvx-armor login ``` ### Pull the keys from the cloud ```sh for app in api web; do (cd "apps/$app" && for f in .env .env.dev .env.staging .env.prod; do dotenvx-armor pull -f "$f"; done) done ``` ### Enable the commit hooks + run ```sh git config core.hooksPath .githooks # auto-encrypts secrets on commit pnpm dev ``` The pre-commit hook **auto-encrypts** the profile files (`.env` / `.env.dev` / `.env.staging` / `.env.prod`) so a hand-typed plaintext value is sealed before it can be committed, and blocks the commit if any unencrypted `.env` slips through. ## Everyday | Task | Command | | --- | --- | | Run (local / dev / staging / prod) | `pnpm dev` · `pnpm dev:dev-env` · `pnpm dev:staging-env` · `pnpm dev:prod-env` | | Verify all envs decrypt | `pnpm test:envs` | | Read a secret | `dotenvx get KEY -f apps/api/.env` (or `.env.dev` / `.env.staging` / `.env.prod`) | | Add / change a secret | `dotenvx set KEY value -f apps/api/.env` (or `.env.dev` / `.env.staging` / `.env.prod`), then commit | | Share a new/rotated key with the team | `dotenvx-armor push -f ` (one file at a time) | > **Warn** > Never write plaintext into the profile files — they're encrypted and committed. Machine-local overrides go in the gitignored `apps/api/.env.local`, which Bun loads at higher precedence.