--- id: CSOC-WP-0006 type: workplan title: "Stage-1 space and page capabilities (CRUD, copy, transfer)" domain: communication repo: coulomb-social status: finished owner: bernd topic_slug: coulomb-social created: "2026-08-12" updated: "2026-08-13" depends_on: - CSOC-WP-0004 related: - CSOC-WP-0001 - CSOC-WP-0003 origin: residual origin_ref: docs/decisions/2026-08-12-feature-cut-stage-1.md state_hub_workstream_id: "e92fe627-7ff4-42f6-a294-23b5a723edab" --- # CSOC-WP-0006 — Stage-1 space and page capabilities Implement product features required by the **stage-1 productive transfer** cut (`docs/capability/stage-1-cutover.md`, `docs/capability/model-v0.yaml`). **Out of scope here:** marketplace, social graph, monetization; Bubble export (CSOC-WP-0001-T02); public registration platform path (CSOC-IN-0001 / NK). ## T01 — Space member CRUD + Title / Abstract ```task id: CSOC-WP-0006-T01 status: done priority: high state_hub_task_id: "337baa68-0459-4985-9981-30a6d37f5bf5" ``` Member-facing create / update / archive for `Space` with **Title** and **Abstract** (`description` + `abstractor` property). Tenant-scoped list/detail. Tests: `tests/test_space_crud.py`, `tests/test_spaces.py`. ## T02 — Space and page Visual ```task id: CSOC-WP-0006-T02 status: done priority: high state_hub_task_id: "1ee74b60-a87d-4aff-91f1-3f97026774a5" ``` **Visual** on Space (DB field + form) and page frontmatter. Storage path is relative to the space tree under `CONTENT_ROOT` (e.g. `assets/cover.jpg`); not app media / secrets in git. Shown on list and detail. ## T03 — Page metadata + product CRUD path ```task id: CSOC-WP-0006-T03 status: done priority: high state_hub_task_id: "fe95438c-2ed1-4efd-b6ea-84966636dbc3" ``` PageOps façade (`pageops.py`) writes markdown with frontmatter title/abstractor/visual + body. Product UI: new/edit/delete page; sidebar page list. SoR is thin dir under `CONTENT_ROOT` (ADR-0004); Forgejo remains optional read fallback. ## T04 — Generate copy of page ```task id: CSOC-WP-0006-T04 status: done priority: high state_hub_task_id: "98d7428c-1b2f-45f1-b080-a833a4790b69" ``` `feat.page-duplicate`: independent copy with new slug/title; optional target space; relative visual assets copied under destination `assets/`. ## T05 — Transfer page to another space ```task id: CSOC-WP-0006-T05 status: done priority: high state_hub_task_id: "5ec81ff4-1d6f-4c86-8c93-b68b1570cc32" ``` `feat.page-move`: move page with source + destination membership checks; index cannot transfer. No Bubble dependency. ## T06 — Stage-1 smoke and capability model update ```task id: CSOC-WP-0006-T06 status: done priority: medium state_hub_task_id: "752f52a8-8c18-402c-8f00-bce6c76a1db7" ``` Updated `docs/capability/model-v0.yaml` feature statuses; extended `docs/identity/smoke.md` with Stage-1 PageOps checks. Automated coverage via `tests/test_pageops.py` and `tests/test_space_crud.py`. ## Acceptance - [x] Members can CRUD spaces with Title, Abstract, Visual without Django admin - [x] Members can CRUD pages with Title, Abstract, Visual + markdown body path - [x] Page copy and page transfer work with membership checks - [x] Capability model statuses match reality - [x] Stage-1 cut doc open questions resolved or explicitly deferred with owner ## Implementation notes - `CONTENT_ROOT` (default `var/content/`, gitignored): `spaces//pages|assets` - Space DB row is an index; bodies live on disk (PageOps) - Optional residual: git commit/push automation for content plane; full asset tree scan beyond Visual path; import Bubble export tree (CSOC-WP-0001-T04) ## Residuals (live records) - Bubble export → content-plane import remains on **CSOC-WP-0001-T04** (depends on this landing pad). - Public registration / NK mailbox remains **CSOC-IN-0001** / NK-WP-0025.