# Matrix Setup — Tactical Media Broadcast Hub team chat OccupyMedia storage phase one adds [group attachment/archive contracts](occupymedia-storage.md) and an [independent files/docs scaffold](../infra/occupymedia/files/README.md). Live `occ-chat` remains conduwuit v0.5.0 with its existing local state/media; no volume or image switch is part of this phase. Future Tuwunel native R2 media requires a separate rehearsal and authorized upgrade. Archive mirroring is restricted to explicitly mapped **unencrypted archive rooms**; encrypted rooms are excluded. Collaborative ODT editing uses oCIS/Collabora WOPI, not Matrix. Matrix (conduwuit homeserver) is the **team/internal** chat plane. Stream viewer chat stays on the S5 hub (`docs/design/streaming-architecture.md` §3). Division of labor: | Plane | Tech | Who it serves | |---|---|---| | Team chat, DMs, bridged Telegram channels | Matrix (conduwuit + bridges) | editors, reviewers, admins | | Stream viewer chat | S5 hub → /realtime WS | Opticast app + control room | | Review threads (per-post) | Tactical Media Broadcast Hub native (WP5.1) | editorial workflow | ## Deploy 1. `cp infra/matrix/.env.example infra/matrix/.env` — set `MATRIX_SERVER_NAME` (permanent!) and a registration token 2. Point your reverse proxy at :6167 with HTTPS (federation requires valid TLS) 3. `docker compose -f infra/matrix/docker-compose.yml up -d` 4. First account: temporarily set `MATRIX_ALLOW_REGISTRATION=true`, register the admin via any Matrix client (Element), then lock it back. Share the token for invites. ## Rich text Conduwuit supports formatted bodies natively — clients (Element et al.) give Markdown, media, reactions, edits, replies, threads. **As good as Telegram** out of the box, plus E2E encryption. ## Telegram bridge (feeds WP15 — join channels & amplify) `mautrix-telegram` runs alongside. One-time setup: 1. `docker compose run --rm mautrix-telegram` — first boot writes `/data/config.yaml`; set homeserver + bridge admin 2. In Matrix, DM `@telegrambot:your-server`, send `login` + the phone/code → your Telegram account is bridged 3. Telegram channels you join appear as Matrix rooms; posts arrive as rich messages. The WP15 grabber (phase 2) reads those rooms → archive → review → amplify — no custom MTProto client needed, and the bridge is the battle-tested path 4. Two-way: replying in the Matrix room posts to Telegram (subject to the same rights/attribution rules as S6) ## 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 - **WP15**: grabber consumes bridged Telegram rooms (above)