Some checks failed
Phase 1 of the loyalty production launch plan: config & security hardening, dropped-data fix, DB integrity guards, rate limiting, and constant-time auth compare. 362 tests pass. - 1.4 Persist customer birth_date (new column + migration). Enrollment form was collecting it but the value was silently dropped because create_customer_for_enrollment never received it. Backfills existing customers without overwriting. - 1.1 LOYALTY_GOOGLE_SERVICE_ACCOUNT_JSON validated at startup (file must exist and be readable; ~ expanded). Adds is_google_wallet_enabled and is_apple_wallet_enabled derived flags. Prod path documented as ~/apps/orion/google-wallet-sa.json. - 1.5 CHECK constraints on loyalty_cards (points_balance, stamp_count non-negative) and loyalty_programs (min_purchase, points_per_euro, welcome_bonus non-negative; stamps_target >= 1). Mirrored as CheckConstraint in models. Pre-flight scan showed zero violations. - 1.3 @rate_limit on store mutating endpoints: stamp 60/min, redeem/points-earn 30-60/min, void/adjust 20/min, pin unlock 10/min. - 1.2 Constant-time hmac.compare_digest for Apple Wallet auth token (pulled forward from Phase 9 — code is safe whenever Apple ships). See app/modules/loyalty/docs/production-launch-plan.md for the full launch plan and remaining phases. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
254 lines
9.3 KiB
Plaintext
254 lines
9.3 KiB
Plaintext
# =============================================================================
|
|
# ENVIRONMENT CONFIGURATION
|
|
# =============================================================================
|
|
DEBUG=False
|
|
|
|
# =============================================================================
|
|
# PROJECT INFORMATION
|
|
# =============================================================================
|
|
PROJECT_NAME=Orion - Multi-Store Marketplace Platform
|
|
DESCRIPTION=Multi-tenants multi-themes ecommerce application
|
|
VERSION=2.2.0
|
|
|
|
# =============================================================================
|
|
# DATABASE CONFIGURATION (PostgreSQL required)
|
|
# =============================================================================
|
|
# Default works with: docker-compose up -d db
|
|
DATABASE_URL=postgresql://orion_user:secure_password@localhost:5432/orion_db
|
|
|
|
# For production, use your PostgreSQL connection string:
|
|
# DATABASE_URL=postgresql://username:password@production-host:5432/orion_db
|
|
|
|
# =============================================================================
|
|
# ADMIN INITIALIZATION
|
|
# =============================================================================
|
|
# These are used by init_production.py to create the platform admin
|
|
# ⚠️ CHANGE THESE IN PRODUCTION!
|
|
ADMIN_EMAIL=admin@wizard.lu
|
|
ADMIN_USERNAME=admin
|
|
ADMIN_PASSWORD=change-me-in-production
|
|
ADMIN_FIRST_NAME=Platform
|
|
ADMIN_LAST_NAME=Administrator
|
|
|
|
# =============================================================================
|
|
# JWT CONFIGURATION
|
|
# =============================================================================
|
|
JWT_SECRET_KEY=your-super-secret-jwt-key-change-in-production
|
|
JWT_EXPIRE_HOURS=24
|
|
JWT_EXPIRE_MINUTES=30
|
|
|
|
# =============================================================================
|
|
# API SERVER
|
|
# =============================================================================
|
|
API_HOST=0.0.0.0
|
|
API_PORT=8000
|
|
|
|
# =============================================================================
|
|
# DOCUMENTATION
|
|
# =============================================================================
|
|
# Development
|
|
DOCUMENTATION_URL=http://localhost:8001
|
|
# Staging
|
|
# DOCUMENTATION_URL=https://staging-docs.wizard.lu
|
|
# Production
|
|
# DOCUMENTATION_URL=https://docs.wizard.lu
|
|
|
|
# =============================================================================
|
|
# RATE LIMITING
|
|
# =============================================================================
|
|
RATE_LIMIT_ENABLED=True
|
|
RATE_LIMIT_REQUESTS=100
|
|
RATE_LIMIT_WINDOW=3600
|
|
|
|
# =============================================================================
|
|
# LOGGING
|
|
# =============================================================================
|
|
LOG_LEVEL=INFO
|
|
LOG_FILE=logs/app.log
|
|
|
|
# =============================================================================
|
|
# MAIN DOMAIN CONFIGURATION
|
|
# =============================================================================
|
|
# Your main platform domain
|
|
MAIN_DOMAIN=wizard.lu
|
|
|
|
# Full base URL for outbound links (emails, billing redirects, etc.)
|
|
# Must include protocol and port if non-standard
|
|
# Examples: http://localhost:8000, http://acme.localhost:9999, https://wizard.lu
|
|
APP_BASE_URL=http://localhost:8000
|
|
|
|
# Custom domain features
|
|
# Enable/disable custom domains
|
|
ALLOW_CUSTOM_DOMAINS=True
|
|
# Require DNS verification
|
|
REQUIRE_DOMAIN_VERIFICATION=True
|
|
|
|
# SSL/TLS configuration
|
|
# "letsencrypt" or "cloudflare", "manual"
|
|
SSL_PROVIDER=letsencrypt
|
|
# Set to True if using automated SSL
|
|
AUTO_PROVISION_SSL=False
|
|
|
|
# DNS verification
|
|
DNS_VERIFICATION_PREFIX=_wizard-verify
|
|
DNS_VERIFICATION_TTL=3600
|
|
|
|
# =============================================================================
|
|
# STRIPE BILLING
|
|
# =============================================================================
|
|
# Get your keys from https://dashboard.stripe.com/apikeys
|
|
# See docs/features/subscription-billing.md for setup guide
|
|
STRIPE_SECRET_KEY=sk_test_your_secret_key_here
|
|
STRIPE_PUBLISHABLE_KEY=pk_test_your_publishable_key_here
|
|
STRIPE_WEBHOOK_SECRET=whsec_your_webhook_secret_here
|
|
STRIPE_TRIAL_DAYS=30
|
|
|
|
# =============================================================================
|
|
# EMAIL CONFIGURATION
|
|
# =============================================================================
|
|
# Provider: smtp, sendgrid, mailgun, ses
|
|
EMAIL_PROVIDER=smtp
|
|
EMAIL_FROM_ADDRESS=noreply@wizard.lu
|
|
EMAIL_FROM_NAME=Wizard
|
|
EMAIL_REPLY_TO=
|
|
|
|
# SMTP Settings (used when EMAIL_PROVIDER=smtp)
|
|
SMTP_HOST=smtp.example.com
|
|
SMTP_PORT=587
|
|
SMTP_USER=
|
|
SMTP_PASSWORD=
|
|
SMTP_USE_TLS=true
|
|
SMTP_USE_SSL=false
|
|
|
|
# SendGrid (used when EMAIL_PROVIDER=sendgrid)
|
|
# SENDGRID_API_KEY=SG.your_api_key_here
|
|
|
|
# Mailgun (used when EMAIL_PROVIDER=mailgun)
|
|
# MAILGUN_API_KEY=your_api_key_here
|
|
# MAILGUN_DOMAIN=mg.yourdomain.com
|
|
|
|
# Amazon SES (used when EMAIL_PROVIDER=ses)
|
|
# AWS_ACCESS_KEY_ID=your_access_key
|
|
# AWS_SECRET_ACCESS_KEY=your_secret_key
|
|
# AWS_REGION=eu-west-1
|
|
|
|
# Email behavior
|
|
EMAIL_ENABLED=true
|
|
EMAIL_DEBUG=false
|
|
|
|
# =============================================================================
|
|
# PLATFORM LIMITS
|
|
# =============================================================================
|
|
MAX_STORES_PER_USER=5
|
|
MAX_TEAM_MEMBERS_PER_STORE=50
|
|
INVITATION_EXPIRY_DAYS=7
|
|
|
|
# =============================================================================
|
|
# DEMO/SEED DATA CONFIGURATION (Development only)
|
|
# =============================================================================
|
|
SEED_DEMO_STORES=3
|
|
SEED_CUSTOMERS_PER_STORE=15
|
|
SEED_PRODUCTS_PER_STORE=20
|
|
SEED_ORDERS_PER_STORE=10
|
|
|
|
# =============================================================================
|
|
# CELERY / REDIS TASK QUEUE
|
|
# =============================================================================
|
|
# Redis password (must match docker-compose.yml --requirepass flag)
|
|
# ⚠️ CHANGE THIS IN PRODUCTION! Generate with: openssl rand -hex 16
|
|
REDIS_PASSWORD=changeme
|
|
|
|
# Redis connection URL (used for Celery broker and backend)
|
|
# Default works with: docker-compose up -d redis
|
|
REDIS_URL=redis://localhost:6379/0
|
|
|
|
# Enable Celery for background tasks (set to false to use FastAPI BackgroundTasks)
|
|
# Recommended: false for development, true for production
|
|
USE_CELERY=false
|
|
|
|
# Flower monitoring dashboard URL (for admin panel links)
|
|
FLOWER_URL=http://localhost:5555
|
|
|
|
# Flower basic authentication password
|
|
# ⚠️ CHANGE THIS IN PRODUCTION!
|
|
FLOWER_PASSWORD=changeme
|
|
|
|
# =============================================================================
|
|
# SENTRY ERROR TRACKING
|
|
# =============================================================================
|
|
# Get your DSN from https://sentry.io (free tier available)
|
|
# Leave empty to disable Sentry
|
|
SENTRY_DSN=
|
|
SENTRY_ENVIRONMENT=production
|
|
SENTRY_TRACES_SAMPLE_RATE=0.1
|
|
|
|
# =============================================================================
|
|
# MONITORING
|
|
# =============================================================================
|
|
ENABLE_METRICS=true
|
|
GRAFANA_URL=https://grafana.wizard.lu
|
|
GRAFANA_ADMIN_USER=admin
|
|
GRAFANA_ADMIN_PASSWORD=changeme
|
|
|
|
# =============================================================================
|
|
# CLOUDFLARE R2 STORAGE
|
|
# =============================================================================
|
|
# Storage backend: "local" (default) or "r2" for Cloudflare R2
|
|
# Set to "r2" for production to enable cloud storage
|
|
STORAGE_BACKEND=local
|
|
|
|
# Cloudflare R2 credentials (required when STORAGE_BACKEND=r2)
|
|
# Get these from Cloudflare Dashboard > R2 > Manage R2 API Tokens
|
|
R2_ACCOUNT_ID=
|
|
R2_ACCESS_KEY_ID=
|
|
R2_SECRET_ACCESS_KEY=
|
|
R2_BUCKET_NAME=orion-media
|
|
|
|
# Public URL for R2 bucket (optional - for custom domain)
|
|
# If not set, uses Cloudflare's default R2 public URL
|
|
# Example: https://media.yoursite.com
|
|
R2_PUBLIC_URL=
|
|
|
|
# Cloudflare R2 backup bucket (used by scripts/backup.sh --upload)
|
|
R2_BACKUP_BUCKET=orion-backups
|
|
|
|
# =============================================================================
|
|
# LOYALTY MODULE
|
|
# =============================================================================
|
|
# Anti-fraud defaults (all optional, shown values are defaults)
|
|
# LOYALTY_DEFAULT_COOLDOWN_MINUTES=15
|
|
# LOYALTY_MAX_DAILY_STAMPS=5
|
|
# LOYALTY_PIN_MAX_FAILED_ATTEMPTS=5
|
|
# LOYALTY_PIN_LOCKOUT_MINUTES=30
|
|
|
|
# Points configuration
|
|
# LOYALTY_DEFAULT_POINTS_PER_EURO=10
|
|
|
|
# Google Wallet integration
|
|
# See docs/deployment/hetzner-server-setup.md Step 25 for setup guide
|
|
# Get Issuer ID from https://pay.google.com/business/console
|
|
# LOYALTY_GOOGLE_ISSUER_ID=3388000000012345678
|
|
# Production convention: ~/apps/orion/google-wallet-sa.json (app user, mode 600).
|
|
# Path is validated at startup — file must exist and be readable, otherwise
|
|
# the app fails fast at import time.
|
|
# LOYALTY_GOOGLE_SERVICE_ACCOUNT_JSON=~/apps/orion/google-wallet-sa.json
|
|
# LOYALTY_GOOGLE_WALLET_ORIGINS=["https://yourdomain.com"]
|
|
# LOYALTY_DEFAULT_LOGO_URL=https://yourdomain.com/path/to/default-logo.png
|
|
|
|
# Apple Wallet integration (requires Apple Developer account)
|
|
# LOYALTY_APPLE_PASS_TYPE_ID=pass.com.example.loyalty
|
|
# LOYALTY_APPLE_TEAM_ID=ABCD1234
|
|
# LOYALTY_APPLE_WWDR_CERT_PATH=/path/to/wwdr.pem
|
|
# LOYALTY_APPLE_SIGNER_CERT_PATH=/path/to/signer.pem
|
|
# LOYALTY_APPLE_SIGNER_KEY_PATH=/path/to/signer.key
|
|
|
|
# QR code size in pixels (default: 300)
|
|
# LOYALTY_QR_CODE_SIZE=300
|
|
|
|
# =============================================================================
|
|
# CLOUDFLARE CDN / PROXY
|
|
# =============================================================================
|
|
# Set to true when your domain is proxied through CloudFlare
|
|
# This enables proper handling of CF-Connecting-IP and other CloudFlare headers
|
|
CLOUDFLARE_ENABLED=false
|