feat: Authentik OIDC SSO, allow/deny RBAC, admin console & Gitea CI
All checks were successful
build-and-push / build (push) Successful in 15m15s

Authentication & RBAC
- Add confidential OIDC client (Authentik) with /auth/oidc/login +
  /auth/oidc/callback: discovery, code exchange, id_token verify (go-oidc),
  groups claim → role (Archivum-admin → admin, else user). Sessions carry groups.
- Rework ACL into an allow/deny model (new `effect` column + migration).
  db.EffectiveAccess resolves user + all groups over the path and its ancestors:
  default deny, explicit deny always beats allow.
- Enforce ACL for ALL non-admin users (not just guest) across list/read/save/
  delete/move/create/history/diff/images/upload. Admins bypass.
- Seed built-in Archivum-admin / Archivum-reader groups; login allow-list on
  users & groups; public (guest) user access is ACL-configurable.

Admin API & UI
- New GraphQL ops: oidcConfig/updateOidcConfig, group CRUD, membership,
  setUserRole/setUserLogin/setGroupLogin, userGroups, loginOptions.
- Rebuilt AdminView: SSO config, user/group management + membership, login
  toggles, and an allow/deny access-control matrix per path.
- LoginView: "Sign in with Authentik" + public-user option; OIDC callback route.

Rendering/editor
- Fix bug where inline marks (bold/italic/code/strike/link) were dropped on
  TipTap→AsciiDoc save. Add RENDERING_IMPROVEMENTS.md with proposals.

CI / build
- .gitea/workflows/build.yaml: build on the Pi5 runner, push
  localhost:5000/archivum:{latest,<sha>}. Add .dockerignore; bump Go image to 1.25.
- Docs: ARCHITECTURE.md, README.md, docs/AUTHENTIK_SETUP.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-05 21:58:50 +02:00
parent d808b0289f
commit cd588197b9
22 changed files with 2458 additions and 735 deletions

120
RENDERING_IMPROVEMENTS.md Normal file
View File

@@ -0,0 +1,120 @@
# Förbättringsförslag — rendering & editor
Genomgång av renderings- och editorlagret (`frontend/src/bridge/*`,
`components/editor/*`) med konkreta, prioriterade förslag. En bekräftad bugg är
redan åtgärdad i denna gren (se punkt 0).
---
## 0. ÅTGÄRDAD bugg: inline-formatering tappades vid sparning
I `asciidoc-bridge.ts → renderTextNodes` byggdes den markerade strängen
(`*fet*`, `_kursiv_`, `` `kod` ``, länkar) men **lades aldrig till utdata** — i
stället lades den *omarkerade* texten till i ett andra `if`-block. Följd: all
inline-formatering försvann tyst varje gång ett dokument sparades från den
visuella editorn. Nu appliceras och skrivs marks korrekt (en enda gång).
> Rekommendation: lägg ett litet round-trip-test (`adoc → toTipTap → fromTipTap`)
> som CI-steg så att den här klassen av regressioner fångas automatiskt.
---
## 1. Round-trip-modellen är den största risken
Idag är flödet vid varje sparning:
```
.adoc ──asciidoctor.convert──▶ HTML ──generateJSON──▶ TipTap-JSON
▲ │
└─────────── fromTipTap (handskriven) ◀──────────────────┘
```
Två lossy konverteringar i rad. Allt som TipTap-schemat inte känner till
(attribut, `ifdef`/`ifeval`, `:attribut:`-definitioner, block-roller, kommentarer,
tabellformat, korsreferenser) går förlorat så fort man öppnar och sparar i den
visuella vyn.
**Förslag (välj en):**
- **A. Källan är sanningen.** Behandla `.adoc` som master. Visuella editorn får
bara redigera dokument som är "rena" (kan round-trippa förlustfritt), annars
öppnas källeditorn. Visa en varning "det här dokumentet innehåller avancerad
AsciiDoc — redigera i källvyn".
- **B. Patch-baserad sparning.** Spara bara de block som faktiskt ändrats i den
visuella vyn i stället för att reserialisera hela dokumentet.
- **C. Byt serialisering.** Använd en riktig AST (t.ex. `downdoc`/`@asciidoctor`
reducer) i stället för den handskrivna `TipTapToAsciidoc`-klassen.
Minst arbete/störst nytta på kort sikt: **A** + en tydlig indikator i UI.
---
## 2. Konkreta serialiseringsluckor i `fromTipTap`
| Nod / mark | Problem | Förslag |
|------------|---------|---------|
| Kombinerade marks (fet+kursiv) | Ger `*_text_*` — bräckligt intill andra tecken | Använd oконstruerad syntax (`**`, `__`) vid behov |
| Tabeller (`convertTable`) | Ingen header-rad (`[%header]`), inga kolumn-specar, colspan/align tappas | Detektera `tableHeader`, skriv `[options="header"]`, `cols=` |
| Listor (`convertListItem`) | Blandning av stycke + nästlad lista i samma item blir fel; principallista använder nivå-räkning som spretar | Rendera item-innehåll block för block med `+`-continuation för flerstycke |
| `blockquote` | Attribution/citat-källa tappas | Stöd `[quote, author, source]` |
| `admonition` | Bara 5 typer, alltid versalt block-format | Bevara ursprunglig form (inline `NOTE:` vs `[NOTE]`-block) |
| Bild | `role`/alignment/`link=` tappas | Utöka `AsciidocImage`-attribut och serialisering |
---
## 3. Renderingspipelinen (adoc → HTML)
- **Regex-omskrivning av admonitions** (`htmlContent.replace(/<div class="admonitionblock…`)
är känslig för nästlat innehåll och flera stycken. En admonition med en lista
eller ett kodblock inuti går sönder. → Rendera i stället admonitions via en
Asciidoctor-**converter/extension** i stället för att patcha HTML i efterhand.
- **`include::`** hanteras med regex och blir en platshållare. Riktiga includes
(t.ex. återanvändbara fragment) renderas aldrig. → Implementera en
include-resolver på backend (den har redan fil-I/O) och rendera server-side,
eller hämta fragmentet via API innan `convert`.
- **Passthrough (`+++`)**: fotnötter injiceras som rå-HTML före parsing. Fungerar,
men kringgår sanering. Låg risk internt, men värt en `DOMPurify` på
renderad HTML om publika/gäst-användare någonsin ska se opålitligt innehåll.
---
## 4. Prestanda / bundle
`DocumentView`-chunken är **~2,8 MB** (880 kB gzip). Två tunga poster:
- **`lowlight` med `all`** (`createLowlight(all)`) drar in *alla* språkgrammatiker.
→ Byt till `common` eller registrera bara de språk ni faktiskt använder
(go, js, ts, bash, python, yaml…). Sparar hundratals kB.
- **`asciidoctor.js`** är stort och laddas i varje dokumentvy. → Lazy-load
(`import()` först när ett dokument öppnas) — delvis redan gjort via
route-splitting, men Asciidoctor kan brytas ut ytterligare. Överväg
server-side-rendering av HTML (backend har redan Go; ett litet
`asciidoctor`-anrop eller cache av renderad HTML per commit-hash skulle ta bort
klientkostnaden helt och göra läsvyn snabb även på Pi5/mobil).
---
## 5. Editor-UX (presentation)
- **Synk mellan Visual och Source.** Gör "source of truth"-valet (punkt 1)
synligt: en toggle med en varningsikon när dokumentet inte kan round-trippa.
- **Live-förhandsvisning i källeditorn.** CodeMirror till vänster, renderad HTML
till höger (delad vy) — vanligt och uppskattat för teknisk dokumentation.
- **Innehållsförteckning / rubriknavigering.** Generera en TOC från rubrikerna
(finns redan `id` på `CustomHeading`) och visa i sidopanelen.
- **Bildhantering.** Uppladdning finns; lägg till drag-and-drop och inklistring
från urklipp direkt i editorn.
- **Autospar / utkast.** Spara utkast lokalt (IndexedDB) så inget tappas vid
session-timeout (sessioner ligger bara i minnet på servern).
- **Diff-vy i redigering.** `HistoryPanel`/`DiffViewer` finns — koppla en
"jämför med sparad version"-knapp direkt i editorn.
---
## Prioriteringsordning (rekommenderad)
1. ✅ Fixa marks-buggen (klar).
2. Lägg round-trip-test i CI.
3. Byt `lowlight` `all` → `common`/whitelist (snabb, stor bundle-vinst).
4. Inför "source of truth"-indikator + öppna källvyn för avancerade dokument.
5. Server-side- eller cachead HTML-rendering (störst läs-prestandavinst).
6. Robustare tabell-/list-serialisering.