diff --git a/CHANGELOG.md b/CHANGELOG.md index b56ae4b..d0863e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,61 @@ skip versions are the composition of each intervening adjacent release's steps in order — no A-to-B path is pre-computed beyond that. +## 0.43.0 — 2026-06-06 + +**Minor (non-breaking) — §22 three-tier refactor, slice S4: *invitation +surfaces + role-aware empty states.* An Owner can now grant scope roles from the +UI, and each tier shows a role-appropriate empty state. Purely additive over S3: +new endpoints and UI, no schema migration, and no change to existing read or +write semantics. Completes acceptance scenarios `@S4` (C2.1–C2.7: invitation +reach, bounding, supersession, and the pending-account floor; C3.3–C3.5: the +create-first-collection and propose-first empty states).** + +See [`docs/design/2026-06-05-three-tier-projects-collections.md`](./docs/design/2026-06-05-three-tier-projects-collections.md) +(Part E slice S4, Part C.2 and C.3). The in-app create-project flow and the +global-directory empty states (C3.1–C3.2) remain S5. + +Added: + +- **Scope-role invitation surface (§22 C.2)** — `POST + /api/projects//members` grants `{owner, contributor}` to an existing + account (looked up by email) at the project, or at one collection (with + `collection_id`). The grant writes a `memberships` row immediately and emits a + §15 personal-direct notification (`scope_role_granted`) naming the project and + role — a direct grant, not an accept round-trip. `GET` lists the project + subtree's grants (project-Owner view); `DELETE + /api/projects//members/` (optionally `?collection_id=`) revokes. +- **Invitation gates** — `auth.can_invite_at_project` / + `can_invite_at_collection`: managing membership is an Owner capability bounded + by the inviter's reach. A project Owner grants at the project or any collection + within it; a collection Owner grants only at that collection (never the project + or globally); an RFC Contributor manages no membership. +- **Broader-scope-supersedes (§22 C.2.6)** — granting at a broader scope removes + the grantee's narrower rows that the new grant subsumes (same-or-lower role + rank within the subtree); a stronger child grant survives a weaker parent grant + (no negative override). +- **Pending-account floor (§22 C.2.7)** — a grant to a `pending` deployment + account is recorded but confers no write until the account is granted at the + deployment (the §6 admission floor in `effective_scope_role`). +- **Viewer capability flags** — `GET /api/projects//collections` carries a + `viewer` block (`can_create_collection`, `can_invite`, `role`); `GET + /api/projects//collections/` carries `viewer.can_contribute / + can_invite / role`. These drive the role-aware UI without a second round-trip. +- **Role-aware empty states (§22 C.3.3–C.3.5)** — a project Owner landing on an + empty project sees a "Create your first collection" CTA (opening the + create-collection modal — surfacing the S2 endpoint, previously UI-less); a + contributor without create rights sees the bare empty directory; a collection + contributor landing on an empty collection sees "Propose the first entry" + (anonymous readers keep the S2 sign-in prompt). The directory also gains an + Owner-only **Members** control opening the invitation modal. + +Upgrade steps: + +1. No operator action is required. S4 adds endpoints and UI only — there is no + migration and no change to existing authorization outcomes. A deployment that + was managing `memberships` rows directly (the S3 administrative path) keeps + working; the new UI is an additional way to write the same rows. + ## 0.42.0 — 2026-06-05 **Minor (breaking — upgrade steps below) — §22 three-tier refactor, slice S3: diff --git a/VERSION b/VERSION index 787ffc3..8298bb0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.42.0 +0.43.0 diff --git a/docs/design/2026-06-05-three-tier-projects-collections.md b/docs/design/2026-06-05-three-tier-projects-collections.md index 4592e3f..6498e6a 100644 --- a/docs/design/2026-06-05-three-tier-projects-collections.md +++ b/docs/design/2026-06-05-three-tier-projects-collections.md @@ -581,13 +581,17 @@ means the deployment runs and either gains a capability or provably loses none hidden from the public. **Completes:** `@S3` (all of C.1 — role usage, inheritance, union, no-negative-override). -- **S4 — Invitation surfaces + role-aware empty states.** The invite UI +- **S4 — Invitation surfaces + role-aware empty states.** *(Shipped v0.43.0.)* + The invite UI (Owner-only) granting Owner/RFC Contributor at a scope or any scope beneath it, with §15 notifications and the broader-scope-supersedes rule; the create-first-collection / propose-first empty states keyed to the actor's role. - **Usable end-state:** an Owner invites collaborators at the right scope from - the UI. **Completes:** `@S4` (all of C.2 — invitation; plus the project/ - collection empty states C3.3–C3.5). + Modelled as a **direct grant** to an existing account looked up by email (the + C.2 scenarios write the membership row immediately and §15-notify an existing + user — no accept round-trip; inviting a not-yet-account email is out of S4 + scope, handled by the admin-create-invite path). **Usable end-state:** an Owner + invites collaborators at the right scope from the UI. **Completes:** `@S4` (all + of C.2 — invitation; plus the project/collection empty states C3.3–C3.5). - **S5 — In-app create-project + the global directory.** The global-Owner **create-project** action (bot provisions a Gitea content repo + commits to diff --git a/frontend/package.json b/frontend/package.json index 1bb033b..29152e4 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "rfc-app-frontend", "private": true, - "version": "0.42.0", + "version": "0.43.0", "type": "module", "scripts": { "dev": "vite",