feat!: remove direct messaging (chat)

E2EE direct messages, the chat dock, the Messages module, the message
WebSocket and its realtime registry, and the messages / message_keys
tables (migration 0097; the downgrade restores the empty schema). Prod
held two welcome notes, no message between people and one key — never
used (owner decision, E34). WebSocket now has no owner module: the lint
bans it everywhere. Privacy policy updated: it no longer promises E2EE
for a feature that is gone.
This commit is contained in:
2026-10-05 00:19:38 +02:00
parent 7f08c510bf
commit cca3315836
71 changed files with 122 additions and 3011 deletions
@@ -60,8 +60,8 @@ describe("Avatar · a failed image must not follow the component to the next ite
});
it("retries a URL it comes back to — a 429 is transient, and so is the memory of it", () => {
// The instance is not remounted here on purpose: the player's channel avatar and the Messages
// thread header both swap `src` on a live instance. A memory that outlived the reason for it
// The instance is not remounted here on purpose: the player's channel avatar swaps `src` on a
// live instance as it steps through a queue. A memory that outlived the reason for it
// would pin a throttled channel to its initial for the rest of the session.
const { rerender } = render(
<Avatar src="https://cdn.test/a.jpg" alt="avatar" fallback="Zed" />,
+1 -1
View File
@@ -29,7 +29,7 @@ export default function Avatar({
//
// Forgetting the URL once `src` has moved off it is the other half, and it is what keeps the 429
// TRANSIENT: without it the memory outlives the reason for it, and a mounted instance whose `src`
// swaps — the player's channel avatar stepping through a queue, the Messages thread header — would
// swaps — the player's channel avatar stepping through a queue — would
// show the initial for a throttled channel forever, never re-requesting even after the CDN
// relented. Written in render because it is convergent (the write falsifies its own condition) and
// because an effect would leave one committed frame in which the memory is stale, which is the
+1 -1
View File
@@ -112,7 +112,7 @@ export function NavRailItem({
}}
// With the label visible the row's name starts with that text (WCAG 2.5.3: the spoken name
// contains the visible one); the full name stays in the tooltip. Icon-only, the full name is the
// name. The exact count rides in the name either way, so "Messages (3)" is heard and not only
// name. The exact count rides in the name either way, so "Alerts (3)" is heard and not only
// seen; the drawn badge is hidden (labelled, it was read first and capped: "9+Alerts").
aria-label={`${showLabel ? shortLabel : label}${shown ? ` (${badge})` : ""}`}
aria-current={active ? "page" : undefined}
+2 -3
View File
@@ -30,9 +30,8 @@ The direction is one-way from below, too: `lib/` may not import from `components
included, not even a type (same lint file). A contract both layers need lives in `lib/`: the `Column`
/ `FilterMap` shape and `filterRows` are `lib/tableColumns`, which `tableHeader` and `DataTable` import.
Counter-examples, deliberately NOT here: `PosterTile` (knows about Plex montage posters), `KeyGate`
(secure-messaging key setup), `plexCards`, `downloadRow`, `channelColumns` — all shared, none
domain-free.
Counter-examples, deliberately NOT here: `PosterTile` (knows about Plex montage posters),
`plexCards`, `downloadRow`, `channelColumns` — all shared, none domain-free.
## What lives here