Area: Cross-cutting infra (audit p14) · Surface: LegalPage model / legal_pages table / AdminLegalController · Dimension: competitor-gap · Severity: major
Terms of Service and Privacy Policy are exactly the documents where dated, retrievable versions matter — for compliance, for showing members 'what changed on this date,' and for a one-click rollback after a bad edit. Iubenda/Termly and most community platforms version legal documents and surface an effective-date history; Discourse keeps full post/wiki revision history with diffs. Mobieus throws the previous text away on every save: a super-admin who pastes the wrong content over the live Privacy Policy cannot recover the old one, and there is no audit-grade record of what the policy said on a given date. The audit log proves an edit happened but not what it replaced.
Evidence
database/migrations/2026-04-29-legal-pages.sql defines `legal_pages` with a single body_md/body_html column and `updated_at ... ON UPDATE CURRENT_TIMESTAMP` — each save mutates the row in place. LegalPage.php save() does an upsert (no revisions table; `grep version|revision|history` in LegalPage.php returns nothing). AdminLegalController.php:103-107 records an AuditLog entry ('legal.page_saved', char count) but NOT the prior body, so there is no recoverable previous version. legal/edit.php:243 publishing card states 'Saving publishes immediately. There is no draft mode.'
Suggested fix. Add a legal_page_revisions table (slug, body_md, body_html, title, edited_by, created_at) written on every save; show a revision timeline with view/diff/restore in /admin/legal/{slug}/edit, and expose an optional public 'effective date / version history' link on the rendered legal page.
Filed by the automated tenant-app audit and adversarially evidence-verified. Status: verified. Open — not yet actioned.
Patrick Bass
@mobieus