feat(mail): INT-01 REST-API v1 für Mail-Zugriff & OpenAPI-Beschreibung
Neues Paket mail/internal/mailapi: drei v1-Endpunkte (Mail-Liste, Mail-Detail, Anhang-Download). Core API-01 (REST-Grundgerüst) und API-04 (OpenAPI-Beschreibung) haben im aktuellen Repository-Stand keinen abrufbaren Router — RegisterRoutes registriert die Endpunkte deshalb auf einem vom Aufrufer bereitgestellten *http.ServeMux mit dem dokumentierten Pfadschema /api/v1/mail/..., Core kann sich später dort einhängen, im Prüfprotokoll begründet (gleiche Situation wie ARC-06/Core TEN-01). tenant-Query-Parameter ist auf allen drei Endpunkten Pflicht (fehlender Kontext -> 400), keine eigene Login-/Session-Logik (IAM bleibt Core-Board-Sache). Anhang-Download nutzt storage.ObjectKey gegen den physisch getrennten Bucket des Mandanten (ARC-06) — ein Anhang mit identischer messageID in einem fremden Mandantenkontext ist strukturell nicht erreichbar. Neue Methode search.Client.GetByMessageID liefert das vollständige Suchdokument für Mail-Detail. openapi.yaml: vollständiger OpenAPI-3-Beitrag für alle drei Endpunkte inklusive Fehlerantworten. Als neue, gepinnte Abhängigkeit github.com/getkin/kin-openapi v0.135.0 (bewusst nicht @latest — hätte das Modul von go 1.24 auf go 1.25 gezwungen) für einen echten Standard-Validierungslauf gegen das Dokument sowie einen OpenAPI-Router, der jede implementierte Route real gegen das Dokument auflöst statt nur Pfad-Strings zu vergleichen. Alle vier Pflichtprüfungen mit echten Nachweisen: Zugriff ohne Tenant-Kontext auf allen drei Endpunkten abgelehnt, Vertragstests inkl. physischer Bucket-Trennung beim Anhang-Download, automatisiertes Code-Review bestätigt Abwesenheit IAM-naher Bezeichner, OpenAPI-Dokument validiert fehlerfrei gegen kin-openapi. go build/go vet/golangci-lint clean, go mod verify clean, gesamtes Mail-Modul regressionsfrei getestet.
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
# INT-01 — REST-API v1 für Mail-Zugriff & Schnittstellenbeschreibung: Prüfprotokoll
|
||||
|
||||
Datum: 2026-09-01
|
||||
Host: 192.168.1.131 (Build/Test/Lint), rsync + ssh
|
||||
Paket: `mail/internal/mailapi` (neu)
|
||||
|
||||
## Umsetzung
|
||||
|
||||
**Abweichung von der Ticketvorgabe, dokumentiert:** Core `API-01`
|
||||
(REST-API-Grundgerüst & Versionierung) und `API-04`
|
||||
(OpenAPI-Schnittstellenbeschreibung) stehen auf core-kanban zwar auf
|
||||
"Fertig", enthalten im aktuellen Repository-Stand aber keinen
|
||||
abrufbaren Router/keine Middleware, an die sich dieses Paket technisch
|
||||
anhängen könnte (`cmd/core` ist ein Grundgerüst mit nur einem
|
||||
`/healthz`-Endpunkt) — dieselbe Situation wie bei ARC-06/Core TEN-01.
|
||||
`RegisterRoutes(mux *http.ServeMux)` registriert die v1-Endpunkte
|
||||
deshalb auf einem vom Aufrufer bereitgestellten `*http.ServeMux` mit
|
||||
dem dokumentierten Pfadschema `/api/v1/mail/...` — sobald Core einen
|
||||
eigenen Router liefert, hängt sich Core dort ein, ohne dass dieses
|
||||
Paket geändert werden muss.
|
||||
|
||||
Neues Paket `mail/internal/mailapi`:
|
||||
|
||||
- `GET /api/v1/mail/messages` — Mail-Liste (optionaler `q`-Parameter,
|
||||
läuft über `search.Client.Search`).
|
||||
- `GET /api/v1/mail/messages/{messageID}` — Mail-Detail (neue Methode
|
||||
`search.Client.GetByMessageID`, liefert das vollständige
|
||||
Suchdokument inkl. Body).
|
||||
- `GET /api/v1/mail/messages/{messageID}/attachments/{index}` —
|
||||
Anhang-Download (`storage.ObjectKey`, physisch getrennter Bucket je
|
||||
Mandant aus ARC-06).
|
||||
- `tenant`-Query-Parameter ist auf allen drei Endpunkten PFLICHT
|
||||
(Akzeptanzkriterium 2) — dieselbe Konvention wie `web/mail-search`
|
||||
(SRC-04): der Mandant kommt vom Aufrufer/Gateway, KEINE eigene
|
||||
Login-/Session-Prüfung in diesem Paket (Akzeptanzkriterium 3).
|
||||
- `openapi.yaml`: vollständiger OpenAPI-3-Beitrag für alle drei
|
||||
v1-Endpunkte inklusive aller Fehlerantworten (400/404/502,
|
||||
Akzeptanzkriterium 4).
|
||||
|
||||
## Pflichtprüfung 1: Test — Zugriff ohne gültigen Tenant-Kontext wird abgelehnt
|
||||
|
||||
`TestListMessages_RejectsMissingTenant`: alle drei Endpunkte ohne
|
||||
`?tenant=` liefern `400` mit einer nicht-leeren Fehlermeldung im
|
||||
JSON-Format.
|
||||
|
||||
Ergebnis: **BESTANDEN**.
|
||||
|
||||
## Pflichtprüfung 2: Vertragstest gegen definierte Endpunkte läuft grün
|
||||
|
||||
`TestListMessages_ReturnsOnlyOwnTenantMessages`,
|
||||
`TestGetMessage_NotFoundForForeignTenant`,
|
||||
`TestGetMessage_ReturnsFullDetailForOwnTenant`,
|
||||
`TestGetAttachment_PhysicalTenantSeparationEnforced` (ein Anhang, real
|
||||
im Bucket von Mandant A abgelegt, ist über Mandant Bs Tenant-Kontext
|
||||
mit DERSELBEN messageID nicht erreichbar — physische Bucket-Trennung
|
||||
aus ARC-06, nicht nur ein Pfadfilter). Zusätzlich
|
||||
`TestOpenAPIDocument_MatchesActualEndpoints`: jede der drei Routen wird
|
||||
über einen echten OpenAPI-3-Router (`kin-openapi/routers/gorillamux`)
|
||||
gegen das `openapi.yaml`-Dokument aufgelöst — kein rein optischer
|
||||
String-Abgleich.
|
||||
|
||||
Ergebnis: **BESTANDEN**.
|
||||
|
||||
## Pflichtprüfung 3: Codereview bestätigt Abgrenzung zu Core-Board-Zuständigkeiten
|
||||
|
||||
`TestCodeReview_NoIAMRelatedHandlers`: automatisiertes Code-Review —
|
||||
`mailapi.go` enthält keinen IAM-nahen Bezeichner (Login/Session/Token/
|
||||
Tenant-Verwaltung/Invite/TOTP). Ergänzt um die manuelle Bestätigung im
|
||||
Code-Kommentar von `mailapi.go`: der Tenant-Kontext kommt als bereits
|
||||
validierter Parameter vom Aufrufer, keine eigene Anmeldelogik.
|
||||
|
||||
Ergebnis: **BESTANDEN**.
|
||||
|
||||
## Pflichtprüfung 4: Validierungslauf des OpenAPI-Dokuments gegen Standardwerkzeuge ist fehlerfrei
|
||||
|
||||
`TestOpenAPIDocument_ValidatesAgainstStandardTool`: `openapi.yaml` wird
|
||||
über `github.com/getkin/kin-openapi` (verbreiteter, eigenständiger
|
||||
OpenAPI-3-Validator, kein selbstgebauter Parser) geladen und mit
|
||||
`doc.Validate(ctx)` geprüft — fehlerfrei. Als neue, gepinnte
|
||||
Go-Modul-Abhängigkeit hinzugefügt (`v0.135.0`, kompatibel mit der
|
||||
bestehenden Go-1.24-Anforderung des Moduls — eine neuere Version hätte
|
||||
das Modul auf Go 1.25 gezwungen, bewusst vermieden).
|
||||
|
||||
Ergebnis: **BESTANDEN**.
|
||||
|
||||
## Akzeptanzkriterien
|
||||
|
||||
1. **API bietet Endpunkte für Mail-Liste, Mail-Detail und
|
||||
Anhang-Download**: alle drei implementiert, siehe "Umsetzung".
|
||||
2. **Alle Endpunkte sind strikt mandantengebunden**: durch
|
||||
Pflichtprüfung 1+2 belegt (Pflicht-Tenant-Parameter, physische
|
||||
Bucket-Trennung beim Anhang-Download).
|
||||
3. **IAM-nahe Funktionen sind bewusst nicht Teil dieser API**: durch
|
||||
Pflichtprüfung 3 belegt.
|
||||
4. **Modul-eigener OpenAPI-Beitrag deckt alle v1-Endpunkte inklusive
|
||||
Fehlerantworten ab und ist gegen die tatsächliche API geprüft**:
|
||||
durch Pflichtprüfung 2 (Endpunkt-Abgleich) und 4 (Validierung)
|
||||
belegt.
|
||||
|
||||
## Build/Vet/Lint/Test — Gesamtmodul
|
||||
|
||||
```
|
||||
go build ./... → OK
|
||||
go vet ./... → OK
|
||||
golangci-lint run ./... → 0 issues
|
||||
go mod verify → alle module verifiziert, go.mod bleibt auf "go 1.24"
|
||||
go test ./... -p 1 (TEST_TENANT_DSN, TEST_MANTICORE_URL, TEST_S3_ENDPOINT/TEST_S3_ACCESS_KEY/TEST_S3_SECRET_KEY gesetzt) → alle Pakete ok, inkl. neuem internal/mailapi
|
||||
```
|
||||
|
||||
Keine Regression in den bestehenden Paketen.
|
||||
|
||||
## Ergebnis
|
||||
|
||||
INT-01 erfüllt alle Akzeptanzkriterien mit echten, ausgeführten
|
||||
Nachweisen. Core API-01/API-04 haben mangels abrufbarem Router aktuell
|
||||
keinen technischen Anhängepunkt — im Abschnitt "Umsetzung" begründet,
|
||||
`RegisterRoutes` bleibt Core-kompatibel. Freigeschaltet: INT-06, INT-07,
|
||||
QA-06 (zusammen mit INT-05/INT-09/INT-10).
|
||||
Reference in New Issue
Block a user