Files
HiveGrid-Wireframes/hivegrid-cloud/docs/boilerplate-mapping/M34-public-api.md
T

19 KiB

Boilerplate-Abgleich: M34 — Public-API & Webhooks

Feld Wert
Modul-ID M34
Name Public-API & Webhooks
Milestones M161 (OpenAPI + Read-Endpoints), M162 (API-Key-Auth + Scopes + Rate-Limit), M163 (Webhooks ein-/ausgehend, signiert)
Pflichtenheft-Block Block 7, Modul 34 (_bmad-output/pflichtenheft/blocks/block7.md Z. 264-311)
Reuse-Level medium

Kurzfazit

Die Boilerplate bringt ein echtes, dediziertes Public-API-Fundament mit: eine eigenständige Hono-App (apps/api) mit OpenAPI-Generierung, Service-Token-/Tenant-API-Key-Auth, Scope-Autorisierung, Rate-Limit-Bausteinen (429 + Retry-After), Error-Envelope, Request-ID-Korrelation, Idempotenz, API-Request-Logging (ApiKeyLog mit den richtigen Indizes), und im Worker eine generische signierte Webhook-Auslieferung mit Backoff (deliver-webhook, 5 Versuche). Das deckt das Querschnitts-Gerüst der drei Milestones zu großen Teilen ab.

ABER: Die fachliche Substanz von M34 fehlt komplett. Die existierenden API-Endpoints sind generisch (/v1/entities/:entity/rows, EntityBuilder-Rows) — es gibt keine typisierten HiveGrid-Read-Endpoints (/api/v1/contacts, deals, projects, leads …), weil die HiveGrid-Domänenentitäten selbst noch nicht existieren (app.prisma ist leerer Platzhalter). Cursor-Pagination, Sparse Fieldsets, Embed-Relations und Scope-basiertes Field-Redact sind nicht vorhanden (nur page/pageSize-Pagination). Das gesamte M34-Datenmodell (WebhookSubscription, WebhookDelivery, WebhookDeliveryAttempt, IncomingWebhookIngestion, IntegrationApiRequest) existiert nicht in der Boilerplate. Das vorhandene Webhook-Modell ist Event/EventWebhookAttempt (Legacy) bzw. form-submission-gebunden — kein Subscription-Modell mit Event-Types, Auto-Disable und HMAC-Secret-pro-Subscription. Swagger-UI mit „Try it out" fehlt (nur Roh-JSON-Viewer unter /v1/docs).


Übernehmbar aus Boilerplate

Boilerplate-Pfad Was Wie nutzbar
apps/api/src/app.ts Hono-App-Komposition (new Hono<ApiEnv>()), Middleware-Kette, register*Routes(app)-Muster, listener-frei für Tests 1:1 (App-Host) — neue HiveGrid-Read-Routes via eigenes registerHiveGridReadRoutes(app) einhängen
apps/api/src/server.ts HTTP-Listener-Entry (API_PORT/PORT/3001) 1:1
apps/api/src/openapi.ts (+ .test.ts) OpenAPI-Contract-Bausteine: Error-Envelope-Schema (code/message/requestId), Rate-Limit-429-Response mit Retry-After, apiErrorResponse()-Helper, createOpenApiDocument() als-vorlage / anpassen — Envelope 1:1; HiveGrid-Endpoint-Schemas (contacts/deals/…) müssen ergänzt werden
apps/api/src/routes/system-routes.ts GET /v1/openapi.json + GET /v1/docs (Doku-Seite) anpassen — /openapi.json 1:1; /v1/docs ist NUR Roh-JSON-Viewer → für „Try it out" durch echte Swagger-UI (swagger-ui-dist) ersetzen
apps/api/src/auth.ts extractBearerToken, extractApiKeyFromRequest, isValidServiceToken, createServicePrincipal, Typ ServicePrincipal 1:1 — Bearer/Key-Extraktion direkt nutzbar; Format Authorization: Bearer hg_<...> deckungsgleich mit Spec B.1
apps/api/src/auth/scope.ts (+ .test.ts) authorizeApiScope(), resolveApiTenantScope(), deny-Reasons (api_key_inactive/expired/tenant_deactivated/tenant_mismatch/…), ApiScopedPrincipal-Union als-vorlage — Tenant-Scope-Resolution + Key-Lifecycle 1:1; HiveGrid-Scopes (read_only/read_full/webhook_inbound/automation_trigger) müssen ergänzt werden (BP-Scopes sind read/create/update/delete pro Entity)
apps/api/src/auth/permission.ts, login-rate-limit.ts Permission-Wiring + Token-/Window-Rate-Limit-Logik (IP-/Account-Scope, retryAfterSeconds) als-vorlage — Rate-Limit-Algorithmus + 429-Shape übernehmen, auf Per-Key/Per-Tenant/Per-Slug erweitern (Redis-Counter)
apps/api/src/routes/shared.ts createLoginRateLimitResponse() (429 + Retry-After + rate_limited-Envelope), authenticateServiceCredentialRequest(), JSON-Body-Parsing, Idempotenz-Helfer als-vorlage — 429-Antwort-Shape und Auth-Helfer direkt als Muster
apps/api/src/middleware/error-envelope.ts apiError(c, status, code, message), createErrorHandler/createNotFoundHandler 1:1 — deckt M34 Antwort-Format {error:{code,message,details}} (34.1.7) ab
apps/api/src/middleware/request-id.ts, audit-context.ts, body-limit.ts, metrics.ts, sentryTracing.ts Standard-API-Middleware-Stack (Request-Korrelation, Audit-Kontext, Body-Limit, Metrik, Tracing) 1:1
apps/api/src/route-access-inventory.ts (+ .test.ts) routeAccessInventory + 11 Auth-Klassen inkl. tenant-api-key, service-or-tenant-api-key, webhook-signature, optional-api-key-validation, public-docs als-vorlage — neue HiveGrid-Routes müssen hier mit Auth-Klasse eingetragen werden (CI-Gate verify:api-inventory/verify:openapi-security)
apps/api/src/idempotency/store.ts, shared-store-client.ts HTTP-Idempotenz-Cache (für Webhook-Empfang + Event-Ingestion-Idempotenz) 1:1
apps/api/src/usage/usage-route.ts Vollständiger API-Key-Request-Flow als Referenz: Key auflösen → ApiKeyLog anlegen → Tenant-Deactivated/Expired/Inactive prüfen → Usage/402 → Log-Status setzen als-vorlage — exaktes Muster für „Loader prüft Key-Existenz, Scope, Tenant, Aktiv-Status" (Spec B) + Request-Logging
apps/api/src/webhooks/mailersend-signature.ts (+ .test.ts) HMAC-SHA256-Signatur-Verifikation mit timingSafeEqual (Constant-Time-Compare), Timestamp-Toleranz, typisierte Failure-Reasons als-vorlage — direkt das Muster für M34 eingehende X-HiveGrid-Signature: sha256=<hex>-Verifikation (Spec B.2)
packages/marketing-outbound/src/adapters/custom-webhook.ts Ausgehender Webhook-POST mit X-Marketing-Signature: sha256=<hmac(body)>, SSRF-Guard (adapterFetch, HTTPS-only, kein RFC1918) als-vorlage — exaktes Muster für M34 ausgehende HMAC-signierte Deliveries (Spec E, Signatur + SSRF-Schutz)
apps/worker/src/jobs/form-submission-webhook-delivery.ts (+ .test.ts) Outbox→Webhook-Delivery-Bridge auf deliver-webhook-Job, Tenant-Mismatch-Validierung als-vorlage — Muster für „BullMQ-Job pro Webhook-Versand" (M163-Hinweis)
packages/queue/src/payloads.ts → WebhookDeliveryJob Typisierter webhook.deliver-Job (url/method/headers/body/eventName/metadata) 1:1 — direkt für ausgehende Webhook-Deliveries
packages/queue/src/producers.ts (buildRetryJobOptions) deliver-webhook: 5 Versuche, exponentielles Backoff + Idempotenz via buildIdempotentJobId() anpassen — 5x deckt Spec E ab; Backoff-Stufen (1m/5m/30m/2h/12h) müssen exakt gesetzt werden (BP-Default ist delay: 2_000 exponentiell)
apps/api/src/webhookDeliveryQueue.ts enqueueJob()-Wrapper für Webhook-Auslieferung mit Idempotenz-Key + TenantId als-vorlage
packages/db/src/event-webhook-attempts.server.ts Repository-Muster für Webhook-Attempt-Persistenz (tenant-scoped find/update) als-vorlage — Muster für neue WebhookDelivery/WebhookDeliveryAttempt-Repos
packages/db/src/api-keys.server.ts API-Key-Repository: findLegacyApiKeyByKey, Key-Hashing (keyHash/keyPrefix/keyLastFour), ApiKeyLog-CRUD, Usage-Aggregation als-vorlage / anpassen — Key-Hashing + Logging 1:1; HiveGrid-Scope-Spalte ergänzen (BP hat per-Entity-Rechte, kein Scope-Enum)
packages/db/src/outbox.ts (publishOutboxEvent) + apps/worker/src/outbox/event-router.ts Transaktionales Outbox + Event-Routing (webhook.-Prefix → outbox.webhook-Queue, longest-prefix-wins) 1:1 — für ausgehende Webhook-Events (contact.created etc.) als Dispatch-Mechanismus
packages/db/src/audit-events.server.ts + AuditEvent (Hash-Kette) Auditierung von Key-Anlage, Webhook-Setup, Inbound-Events (DoD C.13, AV #6) 1:1
apps/api/Dockerfile-Target + .gitea/workflows/ci.yml api-Job Build-/CI-Fundament: verify:openapi-security → typecheck → vitest apps/api/src → build 1:1
infra/grafana/api-latency.json + infra/prometheus/ API-Latenz-/Queue-Health-Dashboards (Metering-Vorbereitung Phase 2) 1:1

Vorhandene Daten-Modelle (Prisma)

Alle in /Users/raffaelsheikh/Documents/GitHub/boilerplate/prisma/schema/.

Modell Datei Deckt M34-Bedarf ab?
ApiKey core.prisma (Z. 100-126) Teilweise. Gehashte Keys (keyHash/keyPrefix/keyLastFour/keyVersion), active, expires, @@unique([tenantId, alias]). Fehlt: Scope-Spalte (BP nutzt ApiKeyEntity-Join mit create/read/update/delete pro Entity, NICHT die M34-Scopes read_only/read_full/webhook_inbound/automation_trigger) und Per-Key-Rate-Limit-Override-Feld. Spec B verweist explizit auf „API-Key-Verwaltung aus M27 Block E" → Scope-Modell gehört zu M27.
ApiKeyLog core.prisma (Z. 128-151) Gut. Deckt M34 IntegrationApiRequest weitgehend: endpoint, method, params, status, duration, error, ip, tenantId, apiKeyId + passende Indizes inkl. (apiKeyId, tenantId, createdAt DESC) und (tenantId, createdAt). Fehlt ggü. Spec A: route_pattern (statt voll-aufgelöstem endpoint), query_params als JSONB (BP: params String), request_body_size_bytes/response_size_bytes, user_agent, Retention-Logik (90/180 Tage). Entweder ApiKeyLog erweitern oder eigenes IntegrationApiRequest bauen.
Event + EventWebhookAttempt core.prisma (Z. 152-178) Schwach / Legacy. Event (name/data/resource) + EventWebhookAttempt (endpoint/success/status/message/body). KEIN Subscription-Modell, keine Event-Types-Liste, kein HMAC-Secret-pro-Subscription, kein Auto-Disable-Counter, kein Idempotenz-event_id. Nur als grobe Vorlage für WebhookDelivery/WebhookDeliveryAttempt tauglich.
EntityWebhook + EntityWebhookLog entityBuilder.prisma (Z. 206-224) Nicht passend. Pro-Entity-Action-Webhook im EntityBuilder (entityId/action/method/endpoint). Kein Tenant-Subscription-Modell, kein Secret, kein Status-Enum/Retry.
Form + FormSubmission formWidget.prisma Teil-Vorlage für eingehenden Lead-Push. Form (key @unique, definition JSON, fieldMapping, allowedOrigins[], Anti-Spam-config), FormSubmission (payload JSON, ipHash, status received/processed/failed/spam). Deckt das Slug-/Mapping-/Status-Muster von M34 IncomingWebhookIngestion konzeptionell ab, ist aber Form-Widget-gebunden, nicht Webhook-Slug-gebunden mit 3 Auth-Methoden.
App / DataConnection / AppSyncRun appsEngine.prisma Randnah. Externe Datensync-Engine (rest-api/oauth2/webhook, Rollback). Nicht für M34-Public-API, eher Phase-2-Inbound-Connectors.
Lead / LeadEvent marketingLeads.prisma Beachten — Konflikt. BP-Lead ist operator-scoped (KEIN tenantId), M34 Lead-Push erzeugt tenant-scoped Leads (Modul 2/M042). M34-Webhook muss auf den HiveGrid-CRM-Lead schreiben, nicht auf diesen Marketing-Lead.
OutboxEvent outbox.prisma 1:1. Transaktionaler Event-Auslöser für ausgehende Webhooks.
IdempotencyKey core.prisma 1:1. HTTP-Idempotenz für Webhook-Empfang/Event-Ingestion.
FeatureFlag featureFlags.prisma 1:1. DoD-Pflicht „Feature-Flag-fähig" (M006).

Komplett fehlende M34-Modelle (in prisma/schema/ NICHT vorhanden — verifiziert)

WebhookSubscription, WebhookDelivery, WebhookDeliveryAttempt, IncomingWebhookIngestion, IntegrationApiRequest — keiner dieser Namen existiert im Schema. Anlageort: prisma/schema/app.prisma (aktuell leerer Platzhalter // custom database models).


Lücken / komplett neu zu bauen

  1. HiveGrid-Domänenentitäten als Voraussetzung. Die typisierten Read-Endpoints (/api/v1/contacts|companies|deals|projects|tasks|leads) setzen voraus, dass diese Module (M042-M074) existieren. app.prisma ist leer → es gibt nichts zum Lesen. M161 hängt hart an den Daten-Modulen (PLAN: „Vorbedingung Daten-Module M042-M074").
  2. Typisierte Read-API-Endpoints. BP bietet nur generische EntityBuilder-Row-Endpoints (/v1/entities/:entity/rows). Die HiveGrid-Endpoints müssen neu gebaut werden (eigenes Route-Modul register*Routes).
  3. Cursor-Pagination. BP hat nur page/pageSize (offset-basiert, pagination/rows.ts). Spec verlangt opaque base64-Cursor + meta.next_cursor → neu.
  4. Sparse Fieldsets (fields=), Embed-Relations (embed=, Tiefe 1), erweiterte Filter (Multi-Value-OR, Date-Range *_gte/_lte, custom.{key}, q-Volltext), Sortierung (sort=-feld) — keiner dieser Mechanismen existiert generisch. Neu.
  5. M34-Scope-Modell (read_only/read_full/webhook_inbound/automation_trigger) + Field-Redact sensibler Felder bei read_only (nicht 403, sondern Feld-Auslassung). BP-Scope ist entity-CRUD-basiert. Neu (kommt fachlich aus M27 Block E, hier konkretisiert).
  6. Rate-Limiting Per-Key / Per-Tenant / Per-Slug mit Token-Bucket + Redis-Counter und Headern X-RateLimit-Limit/Remaining/Reset. BP hat nur Login-Rate-Limit (IP/Account) und Retry-After im 429. Die generischen X-RateLimit-*-Header existieren NICHT (nur in OpenAPI-Schema beschrieben). Neu — Algorithmus von login-rate-limit.ts als Vorlage.
  7. IntegrationApiRequest-Modell (oder Erweiterung von ApiKeyLog) mit route_pattern, query_params JSONB, Größen-Feldern, user_agent + Retention-Job (90/180 Tage). Neu.
  8. Webhook-Subscription-Modell + UI. WebhookSubscription (Event-Types[], HMAC-Secret, Auto-Disable-Counter, Stats), WebhookDelivery (Status-Enum pending/delivered/failed/exhausted/discarded), WebhookDeliveryAttempt. Komplett neu. Inkl. Subscription-Verwaltungs-UI unter /{tenant}/admin/webhooks/, Delivery-Stats-View, Test-Funktion (test.ping), Replay (Phase-2-Out-of-Scope). Auto-Disable nach 10 konsekutiven Fehlern + notify() (M011).
  9. Eingehende Webhook-Slugs. IncomingWebhookIngestion + Slug-Verwaltung mit 3 Auth-Methoden (API-Key / HMAC / URL-Token mit Klartext-Warnung), payload_mapping, Auto-Lead-Anlage + Duplikat-Check (Email-Match → Activity statt neuem Lead), Default-Tags/Assignee. HMAC-Verify-Muster aus mailersend-signature.ts übernehmbar, Rest neu.
  10. Backoff-Stufen exakt. BP deliver-webhook = 5 Versuche exponentiell delay 2000 — Spec verlangt feste Stufen 1m/5m/30m/2h/12h. Job-Options anpassen/custom-Backoff.
  11. Event-Type-Katalog + Payload-Envelope (event_id/event_type/tenant_id/occurred_at/data/previous_data) mit Mapping auf die ~30 HiveGrid-Events (contact.created … call.missed). Neu — Trigger-Punkte in jedem Quell-Modul.
  12. Allgemeine Event-Ingestion POST /api/v1/integrations/events → Automation-Engine-Trigger (M075/M017 external_event). Verdrahtung neu.
  13. Swagger-UI mit „Try it out". BP /v1/docs ist nur ein Roh-JSON-<pre>-Viewer (kein interaktives Swagger-UI, kein API-Key-Eingabefeld). swagger-ui-dist einbinden (M161-Hinweis nennt es als Boilerplate-Dep — als Paket vorhanden, aber NICHT als Route verdrahtet). Neu.
  14. Versionierung/Deprecation-Header (Sunset, Deprecation: true, Stability-Tags). Nicht vorhanden. Neu (leichtgewichtig).
  15. 402-bei-Frozen-Tenant für Schreib (Spec 34.1.10) — da Phase 1 read-only ist, primär ein Webhook-Inbound-403-Pfad (frozen → eingehende Webhooks verworfen). BP-usage-route.ts hat das 402-Muster bereits (payment_required) als Vorlage.
  16. UI-Layer komplett (DoD A-E): View-Models, Adapter, Sidebar-Eintrag (packages/ui-hivegrid/src/app-shell/sidebar.config.ts), Routes, i18n-Keys, Empty/Loading-States, Visual-Regression, Hot-Swap, Smoke-Tests. Reihenfolge & Wiring per docs/INTEGRATION-CONTRACTS.md. Nichts davon HiveGrid-spezifisch vorhanden.

Empfohlenes Vorgehen

Voraussetzung prüfen: M27 (API-Keys + Scope-Definition) und die Daten-Module M042-M074 müssen stehen — sonst gibt es keine Scopes und keine Entitäten zum Lesen. Ohne diese ist M161 nicht sinnvoll baubar.

M161 — Read-API + OpenAPI (zuerst aus BP übernehmen)

  1. App-Host 1:1 nutzen: apps/api/src/app.ts + Middleware-Stack + error-envelope.ts + Request-ID stehen. Nur ein neues Route-Modul registerHiveGridReadRoutes(app) registrieren.
  2. Auth-Flow als Vorlage: usage-route.ts + auth.ts + auth/scope.ts als Blueprint für „Key auflösen → loggen → Tenant/Active/Expired prüfen". extractBearerToken/extractApiKeyFromRequest 1:1.
  3. NEU bauen: typisierte Endpoints, Cursor-Pagination, Filter/Sort/Fields/Embed-Parser, Response-Builder {data, meta}.
  4. OpenAPI: openapi.ts-Envelope + createOpenApiDocument() erweitern; swagger-ui-dist als echte Route ergänzen (BP /v1/docs ersetzen).
  5. Route-Access-Inventar (route-access-inventory.ts) für jede neue Route pflegen → sonst CI-Gate verify:openapi-security/verify:api-inventory rot.

M162 — Scopes + Field-Redact + Rate-Limit

  1. Scope-Modell an ApiKey koppeln (kommt aus M27); authorizeApiScope-Muster für read_only/read_full adaptieren.
  2. Field-Redact im Response-Builder (sensible Felder bei read_only weglassen) — neu, im VM/Serializer.
  3. Rate-Limit: Algorithmus aus auth/login-rate-limit.ts + Redis-Counter (@toolctrl/queue resolveRedisConnectionOptions) auf Per-Key/Per-Tenant/Per-Slug ausweiten; X-RateLimit-*-Header + 429-Shape aus routes/shared.ts übernehmen.
  4. Request-Logging: ApiKeyLog erweitern oder IntegrationApiRequest neu + Retention-Cron (Muster: apps/worker/src/jobs/audit-retention.ts).

M163 — Webhooks (signiert)

  1. Neue Prisma-Modelle in app.prisma: WebhookSubscription, WebhookDelivery, WebhookDeliveryAttempt, IncomingWebhookIngestion (Forward-Only-Migration mit Inverse-SQL, DoD F.28). DSGVO: neue User-FKs in packages/db/src/dsgvo/user-fk-map.ts eintragen (sonst CI rot).
  2. Eingehende Webhooks: HMAC-Verify aus webhooks/mailersend-signature.ts (Constant-Time) übernehmen; Slug-/Mapping-/Auth-Logik neu; Idempotenz via IdempotencyKey; Auto-Lead-Anlage auf HiveGrid-CRM-Lead (nicht Marketing-Lead) + Activity via logActivity.
  3. Ausgehende Webhooks: Outbox (publishOutboxEvent) → webhook.-Prefix-Routing → deliver-webhook-Job (5 Versuche). HMAC-Sign-/SSRF-Muster aus marketing-outbound/custom-webhook.ts. Backoff-Stufen auf 1m/5m/30m/2h/12h anpassen. Auto-Disable nach 10 Fehlern + notify() (M011). Delivery-/Attempt-Persistenz à la event-webhook-attempts.server.ts.
  4. Event-Ingestion POST /v1/integrations/events → Automation-Trigger (M075/M017).
  5. UI für Subscriptions/Slugs/Logs (DoD A-E) zuletzt: Subframe → Adapter → View-Model → Route → Sidebar + Permission-Gate + i18n + Tests.

Querschnitt nicht nachbauen (DoD): Audit (AuditEvent/auditEvent), Outbox, Idempotenz, FeatureFlag, Notifications (notify), Tenant-Scope — alles in BP vorhanden und Pflicht-Wiring.