djangoplay-web / Architecture / DjangoPlay — Deployment & CI/CD Architecture
DocsDjangoPlay WebArchitectureDjangoPlay — Deployment & CI/CD Architecture

DjangoPlay — Deployment & CI/CD Architecture

DjangoPlay uses GitLab CI/CD as the primary source-control and deployment automation platform.

13 min readApplies to v1.2.2
On this page ▾
  1. 1. Overview
  2. 2. Deployment Architecture
  3. 3.1 GitHub Mirror Architecture
  4. 4.1 Production Deployment Flow
  5. 5.1 Connect to Production
  6. 5.2 Determine the Application Directory
  7. 5.3 Update the Application
  8. 5.4 Install Dependencies
  9. 5.5 Run Database Migrations
  10. 5.6 Collect Static Files
  11. 5.7 Restart Application Services
  12. 11.1 DjangoPlay Web Application
  13. 11.2 Python Libraries
  14. Manual production gate
  15. SSH key-based access
  16. Known-host verification
  17. Non-interactive migrations
  18. Service restart
  19. Single production host
  20. Direct SSH deployment
  21. Single primary database
  22. Manual production gate
  23. Limited horizontal scaling

1. Overview

  1. DjangoPlay web application — GitLab CI → manual production deployment over SSH → production GCP VM.
  2. Python/PyPI libraries — GitLab CI → test → build → version check → publish to PyPI.
  3. GitHub is a mirror, not the primary CI/CD source. GitLab triggers GitHub Actions after changes to main.

Production deployment is intentionally simple:

  • GitLab hosts the primary repository.
  • GitLab CI/CD controls the deployment pipeline.
  • Production deployment is initiated manually from the main branch.
  • GitLab connects to the production GCP VM over SSH.
  • The production server pulls the latest main branch.
  • Python dependencies are installed.
  • Django migrations are applied.
  • Static files are collected.
  • DjangoPlay and Celery services are restarted.

GitHub is maintained as a repository mirror and is not the primary deployment platform.


2. Deployment Architecture

The current production delivery architecture is:

The deployment path is deliberately direct. There is currently no Kubernetes cluster, container orchestration platform, or cloud-native deployment controller in the production path.


3. Source Control and Repository Strategy

GitLab is the authoritative repository for DjangoPlay.

The normal development flow is:

text
Developer
    │
    ▼
GitLab
    │
    ▼
main
    │
    ├──────────────► Production Deployment
    │
    └──────────────► GitHub Mirror

The production deployment pipeline operates from the GitLab repository.

GitHub receives a mirror of the repository for redundancy, visibility, and repository availability.

GitHub is therefore not the source of truth for production deployment.


3.1 GitHub Mirror Architecture

After changes reach main, GitLab triggers a GitHub repository-dispatch event.

The GitHub workflow performs a mirror operation using:

  • GitLab access token
  • GitHub access token
  • GitLab repository path

The mirror pushes branches and tags and prunes removed branches.

Internal GitLab references are intentionally not mirrored.


4. DjangoPlay Web Application Deployment

The DjangoPlay web application uses a manual production deployment pipeline.

The deployment job runs only for the main branch and is configured as a manual GitLab CI job.

This provides an explicit deployment gate between a successful merge to main and production rollout.


4.1 Production Deployment Flow


5. Production Deployment Steps

The deployment job performs the following operations.

5.1 Connect to Production

GitLab CI starts an SSH agent and loads the deployment private key.

The production host is obtained from the GitLab CI/CD variable:

text
SERVER_HOST

The server's SSH host key is added to the CI runner's known_hosts.

The deployment connection uses the production deployment account and then uses sudo for operations performed as the djangoplay system user.


5.2 Determine the Application Directory

The production configuration is stored under:

text
/opt/djangoplay/.dplay/config.yaml

The deployment process reads the configured:

text
webapp_dir

value from that configuration.

This is important because the production .dplay configuration is owned by the djangoplay system user and is not assumed to exist under the SSH user's home directory.


5.3 Update the Application

The deployment process switches to the configured application directory and updates the production checkout:

bash
git checkout main
git stash
git pull origin main

The production application therefore follows the GitLab main branch.


5.4 Install Dependencies

The deployment environment activates the application's virtual environment:

text
.venv

The deployment then installs:

bash
pip install -e '.[dev]'
pip install djangoplay-cli

The editable installation ensures that the deployed Django application uses the checked-out source tree.


5.5 Run Database Migrations

Django migrations are executed automatically during deployment:

bash
python manage.py migrate --noinput

Database schema changes are therefore applied before the application services are restarted.


5.6 Collect Static Files

Production static files are collected using:

bash
python manage.py collectstatic --noinput

The deployment does not require a separate manual static-file collection step.


5.7 Restart Application Services

The deployment completes by restarting:

text
djangoplay
djangoplay-celery

The first service runs the Django web application.

The second service runs the Celery worker.

The deployment therefore updates both synchronous web processing and background task processing together.


6. Production Runtime Architecture

The deployment pipeline ultimately updates the following production runtime:


7. Production Server Services

The current production VM runs the core DjangoPlay services directly.

Service Role
nginx Reverse proxy and TLS termination
djangoplay Django/Gunicorn application service
djangoplay-celery Celery background worker
Redis Cache and Celery broker
PostgreSQL Primary application database
AuthX Identity and authentication service

The application and worker are restarted together during deployment.


8. Production Configuration

Production configuration is maintained outside the Git repository.

The deployment server uses the DjangoPlay configuration structure under:

text
/opt/djangoplay/.dplay/

The primary configuration includes:

text
config.yaml
.secrets
.authx
.appdata

The exact configuration keys and their requirement classification are documented separately in the environment configuration reference.

The deployment documentation should therefore describe how configuration participates in deployment, rather than duplicating the complete configuration reference.


9. Deployment Secrets

Deployment credentials are stored as GitLab CI/CD variables rather than being committed to the repository.

The deployment pipeline uses credentials such as:

Variable Purpose
SSH_PRIVATE_KEY SSH authentication to production
SERVER_HOST Production server hostname
GH_TOKEN GitHub mirror trigger

The exact GitLab project/group variable configuration is an operational concern and should be managed through GitLab CI/CD settings.

Private keys, API tokens, passwords, and service credentials must never be committed to source control.


10. Deployment Environment

The current production environment is intentionally lightweight.

text
Cloudflare
     │
     ▼
GCP e2-micro VM
     │
     ├── Nginx
     ├── Gunicorn / DjangoPlay
     ├── Celery
     ├── Redis
     ├── PostgreSQL
     └── AuthX

The small VM is an intentional operational constraint.

The current deployment architecture prioritizes:

  • Low operational overhead
  • Simple administration
  • Predictable deployment
  • Minimal infrastructure
  • Direct service management
  • Easy recovery and troubleshooting

11. Application Deployment vs Library Release

DjangoPlay web application deployment and Python package releases use different CI/CD flows.

11.1 DjangoPlay Web Application

text
GitLab main
    │
    ▼
Manual production deployment
    │
    ▼
SSH → GCP VM
    │
    ▼
Django + Celery restart

11.2 Python Libraries

Python libraries use a package-release pipeline:

text
GitLab main
    │
    ▼
Test
    │
    ▼
Build
    │
    ▼
Version Check
    │
    ▼
Publish
    │
    ▼
PyPI

This separation is intentional.

A library release publishes a Python package, while the DjangoPlay web application deployment updates a running production system.


12. PyPI Release Architecture

The standard Python library pipeline consists of four primary stages:

  1. Test
  2. Build
  3. Version Check
  4. Publish

The pipeline is reused across Python libraries.


13. PyPI Test Stage

The test stage uses a Python 3.11 CI image.

It performs:

bash
pip install -e ".[dev]"
pip install pytest ruff

and then executes:

bash
ruff check .
pytest --tb=short

The current shared library pipeline treats these checks as non-blocking by using:

bash
ruff check . || true
pytest --tb=short || true

The stage therefore provides automated validation feedback without currently blocking the subsequent build stage on lint or test failures.

This behavior is intentional in the current pipeline and should be revisited if the project adopts strict CI quality gates.


14. PyPI Build Stage

The build stage creates standard Python distribution artifacts:

bash
python -m build

The generated artifacts are stored under:

text
dist/

and passed to subsequent jobs as CI artifacts.

Typical outputs include:

text
*.whl
*.tar.gz

15. PyPI Version Check

Before publishing, the pipeline:

  1. Reads the version from pyproject.toml.
  2. Validates the version format.
  3. Queries PyPI for the currently published version.
  4. Prevents publishing when the same version already exists.

The purpose is to prevent accidental republishing of an already-published package version.

If PyPI cannot be reached, the current implementation proceeds rather than blocking the release.


16. PyPI Publishing

The publish job uses Twine:

bash
twine upload dist/* --non-interactive

Authentication is supplied through GitLab CI/CD variables:

text
PYPI_USERNAME
PYPI_PASSWORD

The conventional PyPI token username is:

text
__token__

The PyPI API token is stored as the password value.


17. PyPI Pipeline Trigger Rules

The standard library pipeline supports:

  • Push to main
  • Manual web-triggered pipelines
  • API-triggered pipelines
  • Merge request pipelines

Publishing itself is prevented for merge request pipelines.

The publish stage runs automatically after the required preceding stages for main.

This provides a distinction between:

text
Pipeline execution
        │
        ├── Merge Request → validation
        │
        └── main → release eligible

18. GitLab CI Configuration Structure

The CI configuration is intentionally split into reusable files.

For the DjangoPlay web application:

text
.gitlab/
└── ci/
    ├── github-mirror.yml
    └── deploy.yml

.gitlab-ci.yml

The root pipeline includes the individual CI definitions:

yaml
include:
  - local: '.gitlab/ci/github-mirror.yml'
  - local: '.gitlab/ci/deploy.yml'

For Python libraries, the common structure is:

text
.gitlab/
└── ci/
    ├── pypi-release.yml
    └── github-mirror.yml

.gitlab-ci.yml

The root CI file defines the stages and includes the reusable pipeline components.


19. Deployment Safety Characteristics

The current deployment process includes several operational safeguards.

Manual production gate

Production deployment is explicitly manual:

yaml
rules:
  - if: '$CI_COMMIT_BRANCH == "main"'
    when: manual

A merge to main therefore does not automatically restart production.

SSH key-based access

Production deployment uses an SSH private key stored as a protected CI/CD variable.

Known-host verification

The deployment runner records the production host key before connecting.

Non-interactive migrations

Database migrations run with:

bash
--noinput

Service restart

The Django and Celery services are restarted together so that application code and asynchronous workers are updated consistently.


20. Current Deployment Limitations

The current architecture intentionally remains simple, but it has known limitations.

Single production host

The production runtime currently uses a single GCP VM.

Failure of the VM therefore affects the application.

Direct SSH deployment

Deployment is performed through SSH rather than a container orchestration platform or managed deployment service.

Single primary database

PostgreSQL is currently the primary application database rather than a multi-node database cluster.

Manual production gate

Production deployment requires manual approval.

Limited horizontal scaling

The current deployment model is optimized for simplicity rather than multi-instance horizontal scaling.

These limitations are architectural constraints of the current deployment, not accidental requirements.


21. Future Deployment Evolution

As DjangoPlay usage grows, the deployment architecture can evolve without changing the application's modular architecture.

Possible future improvements include:

  • Multiple application instances
  • Managed PostgreSQL
  • Redis high availability
  • Dedicated Celery workers
  • Load balancing
  • Automated rollback
  • Containerized deployments
  • Infrastructure-as-code
  • Automated health checks
  • Zero-downtime deployment
  • Separate staging deployment
  • Deployment observability

The current architecture deliberately does not introduce these components until operational requirements justify their complexity.


22. Deployment and Infrastructure Relationship

Deployment updates the application running on the infrastructure documented in the infrastructure architecture.

Deployment is therefore an application delivery mechanism, while the infrastructure architecture describes the runtime environment in which the application operates.


23. Operational Responsibilities

Area Current Responsibility
Source repository GitLab
CI/CD GitLab CI/CD
Production approval Manual GitLab deployment
Deployment transport SSH
Production compute GCP VM
Reverse proxy Nginx
Application server Gunicorn
Web application DjangoPlay
Background processing Celery
Cache / broker Redis
Application database PostgreSQL
Identity AuthX
Static / asset delivery Cloudflare / R2
Repository mirror GitHub
Python package registry PyPI

24. Related Documentation

The deployment architecture should be read together with the following documents:

Document Purpose
djangoplay-infrastructure.md Production infrastructure and runtime topology
architecture-style.md Overall architectural style
app-architecture.md Standard Django application architecture
authentication-architecture.md AuthX and authentication architecture
security-architecture.md Security boundaries and controls
integration-architecture.md Internal and external integrations
scaling.md Scaling strategy and future growth
env-configs.md Complete environment/configuration reference

The environment configuration reference remains the authoritative source for individual configuration keys and their setup/runtime requirements.


25. Summary

DjangoPlay uses GitLab CI/CD as its primary delivery platform.

For the Django web application, the current production flow is:

text
GitLab
   │
   ▼
main
   │
   ▼
Manual GitLab Deployment
   │
   ▼
SSH
   │
   ▼
GCP Production VM
   │
   ├── Pull latest main
   ├── Install dependencies
   ├── Run migrations
   ├── Collect static files
   └── Restart Django + Celery

Python libraries use a separate package-release flow:

text
GitLab
   │
   ▼
Test
   │
   ▼
Build
   │
   ▼
Version Check
   │
   ▼
PyPI

GitHub is maintained as a mirror through a GitLab-triggered GitHub Actions workflow and is not part of the primary production deployment path.

The current deployment architecture favors simplicity, explicit production control, and low operational overhead, while leaving room for future horizontal scaling and more automated deployment mechanisms.