Files
nexarch/dms/internal/retentionclient/retentionclient.go
T
sysops 9843275e9c DOC-16: ret-05-client-aufbewahrungsklasse-registrieren-vernichtungs-rueckruf
- dms/internal/retentionclient: HTTP-Client fuer Archive RET-05/RET-09
- dms/internal/retentiondestroy: RegisterOrRequeue (FDN-04-Requeue bei
  Fehlschlag, kein Absturz/stilles Verwerfen), DestroyCallbackHandler
  (physische Loeschung aller Datei-Revisionen ueber storage.Service,
  markiert Dokument als vernichtet, 2xx erst danach)
- dms/cmd/app: mountet destroy-callback, registriert beim Start
- dms/cmd/worker: verarbeitet Requeue-Jobs (Retry)
- nur dms_document registriert (DOC-01/FDN-02 kennen keinen separaten
  Anhang-Typ, kein Umbau angrenzender Bereiche)
- real getestet: registrierung gegen echten fake-RET-05-Server, echte
  Loeschung inkl. Storage-Byte-Nachweis, echter Requeue-Eintrag bei
  Fehlschlag, erfolgreicher Retry
- live auf 131 gegen echten RET-09-Dienst (Port 8095) verifiziert,
  echter curl-Vernichtungs-Rueckruf mit real geloeschter Datei
- reale Core-API-06-Deploy-Luecke dokumentiert (nicht verschwiegen):
  /internal/resync/usage auf 131 aktuell nicht gemountet

Pruefungen siehe dms/docs/DOC-16-PRUEFPROTOKOLL.md
2026-08-30 09:37:12 +02:00

79 lines
2.5 KiB
Go

// Package retentionclient ist ein schlanker HTTP-Client für Archive
// RET-05 (RET-09: archive/internal/moduleadapter.RegisterHandler, real
// als Dienst gestartet). DMS ist ein physisch getrenntes Go-Modul und
// kann Archive-internen Go-Code nicht direkt importieren.
package retentionclient
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
)
type Client struct {
BaseURL string
HTTPClient *http.Client
}
func New(baseURL string) *Client {
return &Client{BaseURL: baseURL, HTTPClient: http.DefaultClient}
}
type registerRequest struct {
ModuleName string `json:"module_name"`
ObjectType string `json:"object_type"`
RetentionClass string `json:"retention_class"`
CallbackURL string `json:"callback_url"`
}
// Registration spiegelt RET-05s Registration-Antwort.
type Registration struct {
ID string `json:"ID"`
ModuleName string `json:"ModuleName"`
ObjectType string `json:"ObjectType"`
RetentionClass string `json:"RetentionClass"`
CallbackURL string `json:"CallbackURL"`
}
// Register registriert einen Objekttyp bei Archive RET-05. Jeder Fehler
// (Transport, Timeout, Nicht-2xx) wird als Fehler zurückgegeben — der
// Aufrufer entscheidet ueber Requeue statt stillem Verwerfen
// (Akzeptanzkriterium 3).
func (c *Client) Register(ctx context.Context, moduleName, objectType, retentionClass, callbackURL string) (Registration, error) {
body, err := json.Marshal(registerRequest{
ModuleName: moduleName, ObjectType: objectType, RetentionClass: retentionClass, CallbackURL: callbackURL,
})
if err != nil {
return Registration{}, fmt.Errorf("retentionclient: request kodieren: %w", err)
}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.BaseURL+"/register", bytes.NewReader(body))
if err != nil {
return Registration{}, fmt.Errorf("retentionclient: request bauen: %w", err)
}
req.Header.Set("Content-Type", "application/json")
resp, err := c.httpClient().Do(req)
if err != nil {
return Registration{}, fmt.Errorf("retentionclient: aufruf fehlgeschlagen: %w", err)
}
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return Registration{}, fmt.Errorf("retentionclient: unerwarteter status %d", resp.StatusCode)
}
var out Registration
if err := json.NewDecoder(resp.Body).Decode(&out); err != nil {
return Registration{}, fmt.Errorf("retentionclient: antwort dekodieren: %w", err)
}
return out, nil
}
func (c *Client) httpClient() *http.Client {
if c.HTTPClient != nil {
return c.HTTPClient
}
return http.DefaultClient
}