Skip to content

Upgrading

  1. Read the changelog for the target version — check CHANGELOG.md or the release notes for breaking changes and migration notes.
  2. Back up PostgreSQL. Valkey state is ephemeral (broker + cache); PostgreSQL is the only stateful service.
    Terminal window
    pg_dump -U trueppm trueppm > trueppm-backup-$(date +%F).sql
    # Or via Docker:
    docker exec trueppm-db-1 pg_dump -U trueppm trueppm \
    > trueppm-backup-$(date +%F).sql
  3. Note your current version before starting.
    Terminal window
    docker inspect ghcr.io/trueppm/api:latest --format '{{.Config.Labels}}'
    # Or: helm list -n trueppm

0.3 adds new database tables and columns for the agile-team feature set. All of the migrations are additive (new models and nullable columns — no destructive operations), so the upgrade is a standard migrate with no manual data steps and no downtime beyond the migration run. Apply them the usual way for your deploy path (the migrate step shown in each section below). The new schema:

  • Forecast snapshots (scheduling.0007_projectforecastsnapshot) — a new ProjectForecastSnapshot table that persists each project’s P50/P80/P95 Monte Carlo forecast over time, so the Schedule view can show a forecast history. Retention is bounded by MC_HISTORY_CAP (see configuration).
  • Sprint outcomes (projects.0064_sprinttaskoutcome, projects.0065_historicalsprint_goal_outcome_sprint_goal_outcome) — a new SprintTaskOutcome table plus a goal_outcome column on Sprint (MET / PARTIAL / MISSED), capturing the sprint close-out snapshot.
  • Scope-change audit (projects.0054_sprintscopechange_goal_impact_and_more) — a goal_impact column on SprintScopeChange, recording whether a post-activation scope change affected the sprint goal.

If you maintain a fork, note that 0.3 also collapses each app’s migration history into a 0001_squashed_… migration via Django’s replaces= (issue #1286). Because the original migrations remain on disk and applyable, an existing database records the squashed migration as already-applied and upgrades as a no-op — there is no drop, recreate, or data step.


Terminal window
git pull origin main
docker compose pull
docker compose up -d

Migrations run automatically when the api container starts.


Terminal window
cd /opt/trueppm
git pull origin main
# Update the target version in .env:
# APP_VERSION=0.2.0
docker compose -f docker-compose.prod.yml pull
docker compose -f docker-compose.prod.yml up -d

The api-init service runs migrate --noinput before the API starts. Watch it complete:

Terminal window
docker compose -f docker-compose.prod.yml logs -f api-init
# Should end with: "0 unapplied migration(s)." or a list of applied migrations.

Terminal window
helm upgrade trueppm oci://ghcr.io/trueppm/charts/trueppm \
--version 0.2.0 \
--namespace trueppm \
-f my-values.yaml

Migrations run in a migrate init container of the api Deployment before the new pods start serving. Check its logs:

Terminal window
kubectl logs -n trueppm deployment/trueppm-api -c migrate

The Helm chart now installs secure by default: it generates the PostgreSQL and Valkey passwords and stores them in a chart-owned connection Secret (<release>-trueppm-connection, annotated helm.sh/resource-policy: keep), injects DATABASE_URL / REDIS_URL via secretKeyRef, enables Valkey auth by default, and applies restricted container security contexts. A few notes when upgrading from a pre-hardening release:

  • Rotate the old default password. Earlier chart versions shipped a default database/cache password of trueppm. If you ran with that default, rotate it. The simplest path is to set explicit, strong passwords on the upgrade so the chart writes them into the connection Secret and the bundled datastores pick them up:
    Terminal window
    helm upgrade trueppm oci://ghcr.io/trueppm/charts/trueppm \
    --namespace trueppm \
    -f my-values.yaml \
    --set postgresql.auth.password="<new-strong-password>" \
    --set valkey.auth.password="<new-strong-password>"
    Prefer supplying these through an external Secret over --set. After the rollout settles you can clear the explicit values and let the chart manage the password from the connection Secret going forward.
  • Leave the passwords blank to keep the generated ones. On an upgrade where a connection Secret already exists, leaving postgresql.auth.password / valkey.auth.password empty makes the chart read the existing password back rather than minting a new one — so re-running helm upgrade never churns the credential or orphans the database PVC.
  • The connection Secret survives helm uninstall. The resource-policy: keep annotation means an accidental uninstall/reinstall reuses the same password and keeps the existing data reachable. If you intend a clean wipe, delete the Secret and the PersistentVolumeClaims explicitly.
  • Using managed datastores? When postgresql.enabled / valkey.enabled are false, env.DATABASE_URL and env.REDIS_URL are now required — the chart fails the render if either is missing. Add them (ideally via an external Secret) before upgrading.
  • App-side auth/CSP defaults. The refresh token now rides an httpOnly Secure cookie and a strict CSP header is sent on every response. A standard same-origin deploy needs no changes. Split-origin deploys must set AUTH_REFRESH_COOKIE_SAMESITE and CSP_CONNECT_SRC — see Configuration.
Terminal window
# Restore the previous APP_VERSION in .env, then:
docker compose -f docker-compose.prod.yml pull
docker compose -f docker-compose.prod.yml up -d

If the migration applied schema changes, restore from the pre-upgrade backup:

Terminal window
docker compose -f docker-compose.prod.yml down
docker volume rm trueppm_postgres_data
docker compose -f docker-compose.prod.yml up db -d
docker exec -i trueppm-db-1 psql -U trueppm trueppm < trueppm-backup-<date>.sql
# Then bring up the full stack at the previous version.
Terminal window
helm rollback trueppm -n trueppm

This restores the previous chart revision. If the migration applied schema changes, restore from backup and trigger a fresh migrate run.


Terminal window
# Check all containers are healthy
docker compose -f docker-compose.prod.yml ps
# or
kubectl get pods -n trueppm
# Hit the health endpoint
curl https://trueppm.example.com/api/v1/health/
# → {"status": "ok"}
# Confirm the expected version is running — check the deployed image tag
kubectl get deployment -n trueppm trueppm-api \
-o jsonpath='{.spec.template.spec.containers[0].image}'
# or: helm list -n trueppm

Migrations fail on startup

Check that DATABASE_URL is correct and the database is reachable. Run migrations manually to see the full traceback:

Terminal window
docker compose -f docker-compose.prod.yml exec api python manage.py migrate --noinput

Static files not updating

Trigger a collectstatic run:

Terminal window
docker compose -f docker-compose.prod.yml exec api python manage.py collectstatic --noinput --clear

WebSocket connections drop after upgrade

Expected — clients reconnect automatically within a few seconds. The Channels layer (Valkey) is not drained between upgrades; in-flight messages are lost but clients recover via the reconnect loop.