coulomb-social/docs/adr/ADR-0002-space-content-forgejo-markdown.md
tegwick be32432d39 Add Space metadata model and provisional Forgejo content ADR
Introduce tenant-scoped Space/SpaceMembership with list and detail views.
Document markdown-in-Forgejo as content SoR (ADR-0002). Run migrations on
container start so app.coulomb.social picks up the new tables.
2026-08-12 01:30:05 +02:00

4.2 KiB

ADR-0002 — Space content as markdown in Forgejo

Field Value
Status Provisional (accepted for T04 vertical slice; revisit write path)
Date 2026-08-12
Deciders bernd
Workplan CSOC-WP-0004-T03

Context

coulomb.social co-creation spaces need durable page/artefact content. Bubble stores opaque page graphs. The rebuild should:

  • keep content agent- and human-editable in git,
  • version and review changes like normal software,
  • avoid making Postgres the system of record for long-form prose,
  • align with Forgejo already hosting fleet code on railiance01.

Identity and space metadata stay in the app DB (Space, memberships).

Decision

1. Canonical content form

  • Markdown (CommonMark + limited GFM: tables, fenced code, images).
  • Static assets (images, attachments) live beside markdown under a content root.
  • Postgres stores metadata and binding only — never full page bodies as SoR.

2. Repository layout (v1)

One Forgejo repository per space under a dedicated org (recommended: coulomb-spaces or tenant-scoped org later).

<forgejo_owner>/<forgejo_repo>/
  README.md                 # optional space intro
  pages/
    index.md                # default landing page
    <page-slug>.md
  assets/                   # images etc. referenced from pages
Field on Space Meaning
forgejo_owner org/user
forgejo_repo repo name
default_branch usually main
content_root default pages

Branch policy (v1): app reads from default_branch only. PRs for review are a human/Forgejo workflow; the app does not merge PRs in v1.

Monorepo alternative (deferred): single repo with spaces/<slug>/… — rejected for v1 to keep permissions and migration packages simple.

3. Read path (T04)

  1. App resolves Space by tenant + slug (authz already enforced).
  2. If binding incomplete → empty state (no silent Bubble fetch).
  3. Fetch file via Forgejo raw/contents API (preferred) or shallow cache:
    • HTTP GET with service token from env/OpenBao.
    • Cache rendered HTML or raw markdown in memory/disk with short TTL + optional webhook invalidation later.
  4. Render markdown → HTML with a locked-down sanitizer (no raw script).
  5. Fail closed on 404/403/network errors with operator-visible reason.

4. Write path (T05 — provisional)

v1 preference: edit in Forgejo (web UI or git) + app refresh.

  • Lowest security surface (no app-held write credentials required if public-read internal repos use deploy token read-only).
  • Optional later: in-app editor → commit as bot user via API.

Not in v1: bidirectional live sync with Bubble.

5. Mapping from Bubble (later CSOC-WP-0001)

Bubble concept Target
Space / room-like container Space row + Forgejo repo
Page / chunk prose pages/<slug>.md
Attachments assets/…
Permissions SpaceMembership + NetKingdom groups (refine later)

Export scripts should emit markdown files + a manifest JSON for binding fields.

6. Secrets

Secret Storage
Forgejo API token (read, later write) K8s Secret / OpenBao — env e.g. FORGEJO_TOKEN
Forgejo base URL non-secret config e.g. FORGEJO_BASE_URL=https://forgejo.coulomb.social

Never commit tokens. Never render tokens in Session details.

Consequences

Positive

  • Content is git-native and agent-friendly.
  • Clear boundary: app = membership + UX; Forgejo = document history.
  • Migration can ship repos per space without rewriting history into SQL.

Negative / follow-ups

  • Need Forgejo org, tokens, and network reachability from the app pod.
  • Offline/local dev needs a stub or fixture markdown path.
  • Search and cross-space queries need a separate index later.

Open questions (non-blocking for T04)

  1. Org name: coulomb-spaces vs per-tenant org.
  2. Private repos only vs public read for some community spaces.
  3. When to add webhook-driven cache purge.
  4. Whether user OAuth to Forgejo is required for in-app write (T05).

References

  • CSOC-WP-0004, Space model in coulomb_social.apps.spaces
  • ADR-0001 NetKingdom identity
  • Host posture: docs/deploy.md (app.coulomb.social)