Skip to content

Gamine CMS

Status: Scaffolded (NOT YET DEPLOYED) — Vikunja critical path: #610→#611→#600→#601→...
Decision: ADR-0005 — Wagtail chosen over Strapi/Ghost/WordPress

Wagtail 6.x CMS for the gamine.org public website. Replaces the legacy WordPress installation on SiteGround.


Architecture

gamine-brain (intelligence) ──POST /api/cms/import/post/──► gamine-cms (Wagtail)
                                                        infra-postgres
                                                        (gamine_cms DB)
                                                        MinIO (gamine-cms-media)
                                                     infra-nginx ──► gamine.org

Factory → Product model: Approved content suggestions from gamine-brain flow automatically into Wagtail as drafts via a single authenticated POST endpoint. Editors (Marta, Alice) review and publish from the Wagtail admin.


Key paths

Item Path
Source code (local) ~/Documents/JB_Hostinger/gamine-cms/
VPS deployment /opt/gamine-cms/ (when deployed)
Forgejo repo joaobrazao/gamine-cms
Compose file /opt/rabbithall-compose/ (to be added)
DB gamine_cms on infra-postgres
MinIO bucket gamine-cms-media
Admin URL https://gamine.org/cms-admin/

Stack

Component Choice
CMS framework Wagtail 6.x
Backend Django + Python 3.11
Database PostgreSQL (gamine_cms schema)
Media storage MinIO (gamine-cms-media bucket)
Multilingual wagtail-localize (PT + EN)
Admin 2FA django-otp (TOTP)
Container Docker (single gamine-cms service)
Port 8200 internal

Environment variables

DJANGO_SECRET_KEY=<from Vaultwarden>
DATABASE_URL=postgresql://litellm:<pwd>@infra-postgres:5432/gamine_cms
MINIO_ENDPOINT=minio:9000
MINIO_BUCKET=gamine-cms-media
MINIO_ACCESS_KEY=<from Vaultwarden>
MINIO_SECRET_KEY=<from Vaultwarden>
CMS_IMPORT_API_KEY=<from Vaultwarden>        # used by gamine-brain to POST drafts
ALLOWED_HOSTS=gamine.org,localhost

Deployment critical path

All 53 tasks are tracked in Vikunja (#600–#668). High-level sequence:

  1. #610 Generate CMS_IMPORT_API_KEY + store in Vaultwarden
  2. #611 All secrets in Vaultwarden
  3. #600 Clone repo to VPS + create .env + create gamine_cms DB
  4. #601 First Docker deploy + manage.py migrate + createsuperuser
  5. #613 gamine-brain rebuild with /api/cms/import/post/ endpoint
  6. #614 Frontend build + "↗ Site" button in gamine-brain UI
  7. #635+#636 2FA + rate limiting
  8. #639+#640 RGPD pages
  9. #621 Marta validates brand book
  10. #625 E2E test: approve → draft → publish → live

User roles

User Role Access
Marta Admin Full Wagtail admin
Alice Editor Create/edit pages, submit for review
Cristina Editor Create/edit pages, submit for review

Security notes

  • /cms-admin/ and /django-admin/ rate-limited at 10 req/min via nginx (#636)
  • All admin users require TOTP 2FA via django-otp (#635)
  • CSRF enforced by Django (default)
  • Session cookies: httpOnly + SameSite=Lax
  • Content-Security-Policy tuned via nginx (#638)

Backup and restore

Daily backup via /opt/backup.shgamine_cms_<DATE>.sql.gz kept 30 days.

Restore procedure: see Runbook — Restore gamine-cms DB