coulomb-social/docs/architecture/ArchitectureBlueprint.md
tegwick ce65b359af Add ADR-0003 and ADR-0004 for page SoR and thin git content plane
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.
2026-08-13 10:04:46 +02:00

323 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Architecture Blueprint — coulomb.social content & platform
| Field | Value |
|-------|--------|
| Status | **draft — decisions recorded 2026-08-13** |
| Product | coulomb.social rebuild (`coulomb-social`) |
| Related | stage-1 cut, capability maps, authoring, stale/derived, upgrade path |
| Non-goals | Implementing UI chrome here; full markitect feature build in this doc |
## 0. Decision log (2026-08-13)
| # | Topic | Decision |
|---|--------|----------|
| D1 | **Content plane** | **Start thin:** directory + markdown files, **secured in git**. Supported **upgrade path**: thin → **shard-wiki** (when wiki/federation matters) via markitect-shaped content; then → **kontextual** (structure, scale, rich media) as a **supported upgrade** of the information base. |
| D2 | **asset-store** | **Extract later.** Stage-1 may use local files next to markdown (and/or temporary blob helpers); do not block on a new repo. |
| D3 | **PolicyGateway / content authz ownership** | **Do not invent a parallel owner.** Prefer **NetKingdom consolidation** so identity *and* authorization decisioning for app resources become the obvious path (flex-auth / NK as one story). Until that lands, coulomb uses coarse product authz (session + SpaceMembership + tenant); content plane stays fail-closed when a PDP is wired. |
| D4 | **Structure UX** | Aspire to **outline-editor flexibility**: **explode** one markdown into smaller **connected** documents; **implode** selection(s) back into one file. **Default = live** (spreadsheet-like: includes/derived resolve to current inputs automatically). **Pin** only when the user freezes a snapshot. |
Earlier freezes (unchanged): NetKingdom identity, Railiance deploy, markdown SoR + DB cache, markitect-tool not host, page-first, dual authoring, lazy projections + lock, stage-1 cut.
---
## 1. Architectural aim
Deliver a co-creation product where:
1. **Identity** (users, groups, tenants) is **NetKingdom** — not reimplemented.
2. **Runtime** is **Railiance** — not reimplemented.
3. **User-owned content** is **markdown (+ assets)** in a **git-secured directory tree**, exportable without the app database.
4. The **database is a cache / projection** for cards, memberships, search speed.
5. **markitect-tool** makes markdown structured and operable (parse, include, explode/implode, later derived slots) — **not** the product host.
6. **coulomb** owns co-creation UI (cards, spaces, outline-oriented editing, copy/transfer).
7. Knowledge work stays **fluent**: top-down and bottom-up; **live** reuse by default; pin when freezing matters.
8. Growth does not strand data: **thin git base → shard-wiki → kontextual** are **supported upgrades**, not rewrites from a proprietary store.
## 2. Non-negotiable rules
| # | Rule |
|---|------|
| R1 | Markdown (frontmatter + body + backmatter) + assets under a **directory tree** are the **exportable SoR**. |
| R2 | App DB holds **projections and app linkage only**; disposable for content bodies. |
| R3 | Authn/IdP = **NetKingdom**; coulomb maps OIDC → Member; no password store. |
| R4 | Authz: prefer **NetKingdom-consolidated** decisioning; no second user directory; no permanent coulomb-specific PolicyGateway fiefdom. |
| R5 | **markitect-main** is legacy reference, not a runtime foundation. |
| R6 | **markitect-tool** is the markdown structure dependency. |
| R7 | **Default content plane = thin dir+git.** PageOps hide the plane; upgrades swap adapters. |
| R8 | Stage-1 must: onboarding; spaces/pages with **Title / Abstractor / Visual**; page copy; page transfer. |
| R9 | **Pages first** — address / live-transclude / explode-implode / promote; not a priori chunk storage. |
| R10 | **Live by default** for includes and other formula-like derived content; **pin** freezes a snapshot; pinned/stale use badge → alternative → **replace \| keep** + lock. |
| R11 | **Explode / implode** (outline-editor flexibility) are first-class structure operations (markitect primitives + coulomb UX). |
| R12 | **asset-store** extraction is **deferred**; assets may live beside markdown until then. |
## 3. System shape
```text
┌──────────────────────────┐
│ NetKingdom │
│ OIDC · groups · tenants│
│ (authz consolidation →)│
└────────────┬─────────────┘
│ principal
┌─────────────────────────────────────────────────────────────┐
│ coulomb.social (product) │
│ • Cards, spaces, dual authoring, outline explode/implode │
│ • PageOps; live resolve; pin when asked │
│ • Railiance deploy │
└───────────────┬─────────────────────────────┬───────────────┘
│ cache │ PageOps
▼ ▼
┌───────────────┐ ┌───────────────────────────┐
│ Postgres │ │ Content plane │
│ projections │ │ ★ A thin dir + git │
└───────────────┘ │ (default / stage-1) │
│ ↗ B shard-wiki upgrade │
│ ↗ C kontextual upgrade │
└─────────────┬─────────────┘
┌─────────────▼─────────────┐
│ markitect-tool │
│ structure · include LIVE │
│ explode/implode · query │
│ pin/derived (proposed) │
└─────────────┬─────────────┘
┌───────────────────────────┐
│ Assets (files next to md) │
│ later: shared asset-store │
└───────────────────────────┘
```
### PageOps (store-agnostic)
| Op | Meaning |
|----|---------|
| `list_pages` / `get_page` / `put_page` / `archive_page` | CRUD |
| `copy_page` / `transfer_page` | Duplicate / re-home |
| `explode_page` / `implode_pages` | Outline-style split/join (markitect) |
| `resolve_view` | Live includes/derived for display (default) |
| `pin_slot` / `unpin` / `refresh_pinned` | Freeze snapshot; stale → alternative → replace\|keep |
| `project_field` / `regenerate` / `lock` | Title/abstractor/visual lifecycle |
| `put_visual` / `get_asset` | Binary next to tree (later asset-store) |
### Upgrade path (supported)
```text
Stage now A dir + .md + assets (+ git)
│ markitect-tool always
When wiki / B same markdown becomes shard-wiki shard(s)
federation │ PageOps adapter swap; export tree still valid
When scale / C kontextual KnowledgeAsset + blobs
rich media / │ markdown remains portable representation
governance │ PageOps adapter swap; migration tooling required
```
**Requirement:** every upgrade **preserves user export** of markdown+assets; no dead-end proprietary body store.
## 4. Information model (product)
| Concept | Representation |
|---------|----------------|
| **Page** | One markdown file (or connected set after explode) |
| **Space** | Directory / container + metadata page |
| **Tree** | Git-secured directory layout |
| **Card** | UI projection (title, abstractor, visual, actions, stale) |
| **Outline** | Headings / exploded connected docs — **not** Bubble chunk rows |
| **Live include** | `mkt:include` resolves current source (default) |
| **Pinned derived** | Optional frozen snapshot; explicit refresh |
| **Member / tenant** | NetKingdom + app session |
### 4.1 Outline editor flexibility (explode / implode)
Aspire to outline-editor UX powered by markitect **explode / implode** (and related compose/include):
| Action | User intent | Markitect analogue |
|--------|-------------|-------------------|
| **Explode** | Split a large page into smaller **connected** documents (sections as pages or files) | `mkt explode` (+ connectivity via includes/refs) |
| **Implode** | Merge selected docs/sections **back into one** markdown file | `mkt implode` / compose |
| **Navigate outline** | Treat structure as editable hierarchy | Headings + connected pages view |
Connectivity after explode: prefer **live includes or content references** so the outline stays one logical document until the user pins or permanently severs links.
### 4.2 Live by default (spreadsheet metaphor)
| | Live (default) | Pinned (exception) |
|--|----------------|-------------------|
| Includes / formula-like derived | Resolve to **current** inputs on view/export | Stored snapshot until refresh |
| Body of a normal page | User text as written | n/a |
| Projections (title/abstractor/visual) | Lazy fill then **persist**; regenerate on demand | Lock freezes; stale offers alternative |
| Stale pinned / locked derived | — | Badge → generate alternative → **replace or keep** |
**Spreadsheet rule:** formulas stay live unless the user **pastes values** (pin).
Pinning is deliberate, not the default co-creation mode.
### 4.3 Dual authoring + lazy projections
Unchanged intent: top-down and bottom-up both natural; missing display fields lazy-fill then persist; regenerate + lock per field.
See `authoring-modes-and-lazy-projections.md`, `stale-derived-content.md`.
## 5. Content plane — decided start + upgrades
### 5.1 Default: A — thin directory + git
```text
spaces/<space-slug>/
pages/<page-slug>.md
assets/…
# entire tree in git (user- or service-mediated commits)
```
| | |
|--|--|
| **Why** | Simplest SoR; user data is files; matches “secured in git” |
| **coulomb role** | PageOps over filesystem/git; DB indexes cards |
| **markitect role** | Parse, live include, explode/implode, validate |
### 5.2 Upgrade B — shard-wiki
When multi-shard wiki behavior, overlays, or federation become product-relevant:
- Ingest the **same** markdown tree (or git repo) as a shard.
- PageOps adapter targets shard-wiki; UI unchanged.
- markitect-tool remains structure layer for resolve/explode.
### 5.3 Upgrade C — kontextual-engine
When asset identity, scale, rich multi-format media, audit/lineage, or ECM-class governance dominate:
- Supported **migration** of the information base into kontextual assets/blobs.
- Markdown remains the portable authoring/export form where applicable.
- **Not** required for stage-1.
### 5.4 What we do *not* do now
- Do not build coulomb **on** markitect-main.
- Do not require kontextual or shard-wiki for first productive transfer.
- Do not extract **asset-store** before a second consumer (D2).
## 6. Assets (deferred extract)
- Stage-1: files under `assets/` (or equivalent) in the content tree; optional simple content-addressing later.
- **asset-store** shared repo: **later** (seed from kontextual BlobStorage when extracted).
- Visual field stores a **ref** into that tree (or future store).
## 7. Identity & access control
```text
Browser → NetKingdom OIDC → coulomb session
├─ product: tenant_id, SpaceMembership (and future NK groups)
└─ long-term: NetKingdom-consolidated authz (flex-auth / NK)
so PolicyGateway ownership becomes trivial or unused
```
| Now | Target |
|-----|--------|
| Session + membership + tenant isolation | Same + NK-group claims |
| Content plane fail-closed if PDP present | PDP = consolidated NK story |
| No coulomb-owned IdP | Unchanged |
**D3:** Avoid multi-team thrash on “who owns PolicyGateway”; push consolidation in NetKingdom so apps only pass principal + resource attributes.
## 8. Deploy sketch (Railiance)
| Component | Deploy |
|-----------|--------|
| coulomb-social | Existing chart; `app.coulomb.social` |
| Content tree | Volume or git-backed storage accessible to the app; **git** is SoR discipline |
| Assets | Beside markdown until asset-store |
| NetKingdom | Existing KeyCape / Authelia |
## 9. Stage-1 product scope
**Must:**
- Onboarding (NetKingdom)
- Spaces/pages: Title, Abstractor, Visual, body
- Copy, transfer
- Cards; dual authoring; lazy projections
- Content as **dir+git** via PageOps
- Live includes when markitect is wired; pin optional
**Aspire early (structure UX):**
- Outline-oriented **explode / implode**
**Later:** social, marketplace, monetization, shard-wiki/kontextual upgrades, asset-store extract.
## 10. ADRs
| ADR | Topic | Status |
|-----|--------|--------|
| ADR-0001 | NetKingdom identity | accepted |
| ADR-0002 | Forgejo vertical slice | partly superseded by 0003/0004 |
| **ADR-0003** | Page-centric markdown SoR, authoring, live/pin | **accepted** |
| **ADR-0004** | Thin git plane, PageOps, upgrades B/C | **accepted** |
| ADR-0005 | asset-store extraction | later |
| — | NetKingdom authz consolidation | platform (NK) |
Markitect-tool: live include (done), explode/implode (done), pin/derived proposal (`proposed-stale-derived-and-include-pinning.md`).
## 11. Spikes (narrowed)
With D1D4, prioritize:
1. **Thin tree layout + git write path** (PageOps on files).
2. **markitect** parse + **live** include in get/view.
3. **Explode/implode** UX prototype on real pages.
4. **Lazy title/abstractor** + stale replace\|keep.
5. Export zip/tar of tree without DB.
Defer deep shard-wiki/kontextual spikes except **export/import round-trip sketches** that prove upgrade feasibility.
Full list remains in `spike-checklist.md` (update scorecard: A = chosen start).
## 12. Closed discussion prompts
| Prompt | Resolution |
|--------|------------|
| A vs B vs C for start | **A**; B/C = supported upgrades |
| asset-store now? | **Later** |
| PolicyGateway owner | **Consolidate under NetKingdom**; dont fork ownership |
| Chunk UX | **Outline editor + explode/implode**, not chunk tables |
| Live vs pin default | **Live**; pin is explicit |
---
## 13. Working recommendation (frozen)
| Layer | Decision |
|-------|----------|
| Product UI | coulomb cards, spaces, outline explode/implode, dual authoring |
| Markdown structure | markitect-tool; **live** includes by default |
| Identity / deploy | NetKingdom / Railiance; authz → NK consolidation |
| Content plane | **Thin dir + git** now |
| Upgrades | → shard-wiki → kontextual (supported, markdown-preserving) |
| Assets | Beside tree now; **asset-store later** |
| Derived/stale | Live default; pin + badge → alternative → replace\|keep |
| markitect-main | Avoid |
---
## References
### coulomb-social
- `docs/architecture/2026-08-12-content-substrate-exploration.md`
- `docs/architecture/transclusion-and-chunks.md`
- `docs/architecture/authoring-modes-and-lazy-projections.md`
- `docs/architecture/stale-derived-content.md`
- `docs/architecture/spike-checklist.md`
- `docs/capability/stage-1-cutover.md`
- `docs/capability/model-v0.yaml`
- `docs/capability/existing-bubble-capability-map.md`
- `docs/decisions/2026-08-12-feature-cut-stage-1.md`
### fleet
- markitect-tool: transform-compose-include, explode-implode, content-references, **proposed-stale-derived-and-include-pinning.md**
- shard-wiki: INTENT (Coulomb as consumer; upgrade target)
- kontextual: blob-storage, asset-registry (upgrade + later asset-store seed)
- markitect-main: successor-gap (legacy only)