Files
orion/docs/deployment/environment.md
Samir Boulahtit 05d31a7fc5
Some checks failed
CI / ruff (push) Successful in 11s
CI / pytest (push) Failing after 45m26s
CI / validate (push) Successful in 22s
CI / dependency-scanning (push) Successful in 29s
CI / docs (push) Has been skipped
CI / deploy (push) Has been skipped
docs: add Google Wallet setup guide and loyalty env vars
Step 25 in Hetzner docs with full Google Cloud/Wallet Console setup,
service account configuration, local testing, and architecture diagrams.
Loyalty module env vars added to environment.md and .env.example.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 00:31:43 +01:00

437 lines
17 KiB
Markdown

# Environment Variables Reference
All configuration for the Orion platform is managed through environment variables, loaded
via Pydantic Settings from an `.env` file or the process environment. This page provides a
complete reference for every variable recognised by `app/core/config.py`.
Variables are read at startup and exposed through the `settings` singleton. In most cases
the defaults are tuned for local development; production deployments **must** override the
security-sensitive values listed in the [Production Checklist](#production-checklist) at the
bottom of this page.
---
## Core / Project
Metadata used in the OpenAPI schema and health endpoints.
| Variable | Description | Default | Required |
|---|---|---|---|
| `PROJECT_NAME` | Display name shown in API docs and health responses | `Orion - Multi-Store Marketplace Platform` | No |
| `VERSION` | Semantic version reported by the platform | `2.2.0` | No |
---
## Database
!!! danger "Production requirement"
You **must** set `DATABASE_URL` to a real PostgreSQL connection string in every
non-development environment. The default value contains a placeholder password and
should never be used in production.
| Variable | Description | Default | Required |
|---|---|---|---|
| `DATABASE_URL` | PostgreSQL connection string (`postgresql://user:pass@host:port/db`) | `postgresql://orion_user:secure_password@localhost:5432/orion_db` | **Yes** |
---
## Admin Initialisation
Used by `init_production.py` and the database seeder to create the initial platform
administrator account.
!!! warning "Change the default password"
The default `ADMIN_PASSWORD` is `admin123`. The production validation check will emit a
warning if this value is left unchanged.
| Variable | Description | Default | Required |
|---|---|---|---|
| `ADMIN_EMAIL` | Email address for the initial admin account | `admin@orion.lu` | No |
| `ADMIN_USERNAME` | Username for the initial admin account | `admin` | No |
| `ADMIN_PASSWORD` | Password for the initial admin account | `admin123` | No (but **must change** in production) |
| `ADMIN_FIRST_NAME` | First name of the admin user | `Platform` | No |
| `ADMIN_LAST_NAME` | Last name of the admin user | `Administrator` | No |
---
## JWT Authentication
Controls JSON Web Token generation and expiry.
!!! danger "Production requirement"
`JWT_SECRET_KEY` **must** be replaced with a strong random value. Generate one with:
```bash
openssl rand -hex 32
```
| Variable | Description | Default | Required |
|---|---|---|---|
| `JWT_SECRET_KEY` | Secret used to sign and verify JWTs | `change-this-in-production` | **Yes** |
| `JWT_EXPIRE_HOURS` | Hours component of the token lifetime | `24` | No |
| `JWT_EXPIRE_MINUTES` | Minutes component of the token lifetime | `30` | No |
---
## API Server
Settings passed to Uvicorn when the application starts.
| Variable | Description | Default | Required |
|---|---|---|---|
| `API_HOST` | Bind address for the API server | `0.0.0.0` | No |
| `API_PORT` | Port the API server listens on | `8000` | No |
| `DEBUG` | Enable debug mode (extra logging, auto-reload) | `True` | No (set `False` in production) |
---
## Documentation
| Variable | Description | Default | Required |
|---|---|---|---|
| `DOCUMENTATION_URL` | URL where the MkDocs site is served | `http://localhost:8001` | No |
---
## Security / Middleware
!!! warning "Restrict allowed hosts"
The default `ALLOWED_HOSTS` value of `["*"]` accepts requests with any `Host` header.
In production, restrict this to your actual domain names.
| Variable | Description | Default | Required |
|---|---|---|---|
| `ALLOWED_HOSTS` | JSON list of permitted `Host` header values | `["*"]` | No (but **restrict** in production) |
| `RATE_LIMIT_ENABLED` | Enable request rate limiting | `True` | No |
| `RATE_LIMIT_REQUESTS` | Maximum number of requests per window | `100` | No |
| `RATE_LIMIT_WINDOW` | Rate limit window duration in seconds | `3600` | No |
---
## Logging
| Variable | Description | Default | Required |
|---|---|---|---|
| `LOG_LEVEL` | Python log level (`DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`) | `INFO` | No |
| `LOG_FILE` | Path to a log file; `None` means stdout only | `None` | No |
---
## Platform Domain
Controls the base domain for store subdomains and custom-domain features.
| Variable | Description | Default | Required |
|---|---|---|---|
| `PLATFORM_DOMAIN` | Root domain under which store subdomains are created | `wizard.lu` | No |
| `ALLOW_CUSTOM_DOMAINS` | Allow stores to use their own domain names | `True` | No |
| `REQUIRE_DOMAIN_VERIFICATION` | Require DNS verification before activating a custom domain | `True` | No |
| `SSL_PROVIDER` | SSL certificate provider (`letsencrypt`, `cloudflare`, `manual`) | `letsencrypt` | No |
| `AUTO_PROVISION_SSL` | Automatically provision SSL certificates for custom domains | `False` | No |
| `DNS_VERIFICATION_PREFIX` | TXT record prefix used for domain ownership verification | `_orion-verify` | No |
| `DNS_VERIFICATION_TTL` | TTL in seconds for DNS verification records | `3600` | No |
---
## Platform Limits
Guard-rails for multi-tenant resource usage.
| Variable | Description | Default | Required |
|---|---|---|---|
| `MAX_STORES_PER_USER` | Maximum number of stores a single user can own | `5` | No |
| `MAX_TEAM_MEMBERS_PER_STORE` | Maximum team members allowed per store | `50` | No |
| `INVITATION_EXPIRY_DAYS` | Days before a team invitation link expires | `7` | No |
---
## Stripe Billing
!!! info "Required for payments"
All three Stripe keys must be set to enable subscription billing and payment
processing. Obtain them from the [Stripe Dashboard](https://dashboard.stripe.com/apikeys).
| Variable | Description | Default | Required |
|---|---|---|---|
| `STRIPE_SECRET_KEY` | Stripe secret API key | `""` (empty) | Yes (for payments) |
| `STRIPE_PUBLISHABLE_KEY` | Stripe publishable API key | `""` (empty) | Yes (for payments) |
| `STRIPE_WEBHOOK_SECRET` | Stripe webhook signing secret | `""` (empty) | Yes (for payments) |
| `STRIPE_TRIAL_DAYS` | Length of the free trial period in days | `30` | No |
---
## Email Configuration
Orion supports multiple email providers. Set `EMAIL_PROVIDER` to choose one, then
configure the matching provider-specific variables below.
| Variable | Description | Default | Required |
|---|---|---|---|
| `EMAIL_PROVIDER` | Email transport backend (`smtp`, `sendgrid`, `mailgun`, `ses`) | `smtp` | No |
| `EMAIL_FROM_ADDRESS` | Sender address for outgoing emails | `noreply@orion.lu` | No |
| `EMAIL_FROM_NAME` | Sender display name | `Orion` | No |
| `EMAIL_REPLY_TO` | Optional reply-to address | `""` (empty) | No |
| `EMAIL_ENABLED` | Master switch to enable/disable all outgoing email | `True` | No |
| `EMAIL_DEBUG` | Log emails to console instead of sending (development only) | `False` | No |
### SMTP Settings
Used when `EMAIL_PROVIDER=smtp`.
| Variable | Description | Default | Required |
|---|---|---|---|
| `SMTP_HOST` | SMTP server hostname | `localhost` | No |
| `SMTP_PORT` | SMTP server port | `587` | No |
| `SMTP_USER` | SMTP authentication username | `""` (empty) | No |
| `SMTP_PASSWORD` | SMTP authentication password | `""` (empty) | No |
| `SMTP_USE_TLS` | Use STARTTLS (port 587) | `True` | No |
| `SMTP_USE_SSL` | Use implicit SSL (port 465) | `False` | No |
### SendGrid Settings
Used when `EMAIL_PROVIDER=sendgrid`.
| Variable | Description | Default | Required |
|---|---|---|---|
| `SENDGRID_API_KEY` | SendGrid API key | `""` (empty) | Yes (if using SendGrid) |
### Mailgun Settings
Used when `EMAIL_PROVIDER=mailgun`.
| Variable | Description | Default | Required |
|---|---|---|---|
| `MAILGUN_API_KEY` | Mailgun API key | `""` (empty) | Yes (if using Mailgun) |
| `MAILGUN_DOMAIN` | Mailgun sending domain | `""` (empty) | Yes (if using Mailgun) |
### Amazon SES Settings
Used when `EMAIL_PROVIDER=ses`.
| Variable | Description | Default | Required |
|---|---|---|---|
| `AWS_ACCESS_KEY_ID` | AWS access key for SES | `""` (empty) | Yes (if using SES) |
| `AWS_SECRET_ACCESS_KEY` | AWS secret key for SES | `""` (empty) | Yes (if using SES) |
| `AWS_REGION` | AWS region for the SES endpoint | `eu-west-1` | No |
---
## Storefront Defaults
Default locale and currency applied to new storefronts. Individual stores can override
these through the admin interface or the `AdminSetting` database table.
| Variable | Description | Default | Required |
|---|---|---|---|
| `DEFAULT_STOREFRONT_LOCALE` | Locale code for currency and number formatting | `fr-LU` | No |
| `DEFAULT_CURRENCY` | ISO 4217 currency code | `EUR` | No |
---
## Seed Data
Controls the volume of demo data generated by the database seeder.
| Variable | Description | Default | Required |
|---|---|---|---|
| `SEED_DEMO_STORES` | Number of demo stores to create | `3` | No |
| `SEED_CUSTOMERS_PER_STORE` | Number of demo customers per store | `15` | No |
| `SEED_PRODUCTS_PER_STORE` | Number of demo products per store | `20` | No |
| `SEED_ORDERS_PER_STORE` | Number of demo orders per store | `10` | No |
---
## Celery / Redis
Background task processing. When `USE_CELERY` is `False`, tasks fall back to FastAPI's
built-in `BackgroundTasks`.
!!! tip "Enable Celery in production"
Set `USE_CELERY=True` and ensure a Redis instance is reachable at `REDIS_URL` for
reliable background task processing.
| Variable | Description | Default | Required |
|---|---|---|---|
| `REDIS_URL` | Redis connection string used as Celery broker and result backend | `redis://localhost:6379/0` | No |
| `USE_CELERY` | Use Celery for background tasks instead of FastAPI BackgroundTasks | `False` | No (set `True` in production) |
| `FLOWER_URL` | URL of the Flower monitoring dashboard | `http://localhost:5555` | No |
| `FLOWER_PASSWORD` | Password for Flower authentication | `changeme` | No (but **change** in production) |
---
## Sentry
Error tracking and performance monitoring via [Sentry](https://sentry.io).
| Variable | Description | Default | Required |
|---|---|---|---|
| `SENTRY_DSN` | Sentry Data Source Name; `None` disables Sentry | `None` | No |
| `SENTRY_ENVIRONMENT` | Environment tag sent with events (`development`, `staging`, `production`) | `development` | No |
| `SENTRY_TRACES_SAMPLE_RATE` | Fraction of transactions sampled for performance monitoring (0.0--1.0) | `0.1` | No |
---
## Monitoring
Prometheus metrics and Grafana dashboard integration.
| Variable | Description | Default | Required |
|---|---|---|---|
| `ENABLE_METRICS` | Expose a `/metrics` endpoint for Prometheus scraping | `False` | No (set `True` in production) |
| `GRAFANA_URL` | URL of the Grafana instance | `https://grafana.wizard.lu` | No |
| `GRAFANA_ADMIN_USER` | Grafana admin username | `admin` | No |
| `GRAFANA_ADMIN_PASSWORD` | Grafana admin password | `""` (empty) | No |
---
## Cloudflare R2 Storage
Object storage for media uploads. When `STORAGE_BACKEND` is `local`, files are stored on
the server filesystem.
| Variable | Description | Default | Required |
|---|---|---|---|
| `STORAGE_BACKEND` | Storage backend to use (`local` or `r2`) | `local` | No |
| `R2_ACCOUNT_ID` | Cloudflare account ID | `None` | Yes (if using R2) |
| `R2_ACCESS_KEY_ID` | R2 API access key | `None` | Yes (if using R2) |
| `R2_SECRET_ACCESS_KEY` | R2 API secret key | `None` | Yes (if using R2) |
| `R2_BUCKET_NAME` | R2 bucket name | `orion-media` | No |
| `R2_PUBLIC_URL` | Custom public URL for media access (e.g. `https://media.yoursite.com`) | `None` | No |
---
## Loyalty Module
Configuration for the loyalty module (stamp/points programs, wallet integration).
All variables use the `LOYALTY_` prefix and are managed by `app/modules/loyalty/config.py`.
### Anti-Fraud Defaults
| Variable | Description | Default | Required |
|---|---|---|---|
| `LOYALTY_DEFAULT_COOLDOWN_MINUTES` | Minimum minutes between stamps for the same card | `15` | No |
| `LOYALTY_MAX_DAILY_STAMPS` | Maximum stamps per card per day | `5` | No |
| `LOYALTY_PIN_MAX_FAILED_ATTEMPTS` | Failed PIN attempts before lockout | `5` | No |
| `LOYALTY_PIN_LOCKOUT_MINUTES` | Duration of PIN lockout in minutes | `30` | No |
### Points
| Variable | Description | Default | Required |
|---|---|---|---|
| `LOYALTY_DEFAULT_POINTS_PER_EURO` | Points earned per euro spent | `10` | No |
### Google Wallet
!!! info "Required for Google Wallet passes"
Both variables must be set for loyalty cards to appear in Google Wallet.
See [Hetzner Step 25](hetzner-server-setup.md#step-25-google-wallet-integration) for setup guide.
| Variable | Description | Default | Required |
|---|---|---|---|
| `LOYALTY_GOOGLE_ISSUER_ID` | Google Wallet Issuer ID (numeric string from [Pay & Wallet Console](https://pay.google.com/business/console)) | `None` | Yes (for Google Wallet) |
| `LOYALTY_GOOGLE_SERVICE_ACCOUNT_JSON` | Path to the Google service account JSON key file | `None` | Yes (for Google Wallet) |
### Apple Wallet
!!! info "Required for Apple Wallet passes"
All five variables must be set for `.pkpass` generation.
Requires an Apple Developer account ($99/year).
| Variable | Description | Default | Required |
|---|---|---|---|
| `LOYALTY_APPLE_PASS_TYPE_ID` | Pass type identifier (e.g., `pass.com.example.loyalty`) | `None` | Yes (for Apple Wallet) |
| `LOYALTY_APPLE_TEAM_ID` | Apple Developer Team ID | `None` | Yes (for Apple Wallet) |
| `LOYALTY_APPLE_WWDR_CERT_PATH` | Path to Apple WWDR intermediate certificate | `None` | Yes (for Apple Wallet) |
| `LOYALTY_APPLE_SIGNER_CERT_PATH` | Path to pass signing certificate (`.pem`) | `None` | Yes (for Apple Wallet) |
| `LOYALTY_APPLE_SIGNER_KEY_PATH` | Path to pass signing private key (`.pem`) | `None` | Yes (for Apple Wallet) |
### QR Code
| Variable | Description | Default | Required |
|---|---|---|---|
| `LOYALTY_QR_CODE_SIZE` | QR code image size in pixels | `300` | No |
---
## Cloudflare CDN / Proxy
| Variable | Description | Default | Required |
|---|---|---|---|
| `CLOUDFLARE_ENABLED` | Set to `True` when the application sits behind Cloudflare proxy (adjusts trusted-proxy headers) | `False` | No (set `True` when proxied) |
---
## Production Checklist
Before deploying to production, ensure the following variables are set correctly. Items
marked **critical** will trigger a startup warning if left at their default values.
!!! danger "Critical -- must change"
- [x] `DATABASE_URL` -- point to a production PostgreSQL instance
- [x] `JWT_SECRET_KEY` -- generate with `openssl rand -hex 32`
- [x] `ADMIN_PASSWORD` -- choose a strong, unique password
- [x] `DEBUG` -- set to `False`
- [x] `ALLOWED_HOSTS` -- restrict to your domain(s)
!!! warning "Strongly recommended"
- [x] `USE_CELERY` -- set to `True` with a production Redis instance
- [x] `FLOWER_PASSWORD` -- change from the default `changeme`
- [x] `ENABLE_METRICS` -- set to `True` for observability
- [x] `SENTRY_DSN` -- configure for error tracking
- [x] `SENTRY_ENVIRONMENT` -- set to `production`
- [x] `STORAGE_BACKEND` -- set to `r2` for scalable media storage
- [x] `CLOUDFLARE_ENABLED` -- set to `True` if behind Cloudflare proxy
!!! info "Required for specific features"
- [x] **Payments:** `STRIPE_SECRET_KEY`, `STRIPE_PUBLISHABLE_KEY`, `STRIPE_WEBHOOK_SECRET`
- [x] **Email (SendGrid — recommended):** `EMAIL_PROVIDER=sendgrid`, `SENDGRID_API_KEY` — handles transactional + marketing in one account
- [x] **Email (Mailgun):** `MAILGUN_API_KEY`, `MAILGUN_DOMAIN` — transactional only, no marketing features
- [x] **Email (SES):** `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` — cheapest at scale
- [x] **R2 Storage:** `R2_ACCOUNT_ID`, `R2_ACCESS_KEY_ID`, `R2_SECRET_ACCESS_KEY`
- [x] **Google Wallet:** `LOYALTY_GOOGLE_ISSUER_ID`, `LOYALTY_GOOGLE_SERVICE_ACCOUNT_JSON`
- [ ] **Apple Wallet:** `LOYALTY_APPLE_PASS_TYPE_ID`, `LOYALTY_APPLE_TEAM_ID`, `LOYALTY_APPLE_WWDR_CERT_PATH`, `LOYALTY_APPLE_SIGNER_CERT_PATH`, `LOYALTY_APPLE_SIGNER_KEY_PATH`
### Example `.env` file (production)
```bash
# Core
DATABASE_URL=postgresql://orion:STRONG_PASSWORD@db.internal:5432/orion
JWT_SECRET_KEY=a]3f...your-random-hex-here...9c2b
DEBUG=False
ALLOWED_HOSTS=["wizard.lu","*.wizard.lu"]
# Admin
ADMIN_PASSWORD=your-strong-admin-password
# Celery / Redis
REDIS_URL=redis://redis.internal:6379/0
USE_CELERY=True
FLOWER_PASSWORD=a-secure-flower-password
# Stripe
STRIPE_SECRET_KEY=sk_live_...
STRIPE_PUBLISHABLE_KEY=pk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
# Email (example: SendGrid)
EMAIL_PROVIDER=sendgrid
SENDGRID_API_KEY=SG....
# R2 Storage
STORAGE_BACKEND=r2
R2_ACCOUNT_ID=your-account-id
R2_ACCESS_KEY_ID=your-access-key
R2_SECRET_ACCESS_KEY=your-secret-key
R2_PUBLIC_URL=https://media.wizard.lu
# Monitoring
ENABLE_METRICS=True
SENTRY_DSN=https://examplePublicKey@o0.ingest.sentry.io/0
SENTRY_ENVIRONMENT=production
CLOUDFLARE_ENABLED=True
# Google Wallet (Loyalty)
LOYALTY_GOOGLE_ISSUER_ID=3388000000023089598
LOYALTY_GOOGLE_SERVICE_ACCOUNT_JSON=/app/google-wallet-sa.json
```