Skip to content

Deployment & Operations

Transitioning the Apptork Root System from a local machine to a production environment is seamless thanks to its strict containerized architecture.


๐Ÿณ Docker Compose Architecture Deep Dive

Root System uses a heavily orchestrated 5-stage boot sequence defined in docker-compose.yml. We don't just throw containers at a server; we ensure absolute dependency resolution.

graph TD
    DB[(PostgreSQL)] --> Migrations(Django Migrations)
    Redis[(Redis)] --> Migrations
    MinIO[(MinIO)] --> Migrations

    Migrations --> CollectStatic(Django CollectStatic)
    CollectStatic --> Seeding(Data Seeding)

    Seeding --> API(Gunicorn API Workers)
    Seeding --> CeleryWorker(Celery Workers)
    Seeding --> CeleryBeat(Celery Beat Scheduler)
  1. Infrastructure: PostgreSQL, Redis, and MinIO boot up with health probes.
  2. Migrations: An ephemeral container waits for the DB to be healthy, then runs python manage.py migrate.
  3. Static Assets: Another ephemeral container runs collectstatic.
  4. Seeding: The final ephemeral container runs the management commands to populate the database with feature flags, AI costs, and constants.
  5. Services: Only after seeding finishes do the actual API and Celery workers boot.

Container Resource Limits

Every worker container in production is sandboxed with mem_limit constraints. If a task leaks memory, Docker kills the container safely before it brings down the host OS.


Deployment Architectures

For early-stage startups or MVPs, a powerful VPS (e.g., DigitalOcean Droplet, Hetzner) is incredibly cost-effective.

We use Docker Swarm or raw Docker Compose on the host. The included docker-compose.yml mounts Nginx as the primary reverse proxy, sitting in front of the Gunicorn API workers.

# On your server
docker compose --env-file .env.prod up --build -d

Make sure to map Nginx to ports 80 and 443, and configure SSL certificates via Let's Encrypt / Certbot.

As you scale, you can rip the docker-compose.yml apart:

  • Host PostgreSQL on Amazon RDS.
  • Host Redis on Amazon ElastiCache.
  • Deploy the api image to AWS ECS / Fargate.
  • Deploy the celeryworker and celerybeat images as continuous background tasks.

CI/CD via GitHub Actions

The boilerplate includes a pre-configured CI/CD pipeline (.github/workflows/deploy.yml) specifically engineered for automated VPS deployments over SSH.

How it works

  1. Trigger: You push a git tag matching v* (e.g., git tag v1.0.0; git push origin v1.0.0).
  2. Action: GitHub Runner spins up and utilizes appleboy/ssh-action.
  3. Execution: It securely SSHes into your server using repository secrets (SERVER_HOST, SERVER_SSH_KEY).
  4. Pull & Restart: The script pulls the latest codebase from main, rebuilds the docker images cleanly, runs database migrations, and restarts the containers with zero-downtime rolling updates.

๐Ÿ”’ Strict Boot Validation

To prevent terrifying production incidents where you boot the app with missing secrets, the Root System uses a strict validation pattern in config/base.py:

get_env_var("POSTGRES_PASSWORD", required=True)

If a required secret is missing from your .env file, the application immediately throws an ImproperlyConfigured exception and refuses to start, failing the deployment before it can serve broken traffic.


Production Management Commands

The Root System includes 10 custom Django management commands designed specifically for DevOps and SaaS administrators:

Command Purpose
seed_ai_config Seeds API providers (OpenAI, Replicate) and their associated task costs.
seed_wallet_config Seeds promotional and default wallet configurations.
seed_core_constants Populates the database-backed JSON key-value store.
seed_feature_flags Sets up default scoped feature flags.
seed_workflows Seeds default DAG workflow templates.
refund_stuck_tasks Identifies hung AI tasks and refunds the exact credit amounts back to users.
export_paid_users Exports a CSV of users who have made real-money purchases for marketing tools.
backfill_file_metadata Uses python-magic to detect content types and update file sizes without downloading files.
cleanup_orphaned_files Safely identifies and deletes files in S3/MinIO that lack database records (supports --dry-run).
cleanup_old_files Sweeps and deletes old files to reduce S3 bills.

๐Ÿ› ๏ธ The Makefile Commands

The included Makefile abstracts away complex Docker orchestration.

Command Action
make init Runs the init_backend.py rebranding script.
make dcb Builds the Docker Compose images.
make dcrun Boots the full Docker Compose stack with live-reloading.
make minio-keys Configures the local MinIO storage buckets securely.
make ngrok Exposes your local MinIO instance to the public internet (for mobile testing).
make ngrokp Exposes your local API to the internet (for receiving webhooks).
make test Runs the Pytest suite.
make lint Runs Ruff to lint the codebase.
make format Runs Ruff to auto-format the codebase.
make typecheck Runs Mypy for strict static typing verification.

๐Ÿงช Code Quality & Testing

We treat this as financial software. Run make test to execute the comprehensive Pytest suite.

The wallets, core, and store apps have the heaviest test coverage. We use freezegun to simulate complex entitlement expiry logic, and we heavily test the select_for_update row-level locking to guarantee no race conditions can ever result in stolen credits.

To ensure code cleanliness across your team, the CI/CD pipeline enforces make lint (Ruff) and make typecheck (Mypy) before allowing merges.


โš™๏ธ Environment Variables Reference

Click to view the Environment Variable Reference

Here are the critical environment variables needed to boot the system:

Core & Security - DJANGO_SECRET_KEY: Cryptographically secure random string. - DJANGO_SETTINGS_MODULE: Set to config.production or config.development. - BRAND_NAME: The human-readable name of your application (used in emails). - ENABLE_APP_STORE_TEST_ACCOUNT: Set to True during App Store reviews.

Database & Cache - POSTGRES_DB / POSTGRES_USER / POSTGRES_PASSWORD: PostgreSQL credentials. - REDIS_URL: The Redis connection string (e.g., redis://redis:6379/0).

Storage (S3 / MinIO) - MINIO_ENDPOINT_URL: The URL to your S3 API. - MINIO_ACCESS_KEY / MINIO_SECRET_KEY: Storage credentials. - MINIO_PUBLIC_BUCKET_NAME / MINIO_PRIVATE_BUCKET_NAME: Bucket names.

Third-Party APIs - SENTRY_DSN: Your Sentry observability tracking URL. - OPENAI_API_KEY: Required for prompt translation and LLM tasks. - REVENUECAT_WEBHOOK_AUTH_TOKEN: Secure string to validate incoming webhooks.