Phase-3-Rename des ehemaligen Multi-App-Monorepos zum eigenständigen Produkt-Repo. Verein heißt mana e.V., Plattform-Domain bleibt mana.how, apps/mana/ bleibt unverändert — nur der Repo-Container kriegt den neuen Namen "managarten" (Garten der mana-Apps). Geändert: - package.json#name + #description - README.md (Titel + erster Absatz) - TROUBLESHOOTING.md - alle Mac-Mini-Skripte (Pfade ~/projects/mana-monorepo → ~/projects/managarten) - COMPOSE_PROJECT_NAME-default in scripts/mac-mini/status.sh - .github/workflows/cd-macmini.yml + mirror-to-forgejo.yml - apps/docs (astro.config.mjs + content) - .claude/settings.local.json (Bash-Permission-Pfade) - alle docs/*.md Pfad-Referenzen - launchd plists, .env.macmini.example, infrastructure/ Forgejo-Repo + GitHub-Repo bereits via API umbenannt. Lokales Verzeichnis-Rename + Mac-Mini-Cutover folgen separat.
11 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, no secrets)
│
├── .env.secrets # Optional gitignored override (your API keys)
▼
scripts/generate-env.mjs # Merges + transforms variables
│
▼
apps/**/apps/**/.env # Generated files (gitignored)
The generator reads .env.development first, then layers .env.secrets (if it exists) on
top — non-empty values in .env.secrets override the matching key in .env.development.
This is where personal dev secrets like MANA_STT_API_KEY live, so you don't have to
re-paste them into per-app .env files after every pnpm setup:env.
To populate .env.secrets from the Mac Mini in one shot, run pnpm setup:secrets (see
docs/LOCAL_DEVELOPMENT.md for
the full walk-through).
The generator then 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/.envapps/chat/apps/server/.envapps/chat/apps/mobile/.envapps/chat/apps/web/.envapps/mana/apps/mobile/.envapps/mana/apps/web/.envapps/cards/apps/server/.envapps/cards/apps/web/.envapps/*/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 |
Mana API — Articles Bulk-Import Worker
| Variable | Description | Default |
|---|---|---|
ARTICLES_IMPORT_WORKER_DISABLED |
Set to true to skip starting the bulk-import worker on this apps/api instance. Useful for tests, or when running multiple apps/api replicas and you want to designate a specific one as the worker. The worker uses pg_try_advisory_xact_lock so multiple instances are safe by default — this env-var is the explicit opt-out. |
false |
Cardecky 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, Notes
voice memos, Todo voice quick-add, etc). The browser never talks to mana-stt directly — requests
go through the SvelteKit server-side proxy at /api/v1/voice/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_KEYis read from~/projects/managarten/.envon the Mac Mini and injected into themana-webcontainer bydocker-compose.macmini.yml(themana-webservice block, alongsideMANA_STT_URL=https://gpu-stt.mana.how). To rotate, update the.envvalue and recreate the container withdocker 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/.envafter runningpnpm setup:env(the generator only writes an empty placeholder). Ask in#mana-devor pull from the team's password manager undermana-stt → web-key. - Source of truth:
services/mana-stt/.envon the Windows GPU box, in theAPI_KEYSvariable. 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 toC:\mana\services\mana-stt\.envAPI_KEYS, restart theManaSTTscheduled 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.
LLM gateway (mana-llm)
Used by the unified Mana web app's voice quick-add features to turn transcripts into structured
data: /api/v1/voice/parse-task (todo titles + due dates + priorities) and /api/v1/voice/parse-habit
(habit picker for voice logging). Both proxies live server-side and degrade gracefully — if
mana-llm is unreachable or unauthorized, the endpoints return a fallback shape and voice quick-add
still works, just without LLM enrichment.
| Variable | Description | Default |
|---|---|---|
MANA_LLM_URL |
mana-llm gateway URL (server-side, never exposed) | http://localhost:3025 |
MANA_LLM_API_KEY |
API key — required when pointing at the GPU LLM proxy. Never commit a real value. | (empty) |
PUBLIC_MANA_LLM_URL |
Same URL exposed to the browser for direct use (status page, playground) | mirrors MANA_LLM_URL |
Local dev: leave MANA_LLM_URL=http://localhost:3025 and run mana-llm in Docker. If your local
mana-llm has no models loaded (curl http://localhost:3025/v1/models returns {"data":[]}), point
at the public proxy with MANA_LLM_URL=https://gpu-llm.mana.how and set MANA_LLM_API_KEY to a key
from services/mana-llm/.env on the GPU box.
Endpoints: http://localhost:3025 (Docker), https://llm.mana.how (Mac Mini, no auth),
https://gpu-llm.mana.how (GPU server, X-API-Key required).
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:
- The generated
.envfiles are gitignored - You can manually edit them after generation
- Or create
.env.localfiles (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.developmentfor shared values - Service-specific
.envfiles for service-specific values
Troubleshooting
"Variable is undefined" Error
- Check if the variable exists in
.env.development - Run
pnpm setup:envto regenerate - Restart your dev server (env changes require restart)
Generated File Has Wrong Value
- Check the mapping in
scripts/generate-env.mjs - Ensure the source variable name matches exactly
- Run
pnpm setup:envagain
New App Not Getting Generated
- Add app config to
APP_CONFIGSinscripts/generate-env.mjs - Ensure the target directory exists
- 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.developmentcontains development-only values- Never put production secrets in this file
- The JWT keys in
.env.developmentare 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:
- Copy important values to
.env.development - Delete the old
.envfiles - Run
pnpm setup:env - Verify apps still work
The old .env.example files can remain as documentation.