docs(teams): phase 4 — the forum's access model, switches and image policy #157

Merged
whitlocktech merged 1 commits from docs/teams-phase4 into edge 2026-08-18 14:18:25 +00:00
Member

What & why

The docs half of Teams phase 4 — Forum 5a, alongside website#153
and Module-uo#12. Records what building the phase settled, and what it
disproved.

The structural correction

TEAMS.md §3.1 gave the forum a core page, and phase 3 deleted every core Team
page. The routes were unaffected — they are all /player and /admin — but the
participant SURFACE had no home, and §5.4's route table did not notice. Settled the
way phase 3 settled the activity feed: module-uo declares a second place on its
guild page and core fills it, so the phase spans two repos rather than the one the
plan named.

Two slots rather than one, because a slot holds one component and the first fill
wins. The panel navigates by search param because a thread must be linkable and
core cannot mount a route on a page it does not own.

Two sanitiser findings worth not re-deriving

  • rel has to be on the allowlist for the transform that WRITES it to survive.
    sanitize-html strips any attribute not allowed — including one its own transform
    just added. Without the entry every forum link shipped without noopener,
    silently.
  • The bare-URL linkifier runs AFTER sanitising, over already-escaped text
    outside tags. That ordering is the security property; running it first would be
    an injection point.

Also recorded

  • The upload sweep runs regardless of the current image mode — which is the
    mechanism behind the dialog's promise that disabling uploads does not delete what
    is already there.
  • Two routes the §5.4 table lacked (GET .../grants and
    GET /admin/teams/forum/settings), and the fact that the grant routes answer
    while the forum is switched off.
  • The org lead's decision that all three proposed acknowledgement additions
    ship.

The other two files

BACKEND_DESIGN.md gains the four forum tables plus the reasoning a reader of the
schema alone would miss: why the guard is at the route and never at the data, why
no stored body ever contains an <img>, what uploads mode hardens, and what the
acknowledgement actually records.

MODULE_API.md's inverted-slot section gains the rule a module author needs — one
slot per PLACE, not one per page
— with the reason: a slot holds one component,
so collapsing two would hand core the placement decision on a page the module owns.

No MODULE_API_VERSION change: declareModuleSlot is unchanged and a second
declaration adds no member.

How it was tested

Prose only. Every claim here was written from the code that landed in the two
companion PRs, and each of the four acceptance criteria named in the phase plan is
an actual test in website/server/test/.

Checklist

  • I have read CONTRIBUTING.md.
  • The change builds and existing tests/checks pass locally.
  • I have added or updated tests/docs where it makes sense.
  • My commits are reasonably scoped with clear messages.

AI-assisted contributions (required)

  • AI tools were used. Tool(s): Claude Code. I have reviewed and understand
    every change, and take responsibility for it. AI-authored commits are
    marked with a Co-Authored-By trailer.

License

  • I agree that my contribution is licensed under this project's license
    (GNU GPL v3.0 or later), and I have the right to contribute it.
## What & why The docs half of Teams **phase 4 — Forum 5a**, alongside **website#153** and **Module-uo#12**. Records what building the phase settled, and what it disproved. ### The structural correction TEAMS.md §3.1 gave the forum a **core** page, and phase 3 deleted every core Team page. The routes were unaffected — they are all `/player` and `/admin` — but the participant SURFACE had no home, and §5.4's route table did not notice. Settled the way phase 3 settled the activity feed: `module-uo` declares a second place on its guild page and core fills it, so the phase spans two repos rather than the one the plan named. Two slots rather than one, because a slot holds one component and the first fill wins. The panel navigates by search param because a thread must be linkable and core cannot mount a route on a page it does not own. ### Two sanitiser findings worth not re-deriving - **`rel` has to be on the allowlist for the transform that WRITES it to survive.** sanitize-html strips any attribute not allowed — including one its own transform just added. Without the entry every forum link shipped without `noopener`, silently. - **The bare-URL linkifier runs AFTER sanitising**, over already-escaped text outside tags. That ordering is the security property; running it first would be an injection point. ### Also recorded - The upload sweep runs **regardless of the current image mode** — which is the mechanism behind the dialog's promise that disabling uploads does not delete what is already there. - Two routes the §5.4 table lacked (`GET .../grants` and `GET /admin/teams/forum/settings`), and the fact that the grant routes answer while the forum is switched off. - The org lead's decision that **all three** proposed acknowledgement additions ship. ### The other two files `BACKEND_DESIGN.md` gains the four forum tables plus the reasoning a reader of the schema alone would miss: why the guard is at the route and never at the data, why no stored body ever contains an `<img>`, what `uploads` mode hardens, and what the acknowledgement actually records. `MODULE_API.md`'s inverted-slot section gains the rule a module author needs — **one slot per PLACE, not one per page** — with the reason: a slot holds one component, so collapsing two would hand core the placement decision on a page the module owns. No `MODULE_API_VERSION` change: `declareModuleSlot` is unchanged and a second declaration adds no member. ## How it was tested Prose only. Every claim here was written from the code that landed in the two companion PRs, and each of the four acceptance criteria named in the phase plan is an actual test in `website/server/test/`. ## Checklist - [x] I have read [CONTRIBUTING.md](CONTRIBUTING.md). - [x] The change builds and existing tests/checks pass locally. - [x] I have added or updated tests/docs where it makes sense. - [x] My commits are reasonably scoped with clear messages. ## AI-assisted contributions (required) - [x] AI tools were used. Tool(s): `Claude Code`. I have reviewed and understand every change, and take responsibility for it. AI-authored commits are marked with a `Co-Authored-By` trailer. ## License - [x] I agree that my contribution is licensed under this project's license (**GNU GPL v3.0 or later**), and I have the right to contribute it.
wtclaude added 1 commit 2026-08-18 12:26:42 +00:00
Records what building phase 4 settled, and what it disproved.

The structural correction first: TEAMS.md 3.1 gave the forum a CORE page and phase
3 deleted every core Team page. The ROUTES were unaffected — they are all /player
and /admin — but the participant surface had no home, and 5.4's route table did not
notice. Settled the way phase 3 settled the activity feed: module-uo declares a
second place on its guild page and core fills it, so the phase spans two repos
rather than the one the plan named.

Two slots rather than one, because a slot holds one component and the first fill
wins; the panel navigates by search param because a thread must be linkable and
core cannot mount a route on a page it does not own.

Two findings from the sanitiser worth not re-deriving: `rel` has to be on the
allowlist for the transform that WRITES it to survive, or every forum link ships
without noopener; and the bare-URL linkifier runs after sanitising, over escaped
text only, which is the property that makes it safe rather than an injection point.

Also recorded: the upload sweep runs regardless of the current image mode, which is
the mechanism behind the dialog's promise that disabling uploads does not delete
what is already there; the two routes the table lacked; and the org lead's decision
that all three proposed acknowledgement additions ship.

BACKEND_DESIGN gains the four forum tables and the reasoning a reader of the schema
alone would miss — why the guard is at the route and never at the data, why no
stored body ever contains an <img>, what `uploads` mode hardens, and what the
acknowledgement actually records. MODULE_API's inverted-slot section gains the rule
a module needs: one slot per PLACE, not one per page.

Co-Authored-By: Claude <noreply@anthropic.com>
whitlocktech merged commit 36dbe9c985 into edge 2026-08-18 14:18:25 +00:00
whitlocktech deleted branch docs/teams-phase4 2026-08-18 14:18:26 +00:00
Sign in to join this conversation.
No description provided.