managarten/docs/ENVIRONMENT_VARIABLES.md
Till JS 28395b313d docs: GPU tunnel setup, STT env wiring, and 2026-04-07 postmortem
Three docs updates landing the institutional knowledge from today's
Memoro voice recording deploy:

- docs/MAC_MINI_SERVER.md: architecture diagram updated to show the
  two-tunnel setup (cloudflared on the Mac Mini for *.mana.how
  except gpu-*, plus a separate cloudflared running as a Windows
  Service on the GPU box for gpu-*.mana.how). New "GPU Tunnel
  (mana-gpu-server)" section explains how to add hostnames in the
  Cloudflare dashboard, the standard 502 debug ladder (DNS misroute,
  service stopped, scheduled task crashed, missing public hostname),
  and how the API key flows from the Windows .env through Mac Mini
  .env to the mana-web container.

- docs/ENVIRONMENT_VARIABLES.md: STT section updated to reflect that
  MANA_STT_URL/API_KEY are now wired into the mana-web container via
  docker-compose.macmini.yml (committed in 42bd2a3a0). Health-check
  command added; cross-link to MAC_MINI_SERVER.md for the debug ladder.

- docs/POSTMORTEM_2026-04-07.md (new): full incident timeline of
  today's deploy. Six root causes (tunnel never started, DB wiped
  without re-push, untracked module-registry files, uncommitted
  Dockerfile heap bump, missing compose env vars, /offline prerender
  500). Three "what went poorly" honest assessments (premature P0
  alarm, miscounted commits, clumsy stash dance). Action items split
  by priority — high priority is the clean-clone build CI job, which
  would have caught half the issues today.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 19:59:04 +02:00

8.7 KiB

Environment Variables Guide

This document explains the centralized environment variable system for the Mana monorepo.

Quick Start

# After cloning the repo, install dependencies (auto-generates .env files)
pnpm install

# Or manually generate .env files
pnpm setup:env

That's it! All app-specific .env files are generated from .env.development.

How It Works

.env.development          # Central config (committed)
        │
        ▼
scripts/generate-env.mjs  # Transforms variables
        │
        ▼
apps/**/apps/**/.env      # Generated files (gitignored)

The generator reads .env.development and creates app-specific .env files with the correct prefixes for each platform:

Platform Prefix Example
Expo (mobile) EXPO_PUBLIC_ EXPO_PUBLIC_SUPABASE_URL
SvelteKit (web) PUBLIC_ PUBLIC_SUPABASE_URL
Hono/Bun (server) None DATABASE_URL

File Locations

Source File

  • .env.development - Single source of truth, committed to git

Generated Files (gitignored)

  • services/mana-auth/.env
  • apps/chat/apps/server/.env
  • apps/chat/apps/mobile/.env
  • apps/chat/apps/web/.env
  • apps/mana/apps/mobile/.env
  • apps/mana/apps/web/.env
  • apps/cards/apps/server/.env
  • apps/cards/apps/web/.env
  • apps/*/apps/server/.env (all apps with compute servers)
  • apps/*/apps/web/.env (all web apps)
  • apps/*/apps/mobile/.env (all mobile apps)

Variable Reference

Shared Variables

Variable Description Used By
MANA_AUTH_URL Auth service URL All apps
JWT_PRIVATE_KEY JWT signing key mana-auth
JWT_PUBLIC_KEY JWT verification key All backends
POSTGRES_USER Database user Docker, backends
POSTGRES_PASSWORD Database password Docker, backends
REDIS_HOST Redis host mana-auth
REDIS_PORT Redis port mana-auth
REDIS_PASSWORD Redis password mana-auth

Mana Auth Service

Variable Description Default
MANA_AUTH_PORT Service port 3001
MANA_AUTH_DATABASE_URL PostgreSQL connection string -
JWT_ACCESS_TOKEN_EXPIRY Access token TTL 15m
JWT_REFRESH_TOKEN_EXPIRY Refresh token TTL 7d
JWT_ISSUER JWT issuer claim mana
JWT_AUDIENCE JWT audience claim mana
STRIPE_SECRET_KEY Stripe secret key -
STRIPE_PUBLISHABLE_KEY Stripe publishable key -
STRIPE_WEBHOOK_SECRET Stripe webhook secret -
CORS_ORIGINS Allowed CORS origins -
RATE_LIMIT_TTL Rate limit window (seconds) 60
RATE_LIMIT_MAX Max requests per window 100

Chat Project

Variable Description Default
CHAT_BACKEND_PORT Backend service port 3002
CHAT_DATABASE_URL PostgreSQL connection string -
AZURE_OPENAI_ENDPOINT Azure OpenAI endpoint URL -
AZURE_OPENAI_API_KEY Azure OpenAI API key -
AZURE_OPENAI_API_VERSION API version 2024-12-01-preview
CHAT_SUPABASE_URL Supabase project URL -
CHAT_SUPABASE_ANON_KEY Supabase anonymous key -

Mana Project

Variable Description
MANA_SUPABASE_URL Supabase project URL
MANA_SUPABASE_ANON_KEY Supabase anonymous key

Cards Project

Variable Description Default
CARDS_BACKEND_PORT Backend service port 3004
CARDS_SUPABASE_URL Supabase project URL -
CARDS_SUPABASE_ANON_KEY Supabase anonymous key -

Speech-to-Text (mana-stt)

Used by the unified Mana web app's voice features (Memoro recording, Dreams voice capture, etc). The browser never talks to mana-stt directly — requests go through the SvelteKit server-side proxy (/api/v1/memoro/transcribe, /api/v1/dreams/transcribe) which attaches the API key from MANA_STT_API_KEY. Keep that key out of the browser bundle.

Variable Description Default
STT_URL Public mana-stt URL — generates MANA_STT_URL for the web app https://gpu-stt.mana.how
MANA_STT_API_KEY API key for mana-stt. Never commit a real value. (empty)

Where to obtain a key:

  • Production (Mac Mini): MANA_STT_API_KEY is read from ~/projects/mana-monorepo/.env on the Mac Mini and injected into the mana-web container by docker-compose.macmini.yml (the mana-web service block, alongside MANA_STT_URL=https://gpu-stt.mana.how). To rotate, update the .env value and recreate the container with docker compose -f docker-compose.macmini.yml up -d --no-deps --force-recreate mana-web.
  • Local dev: paste the dev key into your local apps/mana/apps/web/.env after running pnpm setup:env (the generator only writes an empty placeholder). Ask in #mana-dev or pull from the team's password manager under mana-stt → web-key.
  • Source of truth: services/mana-stt/.env on the Windows GPU box, in the API_KEYS variable. Each entry is <random>:<name> and gets rate-limited per key.
  • Adding a new key: SSH to the Windows GPU box (ssh mana-gpu), append a new entry to C:\mana\services\mana-stt\.env API_KEYS, restart the ManaSTT scheduled task. Use a fresh key per consumer (mana-web, chat-server, etc.) so they can be revoked individually.

Endpoint: https://gpu-stt.mana.how — Cloudflare Tunnel mana-gpu-server (token-managed, runs as a Windows Service on the GPU box, not as a route in the Mac Mini's cloudflared). The tunnel terminates at localhost:3020 on the Windows host.

Health check:

curl https://gpu-stt.mana.how/health
# → {"status":"healthy","whisper_loaded":true,"whisperx":true,...}

If this returns 502, see "GPU Tunnel" in docs/MAC_MINI_SERVER.md for the standard debug ladder.

Adding New Variables

Step 1: Add to .env.development

# In .env.development
MY_NEW_PROJECT_API_KEY=your-api-key
MY_NEW_PROJECT_URL=https://api.example.com

Step 2: Update the Generator Script

Edit scripts/generate-env.mjs and add your app config:

// In APP_CONFIGS array
{
  path: 'apps/my-project/apps/mobile/.env',
  vars: {
    // For Expo, add EXPO_PUBLIC_ prefix
    EXPO_PUBLIC_API_KEY: (env) => env.MY_NEW_PROJECT_API_KEY,
    EXPO_PUBLIC_API_URL: (env) => env.MY_NEW_PROJECT_URL,
  },
},
{
  path: 'apps/my-project/apps/web/.env',
  vars: {
    // For SvelteKit, add PUBLIC_ prefix
    PUBLIC_API_KEY: (env) => env.MY_NEW_PROJECT_API_KEY,
    PUBLIC_API_URL: (env) => env.MY_NEW_PROJECT_URL,
  },
},
{
  path: 'apps/my-project/apps/server/.env',
  vars: {
    // For Hono/Bun servers, no prefix needed
    API_KEY: (env) => env.MY_NEW_PROJECT_API_KEY,
    API_URL: (env) => env.MY_NEW_PROJECT_URL,
  },
},

Step 3: Regenerate

pnpm setup:env

Local Overrides

If you need to override variables locally without affecting others:

  1. The generated .env files are gitignored
  2. You can manually edit them after generation
  3. Or create .env.local files (also gitignored) that some frameworks auto-load

Note: Running pnpm setup:env will overwrite your changes, so use .env.local for persistent overrides.

Docker Integration

The root .env.development is also used by Docker Compose:

# Start all services with shared env
pnpm docker:up:all

Docker services read from:

  • Root .env.development for shared values
  • Service-specific .env files for service-specific values

Troubleshooting

"Variable is undefined" Error

  1. Check if the variable exists in .env.development
  2. Run pnpm setup:env to regenerate
  3. Restart your dev server (env changes require restart)

Generated File Has Wrong Value

  1. Check the mapping in scripts/generate-env.mjs
  2. Ensure the source variable name matches exactly
  3. Run pnpm setup:env again

New App Not Getting Generated

  1. Add app config to APP_CONFIGS in scripts/generate-env.mjs
  2. Ensure the target directory exists
  3. Run pnpm setup:env

Expo Not Picking Up Changes

Expo caches environment variables. Clear the cache:

cd apps/<project>/apps/mobile
npx expo start -c

Security Notes

  • .env.development contains development-only values
  • Never put production secrets in this file
  • The JWT keys in .env.development are for local development only
  • Use separate secrets management for production (1Password, AWS Secrets Manager, etc.)

Migration from Old System

If you have existing .env files with real values:

  1. Copy important values to .env.development
  2. Delete the old .env files
  3. Run pnpm setup:env
  4. Verify apps still work

The old .env.example files can remain as documentation.