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.
166 lines
4.5 KiB
YAML
166 lines
4.5 KiB
YAML
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"
|