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¶
- Deploy application code.
- Run migrations:
./.venv/bin/python manage.py migrate- Run Django checks:
./.venv/bin/python manage.py check
Post-Deploy Verification¶
- Validate versioning invariants:
./.venv/bin/python manage.py verify_parcel_versioning- Run parcel test suite (or smoke subset in production-like env):
./.venv/bin/python manage.py test apps.parcels.tests --verbosity=1- UI smoke checks:
- Parcel update creates a new active version and supersedes prior row.
- Map inline geometry edit creates a new version.
- Batch delete marks rows as
void(no hard delete). - Parcel detail page shows version history.
Rollback Strategy¶
- Preferred: forward-fix with a hotfix release after
0007is 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
inertto both hide and prevent focus.
Export Fails with ogr2ogr Error¶
Checklist:
- Confirm
ogr2ogris 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.
Recommended Workflow¶
- Create storage directories on Dokku host and mount them.
- Set
MEDIA_ROOT,RASTER_TILES_ROOT, andRASTER_QUERY_ROOTto mounted paths. - Deploy app code.
- Run
migrateandcollectstatic. - 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'