docs(teams): design of record for platform Teams & community integration

Teams become a core platform primitive rather than a mechanism for generating
Discord infrastructure: a module stays authoritative for who a Team is and who
belongs to it, and core owns everything the platform attaches to it — pages,
roster, activity, forums, notifications and optional external integrations.

Investigated against the working tree rather than the brief, which corrected
three of its premises:

- guild.update carries member/online COUNTS, not a roster, and one leader. Every
  membership-derived feature has no data source today, so a protocol change
  (PROTOCOL_VERSION 3 -> 4, guild.roster + guild.leave) is the gating phase.
- There is no module->core news hook to generalise. ctx.posts is read-only and
  both registerPostHook and registerAnnounceLeg run core->module, so the activity
  feed needs its own ingestion member modelled on ctx.push.publish.
- Core has no SSE at all; it left with the module cutover. Live roster status is
  module-projected through an extension slot rather than a new core transport.

Also settled: the four-path permission model (game membership / leadership /
forum access / external access) with the non-contamination invariant; envelope-
returning provider methods so module unavailability is structurally staleness
and never an authoritative empty; reserved-name screening with auto-hide and an
admin-approval gate on the three actions that publish untrusted game-sourced
strings; forum admin controls with a renderer-owned image path; abuse reporting;
email as a third notification sink; and a capability-based integration contract
rather than a shared interface, with the Matrix research behind that choice.

Part 10 sorts every artifact into contract / core-internal / module-owned / wire
protocol, because almost none of this is contract: the surface is ten members,
and the ~15 tables are core-internal and off limits to a module even though the
module is what populates them.

Proposes MODULE_API_VERSION 1.6.0 (minor, additions only) and an 11-phase plan.
Design only — nothing is implemented, and MODULE_API.md remains normative.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WnDSWzpUjw8t8C2hghysNz
This commit is contained in:
2026-08-17 03:53:19 -05:00
parent d4beba1a5d
commit 111b412fd5
2 changed files with 2041 additions and 0 deletions

View File

@@ -1112,6 +1112,32 @@ push, and Play (M6M8) follow the designed app.
### Deferred (not a milestone)
- **Platform Teams in the app** — **deferred 2026-08-17, no app work scheduled.** The website is
building Teams as a core platform primitive (pages, roster, activity feed, forums, notifications —
[`../website/TEAMS.md`](../website/TEAMS.md)), and the app has no story for any of it. Deferred
deliberately rather than scheduled: this milestone list is already behind, and adding a large new
surface ahead of the outstanding work would make that worse.
**What lands anyway, with no app change**, when the website ships its Phase 6: the four Team
notification streams (`team.member.joined`, `team.leadership.changed`, `team.forum.post`,
`team.announcement`) appear in `GET /auth/me/notifications/streams`, so the existing Notifications
screen renders toggles for them automatically — the catalog is server-driven.
**The stated limitation, so it is not mistaken for a bug:** a Team tickle opens the app and no more.
There is no Team screen and no deep-link target, and the per-Team mute list
(`GET|PUT /auth/me/notifications/teams`) has no UI — a user who wants to mute one Team has to do it
on the website. Whether to ship the toggles in that state, or hide the four streams behind a
capability check until there is somewhere to land, is the first decision this milestone makes when
it is picked up.
**Revival trigger:** website Phases 35 landed (Team pages, roster and forums exist to link to) *and*
the current milestone backlog is clear. Scope when it comes back: a Teams tab reading
`/public/teams` + `/player/teams`, deep links for the four streams, and the mute list.
> **Note the PUT-the-whole-set trap below applies to `/auth/me/notifications/teams` too** — the mute
> list is a replace-the-set endpoint, so its request DTO field must have **no default** or kotlinx
> drops it when the set is empty.
- **`/api/mobile` facade migration + app-version floor** — briefly planned as its own milestone
(2026-07-22), now **deferred with no app work scheduled**. The website's router refactor is being done in place with
every URL byte-identical and `/api/v1` is not being retired, so the app's ~70 hardcoded `api/v1/…`

2015
website/TEAMS.md Normal file

File diff suppressed because it is too large Load Diff