Collectives P1: participation landing (ES/EN), group tree, room provisioning APIs

- 030: groups.parent_id tree + kind discriminator + group_rooms mapping
- /collectives module: create/tree/join APIs, MatrixProvisioner (open room
  public+federated, closed room E2EE-at-creation, onboarding room), NullProvisioner
  fail-soft when ARCHIVE_PROVISIONER_* unset
- web root becomes the public participation manual (ES-first + EN toggle,
  three paths: join by invite, start collective, solo account)
- participation manual content in core
This commit is contained in:
glass beadian 2026-10-12 13:53:40 +00:00
parent c31762b82d
commit 4a7e78b28d
23 changed files with 2892 additions and 8 deletions

View file

@ -1,5 +1,14 @@
# Collectives architecture — participation, rooms, subcollectives, diffusion
> **Status — P1 shipped (implementation note).** The three scope pillars of P1 are in:
> `groups.parent_id`/`groups.kind`/`group_rooms` (migration `030_collectives.sql`),
> the participation-manual landing page at the app root (`apps/web/src/app/page.tsx`, copy in
> `packages/core/src/participation-manual.ts`), and the provisioner port + Matrix implementation
> (`apps/api/src/collectives/`). Join-by-invite is unchanged: an invite token claims workspace
> membership exactly as before; `GET /collectives-public/for-invite/:token` adds names-only
> collective labelling to the join card. Room addresses in the UI, directory, and the UI/state
> re-parenting surface remain P2+.
Status: design for build (phase 1 dispatch in flight)
Date: 2026-10-12
Decides: landing flow, collective model, room matrix, provisioning, diffusion

View file

@ -35,6 +35,31 @@ Conduwuit supports formatted bodies natively — clients (Element et al.) give M
## Branding
Element Web (if self-hosted as the client) accepts custom CSS — the same propagation rule as PeerTube: repo is the source of truth, a sync script pushes (accent #FF1610 on black, solid disk mark) after any brand change. Native clients keep their own themes; brand consistency applies to web surfaces.
## Provisioner bot (collectives P1)
Room provisioning for collectives (`docs/design/2026-10-12-collectives-architecture.md`) runs as a
**separate bot account from the archive bot** — both are crypto-blind, but they hold different
powers, so they never share credentials or a device id:
```bash
# apps/api reads these; missing config = collective creation answers 503 (never a boot failure)
ARCHIVE_PROVISIONER_HOMESERVER_URL=https://chat.example.com
ARCHIVE_PROVISIONER_USER=@hub-provisioner:chat.example.com # create it like any bot account below
ARCHIVE_PROVISIONER_PASSWORD=...
ARCHIVE_PROVISIONER_DEVICE_ID=HUB_PROVISIONER_BOT # stable: txn-id idempotency survives restarts
```
What it provisions per collective, in one pass (see `apps/api/src/collectives/matrix-provisioner.ts`):
| Room | preset / visibility | federation | encryption | notes |
| --- | --- | --- | --- | --- |
| Open | `public_chat` / public | on (`m.federate: true`) | **never** | `history_visibility: shared`; archive-mirrorable by definition |
| Closed (production) | `private_chat` / private | **off** | **at creation** (`m.megolm.v1.aes-sha2` in `initial_state`) | no unencrypted form ever exists server-side |
| Onboarding | `private_chat` / private | off | no | bot posts the participation manual ES-first, then EN; disposable |
Founder power level is pinned to 100, everyone else 0; the bot keeps 100 to administer the rooms it
built. Room ids (never aliases) are recorded in `group_rooms` (migration 030), tenant-scoped and RLS'd.
## Tactical Media Broadcast Hub integration points (follow-ups)
- **Inbox screen**: swap fixtures for Matrix client-sdk (matrix-js-sdk) — DMs + team rooms render in-app
- **Review notifications**: WP5.1 posts approval-needed events into a team room