Skip to content

Repository files navigation

CVT-Simulator

Authors:

Date of project start: September 10, 2024

CVT-Simulator is a CVT simulation application with a React frontend, a FastAPI backend, and the CINDER simulation model. Published deployments run entirely from Docker images; the application source repository does not need to be checked out on the server.

Production Docker deployment

The repository publishes two public images to GitHub Container Registry:

ghcr.io/gr812b/cvt-simulator-backend
ghcr.io/gr812b/cvt-simulator-frontend

The root docker-compose.yaml is the canonical production deployment. It runs:

reverse proxy
    |
    v
cvt-frontend
    |
    | /api/v1/*
    v
cvt-backend
    |
    v
PostgreSQL 17
    |
    v
Docker named volume

PostgreSQL is fully containerized. You do not install PostgreSQL, Python, Node, Alembic, or the CVT-Simulator repository on the server.

Prerequisites

The deployment machine needs:

  • Docker Engine
  • the Docker Compose plugin (docker compose)
  • an external Docker network used by the reverse proxy; the default name is web
  • a reverse proxy attached to that external network
  • optionally Watchtower, if automatic image updates are desired

The backend and PostgreSQL are not exposed as host ports. The frontend joins the external web network so an existing reverse proxy can reach it directly.

If your reverse-proxy network is not named web, set WEB_NETWORK in .env to its actual name.

Files needed on the server

Only these deployment files are required:

docker-compose.yaml
.env

The server does not need a Git checkout. Copy docker-compose.yaml from this repository and create .env from .env.example.

For example:

mkdir -p /opt/cvt-simulator
cd /opt/cvt-simulator

# Copy docker-compose.yaml and .env.example here by your preferred method.
cp .env.example .env

Edit .env:

POSTGRES_PASSWORD=replace-with-a-random-url-safe-password
CVT_TAG=latest
WEB_NETWORK=web

A clean URL-safe password can be generated with:

openssl rand -hex 32

Do not commit the real .env file.

The PostgreSQL password is used when the database is initialized. Do not simply change POSTGRES_PASSWORD later on an existing database volume; changing the Compose variable does not automatically change the password stored inside an already-initialized PostgreSQL database.

Reverse-proxy network

If web already exists, nothing needs to be done.

Check it with:

docker network inspect web

If you intentionally use web and it does not exist yet:

docker network create web

If your reverse proxy already uses a differently named external Docker network, leave that network alone and set WEB_NETWORK in .env to its name instead.

First deployment

1. Pull the published images

cd /opt/cvt-simulator
docker compose pull

2. Start PostgreSQL

docker compose up -d postgres

Check that it becomes healthy:

docker compose ps

3. Create the schema and seed the initial library

This is the one special step for a brand-new database:

docker compose run --rm cvt-backend \
  sh -c "alembic upgrade head && python -m app.scripts.init_database"

The initializer creates the deterministic demo account and the released library objects currently used by the frontend.

Do this once for a new database. Do not rerun database initialization as a normal update step.

4. Start the application

docker compose up -d

The backend waits for PostgreSQL, applies any pending Alembic migrations, and then starts the API. The frontend waits for the backend health check.

Check the stack:

docker compose ps
docker compose logs --tail=100 cvt-backend
docker compose logs --tail=100 cvt-frontend

PostgreSQL can be checked directly with:

docker compose exec postgres pg_isready -U cvt -d cvt_simulator

Through the configured public hostname, the API health endpoint is:

https://YOUR-HOST/api/v1/health

The backend documentation is available at:

https://YOUR-HOST/docs

Normal startup and restart

Once the database has been initialized:

docker compose up -d

There is no separate migration command to remember. The backend container runs:

alembic upgrade head

before starting Uvicorn on every container start. If there are no new migrations, Alembic simply leaves the schema at the current revision.

Automatic updates with Watchtower

Normal production uses:

CVT_TAG=latest

The GitHub Actions container workflow publishes new latest backend and frontend images whenever develop is pushed.

Watchtower can continue to update those two containers. When a new backend image is recreated, its startup command applies pending database migrations before the API starts.

The PostgreSQL service has this label:

com.centurylinklabs.watchtower.enable=false

so a normal Watchtower configuration ignores the database container. PostgreSQL is intentionally pinned to the major-version image postgres:17-alpine; update the database image deliberately rather than as part of an application release.

No Git pull, source build, or server-side repository checkout is involved in normal deployment.

Publishing and testing a non-latest branch image

The Containerize workflow supports two publishing paths:

  • a push to develop publishes latest plus the commit SHA;
  • a manual workflow run publishes a supplied non-latest tag plus the commit SHA.

Manual runs cannot overwrite latest.

Once this workflow exists on the repository's default branch, another branch can be tested without merging it:

  1. Open Actions -> Containerize -> Run workflow.
  2. Select the branch to build.
  3. Supply a unique image tag, for example test-my-feature.
  4. Run the workflow.

GitHub publishes matching backend and frontend images:

ghcr.io/gr812b/cvt-simulator-backend:test-my-feature
ghcr.io/gr812b/cvt-simulator-frontend:test-my-feature

To deploy those images, set:

CVT_TAG=test-my-feature

then run:

docker compose pull cvt-backend cvt-frontend
docker compose up -d

Watchtower will subsequently follow that tag while the deployment uses it.

To return to normal production images, set:

CVT_TAG=latest

then run:

docker compose pull cvt-backend cvt-frontend
docker compose up -d

Updating manually without Watchtower

If Watchtower is disabled or you want to update immediately:

cd /opt/cvt-simulator
docker compose pull cvt-backend cvt-frontend
docker compose up -d

The backend startup handles migrations automatically.

PostgreSQL persistence

Database files live in the Docker named volume:

cvt-postgres-data

Normal container replacement does not delete it.

These are safe with respect to the database volume:

docker compose restart
docker compose down
docker compose up -d

Do not use this casually:

docker compose down -v

-v deletes the Compose-managed named volume and therefore deletes the PostgreSQL database.

Database backup

Create a plain SQL backup:

cd /opt/cvt-simulator
docker compose exec -T postgres \
  pg_dump -U cvt -d cvt_simulator \
  > "cvt_simulator_$(date +%Y%m%d_%H%M%S).sql"

For releases containing meaningful database migrations, making a backup before the new backend image is deployed is recommended.

Restore a backup

Stop application traffic first:

docker compose stop cvt-frontend cvt-backend

Recreate the database:

docker compose exec -T postgres \
  psql -U cvt -d postgres \
  -c "DROP DATABASE IF EXISTS cvt_simulator;"

docker compose exec -T postgres \
  psql -U cvt -d postgres \
  -c "CREATE DATABASE cvt_simulator OWNER cvt;"

Restore:

docker compose exec -T postgres \
  psql -U cvt -d cvt_simulator \
  < your-backup.sql

Start the application again:

docker compose up -d

Useful operations

View all services:

docker compose ps

Follow backend logs:

docker compose logs -f cvt-backend

Follow frontend logs:

docker compose logs -f cvt-frontend

Follow PostgreSQL logs:

docker compose logs -f postgres

Restart only the application:

docker compose restart cvt-backend cvt-frontend

See the current database migration revision:

docker compose exec cvt-backend alembic current

Development setup

The production Compose file is intentionally image-only. Local source development remains documented by the component-specific guides:

License

This project is licensed under the Creative Commons Attribution-NonCommercial 4.0 International (CC BY-NC 4.0) license.

  • Free for use in personal, educational, or non-commercial projects.
  • Commercial use requires a separate license. Please contact Kai Arseneau, Cameron Dunn, Travis Wing, or Grace McKenna for commercial licensing.

For more details, see the LICENSE file.

About

An advanced continuous variable transmission (CVT) simulator for McMaster Baja Racing

Resources

Contributing

Stars

7 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages