Files
shard-wiki/research/260614-mojomojo-deep-dive/findings.md
tegwick e0c3d0699c research: MojoMojo deep dive (Perl Catalyst DB-backed wiki); UC-81
SHARD-WP-0003 T8. Classic relational-DB-backed wiki: Catalyst/DBIx::Class app,
pages + path tree + full history in SQL tables, Markdown body in a column, no
file store and no content API. Anchors the direct-DB-read binding (map schema
-> page model + journal); DB version rows = a third history source beside git
commits and RCS files. UC-81. Enriched UC-02/40/36/34. Marks T8 done.
Feeds SHARD-WP-0002 T14/T13/T11.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 20:54:40 +02:00

6.9 KiB

MojoMojo — deep dive (findings)

Date: 2026-06-14 · Source: SHARD-WP-0003 T8 · Subject: MojoMojo, a Perl Catalyst wiki/CMS.

Why this dive

The file-store classics (TWiki, Foswiki, Oddmuse, UseMod) keep pages as files; the modern SaaS keep them behind APIs. MojoMojo is the classic relational-DB-backed wiki — a Catalyst MVC app over DBIx::Class with pages and their history in SQL tables, and no file store and no first-class content API. It anchors the "attach by reading the database directly" hard case the adapter contract must account for (T13/T14).

1. Architecture

  • Stack: Perl Catalyst (MVC web framework) + DBIx::Class (ORM) over a relational DB (SQLite / PostgreSQL / MySQL). Templating via Template Toolkit.
  • Content: Markdown (Text::MultiMarkdown) is the page markup — so the body is Markdown, but it lives in a DB column, not a file.
  • Pages are hierarchical: a path tree (/parent/child) modeled as rows with parent/lineage relations — structure is relational, not directory-based.
  • Versioning: each page edit creates a new version row (a page_version-style table) — full revision history lives in DB version tables, with author/timestamp.
  • Features: inline AJAX editing, attachments (stored as DB rows / blobs + metadata), diffs, RSS feeds, full-text search, per-page permissions.

2. The attach problem — DB or nothing

MojoMojo exposes its content through the web app (HTML) and the database; there is no clean REST/GraphQL content API and no file store. So a shard adapter has two realistic paths:

  1. Direct relational read (preferred): read the page + page_version (+ content, attachment) tables via DBIx::Class schema — pages, the path tree, and full history are all there, importable to the coordination journal (UC-41-style history import, but from DB version rows rather than RCS/git).
  2. HTML scrape (fallback): parse rendered pages — lossy, last resort.

This makes MojoMojo the direct-DB-read binding archetype: the canonical store is a relational schema, and the adapter's job is to map that schema to the wiki page model + journal.

3. Capability profile

Dimension (synthesis spectrum) MojoMojo
Attachment mode direct DB read (relational); HTML-scrape fallback; no file store, no API
Addressing granularity page (row); path tree via lineage rows
Content identity DB page id; path as human key
Identity vs placement row id vs path lineage (separable)
Structure relational: page rows + parent/lineage; attachments as rows
History DB version tables (per-edit version rows, author/timestamp)
Merge model app-level last-writer; DB transactions
Native query SQL over the schema (not a wiki query language)
Translation Markdown body in a DB column — minimal translation, but extraction needed
Write granularity page (row) per save
Operational envelope a Perl app + its DB; direct DB access needs credentials
Access grant per-page permissions in DB; app auth
Content opacity transparent if you can read the DB
Provenance author/timestamp on version rows

4. INTENT mapping

Reinforcements

  • Backend-neutral page model: the body is Markdown — once extracted from the DB column it maps directly; the adapter's work is schema→page-model, not format translation.
  • History portability (T13): DB version rows are a third history-source shape beside git commits and RCS files — importable to the journal as discrete revisions with author/timestamp.
  • Graceful degradation: even with only DB read (no API), MojoMojo is a usable read/projection/backup shard; with DB write it could be write-through, but carefully (app invariants).

Divergences (boundaries / notes)

  • No file store, no API ⇒ the direct-DB-read binding is a first-class attach mode the contract must name (alongside file-store, in-engine host, external-API, CRDT, P2P) — or a sub-mode of "external store" where the medium is a relational schema (T14). Reading a third-party app's DB is coupling to its schema (versioned, may drift across MojoMojo versions) — a stated risk (UC-43 backend-swap analogue at the schema level).
  • Writing by direct DB risks violating app invariants (lineage, version counters, search index) — default to read/projection/overlay; write-through only with the app's cooperation.

What to keep

  1. Direct-DB-read as a named binding for DB-backed engines with no file/API (UC-81), mapping a relational schema → wiki page model + journal.
  2. DB version rows as a history source for the journal (T13), beside git and RCS.
  3. Schema-coupling caution — treat the schema as a versioned interface that can drift (relates UC-43).

5. UC seed

# Seed Disposition
UC-81 Attach a DB-backed wiki with no file store / no API (MojoMojo) by reading its relational store directly (page + version tables), mapping schema → page model and importing DB-resident history to the journal new
DB attach vs file attach enrich UC-02 / UC-40
DB version-table history import enrich UC-36
relational page rows / lineage as structure enrich UC-34

6. Architecture notes for SHARD-WP-0002

  • T14 (binding): add direct relational read as a binding (or external-store sub-mode whose medium is a SQL schema) for DB-backed engines lacking a file store or API; HTML scrape is the lossy fallback. Schema is a versioned coupling (drift risk, UC-43).
  • T13 (history portability): DB version rows = a history source alongside git commits and RCS revisions — import as discrete journal entries (author/timestamp).
  • T11 (capability): "has-file-store" / "has-API" are absent here; "has-readable-DB" is the capability — a sparse profile relying on schema knowledge.

7. Open questions

  1. Does shard-wiki sanction direct third-party DB reads as a binding, or restrict them (schema coupling/drift) to a documented best-effort mode? How is schema drift across MojoMojo versions handled (UC-43)?
  2. Is write-through by direct DB ever allowed (risking app invariants), or are DB-backed no-API engines read/projection/overlay/backup only?

8. Sources

  • MojoMojo — github.com/mojomojo/mojomojo; metacpan MojoMojo (Catalyst app, DBIx::Class schema: Page / PageVersion / Content / Attachment)
  • Catalyst + DBIx::Class framework docs (architecture context)
  • prior: research/260613-twiki-deep-dive/ (file-store classic contrast, UC-40/41)

9. Traceability

New UC UC-81 carries the marker in the wikiengines column of spec/UseCaseCatalog.md. Enriched: UC-02, UC-40, UC-36, UC-34. Architecture cross-refs: SHARD-WP-0002 T14 (direct-DB binding), T13 (DB version-row history), T11.