What this project is about
Pressroom is a Django publishing application for teams that need to draft, review and publish content without exposing unfinished edits. It combines a private editorial workspace, a public site and a REST API. The central question is simple: what should readers see while an author is still changing a page?
I built it as a portfolio application with workspace separation, author and editor permissions, revision history and scheduled publishing. A live demo gives each visitor a temporary workspace to try the actual workflow. It is a demonstration, not an established commercial service.
How it works
- Write a draft
- Review an approved revision
- Publish to site + API
Separate drafts from approved content
Authors edit drafts and submit them for review. Editors approve a particular revision for publication. The public page and API read that snapshot, so later edits do not silently change the published content. Restoring an older revision creates a new draft rather than rewriting history.
Handle permissions and competing edits
Owners, editors, authors and viewers have distinct responsibilities within a workspace. Private pages, revisions, membership and audit records are checked against that workspace. Writes include an expected version; outdated API saves return a conflict instead of overwriting another person's work. PostgreSQL row locks protect concurrent changes.
Share rules across the website and API
HTML views and REST endpoints use the same publishing service layer. Page state, revisions and audit events are committed together. A scheduler publishes approved content when due; repeated runs do not repeat the transition. Editing scheduled content cancels approval and scheduling. Markdown is sanitised before rendering.
The important design choices
Publish a snapshot
Keep the approved revision separate from ongoing edits.
The trade-offThere is additional revision state to manage, but readers see precisely the content an editor approved.
Keep the interface server-rendered
Use Django templates and CSS alongside a REST API.
The trade-offLess client-side state makes the workflow simpler to follow. Richer editing would require more interface work. SQLite supports quick local setup, while PostgreSQL is needed to test row-locking behaviour.
Edit without changing the live page
An author needs to revise a page that an editor has already published.
- Change the draft while readers continue seeing the existing approved revision.
- Submit the new revision and have an editor review it before publication.
- If someone else edited the draft first, resolve the version conflict instead of overwriting their work.
What this showsApproval belongs to specific content, while competing writes remain visible.
Illustrative walkthrough of the implemented workflow, not a production incident.
How it was tested—and what it shows
The checks
The repository records 76 PostgreSQL tests, CI across Python 3.12 and 3.13, and browser verification of the publishing workflow. Concurrency checks exercise competing edits and scheduler behaviour; SQLite skips database-specific cases rather than pretending to test row locks.
These are inspectable implementation checks, not proof of production reliability under arbitrary load or an independent security assessment. Verification and architecture notes explain what was exercised.
What to take from the results
The result is a complete draft, review, publish and restore workflow. Public content remains on its approved snapshot while editorial work continues, and stale writes are surfaced rather than silently lost.
The project does not include enterprise SSO, billing, media uploads or email invitations. Audit records are append-only through application behaviour, not tamper-proof storage. Demo rate limits are local to each worker, not a distributed abuse-control system.
What to keep in mind
- A portfolio application, not a replacement for an enterprise CMS or evidence of commercial adoption.
- Media uploads, SSO, billing and email invitations are outside the current release.
- Rate limits use per-worker memory; audit events are not a tamper-proof compliance ledger.
Technical notes & source
Built with
Python · Django · Django REST Framework · PostgreSQL · Docker
Terms used in this project
- Approved snapshot
- The exact reviewed revision served publicly, separate from later draft edits.
- Optimistic version check
- Reject an edit when the record has changed since the editor loaded it.