coulomb-social/docs/spaces-content.md
tegwick 3f30bcd340 Add Forgejo edit/refresh sync path for space content (T05)
Keep git as source of truth: deep-link to Forgejo editor, manual refresh to
drop cache, and optional signed push webhook for automatic invalidation.
2026-08-12 03:29:26 +02:00

2.1 KiB
Raw Blame History

Space content — Forgejo markdown (read + write path)

See ADR-0002. App DB holds metadata; page bodies are markdown in Forgejo.

Read (T04)

  1. Space row has forgejo_owner, forgejo_repo, default_branch, content_root.
  2. App fetches {content_root}/index.md (or ?page=<slug>{slug}.md) via Forgejo raw URL.
  3. HTML is sanitized and cached in-process (successes only).

Env (non-secret defaults in settings):

Variable Purpose
FORGEJO_BASE_URL default https://forgejo.coulomb.social
FORGEJO_TOKEN optional; needed for private repos
FORGEJO_WEBHOOK_SECRET optional; enables push webhook cache bust

Write / sync (T05)

Git remains the source of truth. There is no in-app markdown editor in v1.

Operator / author workflow

  1. Open the space on app.coulomb.social.
  2. Click Edit in Forgejo (file editor) or View source.
  3. Commit on the spaces default_branch (usually main).
  4. Click Refresh content on the space page (or rely on webhook below).

Demo seed (public raw, no token):

python manage.py seed_demo_space
# binds demo → coulomb/coulomb-social @ docs/space-fixtures/demo/pages

So authors do not need to click Refresh after every push:

  1. Set FORGEJO_WEBHOOK_SECRET in the app env Secret (not in git).
  2. In Forgejo: repo → Settings → Webhooks → Add webhook → Gitea.
  3. Target URL: https://app.coulomb.social/app/spaces/hooks/forgejo/
  4. HTTP Method: POST, content type JSON.
  5. Secret: same value as FORGEJO_WEBHOOK_SECRET (Forgejo signs with HMAC-SHA256).
  6. Trigger: Push events.

Auth accepted by the app:

  • X-Gitea-Signature: <hex hmac-sha256 of body> (Forgejo default when secret set), or
  • X-Coulomb-Webhook-Secret: <shared secret>

Response JSON: { ok, owner, repo, cache_entries_cleared, spaces_matched }.

Fail closed

  • Missing binding → clear UI error, no Bubble fallback.
  • Fetch errors → error card; previous cache entry is not used after Refresh.
  • docs/adr/ADR-0002-space-content-forgejo-markdown.md
  • python manage.py seed_demo_space