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,165 @@
|
||||
openapi: "3.0.3"
|
||||
info:
|
||||
title: NEXARCH Mail API
|
||||
version: "1.0.0"
|
||||
description: >
|
||||
Mail-spezifische v1-Endpunkte für lesenden Zugriff auf archivierte
|
||||
Mails/Postfächer (INT-01). IAM-nahe Funktionen (Login,
|
||||
Tenant-Verwaltung) sind bewusst NICHT Teil dieser API — der
|
||||
Tenant-Kontext wird als bereits validierter Query-Parameter vom
|
||||
Aufrufer/Gateway mitgegeben.
|
||||
servers:
|
||||
- url: /api/v1/mail
|
||||
paths:
|
||||
/messages:
|
||||
get:
|
||||
summary: Mail-Liste
|
||||
operationId: listMessages
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Tenant"
|
||||
- name: q
|
||||
in: query
|
||||
required: false
|
||||
description: Optionaler Volltext-Suchbegriff.
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: Liste der Treffer.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/MessageListResponse"
|
||||
"400":
|
||||
$ref: "#/components/responses/BadRequest"
|
||||
"502":
|
||||
$ref: "#/components/responses/UpstreamError"
|
||||
/messages/{messageID}:
|
||||
get:
|
||||
summary: Mail-Detail
|
||||
operationId: getMessage
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Tenant"
|
||||
- $ref: "#/components/parameters/MessageID"
|
||||
responses:
|
||||
"200":
|
||||
description: Vollständige Nachricht.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/MessageDetail"
|
||||
"400":
|
||||
$ref: "#/components/responses/BadRequest"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFound"
|
||||
"502":
|
||||
$ref: "#/components/responses/UpstreamError"
|
||||
/messages/{messageID}/attachments/{index}:
|
||||
get:
|
||||
summary: Anhang-Download
|
||||
operationId: getAttachment
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Tenant"
|
||||
- $ref: "#/components/parameters/MessageID"
|
||||
- name: index
|
||||
in: path
|
||||
required: true
|
||||
description: Anhang-Index innerhalb der Nachricht (0-basiert).
|
||||
schema:
|
||||
type: integer
|
||||
minimum: 0
|
||||
responses:
|
||||
"200":
|
||||
description: Anhangsinhalt.
|
||||
content:
|
||||
application/octet-stream:
|
||||
schema:
|
||||
type: string
|
||||
format: binary
|
||||
"400":
|
||||
$ref: "#/components/responses/BadRequest"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFound"
|
||||
"502":
|
||||
$ref: "#/components/responses/UpstreamError"
|
||||
components:
|
||||
parameters:
|
||||
Tenant:
|
||||
name: tenant
|
||||
in: query
|
||||
required: true
|
||||
description: >
|
||||
Mandanten-Kennung (bereits validiert vom Aufrufer/Gateway —
|
||||
keine Anmeldung/Sitzungsprüfung Bestandteil dieser API).
|
||||
schema:
|
||||
type: string
|
||||
minLength: 1
|
||||
MessageID:
|
||||
name: messageID
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
minLength: 1
|
||||
schemas:
|
||||
MessageListItem:
|
||||
type: object
|
||||
required: [messageId, subject, sentAt]
|
||||
properties:
|
||||
messageId:
|
||||
type: string
|
||||
subject:
|
||||
type: string
|
||||
sentAt:
|
||||
type: integer
|
||||
format: int64
|
||||
MessageListResponse:
|
||||
type: object
|
||||
required: [messages]
|
||||
properties:
|
||||
messages:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/MessageListItem"
|
||||
MessageDetail:
|
||||
type: object
|
||||
required: [messageId, subject, body, sender, mailbox, sentAt]
|
||||
properties:
|
||||
messageId:
|
||||
type: string
|
||||
subject:
|
||||
type: string
|
||||
body:
|
||||
type: string
|
||||
sender:
|
||||
type: string
|
||||
mailbox:
|
||||
type: string
|
||||
sentAt:
|
||||
type: integer
|
||||
format: int64
|
||||
Error:
|
||||
type: object
|
||||
required: [error]
|
||||
properties:
|
||||
error:
|
||||
type: string
|
||||
responses:
|
||||
BadRequest:
|
||||
description: Ungültige oder fehlende Anfrageparameter (u. a. fehlender Tenant-Kontext).
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
NotFound:
|
||||
description: Nachricht oder Anhang für diesen Mandanten nicht gefunden.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
UpstreamError:
|
||||
description: Ein nachgelagerter Dienst (Suchindex/Objektspeicher) hat einen Fehler geliefert.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
Reference in New Issue
Block a user