Files
ThreadNet-Web/docs/axion1337-fork.md
T
Thore Cimbal fa5dcc5fbc docs(fork): the import is not the v1.12.17 tag, and that changes the graft plan
Adding upstream as a second remote was meant to make updates viewable as a diff. The
first measurement contradicted what this document has claimed since August: diffing
v1.12.17 against the import commit yields 783 files, 115 of which exist only on our
side and 62 only in the tag.

The telling ones are MVVM files - TextualBodyViewModel.tsx and RovingTabIndex.tsx -
absent from the v1.12.17 tag, present in v1.12.26 and present in our import. The
changelog stops at 1.12.17 because it is only written at release time. So the base is
a develop state after the 1.12.17 release, not the tag.

That matters for the plan rather than for the code: grafting onto v1.12.17 would build
every future merge on an invented ancestry. Finding the real ancestor means searching
develop history, which a shallow tag fetch cannot do.

The remote is local configuration, so the setup is written down here instead of
committed.
2026-08-19 12:00:00 +00:00

217 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ThreadNet-Web: Fork-Anpassungen für axion1337.chat
Dieses Dokument beschreibt alles, was dieser Fork gegenüber Upstream Element Web ändert. Der
Rest der `docs/`-Ordner-Dateien und das Root-`README.md` sind unverändertes Upstream-Material
und beschreiben absichtlich **nicht** diese Anpassungen - diese Datei ist der zentrale
Anlaufpunkt dafür.
## 1. Discord-Style Room-List (Call-Teilnehmer in der Raumliste)
Zeigt aktive Call-Teilnehmer direkt in der Raumliste an (ähnlich Discords Voice-Channel-UI),
statt nur einen generischen "Call läuft"-Indikator. Betroffene Komponenten:
`apps/web/src/room-list/RoomListItemView/RoomListItemView.tsx` und
`RoomListItemView.module.css` (vertikale Ausrichtung der Teilnehmer-Avatare).
## 2. Client-seitiges ClamAV-Content-Scanning (Issue #19-Erweiterung)
Der Server-seitige Content-Scanner (Synapse-Modul, siehe gitops-Repo
[`docs/deployment-guides/06-moderation-content-scanning.md`](https://rohana.axion1337.de/sorb/axion1337.chat-gitops/src/branch/main/docs/deployment-guides/06-moderation-content-scanning.md))
sieht bei Ende-zu-Ende-verschlüsselten Räumen nur Ciphertext - eine strukturelle Grenze, kein
Bug. Da dieser Client bereits geforkt wird, scannt er stattdessen selbst, auf beiden Seiten:
- **Senden** (`apps/web/src/ContentMessages.ts`, `uploadFile()`): liest die Datei als
ArrayBuffer, scannt sie über `scanContent()` **bevor** verschlüsselt/hochgeladen wird - der
Upload wird bei Treffer gar nicht erst gestartet.
- **Empfangen** (`apps/web/src/utils/DecryptFile.ts`, `decryptFile()`): scannt die
entschlüsselten Bytes direkt nach dem Entschlüsseln, bevor das Blob an die UI zurückgegeben
wird - schützt auch vor Dateien von unveränderten/fremden Matrix-Clients, die diesen Patch
nicht haben.
- Gemeinsame Scan-Logik: `apps/web/src/utils/ContentScanner.ts` - ruft den (im gitops-Repo
deployten) `clamav-http-scanner`-Dienst per `fetch("/_scan", ...)` auf, mit dem eigenen
Matrix-Access-Token als Bearer-Auth. Fail-open bei Netzwerk-/Scanner-Fehlern (blockiert
Uploads/Downloads nicht bei einem Ausfall des Scanners).
- Neuer Fehlertyp `ContentScanRejectedError`, verdrahtet durch die bestehenden
Fehler-Rendering-Pfade in `MImageBody.tsx`, `MAudioBody.tsx`, `VideoBodyViewModel.ts`,
`FileBodyViewModel.ts`.
- Live getestet inkl. Hostile-Sender-Simulation (Datei per rohem API-Call ohne diesen Patch
gesendet, Empfangs-Hook hat trotzdem geblockt).
### ⚠️ Bekannte Lücke: Electron/Desktop (Issue #2)
Dieser Fix ist bestätigt nur für den **Web-Client-Build** wirksam. Der Electron-Desktop-Client
bekommt ihn aktuell **nicht automatisch** - die CI-Workflow-Kette (`build_ew`-Job) checkt
weiterhin `element-hq/element-web` (Upstream) statt diesen Fork aus, und es ist kein GitHub-
Actions-Runner für dieses Repo registriert. Der aktuell veröffentlichte Desktop-Build
(`desktop-v1.12.17-clientscan` Release) wurde manuell gebaut, nicht automatisiert. Details und
Fix-Plan: [Issue #2](https://rohana.axion1337.de/sorb/ThreadNet-Web/issues/2).
## 3. Build-Fixes (historisch, Issue #12)
Zwei Bugs blockierten einen vollständigen `docker build` von Grund auf (mussten für den
Client-Scanning-Rebuild oben behoben werden): (1) mehrere Shell-Skripte waren mit Modus 644
statt 755 committet (nicht ausführbar); (2) der `matrix-js-sdk#develop`-Git-Ref-Pin in
`pnpm-lock.yaml` war veraltet (fehlte `src/oidc/authorize.ts`, das `apps/web` importiert).
Beide behoben.
## 4. Merge-Reibung: was ein Upstream-Update wirklich kostet
*Arbeitspaket 3 aus ThreadNet-Web#7. Gemessen am 2026-08-06, nicht geschätzt.*
### Die unangenehme Grundlage zuerst
**Dieses Repo enthält keine Upstream-Historie.** Am 2026-05-10 wurde ein kompletter
Element-Web-Baum importiert — in `3da3635`, zusammen mit dem ersten eigenen Feature im
selben Commit. Davor liegt nur ein `Initial commit` mit zwei Dateien.
⚠️ **Korrektur 2026-08-19: Der Import ist NICHT der Tag `v1.12.17`.** Gemessen nach
Aufnahme von `upstream` als zweitem Remote (management #0099, Schritt 2):
- `git diff v1.12.17 3da3635` ergibt **783 Dateien, +17443/10371** — weit mehr als
unser damaliges Feature.
- **115 Dateien existieren nur bei uns, 62 nur im Tag.** Darunter MVVM-Dateien wie
`apps/web/src/viewmodels/room/timeline/event-tile/body/TextualBodyViewModel.tsx` und
`packages/shared-components/src/core/roving/RovingTabIndex.tsx`: im Tag `v1.12.17`
**nicht vorhanden**, in `v1.12.26` und in unserem Import **vorhanden**.
- Der `CHANGELOG.md` unseres Imports endet bei 1.12.17 (2026-04-30) — er wird erst
beim Release fortgeschrieben.
Zusammen heißt das: Die Grundlage ist ein **`develop`-Stand nach dem 1.12.17-Release**
(1.12.18 erschien am 2026-05-12), nicht der Tag. Praktische Folge: **Ein Graft auf
`v1.12.17` wäre falsch** und würde jede künftige Zusammenführung auf eine erfundene
Ahnenreihe stellen. Wer den gemeinsamen Vorfahren nachträglich herstellen will, muss
den passenden `develop`-Commit suchen — das braucht die volle Upstream-Historie, ein
flacher Fetch der Tags genügt dafür nicht.
Daraus folgt das Wesentliche: **es gibt keinen gemeinsamen Vorfahren mit
`element-hq/element-web`.** Ein `git merge upstream/develop` ist nicht möglich; mit
`--allow-unrelated-histories` erzwungen, kollidiert praktisch jede Datei. Wer „mal
eben Upstream nachziehen" sagt, meint in diesem Repo also: neuen Upstream-Stand
beschaffen und unsere Änderungen darauf neu auftragen.
Das ist der Grund, warum die Zahl unten überhaupt zählt — sie ist der Aufwand jedes
Updates.
### Unser Delta: 102 Dateien, davon 12 kritische
`git diff --name-only 3da3635..main`:
| Menge | Bereich | Konfliktrisiko |
|---|---|---|
| 46 | CI/Build (`.github/`, `.gitlab-ci.yml`, `dockerbuild/`) | gering — eigene Strecke, Upstreams Workflows brauchen wir nicht |
| 22 | Config, Lockfiles, Upstream-Varianten | mittel — `pnpm-lock.yaml` konfliktet immer, wird aber regeneriert |
| 13 | Web-Assets (`apps/web/res/`) | gering — meist eigene Dateien |
| 4 + 3 | eigene Icons und `apps/desktop/axion1337/` | **keins** — kein Upstream-Pendant |
| **12** | **Upstream-Quellcode** | **hier entsteht die Arbeit** |
### Die 12 Dateien, und warum sie angefasst wurden
**Branding (5)** — flach, gut isolierbar:
- `apps/web/src/SdkConfig.ts` — Defaults für `brand`, `welcome_background_url`, `desktopBuilds`
- `apps/web/src/vector/index.html``<title>`, Favicon-Link, PWA-Namen
- `apps/web/src/async-components/structures/ErrorView.tsx` — Logo der Fehlerseite
- `apps/web/src/components/views/settings/tabs/user/HelpUserSettingsTab.tsx` — Attribution + Danksagung
- `apps/web/src/i18n/strings/en_EN.json` — einzelne Strings
**ClamAV-Client-Scanning (7)** — tief in der Medien-Pipeline:
- `apps/web/src/ContentMessages.ts`, `utils/ContentScanner.ts`, `utils/DecryptFile.ts`
- `apps/web/src/components/views/messages/MImageBody.tsx`, `MAudioBody.tsx`
- `apps/web/src/viewmodels/message-body/FileBodyViewModel.ts`, `VideoBodyViewModel.ts`
### Nicht der Umfang entscheidet, sondern die Art des Eingriffs
Gemessen in geänderten Zeilen nehmen sich beide Gruppen wenig: **ClamAV ~130 Zeilen,
Branding ~104**. Der größte Einzelpatch ist sogar Branding
(`HelpUserSettingsTab.tsx`, 71 Zeilen). Wer nur zählt, hält beide für gleich teuer.
Sie sind es nicht, und der Grund ist die Art des Eingriffs:
- **Branding-Patches stehen am Rand.** Ein zusätzlicher Default in `SdkConfig.ts`,
ein `<link>` im `<head>`, ein `<li>` in einer Settings-Liste. Wird die Datei
umgebaut, sieht man sofort, wo das eigene Stück wieder hin muss.
- **ClamAV-Patches stehen mittendrin** — in Entschlüsselungs- und Fehlerpfaden der
Medien-Pipeline, verschränkt mit Upstream-Logik. Ein geänderter Kontrollfluss
bedeutet nicht „Konflikt lösen", sondern „neu verstehen".
⚠️ **Und der eigentliche Haken: `viewmodels/`.** Element baut die Medien-Anzeige
gerade auf MVVM um (`docs/MVVM.md`; v1 ist dort bereits als deprecated markiert —
der Umbau läuft also schon in zweiter Runde). `FileBodyViewModel.ts` und
`VideoBodyViewModel.ts` gab es in älteren Ständen gar nicht. Unsere Änderung darin
ist mit je 6 Zeilen winzig — aber wenn Upstream diese Dateien verschiebt, umbenennt
oder auflöst, entsteht **kein Konflikt**: die Zeilen sind einfach weg, und Git meldet
nichts. Das ist gefährlicher als ein Konflikt, weil es stillschweigend passiert.
Praktische Folge: Nach einem Upstream-Update ist an ClamAV nicht die Merge-Ausgabe
maßgeblich, sondern ein **Funktionstest** — eine verschlüsselte Datei senden und eine
abgelehnte empfangen. Steht so auch in Abschnitt 2.
### Was daraus für künftige Änderungen folgt
1. **Erst prüfen, ob es die Konfiguration schon kann.** Auth-Logo, `logo_link_url`
und `brand` liefen ohne Rebuild über die ConfigMap; das Call-Widget wurde
vollständig über `VITE_PRODUCT_NAME` umbenannt, ohne eine einzige Quelldatei.
Jede so vermiedene Datei ist eine, die beim Update nicht kollidiert.
2. **Eigene Datei schlagen geänderte Datei.** `apps/desktop/axion1337/` und eigene
Assets kosten beim Merge nichts.
3. **Wenn Upstream-Code sein muss: einen Kommentar mit `ThreadNet-Fork:` und der
Begründung dazu.** Beim Neuauftragen auf einen neuen Stand ist die Frage nie
„was steht hier", sondern „warum stand das da" — und die beantwortet sonst
niemand mehr.
## Repo-Topologie (seit 2026-07-31)
**Kanonisch ist `git.lab/axion1337.chat/ThreadNet-Web`** (Homelab-GitLab, nur im Lab
auflösbar) — dort laufen Entwicklung und CI (`.gitlab-ci.yml`). Die Kopie auf
`rohana.axion1337.de/sorb/ThreadNet-Web` ist ein **Push-Mirror** (automatisch, GitLab →
Gitea) und dient als Lesekopie plus Standort für Issues, Container-Registry und Releases.
**Niemals direkt nach rohana pushen** — der Mirror überschreibt divergente Stände.
## Element Call anheben (`@sorb/threadnet-call-embedded`)
Das Call-Widget kommt als npm-Paket aus der **Gitea-Registry auf rohana**, nicht von
npmjs. `.npmrc` im Wurzelverzeichnis bindet den Scope fest:
```
@sorb:registry=https://rohana.axion1337.de/api/packages/sorb/npm/
```
Zum Anheben genügt damit der normale Weg — **kein Zusatzschritt, keine Umgebungsvariable**:
```sh
# Version in apps/web/package.json setzen, dann:
pnpm install --lockfile-only # Lockfile zieht die neue Tarball-URL von rohana
pnpm --dir apps/web build # NICHT --filter web: das endet mit exit 0, ohne zu bauen
```
Danach muss die Tarball-URL im `pnpm-lock.yaml` auf `rohana.axion1337.de` zeigen. Tut sie
das nicht, ist die `.npmrc` verlorengegangen: **ohne sie löst pnpm gegen npmjs auf**, und
das geht heute nur deshalb laut aus (404), weil der Name `@sorb` dort noch frei ist —
verlässt man sich darauf, ist es ein *dependency-confusion*-Weg. Siehe management#0055.
Vor dem Anheben liegt das Paket erst dann in der Registry, wenn in `threadnet-call` der
manuelle Job `publish_npm` gelaufen ist — der ist bewusst manuell und wird von sorb
ausgelöst.
## Upstream als zweiter Remote (seit 2026-08-19)
Der Remote ist **lokale Konfiguration**, er wird nicht mitcommittet. Wer den Vergleich
braucht, richtet ihn einmal ein:
```sh
git remote add upstream https://github.com/element-hq/element-web.git
git fetch --depth=1 upstream tag v1.12.26 # aktueller Stand
git fetch --depth=1 upstream tag v1.12.17 # zum Vergleich
```
Damit lässt sich ein Update **als Diff betrachten**, statt Dateien blind zu kopieren —
zum Beispiel für die zwölf Dateien, die wir angefasst haben:
```sh
git diff v1.12.26 main -- apps/web/src/... # unser Delta gegen Upstream
git diff v1.12.17 v1.12.26 -- <datei> # was Upstream seither geaendert hat
```
⚠️ Ein flacher Fetch liefert **keine Historie**: `git merge-base`, `git log` über
Upstream und ein Graft-Versuch brauchen `git fetch upstream` ohne `--depth`.