diff --git a/.env.example b/.env.example index 7fc4bdd..e66e44a 100644 --- a/.env.example +++ b/.env.example @@ -26,3 +26,9 @@ USER_ENGINE_EXPECTED_AUDIENCE=user-engine-portal # USER_ENGINE_BASE_URL=https://users.92-205-62-239.nip.io # USER_ENGINE_PROXY_SECRET= # from OpenBao / kubectl user-engine-runtime — never commit # FLEX_AUTH_BASE_URL= + +# --- Space content (Forgejo / ADR-0002) --- +# FORGEJO_BASE_URL=https://forgejo.coulomb.social +# FORGEJO_TOKEN= # optional; private repos only — never commit +# FORGEJO_WEBHOOK_SECRET= # optional push webhook — never commit +# SPACE_CONTENT_FIXTURE_ROOT= # optional offline fixture root for tests diff --git a/INTENT.md b/INTENT.md index bbef96c..4dc5d58 100644 --- a/INTENT.md +++ b/INTENT.md @@ -71,12 +71,14 @@ 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` — **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 +- `workplans/CSOC-WP-0002-netkingdom-user-management-reestablish.md` — **finished**: identity shell on app.coulomb.social +- `workplans/CSOC-WP-0003-self-registration-and-assurance.md` — **finished**: Case A + Create account entry; Case B residuals `CSOC-IN-0001`/`0002` +- `workplans/CSOC-WP-0004-app-shell-and-space-content.md` — **finished**: app home, spaces, Forgejo markdown, operator runbook - `docs/adr/ADR-0001-netkingdom-identity.md` — accepted identity decision - `docs/adr/ADR-0002-space-content-forgejo-markdown.md` — space content as markdown in Forgejo +- `docs/deploy.md` — deploy + spaces operator runbook - `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 +- `workplans/CSOC-WP-0005-resource-demand-and-cost-evidence.md` — resource evidence for platform cost control - `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 diff --git a/README.md b/README.md index e1ed33e..64f5252 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,10 @@ exiting the stalled bubble.io product. **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`). +**Current state:** identity + app shell + Forgejo-backed spaces on +`app.coulomb.social` (`CSOC-WP-0002`–`0004` finished). Operator runbook: +`docs/deploy.md`. Bulk Bubble migration deferred (`CSOC-WP-0001`); public +registration Case B waits on NetKingdom (`docs/intakes/csoc-residuals.md`). ## Quick start diff --git a/SCOPE.md b/SCOPE.md index 6d8c3ac..30a5563 100644 --- a/SCOPE.md +++ b/SCOPE.md @@ -65,13 +65,14 @@ coulomb.social connects people around shared projects and complementary capabili ## Current State -- Status: **parallel hosts** — identity live; product content under construction -- **`https://app.coulomb.social`**: Railiance rebuild (OIDC, shell); spaces/content next +- Status: **parallel hosts** — identity + app shell + Forgejo spaces live on app.* +- **`https://app.coulomb.social`**: Railiance rebuild (OIDC, app home, spaces markdown) - **`https://coulomb.social`**: Bubble.io full product until cutover decision -- Active path: **`CSOC-WP-0004`** (spaces metadata + Forgejo markdown content) +- Finished product path: **`CSOC-WP-0004`** (spaces + Forgejo markdown + runbook) +- Finished identity path: **`CSOC-WP-0002`**, **`CSOC-WP-0003`** (Case A; Case B residual intakes) - Content ADR: `docs/adr/ADR-0002-space-content-forgejo-markdown.md` -- 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) +- Operator: `docs/deploy.md` runbook; residuals `docs/intakes/csoc-residuals.md` +- Open: bulk Bubble migration (`CSOC-WP-0001`); resource evidence (`CSOC-WP-0005`); public registration residuals (`CSOC-IN-0001`/`0002`, NK-WP-0025) --- diff --git a/WORK-RECORDS.md b/WORK-RECORDS.md index 1d9e341..26dbf55 100644 --- a/WORK-RECORDS.md +++ b/WORK-RECORDS.md @@ -9,8 +9,10 @@ | Kind | ID | Status | Lane | Source | | --- | --- | --- | --- | --- | | workplan | CSOC-WP-0001 | active | — | workplans/CSOC-WP-0001-bubble-io-exit-assessment.md | -| workplan | CSOC-WP-0002 | active | — | workplans/CSOC-WP-0002-netkingdom-user-management-reestablish.md | -| workplan | CSOC-WP-0003 | active | — | workplans/CSOC-WP-0003-self-registration-and-assurance.md | +| workplan | CSOC-WP-0002 | done | — | workplans/CSOC-WP-0002-netkingdom-user-management-reestablish.md | +| workplan | CSOC-WP-0003 | finished | — | workplans/CSOC-WP-0003-self-registration-and-assurance.md | +| workplan | CSOC-WP-0004 | finished | — | workplans/CSOC-WP-0004-app-shell-and-space-content.md | +| workplan | CSOC-WP-0005 | ready | — | workplans/CSOC-WP-0005-resource-demand-and-cost-evidence.md | | task | CSOC-WP-0001-T01 | todo | — | workplans/CSOC-WP-0001-bubble-io-exit-assessment.md | | task | CSOC-WP-0001-T02 | todo | — | workplans/CSOC-WP-0001-bubble-io-exit-assessment.md | | task | CSOC-WP-0001-T03 | wait | — | workplans/CSOC-WP-0001-bubble-io-exit-assessment.md | @@ -24,6 +26,18 @@ | task | CSOC-WP-0002-T07 | done | — | workplans/CSOC-WP-0002-netkingdom-user-management-reestablish.md | | task | CSOC-WP-0002-T08 | done | — | workplans/CSOC-WP-0002-netkingdom-user-management-reestablish.md | | task | CSOC-WP-0003-T01 | done | — | workplans/CSOC-WP-0003-self-registration-and-assurance.md | -| task | CSOC-WP-0003-T02 | progress | — | workplans/CSOC-WP-0003-self-registration-and-assurance.md | +| task | CSOC-WP-0003-T02 | done | — | workplans/CSOC-WP-0003-self-registration-and-assurance.md | | task | CSOC-WP-0003-T03 | done | — | workplans/CSOC-WP-0003-self-registration-and-assurance.md | -| task | CSOC-WP-0003-T04 | todo | — | workplans/CSOC-WP-0003-self-registration-and-assurance.md | +| task | CSOC-WP-0003-T04 | done | — | workplans/CSOC-WP-0003-self-registration-and-assurance.md | +| task | CSOC-WP-0004-T01 | done | — | workplans/CSOC-WP-0004-app-shell-and-space-content.md | +| task | CSOC-WP-0004-T02 | done | — | workplans/CSOC-WP-0004-app-shell-and-space-content.md | +| task | CSOC-WP-0004-T03 | done | — | workplans/CSOC-WP-0004-app-shell-and-space-content.md | +| task | CSOC-WP-0004-T04 | done | — | workplans/CSOC-WP-0004-app-shell-and-space-content.md | +| task | CSOC-WP-0004-T05 | done | — | workplans/CSOC-WP-0004-app-shell-and-space-content.md | +| task | CSOC-WP-0004-T06 | done | — | workplans/CSOC-WP-0004-app-shell-and-space-content.md | +| task | CSOC-WP-0004-T07 | done | — | workplans/CSOC-WP-0004-app-shell-and-space-content.md | +| task | CSOC-WP-0005-T01 | todo | — | workplans/CSOC-WP-0005-resource-demand-and-cost-evidence.md | +| task | CSOC-WP-0005-T02 | todo | — | workplans/CSOC-WP-0005-resource-demand-and-cost-evidence.md | +| task | CSOC-WP-0005-T03 | todo | — | workplans/CSOC-WP-0005-resource-demand-and-cost-evidence.md | +| intake | CSOC-IN-0001 | open | blue | docs/intakes/csoc-residuals.md | +| intake | CSOC-IN-0002 | open | green | docs/intakes/csoc-residuals.md | diff --git a/docs/deploy.md b/docs/deploy.md index b28c1c1..5c0dd5e 100644 --- a/docs/deploy.md +++ b/docs/deploy.md @@ -13,7 +13,7 @@ Chart/values/ingress live in **`railiance-apps`** | Host | Role | |------|------| -| **`https://app.coulomb.social`** | **Live** Railiance rebuild (identity shell now; product later) | +| **`https://app.coulomb.social`** | **Live** Railiance rebuild (app home + spaces) | | **`https://coulomb.social`** | **Bubble.io** until data + self-registration + content ready | | `http://127.0.0.1:8008` | Local OIDC/dev | @@ -30,7 +30,16 @@ Apex DNS cutover is **deferred**. Retire Bubble only after an explicit decision. ## Runtime secrets (names only) -K8s Secret `coulomb-social-env` (`SECRET_KEY`, `DATABASE_URL`, `USER_ENGINE_PROXY_SECRET`). +K8s Secret `coulomb-social-env` (mounted via `envFrom`). + +| Key | Required | Purpose | +|-----|----------|---------| +| `SECRET_KEY` | yes | Django secret | +| `DATABASE_URL` | yes | Postgres URL | +| `USER_ENGINE_PROXY_SECRET` | yes (live UE) | trusted proxy to user-engine | +| `FORGEJO_TOKEN` | no | private Forgejo raw/API reads | +| `FORGEJO_WEBHOOK_SECRET` | no | push webhook HMAC / shared secret | +| `NETKINGDOM_REGISTRATION_URL` | no | enable landing **Create account** when NK ships | ```bash # railiance-apps: @@ -38,7 +47,9 @@ make coulomb-social-env-secret-dry-run make coulomb-social-env-secret ``` -OIDC is a **public** client — no client secret. +OIDC is a **public** client — no client secret. Non-secret OIDC / Forgejo base +URL settings live in Helm values (`FORGEJO_BASE_URL` defaults to +`https://forgejo.coulomb.social` in app settings). ## Health @@ -58,10 +69,10 @@ docker build -t forgejo.coulomb.social/coulomb/coulomb-social:$SHA . 1. [x] Helm env / ingress use `app.coulomb.social` 2. [x] KeyCape redirects include `https://app.coulomb.social/auth/callback/` -3. [ ] DNS: `app.coulomb.social` **A → `92.205.62.239`** (prefer DNS-only for LE) -4. [ ] `certificate/coulomb-social-tls` Ready for `app.coulomb.social` -5. [ ] `curl -fsS https://app.coulomb.social/healthz` -6. [ ] Browser Sign in as tegwick → `/app/` +3. [x] DNS: `app.coulomb.social` resolves; HTTPS live (healthz 200) +4. [x] `curl -fsS https://app.coulomb.social/healthz` +5. [x] Browser Sign in as tegwick → `/app/` (Case A; see `docs/identity/smoke.md`) +6. [ ] Seed demo space + open rendered markdown (operator; steps below) ## Future apex cutover (not now) @@ -76,21 +87,135 @@ When Bubble can retire: ```bash make test make run # offline or local OIDC redirect +uv run manage.py seed_demo_space +# Sign in (dev login) → /app/ → Demo space → rendered markdown ``` -## Space content (Forgejo) +--- -See `docs/spaces-content.md`. Demo: +## Operator runbook — spaces on app.coulomb.social + +Product path for **CSOC-WP-0004**. Content model: **ADR-0002**. Detail on +read/write/webhook: `docs/spaces-content.md`. Identity smoke: +`docs/identity/smoke.md`. + +### A. Prerequisites + +1. Image includes spaces app (`spaces` migrations + Forgejo client) and is + deployed to namespace `coulomb-social`. +2. Member can Sign in (existing LLDAP/KeyCape user, e.g. tegwick). +3. Forgejo reachable from the pod (`FORGEJO_BASE_URL`, default + `https://forgejo.coulomb.social`). Public raw needs **no** token; private + repos need `FORGEJO_TOKEN` in `coulomb-social-env`. + +### B. Demo seed (fastest smoke — uses this repo as content) + +In-repo fixture (already on `main`): + +```text +docs/space-fixtures/demo/pages/index.md +``` + +Public raw check (no auth): ```bash -kubectl -n coulomb-social exec deploy/coulomb-social -- python manage.py seed_demo_space +curl -fsS \ + "https://forgejo.coulomb.social/coulomb/coulomb-social/raw/branch/main/docs/space-fixtures/demo/pages/index.md" \ + | head ``` -Optional webhook secret (when configured in cluster env): +Seed metadata in the app DB (binds `demo` → that path): -| Key | Purpose | -|-----|---------| -| `FORGEJO_WEBHOOK_SECRET` | Push webhook cache bust | -| `FORGEJO_TOKEN` | Private repo raw/API reads | +```bash +kubectl -n coulomb-social exec deploy/coulomb-social -- \ + python manage.py seed_demo_space +# optional: --slug demo --title "Demo space" --tenant tenant:coulomb +``` -Webhook URL: `https://app.coulomb.social/app/spaces/hooks/forgejo/` \ No newline at end of file +Browser: + +1. https://app.coulomb.social/ → **Sign in** (tegwick) +2. Land on `/app/` — **Spaces** lists **Demo space** +3. Open `/app/spaces/demo/` — see rendered markdown from Forgejo +4. Profile menu → **Session details** (`/account/session/`) still works +5. **Edit in Forgejo** / **View source** open the bound file; after a commit, + **Refresh content** re-fetches (or configure webhook, section D) + +### C. Production-shaped space (dedicated Forgejo repo) + +ADR-0002: **one repo per space**. + +1. In Forgejo, create org (recommended) `coulomb-spaces` (or tenant org later). +2. Create repo e.g. `space-my-space` with branch `main` and layout: + +```text +pages/ + index.md # default landing page + .md # optional extra pages +assets/ # optional images +README.md # optional +``` + +3. Bind in the app (Django admin, or shell): + +```bash +kubectl -n coulomb-social exec -it deploy/coulomb-social -- python manage.py shell +``` + +```python +from coulomb_social.apps.spaces.models import Space +Space.objects.update_or_create( + tenant_id="tenant:coulomb", + slug="my-space", + defaults={ + "title": "My space", + "forgejo_owner": "coulomb-spaces", + "forgejo_repo": "space-my-space", + "default_branch": "main", + "content_root": "pages", + "is_active": True, + }, +) +``` + +4. If the repo is private, set `FORGEJO_TOKEN` (read-only deploy token) via + `railiance-apps` env-secret tooling — **never** commit the token. +5. Open `https://app.coulomb.social/app/spaces/my-space/` as a signed-in member + of that tenant. + +### D. Optional push webhook (auto cache bust) + +1. Put a random secret in cluster env as `FORGEJO_WEBHOOK_SECRET`. +2. Forgejo repo → **Settings → Webhooks → Add webhook → Gitea**: + - URL: `https://app.coulomb.social/app/spaces/hooks/forgejo/` + - Method POST, content type JSON + - Secret: same value as env + - Trigger: **Push** +3. Push a commit; confirm response JSON includes `cache_entries_cleared` / + `spaces_matched`. Authors can still use **Refresh content** without a webhook. + +### E. Env names quick reference + +| Variable | Secret? | Where | +|----------|---------|--------| +| `FORGEJO_BASE_URL` | no | settings default / Helm | +| `FORGEJO_TOKEN` | yes | `coulomb-social-env` | +| `FORGEJO_WEBHOOK_SECRET` | yes | `coulomb-social-env` | +| `FORGEJO_TIMEOUT_SECONDS` | no | optional | +| `NETKINGDOM_REGISTRATION_URL` | no | enable Create account (residual; NK-WP-0025) | + +### F. Smoke checklist (app.coulomb.social) + +| # | Check | Pass criteria | +|---|--------|----------------| +| 1 | `GET /healthz` | `{"status":"ok","service":"coulomb-social"}` | +| 2 | Landing | Sign in visible; Create account only if registration URL set | +| 3 | OIDC login (known user) | tegwick → `/app/` app home (not principal dump) | +| 4 | Spaces list | empty state or seeded spaces | +| 5 | Space detail | markdown rendered from Forgejo (or clear fail-closed error) | +| 6 | Session details | profile menu → `/account/session/` shows issuer/subject/UE id | +| 7 | Sign out | session cleared; `/app/` requires login | +| 8 | (optional) Edit in Forgejo + Refresh | new commit visible without redeploy | + +Identity detail and historical evidence: `docs/identity/smoke.md`. +Content mechanics: `docs/spaces-content.md`. diff --git a/docs/dev.md b/docs/dev.md index 1130d29..5041dee 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -44,6 +44,10 @@ See `.env.example`. Summary: | `USER_ENGINE_APPLICATION_ID` | `coulomb-social` | App id | | `USER_ENGINE_EXPECTED_AUDIENCE` | `user-engine-portal` | required aud for /me | | `FLEX_AUTH_BASE_URL` | empty (fail-closed except shell:view) | PDP | +| `FORGEJO_BASE_URL` | `https://forgejo.coulomb.social` | Space markdown source | +| `FORGEJO_TOKEN` | empty | Private repo raw reads (secret) | +| `FORGEJO_WEBHOOK_SECRET` | empty | Push webhook cache bust (secret) | +| `NETKINGDOM_REGISTRATION_URL` | empty | Landing Create account (when NK ships) | ### Platform OIDC (KeyCape) diff --git a/docs/identity/smoke.md b/docs/identity/smoke.md index 3739f32..03634ca 100644 --- a/docs/identity/smoke.md +++ b/docs/identity/smoke.md @@ -1,6 +1,6 @@ # Identity smoke checklist -Evidence updated: **2026-08-09**. +Evidence updated: **2026-08-12**. ## Offline (dev claims) — **passed** @@ -13,47 +13,84 @@ uv sync && uv run manage.py migrate && make run |------|--------| | Open `/` → **Sign in** | → `/auth/dev-login/` | | Dev form subject `smoke-1` | 302 → `/app/` | -| Shell shows display name + subject | OK | +| App home shows Spaces + profile chrome | OK (principal dump is under Session details) | +| Profile menu → Session details | issuer / subject / user-engine id | | **Sign out** | session cleared | | `/app/` after logout | 302 → login | | Second login same subject | single `Member` row (idempotent) | -| `make test` | **15 passed** | +| `make test` | green | -Automated POST probe (2026-08-09): +Automated POST probe: ```text dev_login_post → /app/ 200 with subject smoke-1 logout → app 302 to /auth/login/?next=/app/ ``` -## Cluster in-cluster (port-forward) — **passed (start of OIDC)** +## Public host app.coulomb.social — **Case A passed** -DNS for `coulomb.social` still points at Cloudflare/Bubble; TLS ACME is -blocked until cutover. Smoke via: +**Strategy:** live Railiance app on **`app.coulomb.social`**; apex +**`coulomb.social`** stays Bubble until content + self-registration cutover. + +| Check | Detail | +|-------|--------| +| Cluster host | `app.coulomb.social` (Helm + ingress) | +| OIDC redirect | `https://app.coulomb.social/auth/callback/` | +| Health | `curl -fsS https://app.coulomb.social/healthz` → ok | +| Landing | 200; **Sign in** present | +| Case A — known LLDAP user | **done** (tegwick, AAL1, no MFA forced) → `/app/` | +| Create account | hidden until `NETKINGDOM_REGISTRATION_URL` is set | +| Case B — public registration → OIDC → Member | **blocked** on NK mailbox verification (`NK-WP-0025` / residual intakes) | +| Apex | **do not** repoint until Bubble retirement | + +### Product smoke (spaces — after deploy + seed) + +Operator runbook: `docs/deploy.md` § Operator runbook. Short path: ```bash -kubectl -n coulomb-social port-forward svc/coulomb-social 18088:80 -curl -H 'Host: coulomb.social' http://127.0.0.1:18088/healthz -# {"status": "ok", "service": "coulomb-social"} +# fixture raw (public) +curl -fsS \ + "https://forgejo.coulomb.social/coulomb/coulomb-social/raw/branch/main/docs/space-fixtures/demo/pages/index.md" \ + | head +# seed in cluster +kubectl -n coulomb-social exec deploy/coulomb-social -- \ + python manage.py seed_demo_space ``` -| Check | Result | -|-------|--------| -| Image | `forgejo.coulomb.social/coulomb/coulomb-social:7067145` | -| `OIDC_ENABLED` | `true` (values) | -| `GET /healthz` + Host | 200 JSON ok | -| `GET /` + Host | 200 landing shell | -| `GET /auth/login/` + Host | **302** → `https://kc.coulomb.social/authorize?...` with `client_id=coulomb-social`, `redirect_uri=https://coulomb.social/auth/callback/`, PKCE S256 | -| Session cookie | `HttpOnly; Secure; SameSite=Lax` (prod settings) | +| Step | Expected | +|------|----------| +| Sign in tegwick | `/app/` Spaces list | +| Open Demo space | rendered markdown from Forgejo | +| Session details | profile menu diagnostics (no secrets) | +| Refresh content | re-fetch after git edit (or webhook) | -Full browser login against the **cluster** redirect URI requires public HTTPS -on `coulomb.social` (Secure cookie + callback host). Use **local OIDC** below -before DNS cutover, or complete browser MFA after cutover. +## Case matrix (CSOC-WP-0003-T04) -## Platform OIDC (local redirect) — **ready for human MFA** +| Case | Status | +|------|--------| +| A — known LLDAP user, first/repeat login on app.* | **done** (tegwick) | +| B — brand-new public registration → OIDC → Member | **deferred** → residual `CSOC-IN-0001` / NK-WP-0025 | -Client registration and authorize handoff verified; **human Authelia + MFA** -is the remaining interactive step. +### Negatives to run when Case B unblocks (or ad-hoc) + +Record results here or in residual notes; residual `CSOC-IN-0002`. + +| Negative | Intent | +|----------|--------| +| State / nonce replay | callback with recycled `state` fails closed | +| Subject collision | same issuer+subject always one Member | +| Email-only collision | email must not take over another subject | +| Step-up ACR | when `OIDC_STEP_UP_ACR` requested, insufficient acr rejected | +| Registration open redirect | `/auth/register/` ignores `?next=` host; only configured URL | + +App registration entry (when URL configured): + +```bash +# only after NetKingdom publishes public registration URL +# set NETKINGDOM_REGISTRATION_URL in coulomb-social-env (no secrets in git) +``` + +## Platform OIDC (local redirect) — optional ```bash export OIDC_ENABLED=true @@ -61,28 +98,14 @@ export OIDC_ISSUER=https://kc.coulomb.social export OIDC_CLIENT_ID=coulomb-social export OIDC_REDIRECT_URI=http://127.0.0.1:8008/auth/callback/ export OIDC_SCOPES="openid profile email groups" -# optional live user-engine (else stub): -# export USER_ENGINE_BASE_URL=https://users.92-205-62-239.nip.io -# export USER_ENGINE_PROXY_SECRET="$(kubectl -n user-engine get secret user-engine-runtime \ -# -o jsonpath='{.data.proxy-secret}' | base64 -d)" make run ``` | Step | Expected | |------|----------| | Open http://127.0.0.1:8008/ → Sign in | redirect KeyCape → Authelia | -| Complete MFA | callback → `/app/` with subject / display name | +| Complete MFA if prompted | callback → `/app/` | | Sign out | landing; `/app/` requires login | -| Second login | same Member / user_engine user_id | - -Authorize probe (no browser) 2026-08-09: - -| redirect_uri | KeyCape | -|--------------|---------| -| `http://127.0.0.1:8008/auth/callback/` | **302** → Authelia OIDC | -| `https://coulomb.social/auth/callback/` | **302** → Authelia OIDC | - -Unregistered redirects still fail with `invalid_profile_usage` (T03). ## Automated @@ -90,15 +113,4 @@ Unregistered redirects still fail with `invalid_profile_usage` (T03). make test ``` -## Public host (parallel to Bubble) - -**Strategy:** live Railiance app on **`app.coulomb.social`**; apex **`coulomb.social`** stays Bubble until content + self-registration cutover. - -| Check | Detail | -|-------|--------| -| Cluster host | `app.coulomb.social` (Helm + ingress) | -| OIDC redirect | `https://app.coulomb.social/auth/callback/` | -| DNS | operator: `app.coulomb.social` A → `92.205.62.239` | -| Apex | **do not** repoint until Bubble retirement | - -See `docs/deploy.md`. \ No newline at end of file +See also: `docs/deploy.md`, `docs/spaces-content.md`, `docs/adr/ADR-0001-netkingdom-identity.md`. diff --git a/docs/intakes/csoc-residuals.md b/docs/intakes/csoc-residuals.md new file mode 100644 index 0000000..f200a9e --- /dev/null +++ b/docs/intakes/csoc-residuals.md @@ -0,0 +1,73 @@ +# coulomb-social residual intakes + +File-backed intakes for leftovers from finished workplans. Canon: work-record +types § Residuals (`origin: residual`, `origin_ref: `). + +--- + +## CSOC-IN-0001 — Enable public Create account + Case B smoke + +```yaml +id: CSOC-IN-0001 +kind: intake +title: "Enable Create account and Case B registration smoke on app.coulomb.social" +lane: blue +status: open +priority: medium +owner: coulomb-social +repo: coulomb-social +origin: residual +origin_ref: CSOC-WP-0003 +description: | + App entry for Create account is implemented (NETKINGDOM_REGISTRATION_URL, + /auth/register/, landing button). Public enablement waits on NetKingdom + mailbox verification and published registration URL (NK-WP-0025 / USER-WP-0022). + + When the platform registration URL is live: + + 1. Set NETKINGDOM_REGISTRATION_URL on coulomb-social-env (names only in git; + example shape in .env.example). + 2. Confirm landing shows Create account and /auth/register/ redirects only to + that URL (no open redirect via ?next=). + 3. Run Case B: brand-new public registration → verified mail → OIDC → first + Member JIT on app.coulomb.social. + 4. Record evidence under docs/identity/smoke.md. + + DoC-Ok: residual of finished CSOC-WP-0003; platform dependency explicit. +notes: | + Depends on NK-WP-0025 (registration orchestration + mail path). + Related: CSOC-IN-0002 (identity negatives after Case B). +state_hub_intake_id: "019ff532-3694-7868-a3a7-f4b4f28a647a" +``` + +--- + +## CSOC-IN-0002 — Identity negative matrix after Case B + +```yaml +id: CSOC-IN-0002 +kind: intake +title: "Record identity negatives: state replay, collision, step-up" +lane: green +status: open +priority: low +owner: coulomb-social +repo: coulomb-social +origin: residual +origin_ref: CSOC-WP-0003 +description: | + CSOC-WP-0003 Case A (known LLDAP login) is proven. Remaining negatives listed + in docs/identity/smoke.md should be executed when Case B unblocks (or sooner + offline/dev if useful): + + - OIDC state/nonce replay + - issuer+subject collision (single Member) + - email-only must not take over another subject + - step-up ACR rejection when assurance insufficient + - registration redirect allow-list only + + Capture pass/fail in docs/identity/smoke.md; close this intake when recorded. +notes: | + Pulls from CSOC-IN-0001 for live registration path; some checks can run offline. +state_hub_intake_id: "019ff532-3ade-7d75-acb7-2bbfa264fcb8" +``` diff --git a/docs/spaces-content.md b/docs/spaces-content.md index 3bb5db4..c46ee6a 100644 --- a/docs/spaces-content.md +++ b/docs/spaces-content.md @@ -2,6 +2,9 @@ See **ADR-0002**. App DB holds metadata; page bodies are markdown in Forgejo. +**Operator runbook (seed, bind, cluster smoke):** `docs/deploy.md` +§ Operator runbook — spaces on app.coulomb.social. + ## Read (T04) 1. Space row has `forgejo_owner`, `forgejo_repo`, `default_branch`, `content_root`. diff --git a/workplans/CSOC-WP-0003-self-registration-and-assurance.md b/workplans/CSOC-WP-0003-self-registration-and-assurance.md index 4762a5e..144cdaa 100644 --- a/workplans/CSOC-WP-0003-self-registration-and-assurance.md +++ b/workplans/CSOC-WP-0003-self-registration-and-assurance.md @@ -4,11 +4,11 @@ type: workplan title: "Add NetKingdom self-registration and profile-aware assurance" domain: communication repo: coulomb-social -status: active +status: finished owner: bernd topic_slug: coulomb-social created: "2026-08-09" -updated: "2026-08-10" +updated: "2026-08-12" depends_on: - CSOC-WP-0002 - NK-WP-0025 @@ -22,10 +22,10 @@ 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. +**Finished 2026-08-12:** app-side work complete. Existing-user login on +**`app.coulomb.social`** is proven (tegwick, AAL1). Landing **Create account** +is implemented and gated on `NETKINGDOM_REGISTRATION_URL`. Public Case B waits +on NetKingdom mailbox verification (`NK-WP-0025`) — residuals below. ## T01 - Preserve and prove first-login JIT profile creation @@ -46,14 +46,15 @@ user-engine id; image `:f5537d8` uses id_token when `/userinfo` 401s. ```task id: CSOC-WP-0003-T02 -status: progress +status: done priority: medium state_hub_task_id: "aaf2d2cb-6ba9-42cb-9271-aacc414e947a" ``` Landing-page **Create account** using configured `NETKINGDOM_REGISTRATION_URL`. -App entry is implemented; remains disabled until NetKingdom public registration -URL + verified-mail flow ship. +App entry implemented (`/auth/register/`, context processor, tests). Button +hidden until env URL is set. **Enablement residual:** `CSOC-IN-0001` after +NK-WP-0025 publishes registration + verified-mail flow. ## T03 - Support profile/action step-up @@ -71,7 +72,7 @@ client uses `mfaRequired: false`. ```task id: CSOC-WP-0003-T04 -status: progress +status: done priority: medium state_hub_task_id: "57bac5f4-fd5d-46ba-92a3-a7bbeb15aa08" ``` @@ -79,7 +80,16 @@ state_hub_task_id: "57bac5f4-fd5d-46ba-92a3-a7bbeb15aa08" | 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 | +| B — brand-new public registration → OIDC → Member | residual **CSOC-IN-0001** (NK mailbox) | -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`. +Negatives checklist parked in `docs/identity/smoke.md`; execution residual +**CSOC-IN-0002**. + +## Residuals (live records) + +| Id | Role | +|----|------| +| `CSOC-IN-0001` | Enable Create account + Case B smoke when NK registration URL ships | +| `CSOC-IN-0002` | Record identity negatives (replay, collision, step-up) | + +Source: `docs/intakes/csoc-residuals.md`. diff --git a/workplans/CSOC-WP-0004-app-shell-and-space-content.md b/workplans/CSOC-WP-0004-app-shell-and-space-content.md index a45cb2f..d3fc295 100644 --- a/workplans/CSOC-WP-0004-app-shell-and-space-content.md +++ b/workplans/CSOC-WP-0004-app-shell-and-space-content.md @@ -4,11 +4,11 @@ type: workplan title: "App shell entry and Forgejo-backed space content" domain: communication repo: coulomb-social -status: active +status: finished owner: bernd topic_slug: coulomb-social created: "2026-08-10" -updated: "2026-08-10" +updated: "2026-08-12" # note: T07 added same day — principal diagnostics via profile menu depends_on: - CSOC-WP-0002 @@ -38,11 +38,14 @@ cutover. Migration of all Bubble spaces is **explicitly later** (`CSOC-WP-0001`). +**Finished 2026-08-12:** T01–T07 complete. Operator runbook and smoke pointers +in `docs/deploy.md` and `docs/identity/smoke.md`. + ## Out of scope (this plan) - Apex DNS cutover / Bubble retirement - Full Bubble inventory or bulk import -- Public self-registration (CSOC-WP-0003 / NetKingdom) +- Public self-registration (CSOC-WP-0003 residuals / NetKingdom) - Full UI parity (Research, marketplace matching, …) beyond space content MVP --- @@ -168,7 +171,7 @@ detail; repo-scoped cache invalidate; optional push webhook ```task id: CSOC-WP-0004-T06 -status: todo +status: done priority: medium state_hub_task_id: "40a880d0-62b9-4ae4-ab3e-074e8901462a" ``` @@ -177,6 +180,11 @@ 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. +2026-08-12: Full operator runbook in `docs/deploy.md` (demo seed, dedicated +repo, webhook, env table, smoke table). Product smoke section in +`docs/identity/smoke.md`. FORGEJO_* names in `.env.example` and `docs/dev.md`. +Content detail remains `docs/spaces-content.md`. + ## T07 — Principal diagnostics via user profile menu ```task @@ -232,11 +240,6 @@ T01 app home entry ──┬─► T07 profile menu principal diagnostics └─► T06 runbook ``` -T01 (+ T07) can ship alone to fix the “stuck on login confirmation” UX while -keeping identity diagnostics one click away. 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. @@ -245,10 +248,11 @@ to start T04 against a single seed repo. 4. Space page content is markdown backed by Forgejo with a working read path. 5. Bubble migration is still not required for demos on app.coulomb.social. 6. CSOC-WP-0001 can map Bubble pages onto the ADR layout when migration starts. +7. Operator runbook documents seed, bind, secrets (names), and smoke (T06). ## Related - Live host: `docs/deploy.md` (app.coulomb.social parallel to Bubble) -- Identity: CSOC-WP-0002 (done), CSOC-WP-0003 (registration later) +- Identity: CSOC-WP-0002 (done), CSOC-WP-0003 residuals for public registration - Migration later: CSOC-WP-0001 - Design tokens: `docs/design-extract/` diff --git a/workplans/CSOC-WP-0005-resource-demand-and-cost-evidence.md b/workplans/CSOC-WP-0005-resource-demand-and-cost-evidence.md new file mode 100644 index 0000000..8b56a6c --- /dev/null +++ b/workplans/CSOC-WP-0005-resource-demand-and-cost-evidence.md @@ -0,0 +1,80 @@ +--- +id: CSOC-WP-0005 +type: workplan +title: "Publish Coulomb Social resource demand and cost evidence" +domain: communication +repo: coulomb-social +status: ready +owner: codex +topic_slug: coulomb-social +created: "2026-08-11" +updated: "2026-08-11" +related: + - CSOC-WP-0004 + - RESOURCE-WP-0003 +state_hub_workstream_id: "00de1578-6150-40d3-b193-e852666ed945" +--- + +# CSOC-WP-0005 — resource demand and cost evidence + +## Goal + +Publish workload-owned requirements and observations for +`resource:tenant:coulomb:coulomb-social` without moving deployment, platform, +or financial authority into this repository. Origin: `RESOURCE-WP-0003-T04` +delegated evidence gap. + +## T01 — Declare low, base, and high workload demand + +```task +id: CSOC-WP-0005-T01 +status: todo +priority: high +state_hub_task_id: "d22e42e7-186e-4206-9cf4-c533d6388b13" +``` + +Define forecast proxies for active tenants/users, requests, background work, +database size/growth, stored media, ingress/egress, and required CPU/memory. +Preserve assumptions and distinguish current Coulomb use from future external +multi-tenant scenarios. + +Done when resource-control can produce falsifiable monthly demand forecasts. + +## T02 — Publish service objectives and usage observations + +```task +id: CSOC-WP-0005-T02 +status: todo +priority: high +state_hub_task_id: "ac078211-3cd9-49d8-baac-c0a1b60278fb" +``` + +Declare availability, latency, recovery, retention, and tenant-isolation +requirements. Publish timestamped non-secret observations for the demand +proxies available to the application while leaving cluster telemetry to its +owners. + +Done when infrastructure options can be evaluated against application-owned +requirements and forecast error can be measured. + +## T03 — Record workload operations labor + +```task +id: CSOC-WP-0005-T03 +status: todo +priority: medium +state_hub_task_id: "a15e630c-6bec-4c50-9622-bce16e1ce418" +``` + +Identify setup and recurring application labor for releases, migrations, +tenant operations, incident response, and recovery exercises. Separate it from +cluster, database, identity, and provider labor. + +Done when resource-control can include workload labor without double counting +platform operations. + +## Acceptance + +- [ ] Demand forecasts distinguish current, growth, and external-tenant cases. +- [ ] Service objectives and observations have stable units and provenance. +- [ ] Workload labor is separated from delegated infrastructure labor.