diff --git a/dms/.golangci.yml b/dms/.golangci.yml new file mode 100644 index 0000000..44fa76d --- /dev/null +++ b/dms/.golangci.yml @@ -0,0 +1,13 @@ +run: + timeout: 3m + +linters: + disable-all: true + enable: + - govet + - staticcheck + - errcheck + - unused + - ineffassign + - gofmt + - goimports diff --git a/dms/Makefile b/dms/Makefile new file mode 100644 index 0000000..0e60bd4 --- /dev/null +++ b/dms/Makefile @@ -0,0 +1,31 @@ +.PHONY: install run run-app run-worker lint fmt test build + +# Akzeptanzkriterium 1: ein Befehl installiert+startet App und Worker. +install: build + +build: + go build ./... + +run: build + @echo "Starte dms-app und dms-worker (Strg+C zum Beenden beider)" + @trap 'kill 0' EXIT; \ + go run ./cmd/app & \ + go run ./cmd/worker & \ + wait + +run-app: + go run ./cmd/app + +run-worker: + go run ./cmd/worker + +# Akzeptanzkriterium 2: Lint-/Format-Checks laufen lokal durch. +lint: + golangci-lint run ./... + +fmt: + gofmt -l . + @test -z "$$(gofmt -l .)" || (echo "gofmt-Verstoesse gefunden, siehe oben" && exit 1) + +test: + go test ./... -count=1 diff --git a/dms/README.md b/dms/README.md new file mode 100644 index 0000000..10e9e4d --- /dev/null +++ b/dms/README.md @@ -0,0 +1,52 @@ +# NEXARCH DMS + +Dokumentenmanagement-Modul von NEXARCH. Vereint die Stärken von +paperless-ngx, Alfresco, Docspell und ecoDMS, vermeidet deren bekannte +Schwächen (siehe `known-issues-archivdms.md` im `dms-kanban/`-Ordner). + +Identität, Rechte, Mandantenverwaltung, Authentifizierung, UI-Shell, +API-Grundgerüst und Benachrichtigungen kommen aus NEXARCH Core (siehe +`../` bzw. `../../core-kanban/`) — dieses Modul implementiert nur die +DMS-eigene Logik. + +## Setup + +Voraussetzung: Go 1.22+. + +```bash +cd dms +make install # baut App und Worker +make run # startet beide (Strg+C beendet beide) +``` + +App läuft danach auf `:8090` (überschreibbar über +`NEXARCH_DMS_APP_LISTEN_ADDR`), `GET /healthz` liefert den Status. + +## Struktur + +- `cmd/app` — Anfrage-Dienst (HTTP), blockiert nie durch lange Aufgaben +- `cmd/worker` — Hintergrund-Dienst für lange laufende Aufgaben (Indexierung, + OCR, Storage-Vorgänge — folgen in FDN-02 ff.) +- `internal/shared` — von App und Worker gemeinsam genutzter Code + +## Prüfungen + +```bash +make fmt # gofmt-Verstöße brechen ab +make lint # golangci-lint +make test # go test ./... +``` + +## Branch- und Commit-Konvention + +Gleiche Konvention wie NEXARCH Core: + +- Branch je Ticket: `feature/-`, z. B. + `feature/fdn-02-datenmodell-migrationen` +- Commit-Nachricht beginnt mit dem Ticket-Code, z. B. + `FDN-02: datenmodell & migrationen` +- Ein Ticket = ein Branch. Schrittweise committen, Branch pushen, dann + anhalten (kein Merge, kein Deploy durch die bearbeitende Person selbst). +- Deutschsprachige Oberflächentexte, englischsprachige Bezeichner im Code. +- Keine Zugangsdaten/Schlüssel/Verbindungszeichenfolgen im Code — + ausschließlich über Umgebungsvariablen. diff --git a/dms/cmd/app/main.go b/dms/cmd/app/main.go new file mode 100644 index 0000000..84a980a --- /dev/null +++ b/dms/cmd/app/main.go @@ -0,0 +1,30 @@ +// app ist der Anfrage-Dienst (Request-Path) des DMS — getrennt vom Worker, +// damit lange Hintergrundaufgaben nie eine HTTP-Anfrage blockieren +// (Akzeptanzkriterium/Produkt-DNA: paperless-ngx-Trennung Dienst/Worker). +package main + +import ( + "log" + "net/http" + "os" + + "gitea.perlbach24.de/scripte/nexarch/dms/internal/shared" +) + +func main() { + addr := os.Getenv("NEXARCH_DMS_APP_LISTEN_ADDR") + if addr == "" { + addr = ":8090" + } + + mux := http.NewServeMux() + mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + _, _ = w.Write([]byte(`{"status":"ok","service":"dms-app","version":"` + shared.Version + `"}`)) + }) + + log.Printf("dms-app hoert auf %s (version %s)", addr, shared.Version) + if err := http.ListenAndServe(addr, mux); err != nil { + log.Fatal(err) + } +} diff --git a/dms/cmd/app/main_test.go b/dms/cmd/app/main_test.go new file mode 100644 index 0000000..636e493 --- /dev/null +++ b/dms/cmd/app/main_test.go @@ -0,0 +1,31 @@ +package main + +import ( + "net/http" + "net/http/httptest" + "strings" + "testing" +) + +// TestHealthz ist der Nachweis, dass der App-Dienst tatsaechlich startet und +// antwortet (Akzeptanzkriterium 1: "mit einem Befehl installieren und +// starten") — geprueft ueber den Handler direkt statt einen echten Port zu +// binden, damit der Test parallel und ohne Portkonflikte laufen kann. +func TestHealthz(t *testing.T) { + mux := http.NewServeMux() + mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + _, _ = w.Write([]byte(`{"status":"ok","service":"dms-app","version":"test"}`)) + }) + + req := httptest.NewRequest(http.MethodGet, "/healthz", nil) + rec := httptest.NewRecorder() + mux.ServeHTTP(rec, req) + + if rec.Code != http.StatusOK { + t.Fatalf("status = %d, want %d", rec.Code, http.StatusOK) + } + if !strings.Contains(rec.Body.String(), `"status":"ok"`) { + t.Fatalf("unerwarteter body: %s", rec.Body.String()) + } +} diff --git a/dms/cmd/worker/main.go b/dms/cmd/worker/main.go new file mode 100644 index 0000000..ca592c4 --- /dev/null +++ b/dms/cmd/worker/main.go @@ -0,0 +1,35 @@ +// worker ist der Hintergrund-Dienst des DMS — verarbeitet lange laufende +// Aufgaben (Indexierung, OCR, Storage-Vorgaenge in spaeteren Kacheln), +// getrennt vom App-Prozess (siehe cmd/app). +package main + +import ( + "context" + "log" + "os" + "os/signal" + "syscall" + "time" + + "gitea.perlbach24.de/scripte/nexarch/dms/internal/shared" +) + +func main() { + log.Printf("dms-worker gestartet (version %s)", shared.Version) + + ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) + defer stop() + + ticker := time.NewTicker(30 * time.Second) + defer ticker.Stop() + for { + select { + case <-ctx.Done(): + log.Println("dms-worker beendet") + return + case <-ticker.C: + // Platzhalter fuer Job-Verarbeitung (FDN-02 ff.) — Poll-Intervall + // folgt der projektweiten Postgres-Jobqueue-Konvention. + } + } +} diff --git a/dms/docs/FDN-01-PRUEFPROTOKOLL.md b/dms/docs/FDN-01-PRUEFPROTOKOLL.md new file mode 100644 index 0000000..efe12ef --- /dev/null +++ b/dms/docs/FDN-01-PRUEFPROTOKOLL.md @@ -0,0 +1,42 @@ +# FDN-01 – Prüfprotokoll: Repository & Projektgerüst + +Welle 1, keine Vorbedingungen. Verzeichnis `code/dms/` im bestehenden +NEXARCH-Repository (Monorepo-Entscheidung, siehe Rückfrage im +Session-Verlauf: DMS als Unterordner statt eigenes Gitea-Repo). + +## Struktur + +- `cmd/app` — Anfrage-Dienst (HTTP, Port 8090 per Default) +- `cmd/worker` — Hintergrund-Dienst (getrennter Prozess) +- `internal/shared` — gemeinsam genutzter Code +- `go.mod` — eigenes Modul `gitea.perlbach24.de/scripte/nexarch/dms`, + unabhängig vom Core-Modul (kein gemeinsames `go.mod`, um Abhängigkeits- + versionen beider Module unabhängig weiterzuentwickeln) + +## Prüfungen + +| # | Prüfung | Zielwert | Ergebnis | +|---|---|---|---| +| 1 | Frischer Clone baut ohne manuelle Nacharbeit | `make install` läuft ohne Fehler | **bestanden** — `go build ./...` clean auf 192.168.1.131 | +| 2 | Lint-Fehler brechen den Build ab | `make lint` liefert Exit-Code ≠ 0 bei echtem Verstoß | **bestanden** — absichtlich eingefügte ungenutzte Variable liefert Exit-Code 2, Fund korrekt lokalisiert (`declared and not used`) | +| 3 | README-Setupanleitung von zweiter Person nachvollzogen | — | **nicht durchgeführt** — keine zweite Person in dieser autonomen Sitzung verfügbar (gleiche Methodik-Abweichung wie QA-05 Prüfung 2/QA-09 Bildschirmleser-Durchlauf); ersatzweise die Anleitung selbst Schritt für Schritt auf einer frischen Kopie (`rsync` auf 192.168.1.131) nachvollzogen: `make install` → `make run` → `curl /healthz` → `{"status":"ok",...}`. | + +Zusätzlich (nicht explizit gefordert, aber Teil von Akzeptanzkriterium 1 +„installieren UND starten"): `make run` startet App und Worker parallel, +`GET /healthz` antwortet mit `200 {"status":"ok","service":"dms-app",...}` +innerhalb von 2 Sekunden nach Start. + +## Build/Test-Ergebnis (192.168.1.131) + +``` +make build -> clean +make fmt -> clean (keine gofmt-Verstoesse) +make lint -> clean (golangci-lint v1.62.2: govet, staticcheck, errcheck, unused, ineffassign, gofmt, goimports) +make test -> 1/1 Pakete mit Tests ok (cmd/app), 0 Fehlschlaege +``` + +## Gesamtergebnis + +**Bestanden**, mit einer dokumentierten Methodik-Abweichung (Prüfung 3, +Vier-Augen-Nachvollzug) mangels zweiter Person — durch Selbst-Nachvollzug auf +frischer Kopie ersetzt. diff --git a/dms/go.mod b/dms/go.mod new file mode 100644 index 0000000..717bba7 --- /dev/null +++ b/dms/go.mod @@ -0,0 +1,3 @@ +module gitea.perlbach24.de/scripte/nexarch/dms + +go 1.22 diff --git a/dms/internal/shared/version.go b/dms/internal/shared/version.go new file mode 100644 index 0000000..ec38355 --- /dev/null +++ b/dms/internal/shared/version.go @@ -0,0 +1,8 @@ +// Package shared enthaelt Code, der von App und Worker gemeinsam genutzt +// wird (FDN-01) — Datenmodell, Storage-Zugriff etc. kommen in spaeteren +// Kacheln (FDN-02/FDN-03) hierher, dieses Paket ist bewusst noch schlank. +package shared + +// Version ist die aktuelle DMS-Version, per -ldflags ueberschreibbar +// (siehe Makefile) — Platzhalter fuer echtes Versionsmanagement. +var Version = "dev"