- 3.7: MCP-Werkzeug "related" liefert Nachbarn im Verweisgraphen in beide
Richtungen, bis zur zweiten Reihe (store.RelatedEntries).
- 3.5: Einträge, die seit über einem Jahr unverändert sind, tragen in
recall/get/list/related "stale": true; get und recall geben einen
Hinweis, die Eintragsseite eine Marke. instructions erklären das Feld.
- 3.2: Import von Markdown-Dateien als ZIP unter /p/{projekt}/import
(Rolle admin), mit Vorschau, überspringen/überschreiben, Erkennung von
Unverändertem und Papierkorb. Neue Einträge behalten Autor, Herkunft,
Prüfvermerk und Zeitstempel aus dem Export.
Nebenbei behoben: Das 1-MB-Body-Limit für Formulare lag über dem ganzen
Mux und begrenzte damit auch /mcp auf 1 MB statt MAX_API_BODY_BYTES.
LimitBodies wählt die Grenze jetzt einmal außen je Route.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
32 KiB
32 KiB
Repomap — Munin
Übersicht aller Dateien und Ordner mit ihrer Aufgabe.
munin/
├── main.go ← Einstiegspunkt. Liest die Konfiguration, prüft die
│ Pflichtangaben (SESSION_SECRET, ADMIN_TOKEN inkl.
│ Mindestlänge), öffnet Kontroll-Datenbank und
│ Workspace-Verwaltung (legt beim ersten Start den
│ Workspace "Intern" an), setzt die
│ Bestandteile zusammen und startet den Server.
│ Enthält außerdem die Server-Timeouts (gegen
│ Slowloris), die Body-Größenlimits und die
│ täglichen Aufgaben (Protokoll aufräumen,
│ Export), die über fuerJedenWorkspace alle
│ Workspaces erreichen. Tests: main_test.go.
│
├── go.mod / go.sum ← Moduldefinition und Prüfsummen der Abhängigkeiten.
│
├── Dockerfile ← Zweistufiger Bau: Stufe 1 kompiliert mit dem
│ Go-Compiler, Stufe 2 packt nur das fertige Binary
│ in ein minimales Alpine-Abbild. Läuft als
│ gewöhnlicher Benutzer, mit Healthcheck und Volume
│ für die Datenbank.
│
├── .env.example ← Vorlage für .env, mit Erklärung jeder Variable.
├── .gitignore / .dockerignore ← Schließen Datenbank, Binary und Geheimnisse aus.
│
├── README.md ← Anleitung: Schnellstart, MCP einrichten, Werkzeuge,
│ Konfiguration, Sicherheit, Betrieb.
├── AGENTEN-GUIDE.md ← Wie man KI-Werkzeuge anbindet und anspricht,
│ damit sie den Speicher tatsächlich nutzen:
│ Projektprompt zum Übernehmen, slug-Regeln,
│ Muster für einzelne Aufgaben.
├── AUSBAUSTUFEN.md ← Was bewusst nicht gebaut wurde: Messwerte,
│ Begründung und die Auslöser, an denen man
│ merkt, dass es Zeit dafür wird.
├── REPOMAP.md ← Diese Datei.
│
├── internal/
│ │
│ ├── store/ ── Die einzige Stelle, die SQL kennt ──────────────
│ │ ├── store.go ← Öffnet eine Workspace-Datei (Open), setzt die
│ │ │ nötigen PRAGMAs (WAL, busy_timeout, foreign_keys)
│ │ │ und wendet die Migrationen an. Erklärt auch, warum
│ │ │ der Treiber modernc.org/sqlite ist: Er ist reines
│ │ │ Go und erlaubt damit ein statisches Binary.
│ │ │
│ │ ├── control.go ← Die zentrale Kontroll-Datenbank (OpenControl):
│ │ │ Workspaces anlegen, umbenennen, löschen, dazu die
│ │ │ Zuordnung Key-Prüfsumme → Workspace
│ │ │ (ResolveKeyWorkspace). Das ist der erste Schritt
│ │ │ jeder Anmeldung: Erst danach ist klar, welche
│ │ │ Workspace-Datei den Key kennt.
│ │ │
│ │ ├── models.go ← Die Datentypen (Project, APIKey, Entry, …), die
│ │ │ Fehlerwerte (ErrNotFound, ErrConflict,
│ │ │ ErrDuplicate) sowie ID- und Zeitbehandlung.
│ │ │ NewID erzeugt sortierbare IDs in Go statt per
│ │ │ AUTOINCREMENT — das hält den Umstieg auf eine
│ │ │ andere Datenbank offen.
│ │ │
│ │ ├── projects.go ← Projekte: anlegen, lesen, ändern, löschen.
│ │ │ Enthält ValidSlug und Slugify sowie
│ │ │ SetProjectWriteLimit für die eigene Obergrenze
│ │ │ eines Projekts.
│ │ │
│ │ ├── keys.go ← API-Keys. ResolveKeyHash ist der heißeste Pfad im
│ │ │ Programm (jeder MCP-Request) und deshalb ein
│ │ │ indizierter Lookup über die Prüfsumme, keine
│ │ │ Schleife. Zurückgezogene Keys gelten als nicht
│ │ │ vorhanden, der Datensatz bleibt fürs Protokoll.
│ │ │
│ │ ├── entries.go ← Einträge. PutEntry legt an ODER aktualisiert —
│ │ │ der Bezeichner entscheidet, und genau das ist der
│ │ │ Mechanismus gegen Dubletten. Enthält das
│ │ │ optimistische Sperren (ExpectedVersion) und das
│ │ │ Nachladen der Schlagworte in einer Abfrage statt
│ │ │ einer pro Eintrag. Außerdem:
│ │ │ · snapshotEntryVersion sichert vor jeder Änderung
│ │ │ die bisherige Fassung, in derselben Transaktion;
│ │ │ EntryVersions/EntryVersionByNumber lesen sie
│ │ │ · BulkUpdateTags ändert Schlagworte vieler
│ │ │ Einträge auf einmal und überspringt IDs aus
│ │ │ fremden Projekten
│ │ │ · LinkGraph liefert Knoten und Kanten für die
│ │ │ Graph-Ansicht
│ │ │ Jede lesende Abfrage trägt nichtImPapierkorb
│ │ │ (deleted_at IS NULL) — außer PutEntry, das
│ │ │ einen Eintrag im Papierkorb bewusst sieht und
│ │ │ ihn beim Überschreiben zurückholt.
│ │ │
│ │ ├── nutzung.go ← Kennzahlen der Nutzungsübersicht: UsageSummaries
│ │ │ (Schreibvorgänge der letzten 30 Tage aus dem
│ │ │ Protokoll, Bestand aus entries — für ein oder
│ │ │ alle Projekte in zwei Abfragen), dazu
│ │ │ MissingLinks, UntaggedEntries, RecentlyUsedKeys.
│ │ │ Keine eigene Zähltabelle.
│ │ │
│ │ ├── papierkorb.go ← Papierkorb: MoveEntryToTrash (statt DELETE),
│ │ │ ListTrash, RestoreFromTrash, PurgeFromTrash
│ │ │ (nur was schon im Papierkorb liegt) und
│ │ │ PurgeTrash für die tägliche Aufgabe. Die Frist
│ │ │ TrashRetention (30 Tage) steht hier, damit
│ │ │ Oberfläche und Aufräumen dieselbe Zahl nutzen.
│ │ │
│ │ ├── related.go ← RelatedEntries: Nachbarn im Verweisgraphen, in
│ │ │ beide Richtungen, bis zu zwei Schritte weit
│ │ │ (Breitensuche, eine Abfrage je Richtung und Ebene).
│ │ │
│ │ ├── links.go ← Erkennt [[bezeichner]] im Inhalt und ersetzt sie
│ │ │ beim Rendern. Das ersetzt die frühere
│ │ │ Ordnerhierarchie als Struktur zwischen Einträgen.
│ │ │
│ │ ├── audit.go ← Protokoll: schreiben, lesen, aufräumen. Die
│ │ │ Aufbewahrungsfrist ist nicht nur eine Frage des
│ │ │ Plattenplatzes — das Protokoll enthält Adressen
│ │ │ und Zugangsnamen. EntryWriteDetail vermerkt bei
│ │ │ Schreibvorgängen "angelegt" oder "aktualisiert".
│ │ │
│ │ ├── migrations_control/
│ │ │ └── 001_init.sql ← Schema der Kontroll-Datenbank: workspaces und
│ │ │ key_index (Key-Prüfsumme → Workspace). Bewusst
│ │ │ dünn — Inhalte liegen nie hier.
│ │ │
│ │ └── migrations/ ← Schema jeder Workspace-Datei
│ │ ├── 001_init.sql ← Das Schema. Der Kopfkommentar nennt die Regeln
│ │ │ für portables SQL, an die sich alle weiteren
│ │ │ Migrationen halten sollen.
│ │ ├── 002_projekt_in_nebentabellen.sql
│ │ ← Führt project_id auch in entry_tags und
│ │ entry_links. Eine bewusste Redundanz gegen zwei
│ │ gemessene Bremsen: das Schlagwortmenü lief über
│ │ alle Einträge (6,7 ms bei jedem Seitenaufruf),
│ │ und bei den Rückverweisen kippte durch ein
│ │ ORDER BY die Verknüpfungsreihenfolge
│ │ (3,1 ms statt 9 µs).
│ │ ├── 003_schreibbudget_je_projekt.sql
│ │ ← Spalte write_limit_hourly an projects. Vorgabe 0
│ │ heißt "keine eigene Angabe" — dann gilt der
│ │ Standard aus WRITE_LIMIT_HOURLY. So muss die
│ │ Migration keine Daten anfassen.
│ │ ├── 004_aenderungshistorie.sql
│ │ ← Tabelle entry_versions für abgelöste Fassungen.
│ │ Wird mit dem Eintrag gelöscht (ON DELETE CASCADE).
│ │ └── 005_papierkorb.sql
│ │ ← deleted_at/deleted_by an entries und ein
│ │ Teilindex nur über den Papierkorb. Löschen setzt
│ │ nur noch die Markierung; CASCADE greift erst
│ │ beim endgültigen Löschen.
│ │
│ ├── workspace/ ── Welche Datei gehört zu welcher Abteilung? ──────
│ │ └── workspace.go ← Manager öffnet Workspace-Dateien bei Bedarf und
│ │ hält sie offen, jeweils mit eigenem Suchindex.
│ │ Datenbank und Index gehören zusammen, damit kein
│ │ Index versehentlich an der falschen Datei hängt.
│ │ Delete schließt eine Datei und entfernt sie.
│ │
│ ├── auth/ ── Wer ist das? ────────────────────────────────────
│ │ ├── doc.go ← Erklärt die beiden Wege hinein (API-Key im Header,
│ │ │ Sitzungs-Cookie im Browser) und was hier bewusst
│ │ │ NICHT liegt: die Frage, was jemand darf.
│ │ │
│ │ ├── keys.go ← Erzeugen, Prüfsumme bilden, Form prüfen. Enthält
│ │ │ die Rollen (read/write/admin) und die Begründung,
│ │ │ warum SHA-256 statt bcrypt richtig ist.
│ │ │
│ │ ├── session.go ← Signierte Sitzungs-Cookies (HMAC-SHA256). Der
│ │ │ Cookie trägt nur eine Behauptung ("ich bin Key X"),
│ │ │ nie den Key selbst.
│ │ │
│ │ ├── csrf.go ← CSRF-Tokens aus Sitzung und Geheimnis, ohne Zustand
│ │ │ auf dem Server. Der Kopfkommentar erklärt den
│ │ │ Angriff, gegen den das schützt.
│ │ │
│ │ ├── cookies.go ← Setzt HttpOnly, SameSite und Secure an einer
│ │ │ Stelle. Secure ist ohne Konfiguration an, außer
│ │ │ bei localhost — damit die lokale Entwicklung über
│ │ │ http weiter funktioniert.
│ │ │
│ │ ├── ratelimit.go ← Zwei Begrenzungen auf einem gemeinsamen
│ │ │ Fixed-Window-Zähler: RateLimiter sperrt eine
│ │ │ Adresse nach zu vielen Fehlversuchen,
│ │ │ WriteBudget deckelt die schreibenden
│ │ │ MCP-Aufrufe je Projekt und Stunde. Letzteres
│ │ │ hängt am Projekt und nicht am Key — ein
│ │ │ Key-Limit ließe sich mit einem zweiten Key
│ │ │ umgehen.
│ │ │
│ │ └── trustedproxy.go ← Entscheidet, wann X-Forwarded-For geglaubt wird:
│ │ nur bei einer über TRUSTED_PROXY hinterlegten
│ │ Absenderadresse. Ohne Konfiguration wird der
│ │ Header ignoriert — er ist frei fälschbar.
│ │
│ ├── entry/ ── Wie sieht ein Eintrag aus? ─────────────────────
│ │ ├── entry.go ← Markdown nach HTML (über internal/markdown),
│ │ │ Auflösen der [[…]]-Verweise, Textausschnitte für
│ │ │ Trefferlisten samt sicherer Hervorhebung.
│ │ │
│ │ └── diff.go ← Zeilenvergleich zweier Fassungen (DiffLines) als
│ │ LCS ohne externe Abhängigkeit. Bei sehr langen
│ │ Einträgen weicht er auf einen groben Vergleich
│ │ aus (grobDiff), damit Speicher und Rechenzeit
│ │ begrenzt bleiben.
│ │
│ ├── markdown/ ── Markdown nach HTML, eine Regel für alles ───────
│ │ └── markdown.go ← Der gemeinsame goldmark-Renderer für Einträge und
│ │ Hilfe: GFM (Tabellen, Checklisten,
│ │ Durchstreichen, automatische Links), Roh-HTML
│ │ gesperrt. Nur die Hilfe bekommt Überschrift-
│ │ Anker (RenderMitAnkern) — mit gefalteten
│ │ Umlauten über store.Slugify, damit die
│ │ "?"-Links der Oberfläche darauf zeigen können.
│ │
│ ├── export/ ── Sicherung als Markdown ─────────────────────────
│ │ └── export.go ← Schreibt jeden Workspace als Ordner
│ │ (<workspace-id>/, mit _workspace.md) und darin
│ │ jedes Projekt als Ordner voller
│ │ Markdown-Dateien, mit allen Feldern im Dateikopf.
│ │ Kennt selbst keine Datenbank: Der Aufrufer gibt
│ │ die Workspace-Datei je Lauf mit.
│ │ Gedacht als Git-fähige Sicherung: Ein Lauf ohne
│ │ inhaltliche Änderungen fasst keine Datei an und
│ │ erzeugt deshalb auch keinen Diff. Verwaiste
│ │ Dateien gelöschter Einträge werden entfernt,
│ │ fremde Dateien im Zielordner bleiben unberührt.
│ │
│ ├── importer/ ── Gegenstück zum Export ──────────────────────────
│ │ ├── archiv.go ← Liest Markdown-Dateien aus einem ZIP-Archiv, mit
│ │ │ Grenzen für Anzahl und ausgepackte Größe.
│ │ │ Übergeht _index.md, versteckte Ordner, __MACOSX.
│ │ ├── parse.go ← Kleiner Frontmatter-Leser (kein YAML-Paket):
│ │ │ Munin-Export und fremde Köpfe (Hugo, Obsidian).
│ │ │ Ohne Kopf: Bezeichner aus dem Dateinamen, Titel
│ │ │ aus der ersten Überschrift.
│ │ └── importer.go ← Importiere: Vorschau oder Schreiben, bei
│ │ belegtem Bezeichner überspringen oder
│ │ überschreiben (alter Stand in den Verlauf).
│ │ Erkennt Unverändertes und den Papierkorb.
│ │
│ ├── search/ ── Volltextsuche ──────────────────────────────────
│ │ ├── index.go ← Invertierter Index mit BM25-Bewertung. Titel zählen
│ │ │ dreifach, Schlagworte zweifach. Enthält die
│ │ │ Präfix-Rückfallebene: Ohne sie findet "deploy"
│ │ │ den "Deployment-Prozess" nicht — bei einer
│ │ │ KI-Anfrage ein stiller Fehltreffer.
│ │ │
│ │ └── registry.go ← Ein Index je Projekt, verzögert aufgebaut. Getrennte
│ │ Indizes statt eines gemeinsamen mit Filter: So wird
│ │ die Abschottung strukturell, und die BM25-Werte
│ │ werden nicht über Projektgrenzen hinweg verzerrt.
│ │
│ ├── hilfe/ ── Eingebaute Onboarding-Hilfe ───────────────────
│ │ ├── hilfe.go ← Liste der Hilfeseiten (Reihenfolge, Titel) und
│ │ │ das Rendern mit Überschrift-Ankern. Erklärt,
│ │ │ warum die Hilfe im Binary steckt statt als
│ │ │ Einträge in der Datenbank: Sie muss zur
│ │ │ laufenden Fassung des Programms passen.
│ │ └── seiten/*.md ← Die Inhalte, je Seite eine Datei. {{SERVER}} und
│ │ {{PROJEKT}} werden beim Anzeigen ersetzt.
│ │
│ ├── web/ ── HTTP: Browser und API ──────────────────────────
│ │ ├── context.go ← Session-Typ (wer greift zu, was darf er) und die
│ │ │ Ablage im Request-Context. CanAccessProject ist
│ │ │ die Mandantentrennung der Weboberfläche.
│ │ │
│ │ ├── middleware.go ← Sitzungsprüfung (inkl. "gilt der Key noch?"),
│ │ │ CSRF, Projektauflösung aus der URL, Rollenprüfung.
│ │ │ Die Sitzung trägt die Workspace-ID signiert mit
│ │ │ (sessionFromSubject); requireWorkspace hält einen
│ │ │ Plattform-Admin ohne gewählten Workspace von den
│ │ │ Projektseiten fern.
│ │ │ Dazu die allgemeinen Schutzschichten
│ │ │ SecurityHeaders und LimitBody sowie APIAuth für
│ │ │ den MCP-Endpunkt.
│ │ │
│ │ ├── server.go ← Der Server-Typ, alle Routen und das Rendern der
│ │ │ Templates (erst in einen Puffer, dann senden —
│ │ │ sonst gäbe es bei einem Fehler eine halbe Seite
│ │ │ mit Status 200).
│ │ │
│ │ ├── handlers_auth.go ← Anmelden, Abmelden, Startseite. Der
│ │ │ Plattform-Admin ohne gewählten Workspace landet
│ │ │ auf /admin/workspaces.
│ │ ├── handlers_entries.go ← Einträge auflisten, suchen, ansehen, bearbeiten.
│ │ │ Dazu Vorschau (preview), Vorschläge für [[…]]
│ │ │ (suggest), Fassungen und Vergleich, Graph-Daten
│ │ │ und Schlagworte für viele Einträge (bulk-tags).
│ │ ├── handlers_nutzung.go ← Nutzungsseite je Projekt (/p/{projekt}/usage),
│ │ │ für jede Rolle. Die Admin-Projektliste nutzt
│ │ │ dieselben Zahlen (projectListItems).
│ │ ├── handlers_import.go ← ZIP-Upload für den Importer (/p/{projekt}/import),
│ │ │ nur mit Rolle admin. Läuft im Server, damit der
│ │ │ Suchindex im selben Zug nachgezogen wird.
│ │ ├── handlers_papierkorb.go
│ │ │ ← Papierkorb je Projekt: ansehen, wiederherstellen,
│ │ │ endgültig löschen, Filter nach löschendem Zugang.
│ │ │ Alles nur mit Schreibrecht, und bewusst nur hier
│ │ │ — über MCP gibt es kein Wiederherstellen.
│ │ ├── handlers_hilfe.go ← Zeigt die eingebauten Hilfeseiten unter /hilfe
│ │ │ für jede Sitzung. Setzt vorher Server-Adresse
│ │ │ und Projekt-Bezeichner in die Beispiele ein
│ │ │ (serverURL, mit geprüftem Host-Header).
│ │ ├── handlers_workspaces.go
│ │ │ ← Workspaces auflisten, anlegen, wählen, umbenennen,
│ │ │ löschen (nur Plattform-Admin). Löscht jemand den
│ │ │ Workspace der eigenen Sitzung, wird die Auswahl
│ │ │ zurückgesetzt, statt ihn auszusperren.
│ │ └── handlers_admin.go ← Projekte, Zugänge, Protokollansicht, Export. Die
│ │ Bearbeitungsseite je Projekt (Name,
│ │ Beschreibung, Schreibbudget, Löschen) liegt
│ │ hier — bewusst eine Seite je Projekt statt
│ │ eines Auswahlfelds über alle: Nur so stehen die
│ │ tatsächlichen Werte in den Feldern, und ein
│ │ Speichern ohne Änderung überschreibt nichts.
│ │
│ └── mcpserver/ ── Die Hauptschnittstelle ────────────────────────
│ ├── server.go ← Handler und Transport (Streamable HTTP), ein
│ │ MCP-Server je Projekt. Enthält den Text der
│ │ `instructions` — das wirksamste Stellrad für die
│ │ Qualität der Antworten, weil er bei jedem Client
│ │ im Kontext steht.
│ │
│ └── tools.go ← Die sechs Werkzeuge: recall, get, list, related,
│ remember, forget. Alte Einträge tragen in den
│ Antworten "stale": true. Jedes ist eine Closure
│ über genau ein Projekt und kann strukturell
│ nicht an ein anderes.
│
├── templates/ ← HTML der Weboberfläche. partials.html enthält die
│ gemeinsamen Blöcke "kopf" und "fuss", die jede
│ Seite einbindet — kein verschachteltes Layout.
│
├── static/
│ ├── style.css ← Das gesamte Aussehen, ohne Framework. Farben als
│ │ Variablen ganz oben, helle und dunkle Darstellung.
│ ├── confirm.js ← Bestätigungsabfrage vor dem Löschen. Liest das
│ │ Attribut data-confirm, statt onclick="" im HTML zu
│ │ verwenden — Inline-JavaScript verbietet die
│ │ Content-Security-Policy.
│ ├── preview.js ← Reiter "Schreiben"/"Vorschau" im Editor. Holt das
│ │ HTML vom Server, statt Markdown im Browser zu
│ │ rendern. Ohne JavaScript bleibt das Formular
│ │ unverändert nutzbar.
│ ├── autocomplete.js ← Vorschläge nach "[[" im Textfeld, per Tastatur
│ │ und Maus bedienbar.
│ ├── graph.js ← Selbst geschriebene Kräftesimulation und
│ │ SVG-Darstellung für die Graph-Ansicht. Texte nur
│ │ über textContent, nie innerHTML.
│ └── img/ ← Logo in mehreren Fassungen (hell, dunkel, ohne
│ Hintergrund). Die Anmeldeseite wählt je nach
│ Farbschema die passende.
│
├── scripts/
│ └── backup.sh ← Sichert control.db und jede Workspace-Datei
│ einzeln über sqlite3 .backup in einen
│ zeitgestempelten Ordner; RETENTION_DAYS räumt
│ alte Sicherungen auf.
│
└── data/ ← Daten (nicht im Repository, als Volume gemountet)
├── control.db ← Kontroll-Datenbank: Workspaces, Key-Zuordnung
└── workspaces/
└── <workspace-id>.db ← Eine Datei je Workspace
Tests
Jedes Package hat seine Tests direkt daneben. Sie laufen mit go test ./... ohne
weitere Vorbereitung — die Datenbanktests legen jeweils eine echte SQLite-Datei
in einem Testverzeichnis an, damit auch Migrationen und Fremdschlüssel geprüft
werden.
| Datei | Schwerpunkt |
|---|---|
internal/auth/auth_test.go |
Signatur, Manipulation, Ablauf, CSRF, Key-Form, Rollen, Cookie-Flags, Rate-Limiting, X-Forwarded-For |
internal/store/nutzung_test.go |
Zählung nach Art und Weg samt Zeitfenster, Bestand ohne Papierkorb, Verweise ins Leere, aktive Zugänge |
internal/store/papierkorb_test.go |
Jeder lesende Weg blendet den Papierkorb aus (Einzelabruf, Liste mit Filtern, Suchindex/Export, Zählen, Schlagworte, Rückverweise, Graph, Sammelbearbeitung); Wiederherstellen, Zurückholen durch Überschreiben, Konflikt, endgültiges Löschen, Frist |
internal/store/store_test.go |
Migrationen, Slug-Prüfung, Abschottung, Dublettenvermeidung, optimistisches Sperren, Verweise, Protokoll, Änderungshistorie |
internal/store/control_test.go |
Kontroll-Datenbank: Standard-Workspace bleibt stabil, Auflistung, Zuordnung Key → Workspace |
internal/workspace/workspace_test.go |
Manager hält Dateien offen, trennt Workspaces, schließt sauber |
internal/entry/entry_test.go |
HTML-Escaping, Verweisauflösung, Textausschnitte, sichere Hervorhebung |
internal/markdown/markdown_test.go |
GFM-Erweiterungen, kein Roh-HTML und keine javascript:-Links, Anker nur in der Hilfe |
internal/entry/diff_test.go |
Zeilenvergleich, Grenzfälle, Ausweichen bei sehr langen Einträgen |
internal/search/search_test.go |
Bewertung, Präfix-Rückfallebene, Aktualisieren und Entfernen |
internal/store/related_test.go |
Verwandte Einträge über zwei Ebenen, Papierkorb als Sackgasse, Grenze für veraltete Einträge, übernommene Zeitstempel beim Anlegen |
internal/importer/importer_test.go |
Rundlauf Export → ZIP → Import ohne Verlust, Vorschau, Überspringen/Überschreiben, Papierkorb, doppelte Bezeichner, fremde Köpfe, Grenzen des Archivs |
internal/export/export_test.go |
Dateikopf und YAML-Maskierung, Aufräumen verwaister Dateien, Stabilität über mehrere Läufe |
internal/web/import_test.go |
Import mit Vorschau und Übernehmen, Suchindex nachgezogen, ein Protokolleintrag, nur für admin, Body-Grenze je Route |
internal/web/web_test.go |
Anmeldung, zurückgezogene Keys, CSRF, Projektabschottung, Workspace-Trennung, Rollen, Header, Hilfeseiten samt eingesetzter Adresse |
internal/mcpserver/mcpserver_test.go |
Werkzeugbestand, instructions, Dublettenvermeidung, Konflikte, Rollen, Projektabschottung |
internal/hilfe/hilfe_test.go |
Seitenliste und Dateien passen zusammen, interne Links führen zu vorhandenen Seiten, kein Roh-HTML |
Datenfluss: Agent ruft Wissen ab
KI-Werkzeug POST /mcp { "method": "tools/call", "params": { "name": "recall", … } }
→ web/middleware.go (SecurityHeaders, LimitBody)
→ web/middleware.go (APIAuth) Key → Prüfsumme
→ store/control.go (ResolveKeyWorkspace) → Workspace
→ workspace/workspace.go (Get) → dessen Datei und Suchindex
→ store/keys.go (ResolveKeyHash) → Projekt + Rolle
in den Context; Fehlversuche in die Sperre
→ mcpserver/server.go (ServeHTTP) Projekt aus dem Context → dessen MCP-Server
→ mcpserver/tools.go (recall)
→ search/registry.go Index dieses Projekts (beim ersten Mal
aus der Datenbank aufgebaut)
→ search/index.go (Search) BM25, bei Bedarf Präfix-Rückfallebene
→ store/entries.go (EntryBySlug) Treffer nachladen
→ entry/entry.go (Snippet) Textausschnitt je Treffer
→ JSON-Antwort mit Trefferliste und Hinweis zum weiteren Vorgehen
Datenfluss: Agent legt Wissen ab
KI-Werkzeug POST /mcp { … "name": "remember", "arguments": { "slug": …, "content": … } }
→ web/middleware.go (APIAuth) wie oben
→ mcpserver/tools.go (remember)
→ requireWrite() Rolle read wird hier abgewiesen
→ store/entries.go (PutEntry) eine Transaktion:
· Bezeichner vorhanden? → aktualisieren
· ExpectedVersion prüfen → ggf. Konflikt
· Schlagworte und Verweise ersetzen
· Herkunft (agent) und Zugangsname setzen
→ search/registry.go (Update) Index nachziehen
→ store/audit.go (LogAudit) wer, was, wann
→ Antwort: Bezeichner, neue Fassung, angelegt oder aktualisiert
Datenfluss: Mensch bearbeitet im Browser
Browser POST /p/plattform/e/deployment/save
→ web/middleware.go (SecurityHeaders, LimitBody)
→ web/middleware.go (requireSession) Cookie prüfen → Key aus der Datenbank
laden → gilt er noch? → CSRF-Token prüfen
→ web/middleware.go (requireProject) Projekt aus der URL; fremdes Projekt → 404
→ web/middleware.go (requireWrite) Rollenprüfung
→ web/handlers_entries.go (handleEntrySave)
→ store/entries.go (PutEntry) Herkunft: human, Autor: Key-Name
→ search/registry.go (Update)
→ store/audit.go (LogAudit)
→ Weiterleitung zur Detailansicht