Vacancy-Application Submission via Personio-Inbox-Bridge mit Webhook-ACK (Pfad C+)
Status: superseded superseded by ADR-0050 customer-lens-reviewer: APPROVE-WITH-CAVEATS (2026-05-25)TL;DR (historisch) — Drupal-zu-Personio-Application-Submit läuft im MVP via SMTP an die Personio-Inbox des SOLCOM-Tenants; der deterministische ACK kommt über den Personio-Webhook
application.created zurück. Ein direkter HTTP-POST gegen die Personio Recruiting API ist mit SOLCOMs Standard-Recruiting-Credentials nicht erreichbar, weil der Endpoint hinter dem Personio-Multiposting-Partner-Scope gated ist (17 Live-Probes vom 2026-05-25 belegen das mit HTTP 401, nicht 404). Die Email-Inbox-Bridge ist damit der einzig durchgängig funktionierende Submit-Pfad und bleibt MVP-Architektur, sofern Personio den Multiposting-Scope nicht nachträglich aktiviert.
Kontext
F-100 / P2503-90 („Bewerber-Flow“) verlangt eine Drupal-native Bewerbungsseite pro Stelle. Karriere-Interessent:innen sollen vom Apply-CTA auf einer Vacancy-Detailseite (/karriere/<slug>) ohne Medienbruch direkt zu einer Bewerbungsseite auf der SOLCOM-Drupal-Site gelangen, das Formular ausfüllen, ihre Bewerbung absenden und im Personio-Recruiting-Backend wie eine über die Personio-Hosted-Page abgegebene Bewerbung erscheinen.
Die ursprüngliche Anforderung war: „Drupal-Webform sammelt Daten, schickt Submit per HTTP-POST direkt an die Personio Recruiting API, fertig.“ Diese Architektur (in dieser ADR Pfad A genannt) setzt voraus, dass der POST-Endpoint mit SOLCOMs vorhandenen papi--Recruiting-Credentials erreichbar ist. Ein Spike am 2026-05-25 hat das systematisch geprüft.
Spike-Befunde (17 Live-Probes gegen api.personio.de, 2026-05-25)
- v2 Recruiting Service ist vollständig read-only. Der OpenAPI-Spec
recruiting-service-v2.yamldokumentiert 9 GET-Endpoints (Applications, Candidates, Jobs, Categories — jeweils Listing + by-ID), keinen einzigen POST/PATCH/PUT/DELETE für Application-Creation. Diese GETs sind aber für E2E-Smoke-Test-Read-back nutzbar. - v1
POST /v1/recruiting/applicant(Singular) — historisch dokumentierter Endpoint — gibt heute HTTP 404 miterrors.no-resource-foundzurück. Sunset. - v1
POST /v1/recruiting/applications(Plural) existiert technisch (OPTIONS-Discovery zeigtallow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH), gibt aber für jeden getesteten Auth-Pattern HTTP 401 statt 404:- v1-Bearer-Token + JSON-Body (Probe 6, 9)
- v2-Bearer-Token + JSON-Body (Probe 4)
- v1-Bearer-Token + multipart/form-data (Probe 14)
X-Personio-Partner-ID+X-Personio-App-IDHeaders (Probe 11)X-API-Key-Header (Probe 17)- kein Auth-Header (Probe 16)
- Diagnose: Der Endpoint ist hinter dem Personio Multiposting-Partner-Scope gated. SOLCOMs Standard-Recruiting-Credentials decken nur die Scopes
personio:recruiting:read,personio:recruiting:write,personio:legal-entities:read,personio:workplaces:read. Multiposting-Scope ist ein separater Partner-Vertrag und nicht im SOLCOM-Standard-Setup aktiviert. - v1- und v2-Auth-Endpoints funktionieren beide mit SOLCOMs vorhandenen Credentials und liefern gültige Tokens. Personio-Webhook-Service (
/v2/webhooks) erlaubt POST/PATCH/DELETE und ist mit SOLCOM-Standard-Credentials nutzbar — relevant für die ACK-Mechanik. - Personio-Inbox-Import ist der offiziell unterstützte Pfad für externe Career-Pages. Jeder Personio-Tenant hat eine eingehende Inbox-Adresse, die Subject + Body via Heuristik in Application-Felder mappt; Attachments landen als CV-/Dokumenten-Files an der Application.
- Personio-Hosted-Career-Page unter
solcom-gmbh.jobs.personio.deist Vercel-gehostet und JS-rendered — nicht via curl/WebFetch scrapebar. „Custom Apply URL“ pro Job ist im Personio-Admin konfigurierbar und kann auf eine externe Drupal-Sub-Route zeigen.
Stakeholder-Anforderungen aus F-100-Grilling
- Karriere-Interessent:in: kein Medienbruch zwischen Stellenseite und Bewerbungsformular, SOLCOM-Branding durchgängig, Bewerbungsseite per Lesezeichen erreichbar und teilbar.
- HR-Stakeholder:in: jede Bewerbung muss zuverlässig im Personio-Recruiting-Backend ankommen; im Fehlerfall muss eine Recovery-Oberfläche ohne Entwickler-Hilfe nutzbar sein.
- PO / Redakteur:in: kein Mehraufwand pro neuer Stelle; eine zentrale Webform skaliert über alle Vacancies; klare Analytics-URL pro Stelle.
- DSGVO: Auftragsverarbeitungs-Vertrag mit Personio als Vorbedingung; Conditional-Retention (Bewerber-Daten und Files werden nach Personio-Bestätigung im SOLCOM-System gelöscht, bleiben bei Failure persistent als Recovery-Layer).
- Operations / Engineering: existierendes Drupal-Webform-Modul (6.3.0-beta8) als Form-Engine, Drupal Core Queue API für asynchronen Versand, kein zusätzlicher Composer-Dep.
Entscheidung
Pfad C+ — Email-Inbox-Import + Webhook-ACK wird MVP-Architektur. Konkret:
- Drupal-Webform
vacancy_applicationrendert pro Stelle unter/karriere/<slug>/bewerben. Vacancy-Kontext (Personio-Job-ID, Stellentitel, Vacancy-Node-ID) wird per Route-Parameter aufgelöst und als Hidden-Fields in die Form injiziert. - Submit-Handler speichert die Submission und ihre Files in
private://applications/<submission-uuid>/und enqueued ein Queue-Item insolcom_personio_application_queue. - Ein QueueWorker lädt das Item, ruft den deep module
PersonioMailBuilder, der einen strukturierten Key-Value-Text-Body erzeugt, die Files als Attachments anhängt und einen Tracking-Hash ins Subject schreibt (Subject-Format:Bewerbung: <Stellentitel> (Personio-Job-ID <id>) · <Bewerbername> · trace:<hash>). - Der Drupal-Mail-Manager versendet die Mail an die im Drupal-State hinterlegte Personio-Inbox-Adresse des SOLCOM-Tenants. Personio parst die Mail in eine Application im Recruiting-Posteingang und schickt die übliche Personio-Bestätigungsmail an die Bewerber:in.
- Personio feuert anschließend den Webhook
application.createdauf den Drupal-Receiver/personio/webhook/application-created. Drupal verifiziert die HMAC-Signatur viaPersonioWebhookSignatureVerifier, matcht die Submission über den Tracking-Hash (oder hilfsweise über die Bewerber-Email), markiert die Submission alsackedund speichert die Personio-Application-ID in Submission-Meta. - Bei ACK wird die Conditional-Retention scharf: PII-Felder und Files werden aus dem SOLCOM-System gepurged.
- Failure-Pfade: max 5 Retry-Versuche mit Backoff (1 min/5 min/15 min/1 h/6 h); nach DLQ-Erschöpfung Mail an
hr@solcom.de, Submission + Files bleiben persistent. Ein täglicher Cron-Job alarmiert HR, wenn eine Submission länger als 24 h ohne ACK im Statussent_pending_ackliegt. - Eine HR-Recovery-Oberfläche unter
/admin/karriere/dlqerlaubt Re-Queue, Files-Download und „Manuell erledigt“-Mark, nur für die HR-Rolle sichtbar.
Die Webhook-Subscription wird einmalig via Drush-Command solcom:personio:webhook-subscribe angelegt; Subscription-ID wird in Drupal-State persistiert. Ein Drush-Smoke-Test solcom:personio:smoke-test erzeugt regelmäßig eine markierte Test-Application gegen die Dummy-Stelle 2635453 und verifiziert den ACK via Personio v2 Read-back.
Rejected Alternatives
Pfad A — direkter HTTP-POST gegen POST /v1/recruiting/applications
Rejected, weil der Endpoint mit SOLCOMs Standard-Recruiting-Credentials nicht erreichbar ist. 17 Live-Probes mit fünf verschiedenen Auth-Pattern und zwei Content-Type-Variationen lieferten alle HTTP 401. Diagnose: Multiposting-Partner-Scope-Gate. Die Aktivierung dieses Scopes ist ein separater Personio-Vertrag, der von SOLCOMs Personio-Account-Manager neu verhandelt werden muss (Kosten, Vertragsdauer, Onboarding-SLA unbekannt). Diese Klärung läuft parallel als Sub-Task P2503-191 und ist explizit non-blocking für den MVP-Launch.
Future-Refactor-Option: Falls Personio den Multiposting-Scope für SOLCOM aktiviert, kann der QueueWorker-Body in einer Folge-Story von SMTP-Versand auf HTTP-POST gegen POST /v1/recruiting/applications umgestellt werden. Die Drupal-Webform-Architektur (Topology, Sub-Route, File-Upload, Queue-Schale, DLQ-UI) bleibt dabei unverändert; nur der innere Body des QueueWorker-Plugins (plus die PersonioApiClient-Methode) wechseln. Das ist ein 1-PR-Refactor, kein Architektur-Bruch.
Pfad B — Hosted-Page-Redirect (Status Quo)
Rejected, weil es das User-Story-Outcome „kein Medienbruch“ verletzt. Der heutige Apply-CTA leitet auf https://solcom-gmbh.jobs.personio.de/job/<id> weiter; Bewerber:innen verlassen die SOLCOM-Site und landen in einem visuell und URL-strukturell fremden Tool. Drop-Off im Apply-Flow ist höher als bei seitennativen Formularen, Brand-Konsistenz bricht, Drupal-Analytics werden nicht fortgeführt.
Behalten als Notfall-Fallback: Falls die Personio-Inbox-Konfiguration im SOLCOM-Tenant nicht in zumutbarer Zeit eingerichtet werden kann oder das Personio-Mail-Parsing in der initialen Smoke-Test-Phase strukturell scheitert (Felder werden nicht zuverlässig in Application-Felder gemappt), kann F-100 auf Pfad B zurückfallen. Diese Option wird nicht aktiv verfolgt, ist aber als Fallback dokumentiert.
Pfad D — Wechsel auf ein anderes Recruiting-Tool
Rejected, weil out-of-scope. Personio ist SOLCOMs vertraglich gebundenes Recruiting-Tool mit bestehender HR-Workflow-Integration. Ein Vendor-Switch wäre eine separate strategische Entscheidung mit deutlich größerem Scope (HR-Onboarding, Daten-Migration, Vertrags-Ende). Nicht Gegenstand dieser ADR.
Pfad E — Pipe-Through ohne persistente Drupal-Submission
Rejected, weil mit der Queue-Architektur inkompatibel. Pipe-Through (Submit-Request liest die Files direkt aus dem Upload-Stream und schickt sie unmittelbar an Personio, ohne Drupal-Persistierung) wurde initial in der Grilling-Session vorgeschlagen. Mit der HR-Recovery-Anforderung und dem damit erzwungenen Queue-Worker-Pattern ist Pipe-Through nicht möglich: der QueueWorker läuft zeitlich entkoppelt vom Submit-Request und braucht die Files im Filesystem. Persistente private://-Storage ist daher unausweichlich.
Consequences
Positive
- MVP-Implementierung ohne Personio-Vertrags-Änderung möglich. Der Email-Inbox-Pfad nutzt ausschließlich Funktionalität, die SOLCOMs Personio-Standard-Tenant bereits hat: Inbox-Import + Webhook-Service.
- Future-Refactor ist 1-PR-Operation. Falls Multiposting-Scope später aktiviert wird, wechselt der QueueWorker-Body von SMTP auf HTTP; die Webform-Architektur, Sub-Route, Storage und DLQ-UI bleiben.
- Conditional-Retention erfüllt DSGVO-Minimal-Konformität. Bewerber-Daten liegen nur so lange im SOLCOM-System wie nötig — bei Personio-ACK werden sie automatisch gelöscht; nur bei Failure persistieren sie als HR-Recovery-Layer.
- Deterministischer ACK durch Webhook ist robuster als eine zeitbasierte Heuristik. Bei ausbleibendem Webhook deckt der 24h-Cron das Worst-Case ab.
- End-to-End-Demobarkeit pro Slice. Die 7-Sub-Task-Decomposition (siehe Implementation-Plan) ist tracer-bullet-konform; Slice #1 erreicht bereits die Personio-Inbox, alle nachfolgenden Slices erweitern den Pfad.
Negative
- Personio-Mail-Parsing-Verhalten ist nicht durch den Spike validiert. Unklar, ob das Personio-Inbox-Parsing strukturierte Key-Value-Bodies in Application-Felder mappt oder ob alles im Free-Text-Notes-Feld landet. Slice #1 schließt einen Format-Probe-Schritt ein; Outcome wird im Story-Hub Worklog festgehalten.
- Abhängigkeit von Personio-Inbox-Konfiguration. SOLCOM-Personio-Admin muss die Inbox einmalig einrichten (Sub-Task P2503-189). Wenn das scheitert, fällt F-100 auf Pfad B (Hosted-Page-Redirect) zurück.
- Mail-Server-Reputation und SPF/DKIM/DMARC für SOLCOM-Absender sind kritisch. Personio-Inbox filtert eingehende Mails wie ein normales Postfach. Bei schwacher Absender-Reputation landen Bewerbungen im Personio-Spam-Ordner. Implementation-Vorbedingung: DKIM/DMARC-Verifikations-Test.
- Webhook-Service hat keine dokumentierte SLA für Webhook-Zustellung. Fällt die Webhook-Auslieferung aus, deckt der 24h-ACK-Timeout-Cron das Worst-Case ab; HR wird alarmiert.
- Keine direkte Application-ID im Submit-Response. Die Drupal-Bewerbungsseite kann die Bewerber:in nicht synchron auf eine Personio-Application-ID-Seite weiterleiten; stattdessen Drupal-Bestätigungsseite mit Hinweis auf die folgende Personio-Bestätigungsmail.
- Figma-Frame-Lücke für die neuen Seiten. Es existiert heute kein Figma-Pendant für
/karriere/<slug>/bewerben(Form-Seite) und/karriere/<slug>/bewerben/danke(Bestätigungsseite). MVP nutzt das generische byte_theme-Branding und bestehende Webform-Patterns; die explizite Figma-Frame-Spezifikation ist Post-MVP-Design-Task und wird in der Design-Mapping-Pflege (docs/design/MAPPING.html) als Gap nachgeführt.
Neutral / Folgeeffekte
- ADR-0014-Topologie bleibt unverändert; das Field-Binding für Hero-CTA und
sticky-apply-barwechselt vonfield_apply_url.uriauf den computed Wert/karriere/<slug>/bewerbenfür SOLCOM-eigene Stellen. Diefield_apply_url-Property bleibt am Vacancy-Node als Escape-Hatch erhalten: ist sie gefüllt (z. B. für externe Drittanbieter-Stellen oder Projekt-Offers, die nicht über Personio laufen), gewinnt sie und der Apply-CTA zeigt auf den externen Wert; ist sie leer, gewinnt der computed Drupal-Sub-Route-Pfad. Diese Conditional-Binding-Logik wird in Sub-Task P2503-184 (Slice #1) implementiert und im Implementation-Plan unter Risk-Mitigation festgehalten. - ADR-0035 (Personio-XML-Anonymous-Pulling) bleibt unverändert; der Inbound-XML-Feed (Vacancy-Daten von Personio nach Drupal) ist davon unabhängig.
- PRD 2026-05-02-personio-vacancy-integration-prd hatte die Klausel „Bewerbungs-Formular auf Drupal“ explizit als Out-of-Scope markiert; diese Klausel wird durch ADR-0047 formal aufgehoben.
- Sub-Task P2503-191 (Multiposting-Scope-Outreach) ist non-blocking für MVP. Outcome bestimmt, ob eine Folge-Story Pfad A als Refactor anlegt.
- Personio-API-Credentials liegen bereits im SOLCOM-System (in der Grilling-Session geteilt). Die Credentials gelten als kompromittiert; pre-Production-Rotation ist als Implementation-Vorbedingung dokumentiert (war ursprünglich Sub-Task .7, vom User aus dem MVP-Scope gestrichen, wird vor Production-Cutover separat erledigt).
- Pfad-B-Fallback-Schalter ist Engineering-only (Config-Override, kein UI-Toggle). Der Notfall-Switch wird als Drupal-State-Flag
state:solcom_personio.apply_redirect_enabledrealisiert; Umschaltung erfolgt via Drush-Commandsolcom:personio:apply-redirect <on|off>, nicht im Drupal-Admin-UI. Aktiviert leitet der Apply-CTA wieder aufsolcom-gmbh.jobs.personio.de/job/<id>. Bewusste Maintenance-Grenze: HR kann den Schalter nicht selbst bedienen, weil die Auswirkung global ist (alle Stellen). Eskalation: HR meldet Personio-Inbox-Ausfall an Engineering, Engineering schaltet via Drush.
Mitigation
- Smoke-Test gegen Dummy-Stelle 2635453 mit Personio v2 Read-back (Sub-Task P2503-188) deckt das End-to-End-Verhalten täglich ab.
- HR-Notification + DLQ-Recovery-UI (Sub-Task P2503-187) deckt Failure-Pfade ohne Entwickler-Eingriff.
- 24h-ACK-Timeout-Cron (Teil von Sub-Task P2503-186) fängt fehlende Webhook-Auslieferungen ab.
- Pfad B (Hosted-Page-Redirect) bleibt als Notfall-Fallback verfügbar; die Apply-CTA-Konfiguration ist umschaltbar.