Upgrading
Before you upgrade
Section titled “Before you upgrade”- Read the changelog for the target version — check
CHANGELOG.mdor the release notes for breaking changes and migration notes. - 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 - Note your current version before starting.
Terminal window docker inspect ghcr.io/trueppm/api:latest --format '{{.Config.Labels}}'# Or: helm list -n trueppm
Upgrading to 0.3
Section titled “Upgrading to 0.3”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 newProjectForecastSnapshottable 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 byMC_HISTORY_CAP(see configuration). - Sprint outcomes (
projects.0064_sprinttaskoutcome,projects.0065_historicalsprint_goal_outcome_sprint_goal_outcome) — a newSprintTaskOutcometable plus agoal_outcomecolumn onSprint(MET / PARTIAL / MISSED), capturing the sprint close-out snapshot. - Scope-change audit (
projects.0054_sprintscopechange_goal_impact_and_more) — agoal_impactcolumn onSprintScopeChange, 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.
Docker Compose (development)
Section titled “Docker Compose (development)”git pull origin maindocker compose pulldocker compose up -dMigrations run automatically when the api container starts.
Single-server with Docker Compose
Section titled “Single-server with Docker Compose”cd /opt/trueppmgit pull origin main
# Update the target version in .env:# APP_VERSION=0.2.0
docker compose -f docker-compose.prod.yml pulldocker compose -f docker-compose.prod.yml up -dThe api-init service runs migrate --noinput before the API starts. Watch it complete:
docker compose -f docker-compose.prod.yml logs -f api-init# Should end with: "0 unapplied migration(s)." or a list of applied migrations.Helm / Kubernetes
Section titled “Helm / Kubernetes”helm upgrade trueppm oci://ghcr.io/trueppm/charts/trueppm \ --version 0.2.0 \ --namespace trueppm \ -f my-values.yamlMigrations run in a migrate init container of the api Deployment before the new pods start serving. Check its logs:
kubectl logs -n trueppm deployment/trueppm-api -c migrateUpgrading to the hardened Helm chart
Section titled “Upgrading to the hardened Helm chart”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:Prefer supplying these through an external Secret overTerminal 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>"--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.passwordempty makes the chart read the existing password back rather than minting a new one — so re-runninghelm upgradenever churns the credential or orphans the database PVC. - The connection Secret survives
helm uninstall. Theresource-policy: keepannotation 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.enabledarefalse,env.DATABASE_URLandenv.REDIS_URLare 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_SAMESITEandCSP_CONNECT_SRC— see Configuration.
Rollback
Section titled “Rollback”Docker Compose rollback
Section titled “Docker Compose rollback”# Restore the previous APP_VERSION in .env, then:docker compose -f docker-compose.prod.yml pulldocker compose -f docker-compose.prod.yml up -dIf the migration applied schema changes, restore from the pre-upgrade backup:
docker compose -f docker-compose.prod.yml downdocker volume rm trueppm_postgres_datadocker compose -f docker-compose.prod.yml up db -ddocker exec -i trueppm-db-1 psql -U trueppm trueppm < trueppm-backup-<date>.sql# Then bring up the full stack at the previous version.Helm rollback
Section titled “Helm rollback”helm rollback trueppm -n trueppmThis restores the previous chart revision. If the migration applied schema changes, restore from backup and trigger a fresh migrate run.
Post-upgrade verification
Section titled “Post-upgrade verification”# Check all containers are healthydocker compose -f docker-compose.prod.yml ps# orkubectl get pods -n trueppm
# Hit the health endpointcurl https://trueppm.example.com/api/v1/health/# → {"status": "ok"}
# Confirm the expected version is running — check the deployed image tagkubectl get deployment -n trueppm trueppm-api \ -o jsonpath='{.spec.template.spec.containers[0].image}'# or: helm list -n trueppmCommon issues
Section titled “Common issues”Migrations fail on startup
Check that DATABASE_URL is correct and the database is reachable. Run migrations manually to see the full traceback:
docker compose -f docker-compose.prod.yml exec api python manage.py migrate --noinputStatic files not updating
Trigger a collectstatic run:
docker compose -f docker-compose.prod.yml exec api python manage.py collectstatic --noinput --clearWebSocket 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.