3.9 KiB
Local development
Requires Docker Desktop running Linux containers with Docker Compose. Host Python and uv are optional; all application commands run in containers.
First start (PowerShell)
Copy .env.example to .env only if .env does not already exist. Replace
all five values with independent random secrets. To generate one in PowerShell:
[Convert]::ToHexString([System.Security.Cryptography.RandomNumberGenerator]::GetBytes(32))
Never share .env or output from docker compose config without --quiet.
docker compose config --quiet
docker compose build
docker compose up -d db
docker compose run --rm manage migrate
docker compose up -d web
Invoke-RestMethod http://127.0.0.1:8000/health/
The health endpoint returns {"status":"ok"} when PostgreSQL is reachable,
and HTTP 503 with {"status":"unavailable"} when database access fails.
It does not verify schema currency. The dashboard is available at /.
The server binds only to loopback on the host. Ports 8000 and 5432 must be
available. PostgreSQL is exposed only at 127.0.0.1:5432 for local tools; use
database gizmoduck, runtime role gizmoduck_app, and the ignored .env value
of RUNTIME_PASSWORD for routine inspection. This is a local development server.
Verification
docker compose run --rm manage check
docker compose run --rm manage makemigrations --check --dry-run
docker compose run --rm manage migrate --check
docker compose run --rm test
docker compose run --rm permissions
The test suite covers the complete synthetic local MVP workflow. The
runtime-permission check exercises DML grants on both finance_* and
ingestion_* tables. See reviewed imports for the explicit local
preview, decision, and commit workflow, and local owner workflows
for categorization, reports, exports, backups, and recovery.
The test service starts its own PostgreSQL container. Its dedicated non-superuser role can create the temporary pytest database. The test database uses tmpfs; stopping the test database discards only its synthetic test data. The permissions command checks real runtime grants on the migrated development schema, using synthetic group rows in rolled-back transactions (sequence gaps are normal). It verifies DML, sequence access, denied schema/table creation and role escalation, and absence of database creation and administrator privileges.
Runtime gizmoduck_app has only DML and sequence access. Management commands use
gizmoduck_migrate, which owns the schema. Bootstrap administrator credentials
are passed only to the database service. Web startup does not run migrations.
Changes and lifecycle
Rebuild with docker compose build after editing application or test code;
then use docker compose up -d web to replace the web container. Dependencies
are installed from uv.lock with uv sync --frozen. To intentionally update
that lockfile, use uv with Python 3.13 and run uv lock, then rebuild and verify.
docker compose stop web db
docker compose --profile test stop test-db
docker compose --profile backup stop restore-db
Development data persists in the project-scoped postgres_data Docker volume.
Do not delete it to fix setup problems. Database initialization scripts run only
when the volume is empty. Editing .env does not rotate credentials stored in
an existing database: coordinate an explicit database password change and update
the corresponding local environment value together. Schema privilege changes
also require an explicit administrator/migration action on existing volumes.
Preserve or back up valuable data before any maintenance.
If a startup fails, first confirm Docker is running, configuration is complete,
and ports 8000 and 5432 are free. Check service status with
docker compose ps; database or application logs may contain sensitive details
and must remain local.