193 lines
7.4 KiB
Markdown
193 lines
7.4 KiB
Markdown
# Environment Variables Document — The Collective Hub
|
|
|
|
## Overview
|
|
|
|
Environment variables are the only difference between deployments. Each Coolify deployment has its own set of env vars, but all deployments share the same database, CDN, and Discord OAuth app.
|
|
|
|
---
|
|
|
|
## Variable Reference
|
|
|
|
### Required for Every Deployment
|
|
|
|
| Variable | Example | Description | Shared or Per-Site? |
|
|
|----------|---------|-------------|---------------------|
|
|
| `SITE_SLUG` | `bad-movies-theater` | Identifies which site this deployment serves. Must match a `slug` in the `sites` table. | **Per-site** |
|
|
| `PUBLIC_SITE_URL` | `https://badmovies.example.com` | The public URL of this deployment. Used for auth callbacks, canonical URLs. | **Per-site** |
|
|
| `DATABASE_URL` | `postgresql://user:pass@host:5432/collective_hub` | Postgres connection string. | **Shared** (same for all) |
|
|
| `BETTER_AUTH_SECRET` | (generated) | Secret key for Better Auth session signing. | **Shared** (same for all) |
|
|
| `BETTER_AUTH_URL` | `https://badmovies.example.com` | Base URL for auth callbacks. Must match `PUBLIC_SITE_URL`. | **Per-site** |
|
|
| `DISCORD_CLIENT_ID` | `123456789012345678` | Discord OAuth application client ID. | **Shared** |
|
|
| `DISCORD_CLIENT_SECRET` | `abc123...` | Discord OAuth application client secret. | **Shared** |
|
|
| `OWNER_DISCORD_ID` | `123456789012345678` | Discord user ID of the site owner. Used to bootstrap ownership on first login. | **Per-site** |
|
|
|
|
### Required for CDN (Phase 1)
|
|
|
|
| Variable | Example | Description | Shared or Per-Site? |
|
|
|----------|---------|-------------|---------------------|
|
|
| `CDN_BASE_URL` | `https://cdn.example.com` | Base URL for constructing CDN URLs. | **Shared** |
|
|
| `CDN_STORAGE_ENDPOINT` | `https://ny.storage.bunnycdn.com` | Storage API endpoint. | **Shared** |
|
|
| `CDN_ACCESS_KEY` | `abc123...` | Storage access key. | **Shared** |
|
|
| `CDN_SECRET_KEY` | (S3 only) | Secret key for S3-compatible storage. | **Shared** |
|
|
| `CDN_BUCKET` | `collective-hub` | Bucket or storage zone name. | **Shared** |
|
|
| `CDN_REGION` | `us-east-1` | Region for S3-compatible storage. | **Shared** |
|
|
|
|
### Super Admin
|
|
|
|
| Variable | Example | Description | Shared or Per-Site? |
|
|
|----------|---------|-------------|---------------------|
|
|
| `SUPER_ADMIN_DISCORD_IDS` | `123456789,987654321` | Comma-separated Discord user IDs with cross-site super admin access. | **Shared** |
|
|
|
|
### Migration Control
|
|
|
|
| Variable | Example | Description | Shared or Per-Site? |
|
|
|----------|---------|-------------|---------------------|
|
|
| `RUN_MIGRATIONS` | `true` | Whether this deployment should run database migrations on startup. Only one deployment should have this set to `true`. | **Per-site** (only one `true`) |
|
|
|
|
### Optional
|
|
|
|
| Variable | Example | Description | Shared or Per-Site? |
|
|
|----------|---------|-------------|---------------------|
|
|
| `NODE_ENV` | `production` | Node environment. | **Per-site** (usually `production`) |
|
|
| `LOG_LEVEL` | `info` | Logging verbosity. | **Per-site** |
|
|
| `FEATURE_FLAGS` | `events:on` | Comma-separated feature flags (future). | **Per-site** |
|
|
|
|
---
|
|
|
|
## Example: Full Deployment Env File
|
|
|
|
### Deployment: bad-movies-theater (primary — runs migrations)
|
|
|
|
```env
|
|
# Site Identity
|
|
SITE_SLUG=bad-movies-theater
|
|
PUBLIC_SITE_URL=https://badmovies.example.com
|
|
|
|
# Database (shared)
|
|
DATABASE_URL=postgresql://hub_app:password@db.example.com:5432/collective_hub
|
|
|
|
# Auth (Better Auth)
|
|
BETTER_AUTH_SECRET=generated-secret-value-here
|
|
BETTER_AUTH_URL=https://badmovies.example.com
|
|
|
|
# Discord OAuth (shared)
|
|
DISCORD_CLIENT_ID=123456789012345678
|
|
DISCORD_CLIENT_SECRET=your-discord-client-secret
|
|
|
|
# Ownership Bootstrap
|
|
OWNER_DISCORD_ID=123456789012345678
|
|
|
|
# Super Admin
|
|
SUPER_ADMIN_DISCORD_IDS=111111111111111111
|
|
|
|
# Migration Control
|
|
RUN_MIGRATIONS=true
|
|
|
|
# CDN (shared)
|
|
CDN_BASE_URL=https://cdn.example.com
|
|
CDN_STORAGE_ENDPOINT=https://ny.storage.bunnycdn.com
|
|
CDN_ACCESS_KEY=your-bunny-access-key
|
|
CDN_BUCKET=collective-hub
|
|
|
|
# Optional
|
|
NODE_ENV=production
|
|
LOG_LEVEL=info
|
|
```
|
|
|
|
### Deployment: garbage-day (secondary — skips migrations)
|
|
|
|
```env
|
|
# Site Identity
|
|
SITE_SLUG=garbage-day
|
|
PUBLIC_SITE_URL=https://garbageday.example.com
|
|
|
|
# Database (shared — same value)
|
|
DATABASE_URL=postgresql://hub_app:password@db.example.com:5432/collective_hub
|
|
|
|
# Auth (Better Auth)
|
|
BETTER_AUTH_SECRET=generated-secret-value-here
|
|
BETTER_AUTH_URL=https://garbageday.example.com
|
|
|
|
# Discord OAuth (shared — same value)
|
|
DISCORD_CLIENT_ID=123456789012345678
|
|
DISCORD_CLIENT_SECRET=your-discord-client-secret
|
|
|
|
# Ownership Bootstrap
|
|
OWNER_DISCORD_ID=987654321098765432
|
|
|
|
# Super Admin (same value)
|
|
SUPER_ADMIN_DISCORD_IDS=111111111111111111
|
|
|
|
# Migration Control
|
|
RUN_MIGRATIONS=false
|
|
|
|
# CDN (shared — same values)
|
|
CDN_BASE_URL=https://cdn.example.com
|
|
CDN_STORAGE_ENDPOINT=https://ny.storage.bunnycdn.com
|
|
CDN_ACCESS_KEY=your-bunny-access-key
|
|
CDN_BUCKET=collective-hub
|
|
|
|
# Optional
|
|
NODE_ENV=production
|
|
LOG_LEVEL=info
|
|
```
|
|
|
|
---
|
|
|
|
## What's Shared vs Per-Site
|
|
|
|
```
|
|
Shared across ALL deployments:
|
|
├── DATABASE_URL (one database)
|
|
├── BETTER_AUTH_SECRET (same session signing key)
|
|
├── DISCORD_CLIENT_ID (one Discord OAuth app)
|
|
├── DISCORD_CLIENT_SECRET
|
|
├── SUPER_ADMIN_DISCORD_IDS (system maintainers)
|
|
├── CDN_BASE_URL (one CDN bucket)
|
|
├── CDN_STORAGE_ENDPOINT
|
|
├── CDN_ACCESS_KEY
|
|
├── CDN_SECRET_KEY (if S3)
|
|
├── CDN_BUCKET
|
|
└── CDN_REGION (if S3)
|
|
|
|
Unique per deployment:
|
|
├── SITE_SLUG (which site this is)
|
|
├── PUBLIC_SITE_URL (its domain)
|
|
├── BETTER_AUTH_URL (must match PUBLIC_SITE_URL)
|
|
├── OWNER_DISCORD_ID (who owns this site)
|
|
└── RUN_MIGRATIONS (only one deployment = true)
|
|
```
|
|
|
|
---
|
|
|
|
## Notes & Warnings
|
|
|
|
### Discord OAuth: Shared App
|
|
|
|
All sites share one Discord OAuth application. This means:
|
|
- Users see the same app name when authorizing (e.g., "The Collective Hub")
|
|
- The OAuth redirect URL list must include every site's callback URL
|
|
- Discord has a limit on redirect URLs — manageable for a handful of sites
|
|
- If the system grows to many sites, each site may need its own Discord OAuth app, or a central auth domain pattern should be introduced
|
|
|
|
### Better Auth Secret
|
|
|
|
`BETTER_AUTH_SECRET` must be the same across all deployments because sessions are signed with it. This enables super admins to potentially navigate between site admin panels with a single session (future enhancement).
|
|
|
|
### Database Migrations — Automated but Coordinated
|
|
|
|
Migrations run automatically on app startup, but only on the deployment with `RUN_MIGRATIONS=true`. All other deployments skip migrations (`RUN_MIGRATIONS=false`). This means:
|
|
|
|
- **Exactly one deployment** is designated as the migration runner
|
|
- That deployment must be deployed first when schema changes are made
|
|
- If the migration runner is down, other deployments still work (they just can't run new migrations)
|
|
- Choose a stable, low-traffic deployment as the migration runner (or the super admin dashboard deployment)
|
|
|
|
### Super Admin Access
|
|
|
|
`SUPER_ADMIN_DISCORD_IDS` is a comma-separated list of Discord user IDs. Users matching these IDs bypass site-scoped membership checks and can access any site's admin panel. This is intended for David (system maintainer) and should be kept to a minimal, trusted set of IDs.
|
|
|
|
### Sensitive Values
|
|
|
|
All secrets (database URL, auth secrets, Discord secrets, CDN keys) must be stored securely in Coolify's environment variable management — never committed to the repository.
|