Public-sector use-case analysis: shared spaces in practice + derived backlog #59

Closed
opened 2026-07-29 22:34:44 +00:00 by Cordy · 4 comments
Owner

Product-thinking task from Nikola's 2026-07-29 batch. Two parts:

1. Shared spaces already exist — put them to work. The police-records scenario (multiple officers in a unit reading/writing the same case files) is exactly /spaces/<group> (v0.2.7): an IdP group becomes a shared tree for its members, membership managed entirely in AD/Keycloak. Nothing to build — but it must be demonstrated: enable on the dogfood (#50), document the pattern (docs page + a public-sector example in the site docs: group records-unit → space /spaces/records-unit), and validate the day-to-day flow (WebDAV mounts of a space, concurrent edits, per-user quota exemption inside spaces).

2. Persona walk-through → derived backlog. Think through how public-sector workers actually interact with files, and turn every gap into a scoped issue. Personas to cover: case worker (daily reads/writes in one space), records clerk (intake: scanning/uploading into structured folders), team lead (grants access = IdP group membership), IT admin (provisioning, quotas, offboarding = disable in AD), auditor/legal (needs to know who accessed what, when), external party (receives a share link — expiry + password policies).

Expected gaps to evaluate (each becomes its own issue if confirmed):

  • Audit logging — for police/legal records, per-object access logs (who read/wrote/deleted what, when) are usually a procurement requirement, not a nice-to-have. Likely the single most important public-sector feature Cairn lacks. Design constraint: append-only log, no DB (fits the no-database thesis? or the one place a log file is the answer).
  • Read-only space membership — auditor/viewer roles per space (today every member can write). Maps naturally to a second IdP group (<space>-ro).
  • Retention / legal hold — minimum-keep periods, deletion protection beyond trash.
  • Share-link policy — org-enforced max expiry / mandatory password (settings-store panel).

Deliverable: docs/PUBLIC-SECTOR.md (or site docs section) with the persona analysis + the derived issues filed and cross-linked here.

Product-thinking task from Nikola's 2026-07-29 batch. Two parts: **1. Shared spaces already exist — put them to work.** The police-records scenario (multiple officers in a unit reading/writing the same case files) is exactly `/spaces/<group>` (v0.2.7): an IdP group becomes a shared tree for its members, membership managed entirely in AD/Keycloak. Nothing to build — but it must be *demonstrated*: enable on the dogfood (#50), document the pattern (docs page + a public-sector example in the site docs: group `records-unit` → space `/spaces/records-unit`), and validate the day-to-day flow (WebDAV mounts of a space, concurrent edits, per-user quota exemption inside spaces). **2. Persona walk-through → derived backlog.** Think through how public-sector workers actually interact with files, and turn every gap into a scoped issue. Personas to cover: case worker (daily reads/writes in one space), records clerk (intake: scanning/uploading into structured folders), team lead (grants access = IdP group membership), IT admin (provisioning, quotas, offboarding = disable in AD), auditor/legal (needs to know *who accessed what, when*), external party (receives a share link — expiry + password policies). Expected gaps to evaluate (each becomes its own issue if confirmed): - **Audit logging** — for police/legal records, per-object access logs (who read/wrote/deleted what, when) are usually a *procurement requirement*, not a nice-to-have. Likely the single most important public-sector feature Cairn lacks. Design constraint: append-only log, no DB (fits the no-database thesis? or the one place a log file is the answer). - **Read-only space membership** — auditor/viewer roles per space (today every member can write). Maps naturally to a second IdP group (`<space>-ro`). - **Retention / legal hold** — minimum-keep periods, deletion protection beyond trash. - **Share-link policy** — org-enforced max expiry / mandatory password (settings-store panel). **Deliverable:** `docs/PUBLIC-SECTOR.md` (or site docs section) with the persona analysis + the derived issues filed and cross-linked here.
Author
Owner

Analysis delivered: docs/PUBLIC-SECTOR.md on main — persona walk-through (case worker, records clerk, team lead, IT admin, auditor/legal, external party, viewer) mapped against what's shipped, with the bus-factor/records-unit scenario worked as the core /spaces/<group> example.

Derived backlog filed and cross-linked:

  • #61 audit logging (append-only per-object access log) — the single most important gap for procurement
  • #62 share-link policy enforcement (ceiling, not defaults)
  • #63 retention + legal hold
  • #64 read-only space membership (<space>-ro IdP group)

Remaining in this issue: the dogfood demonstration (enable perUserHomes via #50 — Nikola's config flip — then the two-user records-unit walk-through and a public-sector example page in the site docs). Keeping open for that.

Analysis delivered: **docs/PUBLIC-SECTOR.md** on main — persona walk-through (case worker, records clerk, team lead, IT admin, auditor/legal, external party, viewer) mapped against what's shipped, with the bus-factor/records-unit scenario worked as the core `/spaces/<group>` example. Derived backlog filed and cross-linked: - #61 audit logging (append-only per-object access log) — the single most important gap for procurement - #62 share-link policy enforcement (ceiling, not defaults) - #63 retention + legal hold - #64 read-only space membership (`<space>-ro` IdP group) Remaining in this issue: the dogfood *demonstration* (enable `perUserHomes` via #50 — Nikola's config flip — then the two-user `records-unit` walk-through and a public-sector example page in the site docs). Keeping open for that.
Author
Owner

All four derived features are now shipped and live on the dogfood: #61 audit logging (v0.3.15), #62 share-link policy (v0.3.14), #63 retention + legal hold (v0.3.17), #64 read-only spaces (v0.3.16). #50 is closed, so perUserHomes/spaces/trash are active on .249.

Remaining in this issue is the demonstration half:

  1. Create records-unit and records-unit-ro groups in Keycloak plus a non-admin test user (nikola-test is admin and therefore unscoped — the member view can't be observed from it).
  2. Walk the flow: two members writing in /spaces/records-unit over WebDAV, a -ro viewer who can read but not modify, offboarding by group removal, a hold blocking deletion, and the audit log answering "who touched this file".
  3. Write it up as the public-sector example page in the site docs.

Step 3 can be written from the shipped behavior at any time; steps 1–2 need the Keycloak groups.

All four derived features are now shipped and live on the dogfood: #61 audit logging (v0.3.15), #62 share-link policy (v0.3.14), #63 retention + legal hold (v0.3.17), #64 read-only spaces (v0.3.16). #50 is closed, so `perUserHomes`/spaces/trash are active on `.249`. Remaining in this issue is the **demonstration** half: 1. Create `records-unit` and `records-unit-ro` groups in Keycloak plus a non-admin test user (`nikola-test` is admin and therefore unscoped — the member view can't be observed from it). 2. Walk the flow: two members writing in `/spaces/records-unit` over WebDAV, a `-ro` viewer who can read but not modify, offboarding by group removal, a hold blocking deletion, and the audit log answering "who touched this file". 3. Write it up as the public-sector example page in the site docs. Step 3 can be written from the shipped behavior at any time; steps 1–2 need the Keycloak groups.
Author
Owner

Adding a verification dependency here, since it shares this issue's prerequisite rather than needing its own tracking.

The read-only viewer badge (#64 UI, shipped in v0.3.20) is untested against a real read-only space. The wiring is verified — internal/api/api.go resolves readOnly through an optional ReadOnly(ctx, path) bool assertion on the store, and the browser disables mkdir/upload and shows a "View only" chip when it's true. But every account currently available for testing is in cairn-admins, and admins are unscoped, so readOnly is always false and the chip never renders in practice.

Proving it needs the same setup this issue is already blocked on:

  • a Keycloak group records-unit-ro (alongside records-unit) in realm cordyceps
  • a non-admin test user who is a member of records-unit-ro and not of cairn-admins

With those in place the demo walk-through and the badge verification are the same session: log in as the non-admin, open the read-only space, confirm the chip appears and the create/upload controls are disabled, then confirm a direct PUT/MKCOL against that path still returns ErrReadOnly — the badge is advisory, so the server-side refusal is the thing that actually matters and should be checked independently of the UI.

Worth doing in the same pass: confirm a member of records-unit (read-write) sees no chip and full controls, so we know the badge isn't showing up spuriously.

Adding a verification dependency here, since it shares this issue's prerequisite rather than needing its own tracking. **The read-only viewer badge (#64 UI, shipped in v0.3.20) is untested against a real read-only space.** The wiring is verified — `internal/api/api.go` resolves `readOnly` through an optional `ReadOnly(ctx, path) bool` assertion on the store, and the browser disables mkdir/upload and shows a "View only" chip when it's true. But every account currently available for testing is in `cairn-admins`, and admins are unscoped, so `readOnly` is always false and the chip never renders in practice. Proving it needs the same setup this issue is already blocked on: - a Keycloak group `records-unit-ro` (alongside `records-unit`) in realm `cordyceps` - a non-admin test user who is a member of `records-unit-ro` and **not** of `cairn-admins` With those in place the demo walk-through and the badge verification are the same session: log in as the non-admin, open the read-only space, confirm the chip appears and the create/upload controls are disabled, then confirm a direct `PUT`/`MKCOL` against that path still returns `ErrReadOnly` — the badge is advisory, so the server-side refusal is the thing that actually matters and should be checked independently of the UI. Worth doing in the same pass: confirm a member of `records-unit` (read-write) sees no chip and full controls, so we know the badge isn't showing up spuriously.
Author
Owner

Closing per Nikola's roadmap decision (2026-08-04): there will never be a "demonstration" with customers, and no walk-through. The framing this issue carried is replaced by the v0.6 closed beta — hands-on real usage between Manuel, Nikola and possibly a further selection of invited users. That beta is deliberately NOT tracked as a scripted scenario: whatever real usage surfaces gets raised by Nikola as concrete issues inside the v0.6 milestone.

What this issue's prerequisites pointed at is already covered elsewhere: the Keycloak group setup and read-only membership checks live in the #111 dogfood checklist, and the public-sector feature set itself (audit, holds, retention, read-only spaces) shipped v0.3.15–v0.3.21 with docs in docs/PUBLIC-SECTOR.md.

Closing per Nikola's roadmap decision (2026-08-04): **there will never be a "demonstration" with customers, and no walk-through.** The framing this issue carried is replaced by the **v0.6 closed beta** — hands-on real usage between Manuel, Nikola and possibly a further selection of invited users. That beta is deliberately NOT tracked as a scripted scenario: whatever real usage surfaces gets raised by Nikola as concrete issues inside the v0.6 milestone. What this issue's prerequisites pointed at is already covered elsewhere: the Keycloak group setup and read-only membership checks live in the #111 dogfood checklist, and the public-sector feature set itself (audit, holds, retention, read-only spaces) shipped v0.3.15–v0.3.21 with docs in `docs/PUBLIC-SECTOR.md`.
Cordy closed this issue 2026-08-04 17:23:43 +00:00
Sign in to join this conversation.
No labels
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Cordy/Cairn#59
No description provided.