Plan product path: app shell and Forgejo markdown spaces

Mark CSOC-WP-0002 identity done on app.coulomb.social. Defer bulk Bubble
migration until product foundation exists. Open CSOC-WP-0004 for post-login
entry and space content as markdown bound to Forgejo.
This commit is contained in:
tegwick 2026-08-10 09:40:25 +02:00
parent f5537d8365
commit d36795faa6
7 changed files with 288 additions and 84 deletions

View file

@ -1,7 +1,7 @@
---
repo: coulomb-social
updated: "2026-08-09"
status: bootstrap
updated: "2026-08-10"
status: active
---
# INTENT — coulomb-social
@ -39,8 +39,10 @@ The rebuild is deliberately **product-faithful first**: UI and content parity ma
|---------|----------|
| Shape | Standalone service — own repo, own DB, own release values (DR-2 B) |
| Tenancy | Instance-per-client deployment; tenant-keyed data model from migration one (DR-1 C) |
| Identity | App-local member accounts in v1; auth behind a single module for later OIDC (DR-3 A) |
| Delivery lane | commit-SHA images → `gitea.coulomb.social/coulomb/coulomb-social``railiance-apps` values → railiance01 |
| Identity | NetKingdom OIDC (KeyCape) + user-engine (ADR-0001); proven on app host |
| Public hosts | **`app.coulomb.social`** = rebuild; **`coulomb.social`** = Bubble until cutover |
| Delivery lane | commit-SHA images → `forgejo.coulomb.social/coulomb/coulomb-social``railiance-apps` → railiance01 |
| Content direction | Space content as **markdown**, versioned with **Forgejo** (CSOC-WP-0004); bulk Bubble migration later |
| Contract | `the-custodian` `canon/standards/business-app-service-contract_v0.1.md` §§16 |
## What Success Looks Like
@ -69,9 +71,11 @@ The rebuild is deliberately **product-faithful first**: UI and content parity ma
- `GOAL.md` — operator bootstrap note for this repo
- `SCOPE.md` — in/out boundaries and orientation
- `workplans/CSOC-WP-0002-netkingdom-user-management-reestablish.md`**current path**: NetKingdom user management first; content later
- `workplans/CSOC-WP-0002-netkingdom-user-management-reestablish.md`**done**: identity shell on app.coulomb.social
- `workplans/CSOC-WP-0004-app-shell-and-space-content.md`**current path**: leave login shell; spaces + Forgejo markdown
- `docs/adr/ADR-0001-netkingdom-identity.md` — accepted identity decision
- `workplans/CSOC-WP-0001-bubble-io-exit-assessment.md` — Bubble assessment; content claim deferred
- `workplans/CSOC-WP-0001-bubble-io-exit-assessment.md` — Bubble inventory/migration **after** product foundation
- `workplans/CSOC-WP-0003-self-registration-and-assurance.md` — public registration when NetKingdom mail path lands
- `the-custodian/docs/coulomb-social-rebuild-seed.md` — original workplan seed (CUST-WP-0058-T08)
- `the-custodian/canon/standards/business-app-service-contract_v0.1.md`
- NetKingdom: IAM Profile, user-engine boundary, KeyCape/Keycloak modes

View file

@ -3,8 +3,12 @@
Reimplementation of **coulomb.social** on Railiance / NetKingdom / HelixForge —
exiting the stalled bubble.io product.
**Current focus:** NetKingdom user management and authenticated shell
(`CSOC-WP-0002`). Bubble content claim is deferred.
**Hosts:** rebuild at [`app.coulomb.social`](https://app.coulomb.social);
apex [`coulomb.social`](https://coulomb.social) remains Bubble until cutover.
**Current focus:** app shell + spaces with Forgejo-backed markdown content
(`CSOC-WP-0004`). Identity shell is done (`CSOC-WP-0002`). Bulk Bubble
migration is deferred (`CSOC-WP-0001`).
## Quick start

View file

@ -65,12 +65,12 @@ coulomb.social connects people around shared projects and complementary capabili
## Current State
- Status: bootstrap / greenfield — identity-first reestablish in progress
- Implementation: orientation docs + design extract; application scaffold pending (`CSOC-WP-0002`)
- Stability: evolving
- Usage: internal — product rebuild not yet serving members from this stack
- Prior art: rebuild seed from CUST-WP-0058-T08; topic `coulomb-social` already exists in State Hub under domain `communication`
- Active path: **NetKingdom user management** (`CSOC-WP-0002`); Bubble content claim deferred
- Status: **parallel hosts** — identity live; product content under construction
- **`https://app.coulomb.social`**: Railiance rebuild (OIDC, shell); spaces/content next
- **`https://coulomb.social`**: Bubble.io full product until cutover decision
- Active path: **`CSOC-WP-0004`** (app shell + Forgejo markdown spaces)
- Deferred: bulk Bubble migration (`CSOC-WP-0001`); public self-registration (`CSOC-WP-0003` / NK)
- Prior art: design extract; CSOC-WP-0002 identity acceptance (2026-08-10)
---

View file

@ -8,7 +8,7 @@ status: active
owner: bernd
topic_slug: coulomb-social
created: "2026-08-09"
updated: "2026-08-09"
updated: "2026-08-10"
origin: residual
origin_ref: the-custodian/docs/coulomb-social-rebuild-seed.md
state_hub_workstream_id: "ecefaeef-908a-4072-ae34-6406862d4cad"
@ -17,45 +17,56 @@ state_hub_workstream_id: "ecefaeef-908a-4072-ae34-6406862d4cad"
# bubble.io exit assessment
Assess the live coulomb.social bubble.io product, export its data model, decide
the v1 feature cut, and rehearse migration into a tenant-keyed relational
schema. This plan originates from the CUST-WP-0058-T08 seed in
`the-custodian/docs/coulomb-social-rebuild-seed.md`.
the v1 feature cut, and rehearse migration into the code-owned stack.
Repo bootstrap (INTENT, SCOPE, TRSL LICENSE, State Hub registration, agent
files) was completed as part of opening this workplan.
## Operating posture (2026-08-10)
**Priority note (2026-08-09):** product **reestablish** proceeds first via
`CSOC-WP-0002` (NetKingdom user management + authenticated shell). **Content
claim / migration** from Bubble remains in this workplans scope but is
**deferred** until after the identity shell lands — do not block WP-0002 on
inventory completion.
| Host | Role |
|------|------|
| **`https://coulomb.social`** | **Bubble.io** — full product, production members/content |
| **`https://app.coulomb.social`** | **Railiance rebuild** — identity live; product surfaces under construction |
**Strategy:** perfect the rebuild on `app.coulomb.social` **before** migrating all
spaces/data from Bubble. Do **not** repoint apex DNS until product + content
persistence + self-registration are ready and a migration rehearsal has passed.
Identity shell is done (`CSOC-WP-0002`). Product/content foundation is
`CSOC-WP-0004`. This workplan stays the home for **inventory, mapping, feature
cut, and migration rehearsal** — executed when the target schema/content model
exists, not as the immediate next build step.
## Inventory bubble.io app
```task
id: CSOC-WP-0001-T01
status: todo
priority: high
priority: medium
state_hub_task_id: "240a97c5-1f57-4da6-a75b-d7b3416afdd1"
```
Inventory the current bubble.io app: pages, workflows, data types,
integrations, external services, and content surfaces that must be preserved
or deliberately dropped. Record findings under `docs/bubble-inventory/` (create
as needed).
as needed). Prefer **spaces / pages / markdown-shaped content** first so
`CSOC-WP-0004` Forgejo persistence can map cleanly.
## Data export and schema mapping
```task
id: CSOC-WP-0001-T02
status: todo
priority: high
priority: medium
state_hub_task_id: "0bc6eea3-030d-4987-b203-15ccd4f94fcb"
```
Produce a full data dump from bubble.io and map it to a relational model that
is tenant-keyed from migration one (business-app service contract §1.3).
Document the mapping and export procedure under `docs/migration/`.
Produce a full data dump from bubble.io and map it to:
1. tenant-keyed application tables (members, space metadata, …), and
2. **space content as markdown trees** bound to Forgejo repositories
(see CSOC-WP-0004 content model).
Document mapping and export under `docs/migration/`. Depends on CSOC-WP-0004
content layout decisions for lossless mapping of pages/artefacts.
## Feature cut decision (human gate)
@ -66,34 +77,33 @@ priority: high
state_hub_task_id: "35a0af87-2f22-4fae-8c82-e3cc4f77f074"
```
Decide rebuild-as-is vs reduced v1 scope. **Human gate — Bernd.** Capture the
decision as a decision record under `docs/decisions/` (or State Hub decision)
before CSOC-WP-0002 implementation scoping proceeds.
Decide rebuild-as-is vs reduced v1 scope. **Human gate — Bernd.** Capture under
`docs/decisions/`. Gate **apex cutover / bulk migration**, not day-to-day
rebuild work on `app.coulomb.social`.
## Migration rehearsal
```task
id: CSOC-WP-0001-T04
status: todo
priority: medium
priority: low
state_hub_task_id: "2e5be321-3d76-4d7a-86b1-cbe4eb554bd7"
```
Import the exported data into the v1 schema on a dev instance. Record what
failed, what was lossy, and what must change before cutover. Depends on T02
and a scaffolded schema (may start as a schema-only dry run).
Import one or more Bubble spaces into the v1 model on a non-production path
(app host or staging). Record lossiness and residuals. **Blocked until**
CSOC-WP-0004 persistence exists and T02 mapping is written. Explicitly **not**
a prerequisite for building product UX on the empty/new content store.
## Acceptance
- Inventory and mapping docs are committed and reviewable.
- Feature-cut decision is recorded with owner and date.
- At least one migration rehearsal has been run and residual gaps listed.
- Follow-on implementation workplan `CSOC-WP-0002` can be scoped from T03.
- Apex Bubble retirement is only planned after rehearsal + product parity gate.
## Notes
- Parallel hosts: `docs/deploy.md`
- Next product build: `workplans/CSOC-WP-0004-app-shell-and-space-content.md`
- Service contract: `the-custodian/canon/standards/business-app-service-contract_v0.1.md`
- Delivery lane reference: `vergabe-teilnahme`
- Preconditions before serving members (ops backup, ops-hub registration,
fin-hub cost key) remain platform-side; track against the contract, do not
block inventory/export work here.

View file

@ -4,11 +4,11 @@ type: workplan
title: "Reestablish coulomb.social with NetKingdom user management"
domain: communication
repo: coulomb-social
status: active
status: done
owner: bernd
topic_slug: coulomb-social
created: "2026-08-09"
updated: "2026-08-09"
updated: "2026-08-10"
depends_on:
- CSOC-WP-0001
related:
@ -270,6 +270,17 @@ Align with business-app delivery lane without full production cutover:
2026-08-09 (smoke continuation): Offline checklist + `make test` (15) passed. Port-forward with `Host: coulomb.social`: healthz/landing OK; `/auth/login/` 302 to KeyCape with prod redirect + PKCE. KeyCape authorize accepts local and prod redirect URIs (→ Authelia). Full browser MFA login still human step (`docs/identity/smoke.md`); cutover steps in `docs/deploy.md`.
2026-08-10 (acceptance complete on parallel host):
- Public rebuild host **`https://app.coulomb.social`** (apex `coulomb.social` remains Bubble).
- KeyCape client `mfaRequired: false`; id_token claim path deployed (`:f5537d8`).
- Operator **tegwick** signed in end-to-end; authenticated shell shows principal
(display name, subject, user-engine id, tenant).
- Workplan acceptance criteria 17 satisfied for identity/membership shell.
- Content, spaces, and Bubble migration are **out of scope** here — see
`CSOC-WP-0004` (product shell + markdown/Forgejo content) and deferred
`CSOC-WP-0001` migration.
---
## Sequencing
@ -292,10 +303,11 @@ are known.
| Residual | Future home |
|----------|-------------|
| Bubble content claim & migration | New workplan after CSOC-WP-0001 T03 cut |
| Full product UI (Research, Pages, …) | Post-shell product workplans |
| Post-login product entry + spaces UI | **CSOC-WP-0004** (next) |
| Space content as markdown + Forgejo | **CSOC-WP-0004** |
| Public self-registration | CSOC-WP-0003 + NK-WP-0025 (platform) |
| Bubble content claim & full migration | CSOC-WP-0001 — **after** product parity on app.* |
| Production Keycloak expanded mode | NetKingdom (NK-WP-0011 triggers) if demand |
| Member invitation email at scale | email-connect / NK-WP-0024 lanes |
## Related

View file

@ -5,10 +5,10 @@ title: "Add NetKingdom self-registration and profile-aware assurance"
domain: communication
repo: coulomb-social
status: active
owner: codex
owner: bernd
topic_slug: coulomb-social
created: "2026-08-09"
updated: "2026-08-09"
updated: "2026-08-10"
depends_on:
- CSOC-WP-0002
- NK-WP-0025
@ -22,6 +22,11 @@ state_hub_workstream_id: "7cd7d6b8-e01d-4b34-8680-3c0cac68d80e"
Extend the working CSOC-WP-0002 OIDC/JIT shell with a NetKingdom account
creation entry point and optional profile/action step-up.
**2026-08-10 posture:** existing-user login on **`app.coulomb.social`** is proven
(tegwick, AAL1, no MFA). Public **Create account** remains blocked on NetKingdom
mailbox verification (NK-WP-0025 / USER-WP-0022). Product work proceeds via
`CSOC-WP-0004` without waiting on public registration.
## T01 - Preserve and prove first-login JIT profile creation
```task
@ -31,35 +36,24 @@ priority: high
state_hub_task_id: "dde13170-7203-4fcd-b0ce-5874fccc4632"
```
Harden the existing issuer/subject keyed Member creation, concurrent callback
behavior, verified ID-token processing, and user-engine link. Preserve the
current uncommitted CSOC-WP-0002 claim-verification work.
Harden issuer/subject keyed Member creation, concurrent callback behavior,
verified ID-token processing, and user-engine link.
Done when an existing LLDAP identity gets exactly one ordinary Member and
repeat login updates safe display fields without changing identity ownership.
Covered by the issuer/subject uniqueness constraint, unusable local passwords,
idempotent session establishment tests, and verified ID-token claim handling.
**2026-08-10 evidence:** live login on app.coulomb.social shows principal +
user-engine id; image `:f5537d8` uses id_token when `/userinfo` 401s.
## T02 - Add Create NetKingdom account
```task
id: CSOC-WP-0003-T02
status: progress
priority: high
priority: medium
state_hub_task_id: "aaf2d2cb-6ba9-42cb-9271-aacc414e947a"
```
Add a landing-page registration choice using the configured NetKingdom public
registration URL. The configured URL owns any signed return context. Completion must
start a fresh OIDC flow before creating an application session.
Done when a new user can leave coulomb.social, register, and return through
the same callback/JIT path without open redirects.
The application entry point is implemented and ignores browser-supplied
redirect parameters. It remains disabled until the NetKingdom public
registration URL and verified-mail flow are deployed.
Landing-page **Create account** using configured `NETKINGDOM_REGISTRATION_URL`.
App entry is implemented; remains disabled until NetKingdom public registration
URL + verified-mail flow ship.
## T03 - Support profile/action step-up
@ -70,27 +64,22 @@ priority: high
state_hub_task_id: "6636a746-02ca-4a70-ac3c-0219c89cd6a7"
```
Use AAL1 for ordinary member sessions. When profile policy or a protected
action requires MFA, restart authorization with AAL2 acr_values and verify the
returned assurance claim before completing the action.
Done when tegwick can use ordinary login without MFA and opt into or encounter
MFA step-up without affecting another member.
Implemented explicit `?assurance=aal2`, OIDC `acr_values`, and callback-side
assurance validation. Ordinary login sends no ACR request.
AAL1 ordinary sessions; AAL2 via `acr_values` when required. Live coulomb-social
client uses `mfaRequired: false`.
## T04 - Deploy and run Case A / Case B matrix
```task
id: CSOC-WP-0003-T04
status: todo
priority: high
status: progress
priority: medium
state_hub_task_id: "57bac5f4-fd5d-46ba-92a3-a7bbeb15aa08"
```
Test known LLDAP user, new registration, repeated/concurrent callback,
email collision, state replay, disabled identity, local-account coexistence,
password-only login, AAL2 step-up, logout, and rollback on railiance01.
| Case | Status |
|------|--------|
| A — known LLDAP user, first/repeat login on app.* | **done** (tegwick) |
| B — brand-new public registration → OIDC → Member | **blocked** on NK mailbox verification |
Done when both requested cases pass with non-secret evidence.
Record remaining negatives (state replay, collision, step-up) when Case B unblocks
or in a short follow-up smoke note under `docs/identity/smoke.md`.

View file

@ -0,0 +1,185 @@
---
id: CSOC-WP-0004
type: workplan
title: "App shell entry and Forgejo-backed space content"
domain: communication
repo: coulomb-social
status: active
owner: bernd
topic_slug: coulomb-social
created: "2026-08-10"
updated: "2026-08-10"
depends_on:
- CSOC-WP-0002
related:
- CSOC-WP-0001
- CSOC-WP-0003
origin: operator
origin_ref: session-2026-08-10-parallel-host-product-path
---
# CSOC-WP-0004 — App shell entry and Forgejo-backed space content
## Context
Identity is live on **`https://app.coulomb.social`**. After Sign in, members
land on an identity **confirmation shell** (“Signed in” + principal dump) with
no product surface. Bubble on apex remains the full product until we choose
cutover.
**Goal for this phase:** build the new implementation toward product usefulness
**before** bulk Bubble data migration. Immediate product foundation:
1. Leave the login confirmation shell into a real **app home**.
2. Establish **space** persistence whose **content is markdown**, stored and
versioned in close connection with **Forgejo** repositories.
Migration of all Bubble spaces is **explicitly later** (`CSOC-WP-0001`).
## Out of scope (this plan)
- Apex DNS cutover / Bubble retirement
- Full Bubble inventory or bulk import
- Public self-registration (CSOC-WP-0003 / NetKingdom)
- Full UI parity (Research, marketplace matching, …) beyond space content MVP
---
## T01 — Post-login product entry (leave confirmation shell)
```task
id: CSOC-WP-0004-T01
status: todo
priority: high
```
Replace the dead-end “Signed in / Principal” page as the primary post-login
destination with an **app home** that a member can use:
- Clear primary navigation: Spaces (and placeholders for later surfaces).
- Principal summary available but secondary (account menu or `/account/`).
- Empty state when the member has no spaces yet (“Create space” or “No spaces”).
- `LOGIN_REDIRECT_URL` and templates updated; design-extract tokens only as needed.
**Done when:** after OIDC login on app.coulomb.social, tegwick lands on app home
(not a debug-only principal card) and can navigate without guessing URLs.
## T02 — Space domain model (metadata, tenant-keyed)
```task
id: CSOC-WP-0004-T02
status: todo
priority: high
```
Introduce `Space` (name pending Bubble vocabulary alignment) as application
metadata in the app DB:
- `tenant_id`, stable slug, display title, owner/membership linkage to Member
- **no** long-form page bodies in Postgres as the system of record
- optional pointer fields for content binding (repo, default branch, root path)
Migrations + admin + minimal list/detail routes behind auth.
**Done when:** authenticated user can list zero-or-more spaces from DB; tests cover
tenant isolation basics.
## T03 — Content model ADR: markdown + Forgejo
```task
id: CSOC-WP-0004-T03
status: todo
priority: high
```
Write `docs/adr/ADR-0002-space-content-forgejo-markdown.md` deciding:
- Markdown (and assets) as the **canonical content form** for space pages
- Forgejo repo layout (one repo per space vs monorepo paths; branch policy)
- How the app **reads** content (clone/cache, raw API, webhook invalidation)
- How the app **writes** (direct git push as service account vs user OAuth to Forgejo)
- Relationship to Bubble page/chunk model for later CSOC-WP-0001 mapping
- Secrets: Forgejo tokens via OpenBao / env secret names only
**Done when:** ADR accepted (or explicitly provisional with open questions listed)
and linked from INTENT/SCOPE.
## T04 — Read path: render space markdown from bound repo
```task
id: CSOC-WP-0004-T04
status: todo
priority: high
```
Implement a vertical slice:
- Operator or seed binds one space to a Forgejo repo path
- App fetches/renders a markdown page (e.g. `README.md` or `pages/index.md`)
- Authz: member of tenant/space only (flex-auth or coarse membership check)
- Fail closed on missing binding or fetch errors
**Done when:** tegwick can open a space on app.coulomb.social and see rendered
markdown sourced from Forgejo (not Bubble).
## T05 — Write / sync path (minimal)
```task
id: CSOC-WP-0004-T05
status: todo
priority: medium
```
Minimal authoring or sync so content is not read-only forever:
- either in-app edit → commit to Forgejo, or
- documented “edit in Forgejo / pull request” workflow + refresh webhook
Prefer the smaller path that keeps git as source of truth.
**Done when:** a content change in Forgejo appears in the app without redeploy,
and (if in-app write exists) a save produces a commit without secrets in git.
## T06 — Seed and runbook for app.coulomb.social
```task
id: CSOC-WP-0004-T06
status: todo
priority: medium
```
Document operator steps: create Forgejo org/repo, bind space, credentials env
names, smoke checklist on app.coulomb.social. Update `docs/deploy.md` and
`docs/identity/smoke.md` pointers as needed.
---
## Sequencing
```text
T01 app home entry
└─► T02 Space metadata
└─► T03 content ADR
└─► T04 read path (MVP value)
├─► T05 write/sync
└─► T06 runbook
```
T01 can ship alone to fix the “stuck on login confirmation” UX immediately.
T03 should land before large T04 investment if write-model choices are unclear;
a **provisional** ADR is enough to start T04 against a single seed repo.
## Acceptance (workplan)
1. Post-login journey is product-shaped (app home + spaces), not identity-debug-only.
2. Spaces exist as tenant-keyed app records.
3. Space page content is markdown backed by Forgejo with a working read path.
4. Bubble migration is still not required for demos on app.coulomb.social.
5. CSOC-WP-0001 can map Bubble pages onto the ADR layout when migration starts.
## Related
- Live host: `docs/deploy.md` (app.coulomb.social parallel to Bubble)
- Identity: CSOC-WP-0002 (done), CSOC-WP-0003 (registration later)
- Migration later: CSOC-WP-0001
- Design tokens: `docs/design-extract/`