|
1 | 1 | # Environment configuration |
2 | 2 |
|
3 | | -This project separates build-time variables (used by Vite and CI) from runtime variables (provided by Cloudflare Workers). |
| 3 | +This project separates **build-time** variables (used by Vite/CI tooling) from **runtime** variables (provided to Cloudflare Workers at runtime). |
| 4 | + |
| 5 | +## Build-time env (Vite/CI only) |
| 6 | + |
| 7 | +- **Purpose:** tooling only (e.g., Sentry sourcemap upload during CI builds). |
| 8 | +- **Source:** CI environment variables; optionally `.env.local` for local experimentation. |
| 9 | +- **Keys:** `CI`, `VITE_SENTRY_ORG`, `VITE_SENTRY_PROJECT`, `SENTRY_AUTH_TOKEN`, `VITE_SENTRY_DSN`. |
| 10 | +- **Validation:** `parseBuildEnv` in `src/config/validation.ts` (used by `vite.config.ts`). |
| 11 | +- **Notes:** |
| 12 | + - Build-time env should **not** contain runtime secrets like AWS keys or auth secrets. |
| 13 | + - Sourcemap upload should typically run **only in CI**. |
| 14 | + - `SKIP_ENV_LOAD=true` skips loading `.env*` files in Vite; use sparingly. |
| 15 | + |
| 16 | +## Runtime env (Cloudflare Workers) |
| 17 | + |
| 18 | +- **Purpose:** secrets and bindings used by server/runtime code (auth, SES, etc.). |
| 19 | +- **Source (staging/prod):** Cloudflare Workers environment variables/secrets. |
| 20 | +- **Source (local):** `.dev.vars` when running `wrangler dev`. |
| 21 | +- **Keys:** |
| 22 | + - Required: `AUTH_SECRET`, `AWS_REGION`, `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `SES_FROM_EMAIL` |
| 23 | + - Optional: `SENTRY_DSN` |
| 24 | +- **Access:** `getRuntimeEnv()` from `src/config/runtimeEnv.ts` (**Workers runtime only; do not import in client code**). Non-secret runtime metadata (like environment name) may be read from `process.env` when needed. |
| 25 | +- **Validation:** Zod schema in `runtimeEnv.ts`; errors list missing keys but never values. |
4 | 26 |
|
5 | | -## Build-time env |
| 27 | +## Local setup |
6 | 28 |
|
7 | | -- Purpose: tooling only (e.g., Sentry sourcemap upload in CI). |
8 | | -- Source: `.env.local` (optional) or CI env. |
9 | | -- Keys: `CI`, `VITE_SENTRY_ORG`, `VITE_SENTRY_PROJECT`, `SENTRY_AUTH_TOKEN`. |
10 | | -- Validation: `parseBuildEnv` in `src/config/validation.ts` (used by `vite.config.ts`). |
| 29 | +- **Runtime (required for server features):** |
| 30 | + 1. Copy `.dev.vars.example` → `.dev.vars` |
| 31 | + 2. Fill in values (AUTH_SECRET, AWS keys, SES_FROM_EMAIL, etc.) |
| 32 | + 3. Run `pnpm dev` (uses `wrangler dev` on port 3000) |
11 | 33 |
|
12 | | -## Runtime env (Workers) |
| 34 | +- **Build-time (optional):** |
| 35 | + - Copy `.env.example` → `.env.local` only if you want to experiment with CI-like Sentry sourcemap uploads locally. |
| 36 | + - In normal development, you usually don’t need build-time Sentry upload. |
13 | 37 |
|
14 | | -- Purpose: secrets and bindings used by server code at runtime. |
15 | | -- Source: Cloudflare bindings; local via `.dev.vars` when running `wrangler dev`. |
16 | | -- Keys: `AUTH_SECRET`, `AWS_REGION`, `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `SES_FROM_EMAIL`, optional `SENTRY_DSN`. |
17 | | -- Access: `getRuntimeEnv()` from `src/config/runtimeEnv.ts` (Workers runtime only; not for client imports). |
18 | | -- Validation: Zod schema in `runtimeEnv.ts`; errors list missing keys but never values. |
| 38 | +- **Commands:** |
| 39 | + - `pnpm dev` → Workers-parity local dev via Wrangler |
| 40 | + - `pnpm dev:vite` → Vite-only fallback (not Workers-parity; avoid for runtime-dependent work) |
19 | 41 |
|
20 | | -## Local setup |
| 42 | +## Staging / production |
| 43 | + |
| 44 | +- **Secrets** (e.g., `AUTH_SECRET`, AWS keys) should be set with Wrangler: |
| 45 | + - `wrangler secret put AUTH_SECRET` |
| 46 | + - `wrangler secret put AWS_ACCESS_KEY_ID` |
| 47 | + - `wrangler secret put AWS_SECRET_ACCESS_KEY` |
21 | 48 |
|
22 | | -- Build-time: optionally copy `.env.example` to `.env.local` and fill Sentry fields if you need CI-style sourcemap uploads locally. |
23 | | -- Runtime: copy `.dev.vars.example` to `.dev.vars` and fill values; `wrangler dev` will load them. |
24 | | -- Run: `pnpm dev` (uses `wrangler dev` on port 3000). `pnpm dev:vite` is available as a Vite-only fallback. |
| 49 | +- **Non-secrets** (e.g., `AWS_REGION`, `SES_FROM_EMAIL`, optional `SENTRY_DSN`) can be set as vars: |
| 50 | + - via `wrangler.jsonc` `vars` (preferred when values are non-sensitive), or |
| 51 | + - via Cloudflare dashboard for the Worker environment |
25 | 52 |
|
26 | | -## Staging/production |
| 53 | +- **CI build-time Sentry vars** (`VITE_SENTRY_ORG`, `VITE_SENTRY_PROJECT`, `SENTRY_AUTH_TOKEN`, `CI`) are configured in the CI environment (match `.env.example` keys). |
27 | 54 |
|
28 | | -- Secrets (`AUTH_SECRET`, AWS keys) should be set with `wrangler secret put`. |
29 | | -- Non-secrets (`AWS_REGION`, `SES_FROM_EMAIL`, optional `SENTRY_DSN`) can be set via `vars` in `wrangler.toml` or `wrangler deploy --var KEY=value`. |
30 | | -- Build-time Sentry vars for CI are configured in the CI environment (match `.env.example` keys). |
31 | | -- Runtime env must be read only through `getRuntimeEnv()` inside server code. |
| 55 | +- **Domains:** staging uses the default `*.workers.dev` URL; production uses the custom domain `app.happyharmony.dev`. |
| 56 | + |
| 57 | +- **Rule:** runtime env must be read only through `getRuntimeEnv()` inside server code. |
32 | 58 |
|
33 | 59 | ## Validation |
34 | 60 |
|
35 | | -- Build-time keys are validated by `buildEnvSchema` in `src/config/validation.ts` and parsed via `parseBuildEnv` in `vite.config.ts` / `src/env.ts`. When `CI=true`, Sentry keys are required; otherwise they stay optional. |
36 | | -- Runtime keys are validated by `getRuntimeEnv()` in `src/config/runtimeEnv.ts`; error messages list missing keys without revealing values. |
| 61 | +- **Build-time** keys are validated by the schema in `src/config/validation.ts`. |
| 62 | + - When `CI=true`, Sentry build keys are required; otherwise they remain optional. |
| 63 | +- **Runtime** keys are validated by `getRuntimeEnv()` in `src/config/runtimeEnv.ts`. |
| 64 | + - Error messages list missing keys without revealing values. |
37 | 65 |
|
38 | | -## Sentry defaults |
| 66 | +## Sentry (recommended defaults) |
39 | 67 |
|
40 | | -- Server (Workers): DSN from runtime `SENTRY_DSN` via `getRuntimeEnv()`. Sample rates: traces 0.1 / profiles 0.1 in production, 1.0 in dev/staging. Environment comes from `WORKERS_ENVIRONMENT`/`NODE_ENV`. |
41 | | -- Client: DSN from `VITE_SENTRY_DSN` (optional). Sample rates mirror server; replays are off by default (`replaysSessionSampleRate=0`, `replaysOnErrorSampleRate=1.0`). Environment uses `import.meta.env.MODE`. |
| 68 | +- **Server (Workers):** DSN from runtime `SENTRY_DSN` via `getRuntimeEnv()`. |
| 69 | +- **Client:** use whatever TanStack Start / Sentry integration requires (avoid exposing secrets; DSN is not a secret). |
| 70 | +- **Privacy:** never include user-entered activity text/notes in logs, breadcrumbs, or error reports. |
42 | 71 |
|
43 | 72 | ## Testing |
44 | 73 |
|
45 | | -- Playwright uses `pnpm dev` (wrangler) so e2e hits the Workers runtime on port 3000. `.dev.vars` must be present for runtime bindings. |
| 74 | +- Playwright uses `pnpm dev:vite` by default, so E2E tests do **not** hit the Workers runtime unless you change the Playwright `webServer` command. |
| 75 | +- `.dev.vars` is required only when tests exercise runtime-dependent routes and you run via `pnpm dev` (Wrangler). |
| 76 | + |
| 77 | +## Deployment & domains |
| 78 | + |
| 79 | +- `workers_dev` is enabled so deploys always have a `*.workers.dev` URL available (used for staging and debugging). |
| 80 | +- Staging deploys use the `*.workers.dev` URL (no custom domain). |
| 81 | +- Production is served from the **Custom Domain** `app.happyharmony.dev`, managed in the Cloudflare dashboard. |
| 82 | +- **Do not configure `route` patterns in `wrangler.jsonc`** (we intentionally keep the apex `happyharmony.dev` free for marketing later). |
| 83 | + |
| 84 | +## Environment variable reference |
| 85 | + |
| 86 | +### Build-time (Vite/CI) |
| 87 | + |
| 88 | +| Key | Secret? | Used where | Purpose | |
| 89 | +| --------------------- | ------: | ------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | |
| 90 | +| `CI` | No | CI environment; `vite.config.ts` | Controls CI-only behavior (e.g., enabling sourcemap upload). When `true`, Sentry build vars are required. | |
| 91 | +| `VITE_SENTRY_ORG` | No | CI environment; `vite.config.ts` | Sentry org slug for sourcemap upload configuration. | |
| 92 | +| `VITE_SENTRY_PROJECT` | No | CI environment; `vite.config.ts` | Sentry project slug for sourcemap upload configuration. | |
| 93 | +| `SENTRY_AUTH_TOKEN` | **Yes** | CI environment; `vite.config.ts` | Auth token used by the Sentry Vite plugin to upload sourcemaps. Never expose to runtime/client code. | |
| 94 | +| `VITE_SENTRY_DSN` | No | Client build-time env; `src/app/sentry.client.ts` | Client Sentry DSN for browser error reporting. | |
| 95 | + |
| 96 | +### Runtime (Workers) |
| 97 | + |
| 98 | +| Key | Secret? | Set where | Used where | Purpose | |
| 99 | +| ----------------------- | ------: | --------------------------------------- | ------------------------------------ | --------------------------------------------------------------------------------------------- | |
| 100 | +| `AUTH_SECRET` | **Yes** | Wrangler secret / Cloudflare env secret | Server runtime via `getRuntimeEnv()` | Secret used by authentication/session crypto. Must be long and random in staging/prod. | |
| 101 | +| `AWS_REGION` | No | Wrangler var / Cloudflare env var | Server runtime via `getRuntimeEnv()` | AWS region used when calling SES APIs. | |
| 102 | +| `AWS_ACCESS_KEY_ID` | **Yes** | Wrangler secret / Cloudflare env secret | Server runtime via `getRuntimeEnv()` | Access key for SES sending credentials (least-privilege IAM). | |
| 103 | +| `AWS_SECRET_ACCESS_KEY` | **Yes** | Wrangler secret / Cloudflare env secret | Server runtime via `getRuntimeEnv()` | Secret key for SES sending credentials (least-privilege IAM). | |
| 104 | +| `SES_FROM_EMAIL` | No | Wrangler var / Cloudflare env var | Server runtime via `getRuntimeEnv()` | Verified “From” address used for verification/reset emails. | |
| 105 | +| `SENTRY_DSN` | No | Wrangler var / Cloudflare env var | Server runtime via `getRuntimeEnv()` | Sentry DSN for server-side error reporting. DSN is not secret, but treat it as configuration. | |
46 | 106 |
|
47 | | -## Deployment |
| 107 | +### Local files (never commit) |
48 | 108 |
|
49 | | -- `workers_dev` is enabled for the first deploy to `*.workers.dev`. Route settings remain in `wrangler.jsonc` for attaching the custom domain afterward. |
| 109 | +| File | Purpose | Notes | |
| 110 | +| ------------ | ----------------------------------------- | ---------------------------------------------------------------------------------- | |
| 111 | +| `.dev.vars` | Local runtime bindings for `wrangler dev` | Copy from `.dev.vars.example`. Do not commit. | |
| 112 | +| `.env.local` | Optional local build-time vars | Typically only needed if you want CI-like sourcemap upload locally. Do not commit. | |
0 commit comments