Troubleshooting

Parcel Versioning Deploy Runbook

Pre-Deploy

  • Take a PostgreSQL backup/snapshot (or ensure point-in-time restore is available).
  • Confirm app build includes migration parcels.0007_parceltransaction_and_more.
  • Confirm maintenance window for schema migration + smoke tests.

Deploy

  1. Deploy application code.
  2. Run migrations:
  3. ./.venv/bin/python manage.py migrate
  4. Run Django checks:
  5. ./.venv/bin/python manage.py check

Post-Deploy Verification

  1. Validate versioning invariants:
  2. ./.venv/bin/python manage.py verify_parcel_versioning
  3. Run parcel test suite (or smoke subset in production-like env):
  4. ./.venv/bin/python manage.py test apps.parcels.tests --verbosity=1
  5. UI smoke checks:
  6. Parcel update creates a new active version and supersedes prior row.
  7. Map inline geometry edit creates a new version.
  8. Batch delete marks rows as void (no hard delete).
  9. Parcel detail page shows version history.

Rollback Strategy

  • Preferred: forward-fix with a hotfix release after 0007 is applied.
  • If full rollback is required, restore DB from pre-deploy backup and redeploy the matching pre-versioning app build.
  • Do not use ad-hoc manual SQL rollback in production unless tested on a restore copy.

Upload Error: Duplicate Key on (dataset_id, parcel_id)

Symptom:

  • duplicate key value violates unique constraint "parcels_dataset_parcel_id_unique"

Meaning:

  • The upload is trying to create/replace a parcel ID that already exists in the target dataset.

Actions:

  • Verify mapped parcel ID source field
  • Confirm target active dataset is expected
  • Use preview step to inspect matched records before apply

Upload Form Says File Required After Selecting a File

If file input appears cleared during submit, verify form submit lock logic is active and no custom JS resets file fields. Current upload form uses data-disable-on-submit="true" to prevent duplicate submits.

make check Appears to Hang on Black

Potential causes:

  • Running formatter on very large trees (including temporary directories)
  • Slow filesystem/mounted drive performance

Current Makefile excludes tmp, .venv, venv, .git, and staticfiles from formatter/lint scans.

ARIA Warning About aria-hidden and Focus

Warning example:

  • Blocked aria-hidden on an element because its descendant retained focus

Meaning:

  • A focused element was inside a container that became aria-hidden="true".

Fix direction:

  • Move focus before hiding, or use inert to both hide and prevent focus.

Export Fails with ogr2ogr Error

Checklist:

  • Confirm ogr2ogr is installed and in PATH
  • Confirm PostGIS backend is in use for export
  • Check DB connection settings in environment
  • Review server response body for exact command stderr

Dokku: Persistent Storage for Media + Raster

Use persistent mounts, not git-tracked media/ files and not re-ingest on every deploy.

  1. Create storage directories on Dokku host and mount them.
  2. Set MEDIA_ROOT, RASTER_TILES_ROOT, and RASTER_QUERY_ROOT to mounted paths.
  3. Deploy app code.
  4. Run migrate and collectstatic.
  5. Ingest rasters only when data changes.

One-line helper script example:

./scripts/setup_dokku_raster_storage.sh srv.wg lmstool data/raster_inputs/dem01 data/raster_inputs/landcover01

Commands

APP=lmstool2

# Ensure app storage root exists
dokku storage:ensure-directory "$APP"

# Host directories
mkdir -p /var/lib/dokku/data/storage/$APP/staticfiles
mkdir -p /var/lib/dokku/data/storage/$APP/media

# Mount paths
dokku storage:mount "$APP" /var/lib/dokku/data/storage/$APP/staticfiles:/app/staticfiles
dokku storage:mount "$APP" /var/lib/dokku/data/storage/$APP/media:/app/media

# Runtime paths
dokku config:set "$APP" STATIC_ROOT=/app/staticfiles STATIC_URL=/static/
dokku config:set "$APP" MEDIA_ROOT=/app/media MEDIA_URL=/media/
dokku config:set "$APP" RASTER_TILES_ROOT=/app/media/raster_tiles
dokku config:set "$APP" RASTER_QUERY_ROOT=/app/media/raster_query
dokku config:set "$APP" RASTER_TILES_URL=/raster-tiles/

# Deploy + bootstrap
git push dokku main
dokku run "$APP" python manage.py migrate
dokku run "$APP" python manage.py collectstatic --noinput

# Ingest when raster data changes
dokku run "$APP" python manage.py ingest_raster --dataset-dir data/raster_inputs/<dem-folder> --set-default --overwrite
dokku run "$APP" python manage.py ingest_raster --dataset-dir data/raster_inputs/<landcover-folder> --set-default --overwrite

Quick Verification

APP=lmstool2

dokku run "$APP" sh -lc 'ls -lah /app/media/raster_tiles'
dokku run "$APP" sh -lc 'ls -lah /app/media/raster_query'