Kontext
Die Karriere-Stellenanzeigen-Detailseite zeigt heute einen Ansprechpartner-/HR-Kontakt-Block (Live-Beispiel: Laura Gerardi, HR Manager, Tel. 07121/1277-344). Der Block ist Teil des Legacy-Karriere-Systems, kein Drupal-Content-Type. Story P2503-97 („Personen / Team Content Type", Backlog-Position F-170, Parent-Epic P2503-89 „Module & Konfigurationen") fordert einen generischen node.person-Content-Type, der den HR-Block ersetzt und langfristig weitere Use-Cases (Team-Seite, About-Page, Blog-Autoren) traegt.
Vor der Refinement-Session lagen sechs relevante Quellen vor:
- Jira-Story
P2503-97mit User-Story-Text, ohne Akzeptanzkriterien. - Figma-Frame
62110:27008aus SOLCOM — Design System (ContentItem-Komponente, Variantsperson/title). - Live-Screenshot der HR-Card auf
karriere.solcom.de/de/jetzt-bewerben/offene-stellen/…. - Story-Hub
docs/stories/F-170-personen-team-content-type.htmlim StatusIDEE. - ADR-0014, der Recruiter-interne Strings im Personio-
field_bodyals „bekannte Restbedingung" erwaehnt. - Plan
2026-05-15-001-feat-personio-rest-import.html, dessen Slice-3-AK explizit verlangt: „Description-Aggregation excludes ‚Team' und ‚Ansprechpartner/in'-Sections".
Beobachtete Spannungen
Drei wesentliche Spannungen zwischen den Quellen:
- Scope-Konflikt zwischen dem generischen Story-Titel („Personen / Team Content Type") und dem konkreten HR-Recruiter-Kontext (Figma-Frame + Live-URL). Der User hat sich im Grilling fuer den generischen Content-Type entschieden — der Figma-Frame ist eine View-Mode-Anwendung, nicht der Scope der Story.
- Visual-Diff Figma vs. Live: Figma-Frame zeigt horizontal (Foto links, Position klein + Vorname Name gross rechts), Live zeigt vertikal (Foto oben, Name + Funktion + Telefon unten). Die Layouts haben kaum strukturelle Schnittmenge. User-Entscheidung: Live wird ersetzt, Figma-Layout ist Target — aber die Kontakt-Optionen aus Live (Tel, Email, LinkedIn) werden als Stack unter Name ERGAENZT. Das Resultat ist ein „Figma + Extension"-Hybrid, der im
solcom-figma-reviewer-Diff dokumentiert sein muss, sonst wird es als Drift gemeldet. - Personio-Filter: Plan 2026-05-15-001 entfernt die Ansprechpartner/in-Sections aktiv aus dem importierten
field_body. Es gibt heute kein strukturiertes Recruiter-Feld aufnode.vacancy. ADR-0026 schliesst zusaetzlich den Editorial-Workflow fuer Vacancy aus (Personio = Single-Source-of-Truth). Daraus folgt eine Luecke: wer/wie verknuepft eine Vacancy mit der richtigen Person?
Card-Familie heute
Nach ADR-0009 und ADR-0038 stehen im byte_theme heute folgende Card-relevante SDCs (Stand 2026-05-25):
| SDC | Pattern | Render-Quelle | Visual-Frame | Status |
|---|---|---|---|---|
bubble-card-frame | SVG-Layer | Include-only | Notch- / no-Notch-Variant | physisch vorhanden |
card-frame | Slot | Canvas-Page-Builder | Rechteck (ADR-0038) | physisch vorhanden |
card | Prop-driven | View-Mode-Liste (Blog) | Bubble ohne Notch (gradient outline) | physisch vorhanden |
card-feature | Slot | Canvas-Page-Builder | Feature-Block | physisch vorhanden |
card-meta-list | Slot | Canvas-Page-Builder (Vacancy) | Meta-Liste (ADR-0013) | physisch vorhanden |
card-bubble-profile | Slot | Canvas-Page-Builder | Bubble mit Notch (CTA) | geplant (MAPPING, noch nicht gebaut) |
card-bubble-profile-no-button | Slot | Canvas-Page-Builder | Bubble ohne Notch | geplant (MAPPING, noch nicht gebaut) |
Hinweis: card-bubble-profile und card-bubble-profile-no-button sind in docs/design/MAPPING.html als geplante Sibling-SDCs eingetragen, existieren jedoch noch nicht im Dateisystem unter web/themes/custom/byte_theme/components/ (Verifikation Stand 2026-05-25). Die Counts und Argumente in dieser ADR beziehen sich daher auf physisch vorhandene SDCs.
Das prop-driven card ist Blog-spezifisch (Felder heading_text, text, media). Eine Erweiterung um Person-Felder (name, funktion, phone, …) wuerde Conditional-Schema einfuehren, das in ADR-0004 bereits als Anti-Pattern verworfen wurde („dedizierte SDCs schlagen Mode-Switch").
Entscheidung
Wir bauen drei neue Artefakte als kohaerentes Paket fuer den View-Mode-Listen-Render von Personen:
1. Content-Type node.type.person
Generischer Personen-Content-Type, NICHT vacancy-spezifisch. Sechs Felder:
node.type.person
bundle: person
fields:
field_name string, required
field_funktion string, required
field_photo image, required
field_phone telephone, required (klickbar als tel:-Link)
field_email email, optional (klickbar als mailto:-Link)
field_linkedin_url link, optional (klickbar als externer Link)
2. View-Mode card_quote + SDC card-person
entity.entity_view_display.node.person.card_quote rendert node.person ueber die neue SDC byte_theme:card-person. Die SDC ist:
- prop-driven (kein Slot, kein Canvas-Wrapper-Pattern) — folgt ADR-0009 fuer View-Mode-Listen-Render.
- kein
bubble-card-frame-Include: Figma-Frame62110:27008hat keinen Notch und keine Outline. Die Card lebt visuell ohne SOLCOM-Bubble-Layer. - nur
person-Variant: Der Figma-Frame hat zwei Boolean-Variants (personundtitle). Die SDCcard-personrendert ausschliesslich denperson-Variant. Dertitle-Variant (Editorial-Quote-Block) ist explizit out-of-scope und bekommt eigene SDC, falls priorisiert. - Layout-Extension dokumentiert: Figma zeigt nur Position + Vorname Name. Die SDC ergaenzt einen Kontakt-Stack (Tel + Email + LinkedIn) unter Name. Abweichung wird in der Story-Hub-Section
<section id="figma-extensions">festgehalten, damitsolcom-figma-reviewerdie Extension als „intentional" abhaken kann.
Schema-Skizze:
name: "Card · Person"
group: Card
status: experimental
description: |
Prop-driven Person-Card fuer node.person card_quote view_mode.
Horizontal Layout, rundes Foto links, Text rechts.
Optional Contact-Links (tel/mailto/linkedin) als Stack unter Name.
Rendert AUSSCHLIESSLICH den person-Variant von Figma 62110-27008;
title-Variant ist out-of-scope (eigene SDC noetig).
props:
type: object
required: [name, funktion, photo]
properties:
name: { type: string }
funktion: { type: string }
photo: { type: object, properties: { src, alt, width, height } }
phone: { type: string } # optional in Schema, required im Content-Type
email: { type: string }
linkedin_url: { type: string }
3. Canvas-Code-Component CardPerson.jsx
Liegt unter web/themes/custom/byte_theme/canvas-components/CardPerson.jsx (1:1-Namens-Mapping zu card-person, kein PersonCard-Suffix-Flip — Customer-Lens-Empfehlung). Akzeptiert personNid als Prop, laedt node.person via JsonApiClient + SWR und rendert die SDC card-person mit den geladenen Feldern.
Editor-Workflow im MVP: Canvas-Page → Add Block → „Card · Person" → Person waehlen → Save → Publish.
4. MVP-Fallback fuer Vacancy-Detail
Eine globale Default-Person via config_pages.career_settings.field_default_recruiter (ER → node.person). Im Vacancy-Detail-Canvas-Template (node.vacancy.full) wird der CardPerson-Block mit dieser Default-NID auto-instanziert. Granulare Vacancy↔Person-Verknuepfung (Personio-Mapping per recruiter_id, ER-Feld pro Vacancy) ist deferred zu einer Folge-Story.
Konsistenz mit existierenden ADRs
- Erweitert das Pattern aus ADR-0009 auf einen zweiten View-Mode-Use-Case (nach
node.blog.cardjetztnode.person.card_quote). - Vermeidet den in ADR-0004 verworfenen Conditional-Schema-Pattern (kein
variant: blog|person-Switch auf bestehendercard-SDC). - Respektiert ADR-0026 im MVP-Pfad (Vacancy bleibt Personio-only, Default kommt aus
config_pages). Eine spaetere granulare Verknuepfung muss ADR-0026 verhandeln oder umgehen.
Rejected alternatives
Schmaler Scope: nur Recruiter-Card auf Vacancy-Detail, kein generischer Content-Type rejected
Variante A waere ein einmaliger Canvas-Block ohne node.person-Entity oder ein Paragraphs-Typ auf node.vacancy. Verworfen, weil der Story-Titel „Personen / Team Content Type" und die Sitemap-Node N33 („Ansprechpartner" als eigenstaendige Seite) breitere Wiederverwendung implizieren. Ohne generische Entity muesste eine Team-Seite spaeter ein zweites Datenmodell parallel aufbauen.
MVP-Scope auf alle drei View-Modes (card_quote + card_team + full) erweitern rejected
Eine Maximal-Variante wuerde Person-Detail-Page mit eigener Route (Sitemap N33), Team-Uebersicht und Vacancy-Sidebar in einer Story buendeln. Verworfen wegen Story-Groesse (geschaetzt 10+ Sub-Tasks) und MVP-Deadline-Risiko fuer 2026-07-08. Die nicht-priorisierten View-Modes (card_team, full) werden eigene Folge-Stories unter F-170.
Editorial-Override von field_recruiter auf node.vacancy (ADR-0026-Bruch) rejected
Ein dediziertes editorial-pflegbares field_recruiter auf node.vacancy wuerde ADR-0026 partiell brechen (Vacancy nicht mehr 100% Personio-only). Im MVP nicht noetig, weil ein globaler Default in config_pages ausreicht. Falls die Folge-Story granulare Pflege fordert, MUSS sie ADR-0026 explizit verhandeln (z.B. via Personio-Mapping auf recruiter_id, das ADR-0026 respektiert).
Drupal-Block-Plugin person_card_block statt Canvas-Code-Component rejected
Ein klassisches PHP-Block-Plugin im Drupal-Block-Layout-System waere robuster gegen Canvas-Disruptions, aber das Block-Layout-UI ist fuer Editor:innen clunky und kollidiert mit der Canvas-First-Strategie. Canvas-Code-Component bietet bessere Editor-UX. Kernel-Test-Coverage ist mit Canvas-Code-Components ebenfalls moeglich (Jest + Storybook).
Existierende card-SDC um Person-Variante erweitern (variant: blog|person) rejected
Bringt Conditional-Schema-Komplexitaet zurueck (heading_text nur sinnvoll wenn variant: blog, name nur sinnvoll wenn variant: person). ADR-0004 hat das analoge Pattern fuer Buttons explizit rejected. Schema-Validation kann Prop-Conditionality nicht enforcen, Twig-Template enthielte zwei verzweigte Render-Pfade.
Neuer card-quote-SDC mit dual-mode person|title (1:1 Figma-Treue) rejected
Wuerde den Figma-Frame 62110:27008 mit beiden Variants 1:1 abbilden. Verworfen, weil der title-Variant nicht MVP-Scope ist (keine konkrete Anwendung priorisiert) und Conditional-Schema das ADR-0004-Pattern verletzen wuerde. Falls der Editorial-Quote-Block spaeter priorisiert wird, bekommt er eine eigene SDC (z.B. card-quote-statement).
Card-Familie via abstrakter Basis-SDC konsolidieren (card-prop-driven mit kind: blog|person|event) rejected (deferred)
Customer-Lens-Gegenargument: „Eine weitere Card-Sibling-SDC ist Variant-Wildwuchs in Datei-Form. Wenn die Familie weiter waechst (card-event, card-testimonial, card-case-study), wird jede neue Story einen Sibling hinzufuegen." Verworfen-deferred: Abstraktion ist verfrueht, solange der konkrete Use-Case-Set unter 5 prop-driven View-Mode-Siblings bleibt. Die Schmerzschwelle „wann ist es zu viele Siblings?" wird in einer spaeteren ADR neu bewertet, sobald ein fuenfter prop-driven View-Mode-Card-Sibling vorgeschlagen wird.
Consequences
Direkte Folgen
- Card-Familie waechst um eine prop-driven Variante.
card-personist der zweite prop-driven Sibling nebencard(physisch vorhanden: 5 SDCs → 6; MAPPING-geplant zusaetzlich 2). Das ADR-0009-Pattern wird damit explizit als „mehrere Siblings pro View-Mode-Use-Case" interpretiert. - Inkonsistenz-Spannung mit Memory-Eintrag „Card-SDCs sollten Canvas-Wrapper sein". Diese ADR durchbricht die Regel bewusst fuer den Use-Case „Drupal-View-Mode-Listen-Render", analog zu ADR-0009. Beide Pattern existieren parallel, getrennt nach Render-Quelle.
- Naming-Konvention 1:1 zwischen SDC und Canvas-Code-Component:
card-personSDC undCardPerson.jsxCanvas-Component teilen den Wortstamm. Bei zukuenftigen Refactors keine Grep-Friction. - Vacancy-Detail-Layout aenderung sichtbar: Der Live-vertikale-Block (Name + Funktion + Tel als Stack) wird durch das horizontale Figma-Layout (Foto links, Position + Name rechts, Kontakt-Stack darunter) ersetzt. Diese visuelle Aenderung muss im PR-Body und im
solcom-figma-reviewer-Output explizit dokumentiert sein.
Risiken / offene Verifikations-Punkte
- Vacancy-Canvas-Template-Auto-Instanziierung (Customer-Lens-Finding SB-1): Im MVP-Fallback wird angenommen, dass
canvas.canvas.node.vacancy.full.ymldenCardPerson-Block mit der Default-NID automatisch in der Sidebar rendert. Vor Build verifizieren, dass das Canvas-Template diesen Eintrag enthaelt oder ergaenzt wird. Falls Editor pro Vacancy einen Block manuell setzen muss, ist der MVP-Workflow defekt und ADR-0026 ist in Frage gestellt. - config_pages-Pflege-UI (Customer-Lens-Finding SB-2): Editor:innen muessen
config_pages.career_settingserreichen koennen. Sub-Task „Toolbar-Link / Editor-Onboarding fuer Career-Settings" wird im Story-Hub als Pflicht-Task ergaenzt. - Accessibility-Diff: Tel/Email/LinkedIn-Stack braucht korrekte
tel:/mailto:-Schemas,aria-labelfuer icon-only LinkedIn-Link und WCAG-2.1-AA-Kontrast. Diff-Zeit-Sache fuer den SDC-Reviewer. - SWR-Fetch-Performance: Pro
CardPerson-Instance ein JSON:API-Request. Falls eine Page mehrere PersonCards rendert (Team-Uebersicht in einer Folge-Story), N+1-Risiko. Mitigation: Sammel-Request viafilter[id-in]-Query, sobald relevant. - Datenschutz / DSGVO: Recruiter-Telefonnummern und -Email oeffentlich auf Vacancy-Detail. Klaerung mit Stakeholder vor Live-Schaltung empfohlen (eigener Reviewer-Strang, ausserhalb dieser ADR).
Folge-Stories (unter F-170)
- Granulare Vacancy↔Person-Verknuepfung (ADR-pflichtig — Verhandlung mit ADR-0026, Personio-Mapping-Option).
- View-Mode
card_team+ Team-Uebersichts-View (Drupal-View). - View-Mode
full+ Person-Detail-Page mit eigener Route (Sitemap-Node N33). - Bio-Feld + Rich-Editor fuer Person-Detail-Page.
- Optional:
title-Variant als eigenstaendige SDC (z.B.card-quote-statementfuer CEO-Zitate / Editorial-Statements).
Build-Workflow (Reihenfolge der Skills)
solcom-design-mapping— MAPPING.html-Row fuer Frame62110:27008anlegen (heute fehlt sie).solcom-figma-to-sdc— SDCcard-personbauen mit Re-Check gegen Figma bei jedem Schritt.drupal-canvas— Canvas-Code-ComponentCardPerson.jsxbauen + Workbench-Test.solcom-figma-reviewer— Visual-Compliance-Diff bei Mobile 375 / Tablet 768 / Desktop 1280, mit<section id="figma-extensions">als Reference fuer intentional Drifts.