# ============================================================================= # VEZA BACKEND API - ENVIRONMENT TEMPLATE # ============================================================================= # This is a template file. Copy to .env and fill in actual values. # DO NOT commit .env with real secrets to Git! # ============================================================================= # --- ENVIRONMENT --- # Options: development, staging, production APP_ENV=development APP_PORT=8080 LOG_LEVEL=info # --- DOMAIN (single source of truth) --- # All service URLs and CORS origins derive from this in development. # Change this + /etc/hosts to switch domain. APP_DOMAIN=veza.fr # --- DATABASE (REQUIRED) --- # PostgreSQL connection string (host ports when using docker-compose: 15432) # In Docker: postgres:5432 | On host: veza.fr:15432 DATABASE_URL=postgres://veza:password@veza.fr:15432/veza?sslmode=disable # Optional: Read replica for scaling read-heavy workloads (same format as DATABASE_URL) # DATABASE_READ_URL=postgres://veza:password@veza-read-replica:5432/veza?sslmode=disable DATABASE_MAX_OPEN_CONNS=25 DATABASE_MAX_IDLE_CONNS=5 DATABASE_CONN_MAX_LIFETIME=5m # --- JWT & AUTHENTICATION (v0.9.1 RS256) --- # PREFERRED: RS256 with RSA keys (generate with scripts/generate-jwt-keys.sh) # JWT_PRIVATE_KEY_PATH=/path/to/jwt-private.pem # JWT_PUBLIC_KEY_PATH=/path/to/jwt-public.pem # FALLBACK (dev only): JWT_SECRET must be at least 32 characters JWT_SECRET=dev-secret-key-minimum-32-characters-long-for-testing-only JWT_ISSUER=veza-api JWT_AUDIENCE=veza-platform JWT_ACCESS_TOKEN_DURATION=15m JWT_REFRESH_TOKEN_DURATION=30d # --- COOKIES --- # Set to true in production for HTTPS-only cookies COOKIE_SECURE=false COOKIE_SAME_SITE=lax COOKIE_DOMAIN= # --- CORS (REQUIRED) --- # Comma-separated list of allowed origins # Development: http://veza.fr:5173,http://veza.fr:3000 (or your APP_DOMAIN) # Production: https://app.veza.com,https://www.veza.com CORS_ALLOWED_ORIGINS=http://veza.fr:5173,http://veza.fr:3000 # --- REDIS (REQUIRED for CSRF, rate limiting, cache) --- # Redis (host port when using docker-compose: 16379) # In Docker: redis:6379 | On host: veza.fr:16379 REDIS_URL=redis://veza.fr:16379 REDIS_ADDR=veza.fr:6379 REDIS_PASSWORD= REDIS_DB=0 # v1.0.9 W3 Day 11 — Sentinel HA. Leave REDIS_SENTINEL_ADDRS empty for # single-instance dev. Set in prod to enable redis.NewFailoverClient. # Comma-separated host:port list ; the master name must match # `sentinel monitor` in sentinel.conf. REDIS_SENTINEL_ADDRS= REDIS_SENTINEL_MASTER_NAME=veza-master REDIS_SENTINEL_PASSWORD= # v1.0.9 W3 Day 13 — CDN edge in front of S3/MinIO. Optional. # Provider valid values: bunny | cloudflare | cloudflare_r2 | cloudfront | none # CDN_SECURITY_KEY only required for bunny (Pull Zone token-auth key). CDN_ENABLED=false CDN_PROVIDER=none CDN_BASE_URL= CDN_SECURITY_KEY= # --- RABBITMQ --- # Enable message queue for async events (use veza:password, host port 15672 for docker-compose) # In Docker: amqp://veza:password@rabbitmq:5672/ | On host: amqp://veza:password@veza.fr:15672/ RABBITMQ_ENABLE=true RABBITMQ_URL=amqp://veza:password@veza.fr:15672/ # --- SENTRY (OPTIONAL - Recommended for production) --- # Error tracking and monitoring SENTRY_DSN= SENTRY_ENVIRONMENT=development SENTRY_SAMPLE_RATE_ERRORS=1.0 SENTRY_SAMPLE_RATE_TRANSACTIONS=0.1 # --- RATE LIMITING --- RATE_LIMIT_ENABLED=true RATE_LIMIT_REQUESTS_PER_SECOND=100 # --- FILE UPLOADS --- UPLOAD_DIR=./uploads ENABLE_CLAMAV=false CLAMAV_REQUIRED=false # --- HYPERSWITCH (PAYMENTS - OPTIONAL) --- # Required for real payment processing. Leave empty to use simulated payments. HYPERSWITCH_ENABLED=false HYPERSWITCH_URL=http://veza.fr:18081 # From Hyperswitch Control Center (app.hyperswitch.io) > Settings > Developers HYPERSWITCH_API_KEY= # For webhook signature verification HYPERSWITCH_WEBHOOK_SECRET= # Checkout success redirect (used in return_url) CHECKOUT_SUCCESS_URL=http://veza.fr:5173/purchases # --- STRIPE CONNECT (SELLER PAYOUT - OPTIONAL) --- # Required for seller payout (balance, onboarding, transfers). # Get keys from Stripe Dashboard > Connect > Settings STRIPE_CONNECT_ENABLED=false # Secret key for server-side Stripe API calls (sk_test_xxx or sk_live_xxx) STRIPE_SECRET_KEY= # Webhook secret for Connect events (whsec_xxx) STRIPE_CONNECT_WEBHOOK_SECRET= # --- TRANSFER RETRY WORKER (v0.701) --- # Drives failed seller_transfers back to completed when Stripe recovers. # TRANSFER_RETRY_ENABLED=true # TRANSFER_RETRY_MAX=3 # TRANSFER_RETRY_INTERVAL=5m # --- REVERSAL WORKER (v1.0.7 item B) --- # Drives reversal_pending seller_transfers to reversed by calling Stripe # Connect Transfers:reversal. Decouples buyer-facing refund UX from # Stripe-side settlement health. Backoff is exponential (base * 2^retry), # capped at BACKOFF_MAX. # REVERSAL_WORKER_ENABLED=true # REVERSAL_MAX_RETRIES=5 # REVERSAL_CHECK_INTERVAL=1m # REVERSAL_BACKOFF_BASE=1m # REVERSAL_BACKOFF_MAX=1h # --- HYPERSWITCH WEBHOOK LOG (v1.0.7 item E) --- # Every webhook hitting POST /webhooks/hyperswitch is persisted to # hyperswitch_webhook_log regardless of signature-valid / processing # outcome — captures attack attempts alongside legitimate traffic for # forensics. A daily sweep deletes rows older than this many days. # HYPERSWITCH_WEBHOOK_LOG_RETENTION_DAYS=90 # --- RECONCILIATION WORKER (v1.0.7 item C) --- # Periodically sweeps for stuck pending orders and refunds whose # webhook never arrived. Pulls live status from Hyperswitch, feeds a # synthesised webhook into the normal dispatcher. Idempotent with # real webhooks via terminal-state guards on the handlers. # RECONCILE_WORKER_ENABLED=true # RECONCILE_INTERVAL=1h # RECONCILE_ORDER_STUCK_AFTER=30m # RECONCILE_REFUND_STUCK_AFTER=30m # RECONCILE_REFUND_ORPHAN_AFTER=5m # --- EXTERNAL SERVICES (OPTIONAL) --- STREAM_SERVER_URL=http://veza.fr:8082 # Must match stream server INTERNAL_API_KEY for /internal/jobs/transcode (P1.1.2) STREAM_SERVER_INTERNAL_API_KEY= CHAT_SERVER_URL=http://veza.fr:8081 # --- HLS STREAMING (OPTIONAL, default off) --- # Enables the HLS endpoints on the backend. When false (default), the player # falls back to the direct /tracks/:id/stream endpoint with HTTP Range support, # which works for all tracks but without adaptive bitrate. Set to true to # activate HLS manifests/segments (requires stream server + transcoding). # See FUNCTIONAL_AUDIT §4 item 5 for the fallback behaviour. # v1.0.9 W4 Day 17 : default flipped to true. Set to false to disable # the HLS transcoder pipeline in lightweight dev / unit-test envs. HLS_STREAMING=true # HLS segment storage directory (used only when HLS_STREAMING=true) HLS_STORAGE_DIR=/tmp/veza-hls # --- TRACK UPLOAD STORAGE BACKEND (v1.0.8 Phase 0, default local) --- # Where TrackService.UploadTrack() writes new track files. # local — writes to veza-backend-api/uploads/tracks/ (legacy behaviour, # works single-pod, doesn't scale multi-pod) # s3 — writes to S3/MinIO via S3StorageService. Requires # AWS_S3_ENABLED=true and AWS_S3_BUCKET. In production, setting # this to 's3' without S3 enabled fails startup with an explicit # error (dev/staging warn and fall back to 'local'). # Phase 1 wires this into TrackService; Phase 2 migrates the read path; # Phase 3 provides a migration CLI for existing local tracks. TRACK_STORAGE_BACKEND=local # --- FRONTEND URL --- # Used for password reset links, email templates, etc. FRONTEND_URL=http://veza.fr:5173 # --- BASE URL --- # Public base URL of this backend (used for OAuth callbacks, etc.) BASE_URL=http://veza.fr:8080 # --- EMAIL (REQUIRED for registration + password reset) --- # Local dev: MailHog ships with `make infra-up-dev` — the defaults below # point at it on localhost:1025, with the web UI at http://localhost:8025 # to inspect captured emails. # Production: override with your SMTP provider (SendGrid, AWS SES, etc.). # # v1.0.6: unified on canonical SMTP_* names. The legacy SMTP_USER / # FROM_EMAIL / FROM_NAME are still accepted as a deprecation fallback # (backend logs a warning on use; removed in v1.1.0). SMTP_HOST=localhost SMTP_PORT=1025 SMTP_USERNAME= SMTP_PASSWORD= SMTP_FROM=no-reply@veza.local SMTP_FROM_NAME=Veza (dev) # --- MONITORING (OPTIONAL) --- PROMETHEUS_URL= # ============================================================================= # VALIDATION RULES # ============================================================================= # # REQUIRED (app will not start without these): # - DATABASE_URL # - JWT_SECRET (min 32 chars) # - REDIS_URL or REDIS_ADDR # - CORS_ALLOWED_ORIGINS (can be empty for strict mode) # # RECOMMENDED for production: # - SENTRY_DSN # - COOKIE_SECURE=true # - COOKIE_SAME_SITE=strict # # OPTIONAL: # - RABBITMQ_* (if async events not used) # - SMTP_* (if email not used) # - CLAMAV_* (if file scanning not used) # # =============================================================================