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.
123 lines
4.2 KiB
Markdown
123 lines
4.2 KiB
Markdown
# 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).
|
|
|
|
```text
|
|
<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)
|