--- type: aar status: harvested date: 2026-08-13 related: [docs/issues/0046-wiki-in-threadnet-server-suite-umziehen.md, docs/issues/0048-wikijs-in-der-suite-deployen.md, docs/issues/0050-wikijs-theming-farben-logo.md, docs/adr/0014-wikijs-loest-docusaurus-ab.md, docs/adr/0015-wiki-git-storage-ueber-gitea-kanonisieren.md] --- # AAR — Wiki.js-Umzug: Deploy, Theming, Git-Storage, Inhalts-Migration **Datum:** 2026-08-13 · **Stack:** `matrix`-Namespace (K3s Hetzner), gitops-Repo + Wiki.js **Auftrag:** Docusaurus durch Wiki.js ablösen (ADR-0014): reproduzierbar/deploybar, mit Authentik-OIDC-Login + Abschottung, Theming, Git-Storage (ADR-0015), Postgres-Backup und Migration der alten Inhalte. ## 1. Ergebnis Alles live und verifiziert: headless Deploy über einen Konfig-Job, Authentik-OIDC-only Login (`hideLocal`), Rollen + Abschottung (403-Nachweis mit echtem Anwender-Konto), Branding, Git-Storage Wiki.js→Gitea→git.lab, nächtliches Postgres-Backup, 10 alte Seiten migriert. #0046/#0048/#0049/#0050 `done`, ADR-0014/0015 `accepted`. Der Weg dahin hatte mehrere nicht-offensichtliche Stolpersteine — das ist der eigentliche Wert dieses AAR: Wiki.js- und Flux-Eigenheiten, die ein Forker oder eine spätere Session sonst teuer neu lernt. ## 2. Befunde / Stolpersteine | # | Stolperstein | Klasse | Dokumentiert | |---|---|---|---| | 1 | **Wiki.js-Login-Seite ist nicht per Custom-CSS themebar.** `master.pug` rendert kein `injectCSS`, der Login-Bundle wendet es nicht an → eine dunkle Login-Karte ist config-seitig unmöglich; bleibt hell. | tool | #0050 | | 2 | **Config-Werte brauchen `{"v": value}`-Kodierung.** Auth-Strategy UND Storage-Target lesen jeden Wert via `_.get(JSON.parse(value),'v',null)`. Ohne die Kodierung sind alle Werte `null` („requires an issuer option"). | tool | `wikijs-config.py` | | 3 | **`hideLocal` statt local deaktivieren.** Wiki.js braucht eine Formular-Strategie, sonst rendert die Login-Seite leer. „Nur OIDC" ⇒ local aktiv lassen + `authHideLocal=true`; Break-Glass `/login?all`. | tool | `wikijs-config.py` | | 4 | **Branding als statische Datei, nicht als gated Asset.** Ein per Upload eingespieltes Logo hängt an `read:assets` → 403 auf der unauth. Login-Seite. Lösung: unter `/_assets/img/...` mounten (öffentlich). | tool | `wikijs.yaml` | | 5 | **Flux streift Bilder aus dem Build-Artefakt** (`*.png`/`*.jpg` in der Default-Ignore) → `configMapGenerator` scheitert mit „no such file or directory". Fix: `.sourceignore` mit Negationen. | infra | `gitops/.sourceignore` | | 6 | **Geänderte immutable Job-Spec blockiert den GANZEN Flux-Apply.** Ändert sich die `wikijs-config`-Job-env, scheitert der Apply an der immutable Job — und **auch unabhängige Änderungen (ConfigMaps, Mounts) kommen still nicht durch**, obwohl die Source-Revision schon aktuell ist. Fix: Job löschen, Flux legt ihn neu an. | infra | dieser AAR | | 7 | **1-MiB-ConfigMap-Limit.** Hochskalierte Favicons + 604-KB-Hintergrund sprengten es (kurzzeitig ein Split in zwei ConfigMaps). Fix: Hintergrund runterskalieren (2560→1920 px, 400 KB), alles in EINER ConfigMap. Icons NICHT hochskalieren (Bloat + unscharf). | infra | #0050 | | 8 | **Git-Storage braucht den Remote-Branch vorab.** Wiki.js: „Invalid branch! Make sure it exists on the remote first." Ziel-Repo mit leerem Initial-Commit auf `main` bootstrappen. Nach fehlgeschlagenem Init sitzt der lokale Klon fest → `purge`-Action + re-init. | tool | ADR-0015 | | 9 | **Cluster erreicht git.lab nicht (Absicht).** Wiki.js pusht nach Gitea, ein CI-Job kanonisiert Gitea→git.lab (Muster `canonize_rotation`, umgekehrte Richtung). | infra | ADR-0015 | | 10 | **Nav-Sidebar rendert `target` wortwörtlich als `href`** (Default-Theme: `href: item.target`, keine `targetType`- oder Slash-Behandlung). Page-Targets ohne führenden Slash lösen **relativ** auf → von `/betrieb/x` aus wird `betrieb/y` zu `/betrieb/betrieb/y` → 404 (von `/` aus geht es zufällig, daher lange unbemerkt). `home` mit leerem Target ist ebenfalls tot. Fix: Targets absolut speichern (`/`; `home` → `/`) — Wiki.js' eigener Editor nutzt `//`. | tool | `wikijs-config.py` (`set_navigation`) | | 11 | **Locale-Wechsel migriert nur `pages`.** Default en→de via `localization.updateLocale` (lädt live, KEIN Neustart) + `pages.migrateToLocale`; letzteres patcht NUR die `pages`-Tabelle (Kollisions-Guard). `pageTree`/`pageLinks`/`pageHistory`/Suchindex bleiben auf der alten Locale → danach `pages.rebuildTree` + `search.rebuildIndex`, die Restzeilen in `pageLinks`/`pageHistory` einmalig nachziehen. **Nav-Baum muss unter der NEUEN Locale liegen** (getTree nutzt die Seiten-Locale), sonst leere Sidebar. `namespacing:false` → saubere `/`-URLs. | tool | `wikijs-config.py` (`ensure_locale`) | | 12 | **New-User-Zeitzone kommt aus dem DB-Spalten-Default** (`users.timezone` = `America/New_York`), NICHT aus Config: SSO-`processProfile` legt Nutzer ohne `timezone` an (`localeCode` dagegen aus `WIKI.config.lang.code`). Bestehende Konten per `users.update` korrigieren (patcht nur übergebene Felder, kein Nulling). Neue Nutzer brauchen den **Fork-Patch** (s. Nachtrag). | tool | `wikijs-config.py` (`ensure_timezones`) | | 13 | **Wiki-Inhalt nur über die Wiki.js-API editieren** — git-storage ist bidirektional, **nie** direkt nach Gitea schreiben (würde beim nächsten Sync kollidieren/überschrieben). Reproduzierbar via kurzlebigem In-Cluster-Job mit gemountetem Admin-Secret (Creds bleiben im Cluster; Pod-Label `app.kubernetes.io/name: wikijs-config` matcht die NetworkPolicy zu Wiki.js). | tool | dieser AAR | ## 3. Learnings (knapp) - **`checkAccess` ist Default-Deny** (`match && !deny`): eine Gruppe mit globalem `read:pages` + Pfad-Regel auf `anwender` sieht `betrieb/*` von allein nicht — Abschottung ohne explizite Deny-Regeln. Aber **immer mit einem echten Anwender-Konto gegentesten** (lokaler Testnutzer in `wiki-anwender`, HTTP-Status je Seite prüfen). - **Wiki.js ist config-seitig mächtig, aber eigenwillig** — vieles ist nur über Quellcode-Lesen im Pod (`/wiki/server/...`) herauszufinden. Der Konfig-Job (`wikijs-config.py`) kapselt das reproduzierbar; er ist die Doku. - **Browser cachen Favicons hartnäckig** — ein „falsches" Tab-Icon ist meist Cache, kein Deploy-Fehler. Erst server-seitig 16/32/`favicon.ico` prüfen, dann hart neu laden. ## 4. Actions - In-place dokumentiert: Kommentare in `wikijs-config.py`, `wikijs.yaml`, `.sourceignore` (gitops); Notizen in #0048/#0050; Architektur in ADR-0015. - **Geerntet 2026-08-14:** Befunde 1–13 + Learnings sind in [`docs/wiki/stolpersteine/wikijs.md`](../wiki/stolpersteine/wikijs.md) zusammengezogen (Wiki.js-Betriebswissen an einem Ort); dieser AAR ist damit `status: harvested`. ## 5. Nachtrag 2026-08-14 — Deutsch-Locale, Zeitzone & stehende Fork-Abweichung Nach dem Umzug fielen drei Dinge auf (sorb): die deutschen Inhalte hingen an der Locale `en`, die Default-Sprache war Englisch, die Systemkonten standen auf `America/New_York`. Alles behoben und reproduzierbar im Konfig-Job verankert: - **Default-Sprache `de` + 25 Seiten en→de migriert** (`ensure_locale`) — Mechanik siehe Stolperstein #11. - **Zeitzone `Europe/Berlin`** für die Systemkonten (`ensure_timezones`, #12); der Nav-`href`-Bug (#10) wurde im selben Zug gefixt. **⚠️ Stehende Upstream-Abweichung (Fork-Patch) — framework-relevant:** Wiki.js läuft als Upstream-Image (`ghcr.io/requarks/wiki:2.5`), es gibt **keine** Build-Pipeline. Damit **neue** OIDC-Nutzer `Europe/Berlin` statt des im DB-Spalten-Default verankerten `America/New_York` bekommen, patcht der Container beim Start `server/models/users.js` (`processProfile`) per `sed` (idempotent, fail-open). Das ist eine **dauerhafte Abweichung vom Upstream**, hängt am Anker `localeCode: WIKI.config.lang.code,` und **muss bei jedem Wiki.js-Upgrade gegengeprüft** werden. - Dokumentiert: ⚠️-Kommentar in `apps/production/wikijs.yaml` **und** in der Upgrade-Doku `/betrieb/upgrades` (Abschnitt „Wiki.js: Startup-Patch"), neben den Element-Fork-Einträgen. - **ADR m.E. nicht nötig** (kleine operative Abweichung, kein Architektur-/Regel-Grundsatz); Nachverfolgung läuft über die Upgrade-Doku + diesen AAR. Wer das anders sieht, hebt es per ADR nach. gitops-Commits: Locale/Nav/Zeitzone `2250969`, Nav-Slash-Fix `9f8eed3`, Fork-Patch `5f54fbe`.