295 lines
18 KiB
Markdown
295 lines
18 KiB
Markdown
# Repomap
|
|
|
|
Übersicht aller Dateien und Ordner im Projekt.
|
|
|
|
```
|
|
go-wiki/
|
|
├── main.go ← Einstiegspunkt. Lädt .env, prüft Pflicht-Secrets
|
|
│ (SESSION_SECRET, ADMIN_TOKEN), lädt teams.yaml und
|
|
│ baut die TeamRegistry auf, richtet alle Routen ein
|
|
│ und verwaltet den Graceful Shutdown (wartet auf
|
|
│ laufende Requests bevor der Server sich bei
|
|
│ CTRL+C / docker stop beendet).
|
|
│
|
|
├── go.mod ← Go-Moduldefinition (Name, Go-Version, direkte Dependencies).
|
|
│ Entspricht in etwa einer package.json in Node.
|
|
│
|
|
├── go.sum ← Automatisch generierte Checksummen aller Dependencies.
|
|
│ Nicht manuell bearbeiten.
|
|
│
|
|
├── Dockerfile ← Multi-Stage Build: Stage 1 kompiliert das Binary mit dem
|
|
│ Go-Compiler, Stage 2 packt nur das fertige Binary in ein
|
|
│ minimales Alpine-Linux-Image (mit git, für den Webhook).
|
|
│
|
|
├── deploy.sh ← Shell-Skript zum Hochladen einer lokalen Markdown-Datei
|
|
│ auf den Wiki-Server via REST-API (curl + Team-Key oder
|
|
│ Admin-Token).
|
|
│
|
|
├── .gitignore ← Schließt Binary, data/-Ordner, .env, teams.yaml und
|
|
│ .DS_Store aus Git aus.
|
|
│
|
|
├── .dockerignore ← Schließt data/, Binary und .git aus dem Docker-Build-
|
|
│ Kontext aus — macht den Build schneller.
|
|
│
|
|
├── .env.example ← Vorlage für die .env-Datei. Zeigt alle verfügbaren
|
|
│ Umgebungsvariablen mit Erklärungen (u.a. SESSION_SECRET
|
|
│ und ADMIN_TOKEN — beides Pflichtfelder ohne unsicheren
|
|
│ Default). Kopieren nach .env und mit echten Werten befüllen.
|
|
│
|
|
├── teams.yaml.example ← Vorlage für die Team-Konfiguration. Jedes Team bekommt
|
|
│ eine ID (a-z, 0-9, -, _), einen Anzeigenamen und einen
|
|
│ Zugriffskey. Kopieren nach teams.yaml.
|
|
│
|
|
├── golang-wiki-spec.md ← Ursprüngliche Projektspezifikation (Planungsdokument).
|
|
│
|
|
├── README.md ← Dokumentation: Server starten, Teams anlegen, Seiten
|
|
│ anlegen, Deployment, MCP-Integration, API-Übersicht.
|
|
│
|
|
├── REPOMAP.md ← Diese Datei.
|
|
│
|
|
├── handler/
|
|
│ ├── registry.go ← TeamRegistry: zentrale Stelle die weiß welche Teams es
|
|
│ │ gibt, wo ihre Markdown-Dateien liegen (data/<id>/content)
|
|
│ │ und welcher Zugriffskey zu welchem Team gehört. Löst Keys
|
|
│ │ timing-sicher auf (subtle.ConstantTimeCompare) und
|
|
│ │ unterscheidet Team-Key vom globalen Admin-Token.
|
|
│ │ Unterstützt Hot-Reload (Reload()) für teams.yaml-Änderungen
|
|
│ │ ohne Serverneustart. Stellt außerdem die Request-Context-
|
|
│ │ Helfer bereit (WithTeam/TeamFromContext/IsAdminFromContext).
|
|
│ │
|
|
│ ├── teams_config.go ← Lädt und validiert teams.yaml (LoadTeamsConfig) und
|
|
│ │ überwacht die Datei per mtime-Polling auf Änderungen
|
|
│ │ (StartTeamsConfigWatcher) — lädt neue/geänderte/entfernte
|
|
│ │ Teams automatisch in die Registry.
|
|
│ │
|
|
│ ├── cache.go ← In-Memory-Cache für Wiki-Seiten, ein PageCache pro Team.
|
|
│ │ Beim Serverstart werden alle .md-Dateien eines Teams
|
|
│ │ einmal geladen und im Arbeitsspeicher gehalten — Metadaten
|
|
│ │ (Titel, Tags, Hidden) sind danach sofort verfügbar ohne
|
|
│ │ Dateisystem-Zugriff. Thread-sicher via sync.RWMutex.
|
|
│ │ Hält außerdem den BM25-Suchindex des Teams aktuell.
|
|
│ │ Wird nach jedem Upload/Delete sofort aktualisiert.
|
|
│ │
|
|
│ ├── search.go ← In-Memory-Volltextindex mit BM25-Ranking (invertierter
|
|
│ │ Index: Begriff → Dokumente). Titel-Treffer werden 3x,
|
|
│ │ Tag-Treffer 2x höher gewichtet als Body-Treffer. Genutzt
|
|
│ │ von /search (Web) und dem search_pages-MCP-Tool.
|
|
│ │
|
|
│ ├── session.go ← Signierte Web-Session fürs Team-Login. SignSession/
|
|
│ │ VerifySession erzeugen bzw. prüfen einen HMAC-SHA256-
|
|
│ │ signierten, ablaufenden Cookie-Wert ("team:<id>", "admin"
|
|
│ │ oder "admin:<id>") — der Server signiert nur eine
|
|
│ │ Behauptung, nie den Zugriffskey selbst.
|
|
│ │
|
|
│ ├── auth.go ← Team-Login fürs Web: Formular (GET/POST /login), Logout
|
|
│ │ (/logout) und Team-Umschaltung für Admins (/switch-team).
|
|
│ │ Nutzt den LoginRateLimiter (ratelimit.go) gegen Brute-Force
|
|
│ │ und schreibt Login-Versuche ins Audit-Log. clientIP()
|
|
│ │ liest bewusst nur r.RemoteAddr, keinen X-Forwarded-For-
|
|
│ │ Header (sonst wäre das Rate-Limiting ohne bekannte,
|
|
│ │ vertrauenswürdige Proxy-Kette leicht auszuhebeln).
|
|
│ │
|
|
│ ├── ratelimit.go ← LoginRateLimiter: Fixed-Window-Zähler pro Client-IP
|
|
│ │ (5 Fehlversuche/Minute). Wird sowohl vom Team-Login
|
|
│ │ (auth.go) als auch vom Seiten-Passwort (wiki.go,
|
|
│ │ HandlePasswordSubmit) genutzt, damit keiner der beiden
|
|
│ │ Auth-Wege unbegrenzt durchprobiert werden kann.
|
|
│ │
|
|
│ ├── wiki.go ← Liefert Wiki-Seiten des aktiven Teams aus (GET /:pfad,
|
|
│ │ Team kommt aus dem Request-Context). Liest Markdown-
|
|
│ │ Datei, prüft Seiten-Passwortschutz via Cookie
|
|
│ │ (konstantzeitiger Vergleich + Rate-Limiting), baut die
|
|
│ │ Sidebar-Navigation rekursiv aus der Ordnerstruktur und
|
|
│ │ rendert das HTML-Template. Verarbeitet auch
|
|
│ │ POST /auth/:pfad (Passwort-Formular) und GET /search
|
|
│ │ (BM25-Trefferliste im normalen Wiki-Layout).
|
|
│ │
|
|
│ ├── api.go ← REST-API für das Deployment. POST /api/upload lädt eine
|
|
│ │ Markdown-Datei hoch, DELETE /api/delete löscht eine Datei.
|
|
│ │ Team-Key wirkt nur aufs eigene Team; der globale Admin-Key
|
|
│ │ muss das Zielteam explizit per Parameter "team" angeben.
|
|
│ │ Prüft Pfade gegen Path-Traversal ("..") und aktualisiert
|
|
│ │ nach jeder Änderung den PageCache sowie das Audit-Log.
|
|
│ │
|
|
│ ├── webhook.go ← Git-Webhook-Handler (POST /api/webhook, nur aktiv wenn
|
|
│ │ WEBHOOK_SECRET gesetzt ist). Erkennt den Anbieter anhand
|
|
│ │ der Request-Headers und prüft die Signatur: GitHub
|
|
│ │ (X-Hub-Signature-256, HMAC-SHA256), GitLab
|
|
│ │ (X-Gitlab-Token, direkter Vergleich), Bitbucket
|
|
│ │ (X-Hub-Signature, HMAC-SHA256). Nach erfolgreicher Prüfung:
|
|
│ │ git pull im gemeinsamen data-Wurzelverzeichnis, danach
|
|
│ │ Cache aller Teams komplett neu aufbauen (RebuildAll).
|
|
│ │
|
|
│ ├── mcp.go ← MCP-Server (Model Context Protocol) über Streamable HTTP
|
|
│ │ (POST /mcp, ein MCP-Server pro Team, lazy gebaut). Ermöglicht
|
|
│ │ KI-Tools (Claude Desktop, Cline, Opencode) direkten Zugriff
|
|
│ │ auf das Wiki des aufgelösten Teams.
|
|
│ │ Resources (Daten):
|
|
│ │ wiki://pages — alle Seiten als JSON
|
|
│ │ wiki://page/{+path} — eine Seite als rohes Markdown
|
|
│ │ Tools (Aktionen):
|
|
│ │ search_pages — BM25-Volltextsuche mit Snippet
|
|
│ │ upload_page — Seite erstellen/überschreiben
|
|
│ │ delete_page — Seite löschen
|
|
│ │ rebuild_index — generiert _index.md (Karpathy-Wiki-Index)
|
|
│ │ Admin-Zugriff braucht den Header "X-Wiki-Team". Alle
|
|
│ │ lesenden Operationen nutzen den PageCache.
|
|
│ │
|
|
│ ├── audit.go ← AuditLogger: schreibt sicherheits-/nachvollziehbarkeits-
|
|
│ │ relevante Ereignisse (Upload, Delete, Login-Versuche,
|
|
│ │ Webhook-Sync) als JSON Lines in data/audit.log — eine
|
|
│ │ gemeinsame Datei für alle Teams. Tail(n) liest die letzten
|
|
│ │ n Ereignisse für die Admin-Ansicht, neueste zuerst.
|
|
│ │
|
|
│ └── audit_page.go ← Admin-Ansicht des Audit-Logs (GET /admin/audit). Nur mit
|
|
│ dem globalen Admin-Zugang erreichbar, zeigt die letzten
|
|
│ 200 Ereignisse als Tabelle.
|
|
│
|
|
├── middleware/
|
|
│ ├── session.go ← RequireTeamSession: schützt die Web-Ansicht ("/",
|
|
│ │ "/search", "/auth/", "/switch-team", "/admin/audit").
|
|
│ │ Prüft den Session-Cookie (handler.VerifySession) und legt
|
|
│ │ das aufgelöste Team bzw. den Admin-Status im Request-
|
|
│ │ Context ab. Ohne gültige Session: Redirect zu /login.
|
|
│ │
|
|
│ └── auth.go ← RequireTeamOrAdminKey: schützt /api/upload, /api/delete
|
|
│ und /mcp. Liest den Bearer-Token aus dem Authorization-
|
|
│ Header und löst ihn timing-sicher gegen die TeamRegistry
|
|
│ auf (handler.TeamRegistry.Resolve) — legt das Team bzw.
|
|
│ den Admin-Status im Request-Context ab.
|
|
│
|
|
├── render/
|
|
│ └── markdown.go ← Kernlogik: Liest eine .md-Datei, trennt den YAML-
|
|
│ Frontmatter-Block (title, password, tags, hidden) vom
|
|
│ Markdown-Body und wandelt den Body mit goldmark (Default-
|
|
│ Konfiguration, kein html.WithUnsafe — eingebettetes
|
|
│ Roh-HTML wird sicher escaped) in HTML um. Gibt ein
|
|
│ Page-Struct zurück, inkl. RawBody für die Volltextsuche.
|
|
│
|
|
├── templates/
|
|
│ ├── page.html ← HTML-Template für eine Wiki-Seite. Zweispaltiges Layout
|
|
│ │ mit Sidebar (rekursive Navigation, Team-Name, "Team
|
|
│ │ wechseln"-Link für Admins) und Hauptinhalt bzw.
|
|
│ │ BM25-Suchergebnissen. Kein CSS inline — lädt
|
|
│ │ /static/style.css und /static/sidebar.js.
|
|
│ │
|
|
│ ├── password.html ← HTML-Template für das Seiten-Passwort-Formular. Wird
|
|
│ │ angezeigt wenn eine Seite passwortgeschützt ist und kein
|
|
│ │ gültiger Auth-Cookie vorhanden ist.
|
|
│ │
|
|
│ ├── login.html ← HTML-Template für den Team-Login (GET/POST /login) —
|
|
│ │ fragt den Zugriffskey des Teams oder den Admin-Token ab.
|
|
│ │
|
|
│ ├── switch-team.html ← HTML-Template für die Team-Auswahl des Admin-Zugangs
|
|
│ │ (GET/POST /switch-team) — listet alle Teams aus der
|
|
│ │ Registry als Buttons.
|
|
│ │
|
|
│ └── audit.html ← HTML-Template für die Audit-Log-Ansicht
|
|
│ (GET /admin/audit) — Tabelle mit Zeit, Team, Akteur,
|
|
│ Aktion, Pfad, Quelle und Details je Ereignis.
|
|
│
|
|
├── static/
|
|
│ ├── style.css ← Gesamtes CSS des Wikis an einem Ort: Layout, Sidebar,
|
|
│ │ Navigation, Markdown-Styling, Login-/Passwort-Formulare,
|
|
│ │ Audit-Tabelle. Wird unter /static/ ausgeliefert.
|
|
│ │
|
|
│ └── sidebar.js ← Steuert das Ein-/Ausklappen der Sidebar, getrennt für
|
|
│ Desktop (Zustand in localStorage gemerkt) und Mobile
|
|
│ (Overlay, startet nach jedem Seitenaufruf zu).
|
|
│
|
|
└── data/ ← Wurzelverzeichnis aller Teams (DATA_ROOT). Nicht im
|
|
├── audit.log Git-Repository — wird als Docker-Volume eingehängt.
|
|
├── <team-id>/
|
|
│ └── content/ ← Markdown-Dateien dieses Teams, z.B. data/alpha/content/.
|
|
│ └── index.md Wird beim Serverstart automatisch angelegt, pro Team
|
|
│ per deploy.sh, REST-API, MCP oder Git-Webhook befüllt.
|
|
└── audit.log ← JSON-Lines-Protokoll aller Uploads/Deletes/Logins/
|
|
Webhook-Syncs (teamübergreifend, eine Datei für alle).
|
|
```
|
|
|
|
## Datenfluss: Browser ruft eine Seite auf
|
|
|
|
```
|
|
Browser GET /projekte/notizen
|
|
→ middleware/session.go (RequireTeamSession) Session-Cookie prüfen, Team auflösen
|
|
→ handler/wiki.go (ServeHTTP)
|
|
→ render/markdown.go (LoadPage) Datei lesen, Frontmatter + HTML
|
|
→ Seiten-Passwortprüfung via Cookie (konstantzeitig, rate-limited)
|
|
→ buildNavForDir() (rekursiv) Ordnerstruktur → Baumnavigation
|
|
→ templates/page.html Template rendern
|
|
→ HTML an Browser
|
|
```
|
|
|
|
## Datenfluss: Team-Login und Team-Umschaltung
|
|
|
|
```
|
|
Browser POST /login { key }
|
|
→ handler/auth.go (HandleLogin)
|
|
→ handler/ratelimit.go (LoginRateLimiter) IP-Sperre nach 5 Fehlversuchen/Minute
|
|
→ handler/registry.go (TeamRegistry.Resolve) Key → Team oder Admin, timing-sicher
|
|
→ handler/audit.go (Log) login_success / login_failure
|
|
→ handler/session.go (SignSession) signierten Cookie setzen
|
|
→ Redirect zu "/" (Team) oder "/switch-team" (Admin)
|
|
|
|
Admin POST /switch-team { team }
|
|
→ handler/auth.go (HandleSwitchTeam) nur mit Admin-Session erreichbar
|
|
→ handler/session.go (SignSession) Cookie "admin:<team-id>" setzen
|
|
→ Redirect zu "/"
|
|
```
|
|
|
|
## Datenfluss: KI-Tool liest/schreibt Seiten via MCP
|
|
|
|
```
|
|
Claude Desktop/Cline/Opencode → POST /mcp (Streamable HTTP, JSON-RPC pro Request)
|
|
→ middleware/auth.go (RequireTeamOrAdminKey)
|
|
Bearer-Token → Team (oder Admin + Header X-Wiki-Team)
|
|
→ handler/mcp.go (Team-Server, lazy gebaut)
|
|
|
|
Resource: wiki://pages
|
|
→ handler/cache.go (All()) aus dem Cache, kein Disk-Zugriff
|
|
→ JSON-Liste aller Seiten des Teams zurück
|
|
|
|
Resource: wiki://page/projekte/notizen
|
|
→ handler/cache.go (URLPathToFilePath)
|
|
→ os.ReadFile() Markdown direkt von Disk
|
|
→ Frontmatter entfernt, Titel als H1 vorangestellt
|
|
|
|
Tool: search_pages { query: "Docker" }
|
|
→ handler/search.go (BM25 Search) invertierter Index, kein Disk-Zugriff
|
|
→ Treffer mit Snippet zurück
|
|
|
|
Tool: upload_page / delete_page
|
|
→ Datei auf Disk schreiben/löschen
|
|
→ handler/cache.go (Set/Delete) Cache + Suchindex aktualisieren
|
|
→ buildWikiIndex() _index.md automatisch neu generieren
|
|
→ handler/audit.go (Log) Audit-Eintrag schreiben
|
|
```
|
|
|
|
## Datenfluss: Git-Webhook (automatische Synchronisation)
|
|
|
|
```
|
|
Nutzer git push
|
|
→ GitHub / GitLab / Bitbucket
|
|
→ POST /api/webhook
|
|
→ handler/webhook.go
|
|
→ Anbieter erkennen (Header-Analyse)
|
|
→ Signatur prüfen (HMAC-SHA256 oder Token-Vergleich, konstantzeitig)
|
|
→ git pull im data-Wurzelverzeichnis (alle Teams)
|
|
→ handler/registry.go (RebuildAll) Cache + Suchindex jedes Teams neu aufbauen
|
|
→ handler/audit.go (Log) webhook_sync protokollieren
|
|
→ Seiten aller Teams sofort live ohne Neustart
|
|
```
|
|
|
|
## Datenfluss: Datei deployen (REST oder MCP)
|
|
|
|
```
|
|
deploy.sh / MCP upload_page
|
|
→ POST /api/upload oder Tool: upload_page
|
|
→ middleware/auth.go (Token prüfen, Team auflösen)
|
|
→ Pfad gegen Path-Traversal prüfen ("..")
|
|
→ Datei auf Disk schreiben
|
|
→ render/markdown.go (LoadPage) neue Seite laden
|
|
→ handler/cache.go (Set()) Cache + Suchindex sofort aktualisieren
|
|
→ handler/audit.go (Log) Audit-Eintrag schreiben
|
|
→ ab sofort in Navigation, Suche und MCP sichtbar
|
|
```
|