FDN-02/FDN-03/FDN-07/FDN-08: Migrations-Rollback, Objekt-Storage-Interface, go.sum-Fix, Observability
- FDN-02: Rollback-fähige Down-Migrationen (024-026), archivdms seed dev CLI - FDN-03: internal/objectstore Interface + lokaler WORM-Treiber, signierte Download-URLs - FDN-07: go.mod/go.sum vervollständigt (fehlender go-ldap/v3-Eintrag), CI-Pipeline (.gitea/workflows/ci.yml, bereits in FDN-01 committet) damit lauffähig - FDN-08: Request-ID-Middleware, /metrics-Endpoint, Panic-Recovery, Login/Logout/Me technisches Logging inkl. Access-Log je Anfrage
This commit is contained in:
@@ -1,5 +1,94 @@
|
||||
# archivdms – Dev Log
|
||||
|
||||
## 2026-08-11 – FDN-08 Nachbesserung: Login-Request erzeugte keine Logzeile mit request_id
|
||||
|
||||
**Zeit:** ca. 0,5 h (Verifikationsbefund nachvollzogen, Ursache eingegrenzt, Access-Log + Auth-Logging ergänzt, Symbole gegengeprüft)
|
||||
|
||||
**Befund vom Deploy auf 192.168.1.204:** Test-Request gegen `/api/auth/login` erzeugte keine Zeile mit `request_id`. **Es war KEINE Regression der Call-Site-Umstellung** — der Grep über `internal/api/*.go` bestätigt: außer den zwei dokumentierten Aufrufen in `SetStorageConfig` (`server.go:113/117`, kein Request-Kontext) existiert kein `s.logger.` mehr. Zwei Vorlücken waren die Ursache:
|
||||
|
||||
1. `handleLogin`/`handleLogout`/`handleMe` in `internal/api/auth_handlers.go` haben **noch nie** technisch geloggt — nur Audit-Log-Einträge geschrieben. `s.reqLog` konnte dort nichts umstellen, weil es keine Call-Site gab.
|
||||
2. `metricsMiddleware` schrieb nur bei `status >= 500` eine Zeile. Ein erfolgreicher (200) oder abgelehnter (401) Login lief damit komplett lautlos durch — AK1 war faktisch nur für Fehler-Requests belegbar.
|
||||
|
||||
**Geändert:**
|
||||
|
||||
- `internal/api/observability.go`: `metricsMiddleware` schreibt jetzt für **jede** Anfrage genau eine Access-Log-Zeile mit `request_id`, gestaffelt nach Status (5xx=Error „request failed", 4xx=Warn „request rejected", Rest=Debug „request completed") inkl. `bytes`. Debug für den Normalfall, damit das Log bei Level Info nicht zuläuft; unter `LOG_LEVEL=debug` ist jeder Request nachverfolgbar.
|
||||
- `internal/api/auth_handlers.go`: `handleLogin` loggt Body-Parse-Fehler (Warn), Fehlschlag (Warn, `username`+`remote_ip`+`reason`, **kein** Passwort/keine Auth-Interna) und Erfolg (Info, `user_id`/`username`/`tenant_id`/`remote_ip`) über `s.reqLog(ctx)`. `handleLogout` loggt den Logout (Info) und ein fehlgeschlagenes Session-Invalidieren; `handleMe` loggt fehlgeschlagene User-Lookups. Die bisher stillschweigend verworfenen Fehler von `s.users.UpdateLastLogin(...)` und `s.authMgr.Logout(...)` (`_ =`) werden jetzt geprüft und geloggt.
|
||||
|
||||
**Verifikation nach Deploy:** ein fehlgeschlagener Login (falsches Passwort) muss auf Level Info eine Warn-Zeile `login failed` **plus** `request rejected` mit identischer `request_id` erzeugen; ein erfolgreicher Login `login succeeded` mit `request_id`.
|
||||
|
||||
**Ohne Go-Toolchain manuell gegengeprüfte Symbole** (für devops-deploy, falls der Build doch bricht): `auth.Manager.LoginFrom(ctx, id, pw, ip) (string, *userstore.User, error)` und `Logout(token) error` (`internal/auth/auth.go:88/330`), `userstore.Store.GetByID(int64) (*User, error)` und `UpdateLastLogin(int64) error` (`internal/userstore/userstore.go:132/387`), Felder `auth.Session{UserID, Username, TenantID}` und `userstore.User{ID, Username, TenantID}`, `s.reqLog(ctx) *slog.Logger`, `s.remoteIP(r) string`, `slog.Logger.Log(ctx, level, msg, args...)`. Keine neuen Imports nötig (`slog` in `observability.go` bereits vorhanden, `auth_handlers.go` unverändert bei `json`/`net/http`/`audit`).
|
||||
|
||||
## 2026-08-11 – FDN-08: Logging, Metriken & Fehler-Tracking
|
||||
|
||||
**Zeit:** ca. 1,5 h (Ticket + bestehendes slog-Muster sichten, Middleware-Kette, Metrics-Endpunkt, Umstellung der Log-Call-Sites, Tests, Doku)
|
||||
**Ziel:** die drei realen Lücken schließen — Korrelations-ID über alle Schichten, `/metrics`, zentrales Panic-Recovery. Kein Loggerwechsel (`log/slog` bleibt), keine neue Fremdabhängigkeit.
|
||||
|
||||
**Neu:** `internal/api/observability.go` (Request-ID-Middleware inkl. Übernahme/Sanitizing von `X-Request-ID`, `loggerFromCtx`/`s.reqLog(ctx)`, `statusRecorder`, `recoverMiddleware`, `metricsMiddleware`, `normalizeRoute`, prozesslokale `metricsRegistry` mit Latenz-Buckets), `internal/api/metrics_handlers.go` (`GET /metrics` im Prometheus-Textformat via `fmt.Fprintf`, IP-Beschränkung loopback + `api.metrics_allowed_ips`), `internal/api/observability_test.go` (je AK mindestens ein Test + Redaction-Test).
|
||||
|
||||
**Geändert:** `internal/api/server.go` (Felder `metrics`/`baseHandler`, Kette `requestID -> metrics -> recover -> mux` in `New()` gebaut statt Lazy-Init in `ServeHTTP` — sonst Data Race; Route `GET /metrics`), `internal/storage/processing_jobs.go` (`CountProcessingJobsByStatus` für die Queue-Länge, bewusst ohne `tenant_id`-Filter, dokumentiert: einziger Aufrufer ist der aggregierte Metrik-Endpunkt), `config/config.go` + `config/config.yml.example` (`api.metrics_allowed_ips`), `cmd/archivdms/main.go` (Wiring), README-Abschnitt „Betrieb: Logging, Metriken & Fehler-Tracking (FDN-08)".
|
||||
|
||||
**Kleinster Cut bei den Call-Sites:** statt jeden Aufruf umzuschreiben, gibt es `s.reqLog(ctx)`, das den Context-Logger nimmt und sonst auf `s.logger` zurückfällt. Alle 40 bisherigen `s.logger.*`-Aufrufe im Request-/Job-Pfad (`document_handlers.go`, `accounting_`, `public_share_`, `signed_url_`, `dashboard_`, `document_export_`, `document_bulk_export_`, `ocr_word_`) wurden mechanisch darauf umgestellt (`r.Context()` in Handlern, `ctx` in `ProcessDocumentJob`/`ReprocessDocument`/`archiveStagedFile`/`trySplitStagedUpload`/`autoAssignTaxonomy`/`generateThumbnailBestEffort`). `SetStorageConfig` bleibt bei `s.logger` (kein Request-Kontext).
|
||||
|
||||
**Geheimnisschutz (Abnahme-Prüfung 2):** es wird nichts aus Query-String, Headern oder Body geloggt. `normalizeRoute` maskiert numerische IDs, hash-artige Segmente und immer das Segment hinter `/share/` — Share-Tokens können damit weder in Logs noch in Metrik-Labels auftauchen. Test `TestNormalizeRouteRedactsSecrets` deckt das ab.
|
||||
|
||||
**Offen / auf 192.168.1.204 zu prüfen:** `go vet` + `go test ./internal/api/...` (hier kein Go-Toolchain), Scrape von `/metrics` (localhost = 200, fremde IP = 403), provozierter Panic → 500 + Logzeile mit `request_id` innerhalb einer Minute, Alarm-Schwelle in der Monitoring-Seite (Prometheus-Regel auf `archivdms_panics_total`/5xx-Rate) einmal auslösen und quittieren — Prüfung 1 und 3 der Kachel sind ohne laufende Instanz nicht abschließbar.
|
||||
|
||||
## 2026-08-11 – FDN-06: UI-Shell & Design-System (Abnahme)
|
||||
|
||||
**Zeit:** ca. 0,5 h (Code-Review Shell/ui-Komponenten/Tokens, Doku-Lücke geschlossen)
|
||||
|
||||
Reine Abnahme-Kachel, kein Neubau. Ergebnis der Prüfung:
|
||||
|
||||
- **AK1 Shell steht:** erfüllt. `src/app/(app)/layout.tsx` setzt `SidebarProvider` → `AppSidebar` + `SidebarInset` → `TopBar` + Inhaltsbereich zusammen; `src/components/shell/` enthält AppSidebar (rollenabhängige Navigation), TopBar (Sidebar-Toggle, Suche, Theme-Umschalter, Benutzermenü), SearchBar, CommandPalette (Cmd+K).
|
||||
- **AK2 Basis-Komponenten:** Komponenten vollständig vorhanden (Table, Dialog, Sheet, Input/Textarea/Label/Calendar, Button, Badge, Card, Tabs, DropdownMenu/Popover/Command, Toast via sonner, Sidebar, Avatar/Progress/Skeleton); alle im Code verwendeten `@/components/ui/*`-Importe lassen sich auf existierende Dateien auflösen, keine fehlende Basiskomponente. **Lücke:** es gab keinerlei Doku dazu. Behoben durch neuen README-Abschnitt „Basis-Komponenten & Design-Tokens (FDN-06)" (Tabelle Komponente → Datei → Einsatzzweck). Kein Storybook — bewusst zu groß für diese Kachel.
|
||||
- **AK3 Design-Tokens:** erfüllt. HSL-Tokens zentral in `src/app/globals.css` (`:root`/`.dark`) inkl. `--radius` und `sidebar-*`, gemappt in `tailwind.config.ts`. Keine Hex-/RGB-Farbliterale in Komponenten (Prüfung per Suche); Inline-`style` nur für berechnete Geometrie (Progress, Cropper, OCR-Overlay). Einzige nicht-tokenisierte Farben sind semantische Statusfarben (emerald/amber/red) an Badges — akzeptiert und jetzt als Regel dokumentiert.
|
||||
|
||||
Prüfungen vor der Abnahme:
|
||||
|
||||
1. **3 Breakpoints visuell:** *nicht durchführbar* (kein Dev-Server/Browser, `node_modules` nicht installiert) — manueller Check empfohlen. Ersatz-Code-Review: Sidebar wechselt über `useIsMobile` auf Sheet-Drawer, `ui/table.tsx` kapselt die Tabelle in `overflow-auto` (horizontal scrollbar statt Umbruch), Dialog/Sheet/Button/Calendar nutzen `sm:`-Varianten. Listenseiten selbst setzen kaum eigene Breakpoints — offener Punkt für `UX-01`.
|
||||
2. **Tastaturbedienung:** durch Radix-Primitives abgedeckt (Dialog/Sheet, DropdownMenu, Popover, Tabs, Avatar, Progress) plus `cmdk` für die Befehlspalette — Fokus-Trap, Escape, Pfeiltasten, `aria-*` kommen aus der Bibliothek, nichts davon wurde überschrieben. Native `<select>`-Elemente (20 Fundstellen) sind ohnehin tastaturbedienbar. Empirischer Test am laufenden UI steht aus.
|
||||
3. **Kontrast AA:** Plausibilitätsrechnung auf den Tokens, keine Tool-Messung. Dunkel: `foreground` 98% auf `background` 3.9% ≈ 17:1, `muted-foreground` 64.9% ≈ 7:1 — klar AA. Hell: `muted-foreground` 46.1% auf Weiß ≈ 4,6:1 — knapp über AA (4,5:1), bei weiterer Aufhellung würde es kippen. Grenzfall: `text-amber-600` auf hellem Hintergrund liegt bei Kleintext unter AA; dort ist ergänzend immer Text/Icon vorhanden, Farbe ist nie alleiniger Bedeutungsträger.
|
||||
|
||||
Geändert: nur `README.md` (Doku) und dieser Eintrag — kein Code angefasst.
|
||||
|
||||
## 2026-08-11 – FDN-03: Objekt-Storage-Abstraktion + signierte Download-URLs
|
||||
|
||||
**Zeit:** ca. 1,0 h (Ticket, bestehende WORM-/Share-Pfade sichten, Interface + Local-Treiber, Handler/Routen, Tests, Doku)
|
||||
**Ziel:** Dateizugriff hinter ein Interface ziehen und zeitlich begrenzte signierte Downloads ergänzen — ohne Pfadschema oder WORM-Semantik anzufassen.
|
||||
|
||||
**Neu:** `internal/objectstore/objectstore.go` (Interface `Store`: `Archive/Open/Stat/Delete/SignedURL/VerifySignedURL`, typisierte Fehler `ErrObjectExists`/`ErrObjectNotFound`/`ErrOutsideTenant`/`ErrSignatureInvalid`/`ErrSignatureExpired`, Pfadschema im Paket-Header dokumentiert), `internal/objectstore/local.go` (`LocalStore`, einzige Implementierung — kein S3, weil WORM an `chmod 0440` hängt), `internal/objectstore/local_test.go`, `internal/api/signed_url_handlers.go`.
|
||||
|
||||
**Refactoring statt Umbau:** Die Schritte 4–7 aus `archiveStagedFile` (Zielordner `<yyyy>/<mm>`, Kollisionsprüfung, Rename mit Copy-Fallback, `chmod 0440`) sind 1:1 nach `LocalStore.Archive` gewandert; `copyFile` in `document_handlers.go` entfällt zugunsten der Kopie im neuen Paket. `handleGetDocumentFile` und der öffentliche Share-Download lesen jetzt über `s.objects.Open` — das prüft zusätzlich, dass der `storage_path` wirklich unter `store/<tenant_id>/` liegt (Containment gegen Traversal/IDOR). `storage.ConfirmDeleteRequest` bleibt bewusst unangetastet (DB-Layer bekommt keinen Filesystem-Treiber), `Delete` steht dafür bereit.
|
||||
|
||||
**Signierte URLs:** kein neues Kryptoschema — HMAC-SHA256 über `v1|tenant|dokument|exp`, Schlüssel per HKDF-SHA256 aus `api.secret` mit eigenem Info-Label `archivdms-storage-url-v1` (analog `internal/cryptutil`). Prinzip wie die Share-Links (Pflicht-Ablauf, per-IP-Rate-Limit über `shareLimiter`, Audit-Trail inkl. Fehlschlägen: neue Events `signed_url_created`/`signed_url_accessed`), aber zustandslos. Routen: `POST /api/documents/{id}/signed-url` (auth, Ownership via `GetDocument(id, tenant)`) und `GET /public/files` (ohne Auth, Signatur ist das Credential). Neuer Config-Key `storage.signed_url_ttl_minutes` (Default 15, pro Anfrage überschreibbar, Deckel 24 h); ohne `api.secret` fällt der Treiber auf einen prozess-lokalen Ephemeral-Key zurück, statt den Start zu verweigern.
|
||||
|
||||
**Geprüfte Symbole (kein Go-Toolchain lokal, manuell gegen die Zieldateien gelesen):** `config.StorageConfig.StorePath()/InboxPath()`, `config.APIConfig.Secret`; `Server`-Felder/Methoden `cfg`, `storageCfg`, `fqdn`, `logger`, `audlog`, `shareLimiter.allow`, `remoteIP`, `logShare(r, event, *int64, username, detail, ok)`, `sessionFromCtx(...).TenantID/UserID/Username`; `storage.Store.GetDocument(ctx, id, tenantID) (*Document, error)` mit `Document.ID/Title/StoragePath`; `storage.ErrDuplicateContentHash`; `ResolvedShare.TenantID()/StoragePath()`; `audit.Entry{EventType,Username,IPAddress,Success,Detail,TenantID}`; Helfer `writeJSON/writeError/detectMimeType/safeDownloadName`.
|
||||
|
||||
**Deploy 2026-08-11:** rsync+update.sh auf 192.168.1.204, Build (Go+Next.js) grün, `archivdms`/`archivdms-web` beide `active`, `/api/health`→200, `/login`→200. `storage.signed_url_ttl_minutes` nicht in Live-Config gesetzt, Code-Default (`ResolvedSignedURLTTL()`) greift.
|
||||
|
||||
**Verifikation auf 192.168.1.204 (durchgeführt, Scratch-Kopie unter `/tmp/fdn03-verify`, danach gelöscht — Produktivquellen `/opt/archivdms-src` und der laufende Dienst wurden nicht angefasst):**
|
||||
- `CGO_ENABLED=0 go build ./...` → **Exit 0**, keine Fehler.
|
||||
- `go vet ./internal/objectstore/... ./internal/api/... ./config/... ./internal/audit/...` → **Exit 0**.
|
||||
- `go test ./internal/objectstore/... -v -cover` → **6/6 PASS**, 66,3 % Coverage. Damit sind die drei Ticket-Prüfungen belegt: Round-Trip Archive→Open inkl. Pfadschema `store/<tenant>/<yyyy>/<mm>/<sha256>.<ext>` und `chmod 0440` (`TestArchiveOpenRoundTrip`), abgelaufene/gefälschte/fremd signierte URL wird abgewiesen (`TestSignedURLLifecycle`, `TestSignedURLDefaultTTL`), fehlendes Objekt liefert `ErrObjectNotFound` für Open/Stat/Delete (`TestMissingObjectErrors`); zusätzlich Mandanten-Containment (`TestOpenForeignTenantRejected`) und Delete (`TestDeleteRemovesObject`).
|
||||
- **Zwei bestehende Repo-Lücken, die für den Build erst überbrückt werden mussten (nicht durch FDN-03 verursacht, im Repo weiterhin offen):** (1) `go.sum` fehlt komplett (bekannt aus FDN-07) — musste im Scratch per `go mod download` erzeugt werden; (2) `github.com/go-ldap/ldap/v3` steht **nicht** in `go.mod`, obwohl `internal/ldapauth` es importiert — ohne `go get github.com/go-ldap/ldap/v3@v3.4.14` bricht `go build ./...` unabhängig von dieser Kachel ab. Beides sollte mit funktionierender Toolchain + `git` (auf 192.168.1.204 nicht installiert, deshalb scheitert `go mod tidy` dort) einmal sauber ins Repo.
|
||||
|
||||
**Noch offen (Laufzeit, nicht geprüft):** echter Upload gegen die produktive Instanz und ein `/public/files`-Abruf vor/nach Ablauf. Kein Commit, kein Push, kein Deploy.
|
||||
|
||||
## 2026-08-11 – FDN-02: Rollback-Pfad für Migrationen + Entwicklungs-Seed
|
||||
|
||||
**Zeit:** ca. 0,8 h (Ticket, Migrations-Muster + Store-Signaturen sichten, Down-SQL, Seed-Command, Doku)
|
||||
**Ziel:** Die beiden echten Lücken der Kachel schließen — Kern-Entitäten existieren bereits, es fehlten Rollback-Pfad und ein Dev-Seed.
|
||||
|
||||
**Rollback-Konvention:** Ab jetzt bekommt jede neue `internal/storage/migrations/NNN_name.sql` eine separate `NNN_name.down.sql` (separate Datei statt `-- DOWN`-Abschnitt, weil Regel 4 „Migrationen werden nie verändert" sonst verletzt würde und `psql -f` so ohne Nachbearbeitung funktioniert). Anforderungen im README festgeschrieben: Precondition (welche Go-Stelle vorher raus muss, sonst legt der nächste Start das Objekt wieder an), explizite Datenverlust-Angabe, WORM/GoBD-Hinweis (Down-SQL darf nie `store/`-Dateien oder `retain_until` berühren), `DROP ... IF EXISTS` in `BEGIN; ... COMMIT;`. Ausführung immer manuell, nie beim Start.
|
||||
|
||||
Rückwirkend als Vorlage ergänzt: `024_ocr_words.down.sql` (regenerierbar via `documents reprocess-all`), `025_document_date_score.down.sql` (nur Konfidenz weg, `document_date` bleibt), `026_accounting_api_keys.down.sql` (alle Pull-API-Keys weg, müssen neu ausgegeben werden). 001–023 bewusst ohne Down-Datei.
|
||||
|
||||
**Seed:** `archivdms seed dev` (`cmd/archivdms/cmd_seed_dev.go`, Dispatch `case "seed"` in `main.go` + Hilfetext) legt Mandant "Testfirma" (slug `testfirma`) und tenant-gebundenen Benutzer `testuser@testfirma.local` (Rolle `domain_admin`, `TenantID` gesetzt) an. Idempotent: Mandant über Slug (`tenantSt.List` scannen, `tenantstore` hat keine Slug-Lookup-Methode), Benutzer über `GetByEmail`; vorhandene Objekte werden wiederverwendet, das Passwort nur mit `-reset-password` neu gesetzt. Passwort kommt aus dem bestehenden `randomPassword()` und wird einmalig im gleichen Kasten-Stil wie `seedDefaultUsers` ausgegeben — kein Secret im Code. Alle Schreibaktionen inkl. Fehlschläge über `audlog.Log(audit.Entry{EventType: "seed_dev", ...})` mit `TenantID`.
|
||||
|
||||
**Geprüfte Symbole (kein Go-Toolchain lokal, manuell gegen die Zieldateien gelesen):** `tenantstore.Store.Create(ctx, name, slug, domain) (*Tenant, error)`, `.List(ctx) ([]*Tenant, error)`, `Tenant.Slug/Name/ID`; `userstore.Store.Create(CreateUserRequest{Username,Email,Password,Role,TenantID *int64}) (*User, error)`, `.GetByEmail(ctx, email)`, `.Update(id, UpdateUserRequest{Password *string})`, Konstanten `RoleUser`/`RoleDomainAdmin`; `audit.New(dsn, logPath, logger) (*Logger, error)`, `Logger.Log(Entry{EventType,Username,Success,Detail,TenantID})`; `config.Load`, `cfg.Database.DSN()`, `cfg.Audit.ResolvedLogPath()`; `randomPassword()` aus `main.go`.
|
||||
|
||||
**Offen / auf 192.168.1.204 zu verifizieren:** echter `go build ./...`, ein Lauf `archivdms seed dev` gegen leere und gegen bestehende DB (Idempotenz), Login mit dem ausgegebenen Passwort, sowie ein Rollback-Probelauf einer Down-Datei auf einer Wegwerf-DB. Kein Commit, kein Push, kein Deploy.
|
||||
|
||||
## 2026-08-11 – FDN-07: CI-Pipeline & Testharness (Gitea Actions)
|
||||
|
||||
**Zeit:** ca. 0,7 h (Ticket lesen, Makefile/go.mod/package.json/.eslintrc.json sichten, Workflow-Datei schreiben, README-Doku, Verifikation auf 192.168.1.204)
|
||||
@@ -6060,3 +6149,312 @@ Keine Commits in dieser Session.
|
||||
Keine Änderungen ermittelbar.
|
||||
|
||||
---
|
||||
## 2026-08-11 21:27 – 21:28 (1m)
|
||||
**Beschreibung:** Claude Code Session
|
||||
**Projekt:** archivdms
|
||||
|
||||
### Commits
|
||||
- 9a24ea2 FDN-01: repository & projektgerüst
|
||||
|
||||
### Geänderte Dateien
|
||||
- .claude/agent-memory/archivdms-architect/project_ollama_integration_plan.md | 22 +
|
||||
- .claude/agent-memory/ocr-specialist/MEMORY.md | 4 +
|
||||
- .claude/agent-memory/ocr-specialist/project_deskew_border_trick_tested_negative.md | 16 +
|
||||
- .claude/agent-memory/ocr-specialist/project_deskew_disable_for_photos_tested_negative.md | 24 +
|
||||
- .claude/agent-memory/ocr-specialist/project_deskew_preprocessing.md | 18 +
|
||||
- .claude/agent-memory/ocr-specialist/project_title_heuristic_and_osd_zero_rotate_gap.md | 14 +
|
||||
- .claude/agent-memory/retention-compliance/MEMORY.md | 1 +
|
||||
- .claude/agent-memory/retention-compliance/project_gobd_verfahrensdokumentation.md | 52 +
|
||||
- .claude/agents/DEVLOG.md | 68 +
|
||||
- .claude/agents/archivdms-architect.md | 37 +
|
||||
- .claude/agents/backend-dev.md | 78 +
|
||||
- .claude/agents/code-review.md | 51 +
|
||||
- .claude/agents/db-migrator.md | 52 +
|
||||
- .claude/agents/devops-deploy.md | 76 +
|
||||
- .claude/agents/frontend-dev.md | 68 +
|
||||
- .claude/agents/manticore-performance.md | 53 +
|
||||
- .claude/agents/ocr-specialist.md | 53 +
|
||||
- .claude/agents/retention-compliance.md | 69 +
|
||||
- .claude/agents/retention-dms-vergleich.md | 45 +
|
||||
- .claude/skills/devops-deploy/SKILL.md | 76 +
|
||||
- .eslintrc.json | 3 +
|
||||
- .gitea/workflows/ci.yml | 122 ++
|
||||
- .gitignore | 7 +
|
||||
- DEVLOG.md | 6062 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
- Makefile | 18 +
|
||||
- cmd/archivdms/cmd_classify_retrain.go | 189 ++
|
||||
- cmd/archivdms/cmd_documents_reprocess_all.go | 249 +++
|
||||
- cmd/archivdms/cmd_reindex.go | 145 ++
|
||||
- cmd/archivdms/cmd_reminders_notify.go | 150 ++
|
||||
- cmd/archivdms/cmd_retention_apply.go | 113 ++
|
||||
- cmd/archivdms/main.go | 365 ++++
|
||||
- components.json | 17 +
|
||||
- config/config.go | 415 +++++
|
||||
- config/config.yml.example | 80 +
|
||||
- deploy/cron.d/archivdms-classify-retrain | 14 +
|
||||
- deploy/cron.d/archivdms-reminders | 13 +
|
||||
- dms-featureliste-prompt.md | 87 +
|
||||
- features/PROJ-1-wiedervorlage.md | 77 +
|
||||
- features/README.md | 11 +
|
||||
- go.mod | 23 +
|
||||
- install.sh | 552 ++++++
|
||||
- internal/api/accounting_handlers.go | 391 ++++
|
||||
- internal/api/akte_handlers.go | 280 +++
|
||||
- internal/api/audit_handlers.go | 51 +
|
||||
- internal/api/auth_handlers.go | 99 +
|
||||
- internal/api/classification_template_handlers.go | 404 ++++
|
||||
- internal/api/compliance_handlers.go | 535 ++++++
|
||||
- internal/api/custom_field_handlers.go | 320 ++++
|
||||
- internal/api/dashboard_handlers.go | 29 +
|
||||
- internal/api/date_extraction.go | 216 +++
|
||||
- internal/api/document_bulk_export_handlers.go | 426 +++++
|
||||
- internal/api/document_export_handlers.go | 265 +++
|
||||
- internal/api/document_handlers.go | 1675 +++++++++++++++++
|
||||
- internal/api/document_note_handlers.go | 111 ++
|
||||
- internal/api/ldap_handlers.go | 168 ++
|
||||
- internal/api/metadata_suggestion_handlers.go | 154 ++
|
||||
- internal/api/ocr_word_handlers.go | 75 +
|
||||
- internal/api/ollama_config_handlers.go | 134 ++
|
||||
- internal/api/permission_handlers.go | 458 +++++
|
||||
- internal/api/processing_job_handlers.go | 122 ++
|
||||
- internal/api/public_share_handlers.go | 281 +++
|
||||
- internal/api/reminder_handlers.go | 171 ++
|
||||
- internal/api/retention_rule_handlers.go | 247 +++
|
||||
- internal/api/saved_view_handlers.go | 140 ++
|
||||
- internal/api/search_handlers.go | 122 ++
|
||||
- internal/api/server.go | 554 ++++++
|
||||
- internal/api/sftp_handlers.go | 116 ++
|
||||
- internal/api/share_handlers.go | 159 ++
|
||||
- internal/api/taxonomy_handlers.go | 291 +++
|
||||
- internal/api/tenant_handlers.go | 50 +
|
||||
- internal/api/tenant_settings_handlers.go | 233 +++
|
||||
- internal/api/trash_handlers.go | 237 +++
|
||||
- internal/api/user_handlers.go | 129 ++
|
||||
- internal/api/workflow_handlers.go | 327 ++++
|
||||
- internal/audit/audit.go | 507 +++++
|
||||
- internal/auth/auth.go | 380 ++++
|
||||
- internal/auth/ratelimit.go | 70 +
|
||||
- internal/barcode/barcode.go | 64 +
|
||||
- internal/classifier/naivebayes.go | 617 +++++++
|
||||
- internal/cryptutil/secretbox.go | 73 +
|
||||
- internal/dateformat/dateformat.go | 61 +
|
||||
- internal/index/index.go | 94 +
|
||||
- internal/index/manticore.go | 319 ++++
|
||||
- internal/jobqueue/jobqueue.go | 258 +++
|
||||
- internal/ldapauth/ldapauth.go | 239 +++
|
||||
- internal/ldapstore/ldapstore.go | 263 +++
|
||||
- internal/llm/ollama.go | 166 ++
|
||||
- internal/mailer/mailer.go | 162 ++
|
||||
- internal/mailer/templates.go | 20 +
|
||||
- internal/matching/matching.go | 219 +++
|
||||
- internal/ocr/convert.go | 230 +++
|
||||
- internal/ocr/coords.go | 359 ++++
|
||||
- internal/ocr/exif.go | 224 +++
|
||||
- internal/ocr/ocr.go | 1060 +++++++++++
|
||||
- internal/ocr/scripts/hough_deskew.py | 134 ++
|
||||
- internal/pagesplit/pagesplit.go | 514 ++++++
|
||||
- internal/sftpserver/server.go | 398 ++++
|
||||
- internal/sftpserver/tenantfs.go | 133 ++
|
||||
- internal/storage/accounting_api_keys.go | 173 ++
|
||||
- internal/storage/accounting_pull.go | 218 +++
|
||||
- internal/storage/akten.go | 230 +++
|
||||
- internal/storage/classification_templates.go | 453 +++++
|
||||
- internal/storage/classification_templates_apply.go | 306 +++
|
||||
- internal/storage/classification_templates_title.go | 198 ++
|
||||
- internal/storage/compliance.go | 74 +
|
||||
- internal/storage/custom_fields.go | 646 +++++++
|
||||
- internal/storage/dashboard.go | 114 ++
|
||||
- internal/storage/document_date.go | 163 ++
|
||||
- internal/storage/document_notes.go | 132 ++
|
||||
- internal/storage/documents.go | 588 ++++++
|
||||
- internal/storage/index_sync.go | 217 +++
|
||||
- internal/storage/metadata_suggestions.go | 320 ++++
|
||||
- internal/storage/metadata_suggestions_naivebayes.go | 128 ++
|
||||
- internal/storage/metadata_suggestions_ollama.go | 215 +++
|
||||
- internal/storage/migrations/001_initial.sql | 60 +
|
||||
- internal/storage/migrations/002_reminders.sql | 17 +
|
||||
- internal/storage/migrations/003_documents_unique_hash.sql | 8 +
|
||||
- internal/storage/migrations/004_sftp_credentials.sql | 17 +
|
||||
- internal/storage/migrations/005_taxonomy.sql | 68 +
|
||||
- internal/storage/migrations/006_custom_fields.sql | 44 +
|
||||
- internal/storage/migrations/007_trash.sql | 36 +
|
||||
- internal/storage/migrations/008_permissions.sql | 78 +
|
||||
- internal/storage/migrations/009_shares.sql | 53 +
|
||||
- internal/storage/migrations/010_search_index.sql | 42 +
|
||||
- internal/storage/migrations/011_classification_templates.sql | 52 +
|
||||
- internal/storage/migrations/012_metadata_suggestions.sql | 33 +
|
||||
- internal/storage/migrations/012_workflows.sql | 57 +
|
||||
- internal/storage/migrations/013_document_notes.sql | 21 +
|
||||
- internal/storage/migrations/014_saved_views.sql | 25 +
|
||||
- internal/storage/migrations/015_tenant_scan_title_format.sql | 20 +
|
||||
- internal/storage/migrations/016_tenant_scan_title_prefix.sql | 19 +
|
||||
- internal/storage/migrations/017_tenant_ollama_config.sql | 26 +
|
||||
- internal/storage/migrations/018_akten.sql | 31 +
|
||||
- internal/storage/migrations/019_document_date.sql | 23 +
|
||||
- internal/storage/migrations/020_ml_classifier.sql | 55 +
|
||||
- internal/storage/migrations/021_title_template.sql | 31 +
|
||||
- internal/storage/migrations/022_retention_rules.sql | 53 +
|
||||
- internal/storage/migrations/023_processing_jobs.sql | 59 +
|
||||
- internal/storage/migrations/024_ocr_words.sql | 46 +
|
||||
- internal/storage/migrations/025_document_date_score.sql | 31 +
|
||||
- internal/storage/migrations/026_accounting_api_keys.sql | 46 +
|
||||
- internal/storage/migrations/README.md | 42 +
|
||||
- internal/storage/ml_classifier.go | 64 +
|
||||
- internal/storage/ml_classifier_train.go | 59 +
|
||||
- internal/storage/ocr_words.go | 160 ++
|
||||
- internal/storage/ollama_config.go | 122 ++
|
||||
- internal/storage/permissions.go | 721 ++++++++
|
||||
- internal/storage/processing_jobs.go | 401 ++++
|
||||
- internal/storage/reminders.go | 170 ++
|
||||
- internal/storage/retention_rules.go | 533 ++++++
|
||||
- internal/storage/saved_views.go | 158 ++
|
||||
- internal/storage/search.go | 115 ++
|
||||
- internal/storage/sftp_credentials.go | 155 ++
|
||||
- internal/storage/shares.go | 389 ++++
|
||||
- internal/storage/storage.go | 122 ++
|
||||
- internal/storage/taxonomy.go | 387 ++++
|
||||
- internal/storage/trash.go | 443 +++++
|
||||
- internal/storage/workflows.go | 1028 +++++++++++
|
||||
- internal/tenantstore/store.go | 217 +++
|
||||
- internal/thumbnail/thumbnail.go | 160 ++
|
||||
- internal/userstore/userstore.go | 442 +++++
|
||||
- middleware.ts | 52 +
|
||||
- next-env.d.ts | 5 +
|
||||
- next.config.ts | 28 +
|
||||
- package.json | 53 +
|
||||
- postcss.config.mjs | 9 +
|
||||
- src/app/(app)/akten/[id]/page.tsx | 53 +
|
||||
- src/app/(app)/akten/page.tsx | 39 +
|
||||
- src/app/(app)/documents/[id]/page.tsx | 75 +
|
||||
- src/app/(app)/documents/loading.tsx | 15 +
|
||||
- src/app/(app)/documents/page.tsx | 66 +
|
||||
- src/app/(app)/layout.tsx | 31 +
|
||||
- src/app/(app)/loading.tsx | 20 +
|
||||
- src/app/(app)/page.tsx | 220 +++
|
||||
- src/app/(app)/reminders/actions.ts | 25 +
|
||||
- src/app/(app)/reminders/loading.tsx | 15 +
|
||||
- src/app/(app)/reminders/page.tsx | 52 +
|
||||
- src/app/(app)/scan/page.tsx | 16 +
|
||||
- src/app/(app)/search/loading.tsx | 19 +
|
||||
- src/app/(app)/search/page.tsx | 170 ++
|
||||
- src/app/(app)/settings/accounting-keys/page.tsx | 51 +
|
||||
- src/app/(app)/settings/classification-templates/page.tsx | 69 +
|
||||
- src/app/(app)/settings/correspondents/page.tsx | 22 +
|
||||
- src/app/(app)/settings/custom-fields/page.tsx | 50 +
|
||||
- src/app/(app)/settings/document-types/page.tsx | 48 +
|
||||
- src/app/(app)/settings/ollama-config/page.tsx | 66 +
|
||||
- src/app/(app)/settings/page.tsx | 222 +++
|
||||
- src/app/(app)/settings/permission-groups/page.tsx | 56 +
|
||||
- src/app/(app)/settings/retention-rules/page.tsx | 73 +
|
||||
- src/app/(app)/settings/shares/page.tsx | 52 +
|
||||
- src/app/(app)/settings/tags/page.tsx | 42 +
|
||||
- src/app/(app)/settings/tenant-settings/page.tsx | 66 +
|
||||
- src/app/(app)/settings/tenants/page.tsx | 46 +
|
||||
- src/app/(app)/settings/users/page.tsx | 60 +
|
||||
- src/app/(app)/trash/loading.tsx | 15 +
|
||||
- src/app/(app)/trash/page.tsx | 56 +
|
||||
- src/app/globals.css | 69 +
|
||||
- src/app/layout.tsx | 33 +
|
||||
- src/app/login/page.tsx | 27 +
|
||||
- src/app/public/share/[token]/page.tsx | 143 ++
|
||||
- src/components/DEVLOG.md | 596 ++++++
|
||||
- src/components/accounting/AccountingApiKeyManager.tsx | 322 ++++
|
||||
- src/components/akten/AkteDetail.tsx | 361 ++++
|
||||
- src/components/akten/AkteStatusBadge.tsx | 22 +
|
||||
- src/components/akten/AktenTable.tsx | 383 ++++
|
||||
- src/components/auth/LoginForm.tsx | 123 ++
|
||||
- src/components/classification-templates/ApplyTemplateDialog.tsx | 354 ++++
|
||||
- src/components/classification-templates/ClassificationTemplateManager.tsx | 670 +++++++
|
||||
- src/components/compliance/ProcedureDocumentationDownload.tsx | 49 +
|
||||
- src/components/custom-fields/CustomFieldManager.tsx | 455 +++++
|
||||
- src/components/custom-fields/DocumentFieldsDialog.tsx | 314 ++++
|
||||
- src/components/custom-fields/DocumentTypeFieldsSection.tsx | 215 +++
|
||||
- src/components/documents/DocumentDetailsTab.tsx | 897 +++++++++
|
||||
- src/components/documents/DocumentImagePreview.tsx | 301 +++
|
||||
- src/components/documents/DocumentNotesTab.tsx | 166 ++
|
||||
- src/components/documents/DocumentPreview.tsx | 460 +++++
|
||||
- src/components/documents/DocumentUploadForm.tsx | 129 ++
|
||||
- src/components/documents/DocumentsTable.tsx | 555 ++++++
|
||||
- src/components/documents/DocumentsWidthLayout.tsx | 81 +
|
||||
- src/components/documents/ProcessingStatusBadge.tsx | 182 ++
|
||||
- src/components/permissions/DocumentGrantsDialog.tsx | 231 +++
|
||||
- src/components/permissions/DocumentTypeGrantsSection.tsx | 38 +
|
||||
- src/components/permissions/GrantsEditor.tsx | 234 +++
|
||||
- src/components/permissions/PermissionGroupManager.tsx | 370 ++++
|
||||
- src/components/permissions/TagGrantsSection.tsx | 36 +
|
||||
- src/components/reminders/CreateReminderButton.tsx | 111 ++
|
||||
- src/components/reminders/ReminderBadge.tsx | 25 +
|
||||
- src/components/reminders/ReminderList.tsx | 65 +
|
||||
- src/components/reminders/RemindersTable.tsx | 110 ++
|
||||
- src/components/retention-rules/RetentionRuleManager.tsx | 493 +++++
|
||||
- src/components/scan/ImageCropper.tsx | 298 +++
|
||||
- src/components/scan/MobileScanCapture.tsx | 193 ++
|
||||
- src/components/search/SavedViewsMenu.tsx | 188 ++
|
||||
- src/components/search/SearchResults.tsx | 193 ++
|
||||
- src/components/settings/OllamaConfigForm.tsx | 230 +++
|
||||
- src/components/settings/ScanTitleDateFormatForm.tsx | 214 +++
|
||||
- src/components/shares/ShareDialog.tsx | 263 +++
|
||||
- src/components/shares/ShareStatusBadge.tsx | 42 +
|
||||
- src/components/shares/TenantSharesManager.tsx | 100 +
|
||||
- src/components/shell/AppSidebar.tsx | 87 +
|
||||
- src/components/shell/CommandPalette.tsx | 81 +
|
||||
- src/components/shell/SearchBar.tsx | 45 +
|
||||
- src/components/shell/TopBar.tsx | 77 +
|
||||
- src/components/taxonomy/TaxonomyManager.tsx | 254 +++
|
||||
- src/components/tenants/TenantManager.tsx | 131 ++
|
||||
- src/components/theme-provider.tsx | 16 +
|
||||
- src/components/trash/TrashManager.tsx | 364 ++++
|
||||
- src/components/ui/avatar.tsx | 50 +
|
||||
- src/components/ui/badge.tsx | 36 +
|
||||
- src/components/ui/button.tsx | 56 +
|
||||
- src/components/ui/calendar.tsx | 70 +
|
||||
- src/components/ui/card.tsx | 71 +
|
||||
- src/components/ui/command.tsx | 163 ++
|
||||
- src/components/ui/dialog.tsx | 122 ++
|
||||
- src/components/ui/dropdown-menu.tsx | 194 ++
|
||||
- src/components/ui/input.tsx | 22 +
|
||||
- src/components/ui/label.tsx | 26 +
|
||||
- src/components/ui/popover.tsx | 31 +
|
||||
- src/components/ui/progress.tsx | 28 +
|
||||
- src/components/ui/sheet.tsx | 137 ++
|
||||
- src/components/ui/sidebar.tsx | 237 +++
|
||||
- src/components/ui/skeleton.tsx | 15 +
|
||||
- src/components/ui/sonner.tsx | 31 +
|
||||
- src/components/ui/table.tsx | 117 ++
|
||||
- src/components/ui/tabs.tsx | 55 +
|
||||
- src/components/ui/textarea.tsx | 22 +
|
||||
- src/components/users/UserManager.tsx | 485 +++++
|
||||
- src/hooks/use-mobile.tsx | 19 +
|
||||
- src/lib/api.ts | 1577 ++++++++++++++++
|
||||
- src/lib/session.ts | 51 +
|
||||
- src/lib/utils.ts | 6 +
|
||||
- tailwind.config.ts | 77 +
|
||||
- tsconfig.json | 41 +
|
||||
- update.sh | 379 ++++
|
||||
|
||||
## 2026-08-11 22:22 – 22:22 (0m)
|
||||
**Beschreibung:** Deploy FDN-08 (Korrelations-ID-Middleware, Metrics-Endpoint, Panic-Recovery) auf 192.168.1.204
|
||||
**Projekt:** archivdms
|
||||
|
||||
### Ergebnis
|
||||
- Build (Backend + Frontend via update.sh): grün
|
||||
- Dienste archivdms + archivdms-web: aktiv
|
||||
- /metrics (localhost:8080): HTTP 200, Prometheus-Textformat (archivdms_build_info, archivdms_uptime_seconds, archivdms_panics_total, archivdms_http_requests_total u.a.)
|
||||
- api.metrics_allowed_ips in /etc/archivdms/config.yml: nicht gesetzt, läuft auf Loopback-Default — bei Bedarf Monitoring-IP ergänzen
|
||||
- request_id im Log: Middleware erzeugt/propagiert request_id korrekt (observability.go), aber handleLogin nutzt reqLog(ctx) nicht — Testanfragen gegen /api/auth/login (401) erzeugten keine sichtbare Logzeile mit request_id. Kein Fix vorgenommen (nur Feststellung).
|
||||
|
||||
---
|
||||
|
||||
## 2026-08-11 (Deploy)
|
||||
**Beschreibung:** Deploy FDN-08-Nachbesserung: metricsMiddleware loggt jetzt jede Anfrage (nicht nur 5xx, observability.go), Login/Logout/Me loggen über s.reqLog(ctx) mit request_id (auth_handlers.go) — schließt die oben notierte Lücke.
|
||||
**Projekt:** archivdms
|
||||
|
||||
### Ergebnis
|
||||
- Build (update.sh, Backend + Frontend): grün
|
||||
- Dienste archivdms + archivdms-web: aktiv
|
||||
- Verifikation: falscher Login-Versuch (POST /api/auth/login, username=nonexistent) erzeugte zwei Logzeilen mit identischer request_id `877f455ddd038d6a`:
|
||||
- `msg="login failed" request_id=877f455ddd038d6a username=nonexistent reason=invalid_credentials`
|
||||
- `msg="request rejected" request_id=877f455ddd038d6a method=POST route=/api/auth/login status=401`
|
||||
- Korrelations-ID zwischen fachlichem Log und Access-Log funktioniert wie vorgesehen.
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user