Accept page-centric markdown SoR with dual authoring, live includes, and lazy projections; accept thin dir+git plane with PageOps and supported upgrades to shard-wiki and kontextual. Demote ADR-0002 Forgejo-as-SoR.
169 lines
7.7 KiB
Markdown
169 lines
7.7 KiB
Markdown
---
|
||
id: ADR-0003
|
||
title: Page-centric markdown SoR, authoring, and live derived content
|
||
status: accepted
|
||
date: 2026-08-13
|
||
deciders: bernd
|
||
related:
|
||
- ADR-0001
|
||
- ADR-0002
|
||
- ADR-0004
|
||
- docs/architecture/ArchitectureBlueprint.md
|
||
- docs/decisions/2026-08-12-feature-cut-stage-1.md
|
||
workplans:
|
||
- CSOC-WP-0004
|
||
- CSOC-WP-0006
|
||
- CSOC-WP-0001
|
||
---
|
||
|
||
# ADR-0003 — Page-centric markdown SoR, authoring, and live derived content
|
||
|
||
## Status
|
||
|
||
**Accepted** (2026-08-13).
|
||
|
||
Supersedes the parts of **ADR-0002** that treated “one Forgejo repo per space
|
||
as the product SoR.” ADR-0002 remains valid as a **historical vertical slice**
|
||
and as **one optional git/Forgejo binding shape** under ADR-0004.
|
||
|
||
## Context
|
||
|
||
The rebuild must exit Bubble with **user-owned content** that is easy to
|
||
export and reuse. Live coulomb models spaces, pages, and chunks; stage-1 cut
|
||
requires Title, Abstractor, Visual, copy, and transfer without recreating
|
||
Bubble’s full chunk graph.
|
||
|
||
Prior work delivered a Forgejo-bound read/write slice (ADR-0002). Architecture
|
||
discussion established:
|
||
|
||
- Markdown (+ assets) as exportable system of record; database as cache.
|
||
- **markitect-tool** as structure library (not product host); markitect-main avoided.
|
||
- Page-first knowledge work with transclusion rather than a priori chunks.
|
||
- Dual authoring (top-down and bottom-up) and lazy display fields.
|
||
- Live includes by default (spreadsheet-like); pin as exception.
|
||
|
||
## Decision
|
||
|
||
### 1. System of record
|
||
|
||
1. **Content SoR** is **markdown files** (frontmatter + body + backmatter) and
|
||
**assets** under a **directory tree** versioned in **git** (see ADR-0004).
|
||
2. **Postgres** (or any app DB) holds only:
|
||
- identity linkage (`Member` ↔ NetKingdom subject),
|
||
- product indexes / **projections** for cards and lists,
|
||
- optional pointers into the tree (paths, digests) —
|
||
**not** long-form page bodies as SoR.
|
||
3. Anything a user should take on export must live in the tree; DB content for
|
||
bodies is disposable and rebuildable.
|
||
|
||
### 2. Information model
|
||
|
||
| Concept | Meaning |
|
||
|---------|---------|
|
||
| **Page** | Primary knowledge object: one markdown document (or connected set after explode). |
|
||
| **Space** | Container / context for pages (directory + metadata; may itself be a page of `type: space`). |
|
||
| **Card** | UI projection only (title, abstractor, visual, actions) — not a storage type. |
|
||
| **Region / “chunk”** | Addressable unit *within* a page (heading, named region, selector). **Not** a required first-class storage row. |
|
||
| **Member / tenant** | NetKingdom + app session (ADR-0001); not stored as page content. |
|
||
|
||
**Stage-1 fields** on pages and spaces (frontmatter or equivalent):
|
||
|
||
- **title**
|
||
- **abstractor** (short description; Bubble “Abstractor”)
|
||
- **visual** (ref to an asset)
|
||
- **body** (markdown)
|
||
|
||
### 3. Page-first structure (not a priori chunks)
|
||
|
||
1. Authors write **pages** fluently; structure is headings and optional named regions.
|
||
2. Reuse uses **address → live transclude → promote** (markitect include/selector/region), not a mandatory `Chunk` entity graph.
|
||
3. Bubble `custom.chunk` migration **prefers** sections/regions or connected pages with includes — not permanent recreation of chunk tables.
|
||
4. Outline flexibility uses markitect **explode / implode** (and related compose/include): split one document into smaller **connected** documents; merge selected docs back into one. Connectivity after explode prefers **live** includes or content references.
|
||
|
||
### 4. Dual authoring modes
|
||
|
||
Both are first-class; no forced mode toggle:
|
||
|
||
| Mode | Flow |
|
||
|------|------|
|
||
| **Top-down** | Title → abstractor → outline (headings) → elaborate body → optional visual |
|
||
| **Bottom-up** | Body first; title / abstractor / structure / visual established later or while writing |
|
||
|
||
Creating or saving content **must not** require a complete metadata form.
|
||
|
||
### 5. Lazy projections, lock, and staleness
|
||
|
||
For display fields (title, abstractor, visual) and other **derived** values:
|
||
|
||
1. If **absent** and display needs them → **generate lazily** → **persist** as normal field values (as if user-provided for export).
|
||
2. Per-field **regenerate** and **lock** (lock blocks auto-fill and regenerate until unlock).
|
||
3. If inputs change and the field is unlocked derived → **May be stale** badge → **Generate updated version** → side-by-side **Current | Alternative** → **Keep current** or **Use alternative** (replace). Optional ack updates fingerprint without changing text.
|
||
4. **Never** silently overwrite **locked** or last-**user**-edited values without consent.
|
||
|
||
Generator policy: deterministic first (e.g. first H1, first paragraph); optional LLM/pipeline behind the same contract.
|
||
|
||
### 6. Live by default; pin as exception
|
||
|
||
| Mode | Behavior |
|
||
|------|----------|
|
||
| **Live (default)** | Includes and formula-like derived content resolve to **current** inputs on view/export (spreadsheet metaphor). |
|
||
| **Pinned (exception)** | Explicit freeze of a snapshot in the host document; refresh uses stale → alternative → replace \| keep. |
|
||
|
||
Pure live includes do not require replace/keep; pinned/`mkt:derived` (markitect proposal) and projection fields do.
|
||
|
||
### 7. markitect-tool role
|
||
|
||
1. coulomb **depends on markitect-tool** for parse, frontmatter, query/extract, **live include**, explode/implode, and (when implemented) derived-slot stale/refresh APIs.
|
||
2. coulomb does **not** “run on” markitect as a product platform; markitect-main is not a runtime foundation.
|
||
3. Cross-repo: pin/derived contract tracked in markitect-tool
|
||
`docs/proposed-stale-derived-and-include-pinning.md`.
|
||
|
||
### 8. Relationship to ADR-0002
|
||
|
||
| ADR-0002 item | Under ADR-0003/0004 |
|
||
|---------------|---------------------|
|
||
| Markdown as content form | **Confirmed** |
|
||
| Assets beside content | **Confirmed** (tree layout; asset-store later) |
|
||
| Postgres not body SoR | **Confirmed** |
|
||
| One Forgejo repo per space as SoR | **Demoted** — optional remote/export; SoR is the **content tree + git** (ADR-0004) |
|
||
| Edit-in-Forgejo as primary write | **Optional** path; product PageOps may write tree/git directly |
|
||
|
||
## Consequences
|
||
|
||
### Positive
|
||
|
||
- User data remains files; agents and humans edit without the app DB.
|
||
- Stage-1 fields and card UI align with live Bubble vocabulary (Title, Abstractor, Visual).
|
||
- Fluency: top-down and bottom-up; live reuse; outline explode/implode without chunk ontology tax.
|
||
- Clear demotion of Forgejo-as-unique-SoR reduces lock-in to one forge layout.
|
||
|
||
### Negative / costs
|
||
|
||
- App must implement projection index invalidation when files change.
|
||
- Live includes need careful caching and security (path sandbox, cycles) via markitect.
|
||
- Lazy/AI generators need UX discipline so writers are not interrupted or overwritten.
|
||
- Explode/implode UX is non-trivial product work (connectivity, navigation).
|
||
|
||
### Neutral
|
||
|
||
- Identity remains ADR-0001; content authz consolidation is NetKingdom-side (ArchitectureBlueprint D3).
|
||
- Content plane storage mechanics and upgrades are **ADR-0004**.
|
||
|
||
## Non-goals
|
||
|
||
- Recreating Bubble marketplace, social graph, or monetization in this ADR.
|
||
- Choosing shard-wiki or kontextual as the *initial* plane (upgrade path only).
|
||
- Extracting a fleet asset-store repo (deferred).
|
||
- Full markitect derived-slot implementation timeline (owned by markitect-tool).
|
||
|
||
## References
|
||
|
||
- `docs/architecture/ArchitectureBlueprint.md` (D1–D4, R1–R12)
|
||
- `docs/architecture/transclusion-and-chunks.md`
|
||
- `docs/architecture/authoring-modes-and-lazy-projections.md`
|
||
- `docs/architecture/stale-derived-content.md`
|
||
- `docs/capability/stage-1-cutover.md`
|
||
- `docs/capability/existing-bubble-capability-map.md`
|
||
- ADR-0002 (provisional slice; partially superseded)
|
||
- markitect-tool: `docs/transform-compose-include.md`, `docs/explode-implode.md`,
|
||
`docs/proposed-stale-derived-and-include-pinning.md`
|