Backend-first project · Django REST API
Dependency-aware workflows with explicit permissions and auditable state transitions.
QuestBoard is a Python and Django backend API for collaborative work with dependencies and review. Unlike basic task CRUD, it enforces what work can start, who can approve it, and keeps meaningful changes consistent and auditable.
- Python
- Django
- Django REST Framework
- PostgreSQL
- Docker
- Gunicorn
Overview
The project concentrates on backend rules that ordinary create, update and delete endpoints do not express well: workflow eligibility, project-scoped authority, dependency integrity, review separation and durable audit history.
Explicit workflow
Quest state changes use a dedicated transition operation rather than unrestricted PATCH behavior. Legal transitions carry their own permissions and preconditions, including a controlled review return to IN_PROGRESS.
BACKLOGREADYIN_PROGRESSREVIEWDONE
Dependency-aware progression
Dependencies form a validated project-local graph. Planning operations reject invalid edges before insertion, while PostgreSQL constraints backstop duplicate and self-referential relationships. Prerequisites directly gate whether a BACKLOG quest may become READY.
- Self-dependencies are rejected
- Dependencies must remain within one project
- Duplicate edges and cycles are rejected
- Every prerequisite must be DONE before READY
Contextual permissions and invariants
Authorization is evaluated against project membership, role, assignment and workflow state. OWNER and REVIEWER authority is separated from CONTRIBUTOR execution, and an assignee cannot approve their own work.
Auditability
QuestEvent persists significant creation, assignment, dependency and state mutations with actor, timestamp and structured context. A quest_id_snapshot keeps the historical identifier available after a legal quest deletion.
Transactions and concurrency
Domain mutations use transaction.atomic. Quest rows are locked for concurrent state changes, while project-level select_for_update locks serialize graph-sensitive dependency writes and membership changes whose invariants span multiple rows.
transaction.atomicQuest row · select_for_updateProject row · graph and owner invariants
Engineering challenge
A PostgreSQL-specific failure exposed an invalid SELECT FOR UPDATE shape through the nullable assignee relation. The fix preserved locking: transition_quest now locks the Quest row only and resolves the nullable relation separately, keeping the transaction boundary and workflow invariants intact.
Testing and delivery
GitHub Actions exercises the backend against PostgreSQL 17 and validates code quality, migrations, Django configuration, the OpenAPI contract, domain/API tests and Docker image construction. The same Docker runtime is deployed through Gunicorn on Render with managed PostgreSQL.
PostgreSQL 17Ruff lint and formatMigration driftDjango system checksOpenAPI validationBackend/API testsDocker image build