P2503 · Projektpartnerportal · Self-Service

Projektpartnerportal Self-Service

REFINED P2503-226 Erstellt & Refined: 2026-06-15 (Grilling) · ADR-0052 · PRD

User Story

Als Freiberufler möchte ich mich im Projektpartnerportal registrieren, einloggen und mein Profil mit allen Angaben aus dem Bestandssystem selbst pflegen, damit meine Daten aktuell sind und SOLCOM mich passenden Projekten zuordnen kann.

Outcome

Ein Freiberufler legt über einen geführten dreistufigen Wizard ein Konto an, bestätigt es per E-Mail, loggt sich mit E-Mail + Passwort ein und pflegt fortlaufend ein vollständiges Profil (Stammdaten, Kontakt, Verfügbarkeit, Qualifikation, Netzwerk-IDs, private Unterlagen). Er kann einen Suchagenten betreiben, Projekte merken und sein Konto DSGVO-konform vollständig löschen. ~37.700 Bestandspartner aus dem Neos-Altsystem sind migriert und werden beim ersten Login zum Passwort-Reset geführt. Redakteure behalten unverändert ihr Standard-Drupal-Benutzerformular.

Status

REFINED 2026-06-15 via Grilling. Der ursprüngliche „erste Wurf" (Sub-Tasks P2503-227 bis P2503-235) wurde gegen das Neos-Bestandssystem (MySQL-Dump, ~37.700 User) und gegen Drupal-Best-Practice gestresstet. Kern-Architektur entschieden und in ADR-0052 dokumentiert (customer-lens-reviewed, D11-Kompatibilität von drupal/profile empirisch bestätigt). Scope erweitert um Suchagent + Bookmarks; Verfügbarkeits-Flow als internes Tool ausgeschlossen.

Gegrillte Entscheidungen

AchseEntscheidungBegründung
Feature-ScopeSuchagent + Bookmarks rein; Verfügbarkeits-Flow rausVerfügbarkeits-Abfrage (Neos availability, ~196k) ist internes SOLCOM-Outbound-Tool, kein Self-Service
Datenmodelldrupal/profile, Typ projektpartnerTrennt Login-Identität (User) von Fachprofil; Rollen-Trennung fällt strukturell raus. ADR-0052
PPP-IDfield_ppp_id auf User-Entity (nicht Profil)Identitäts-/Migrations-/Salesforce-Anker am Account; konsistent mit ADR-0048
RegistrierungWebform-Wizard (3 Seiten)Repo-konsistent; Draft-Submission löst Orphan-File-Problem vor User-Existenz
Profil-EditNative drupal/profile-Edit-FormFeldliste einmal definiert; Webform spiegelt nur Erstanlage; minimales Drift-Risiko
Migration-SourceSqlBase direkt gegen Dump (nicht XML)Quelle ist SQL; Joins + DC2Type:array-Deserialisierung (PHP-serialize) direkt
Alerts / BookmarksAlert-Kriterien migrieren; Bookmarks greenfieldKein gemeinsamer Projekt-Schlüssel (Neos project.id/gulp vs. Drupal field_sf_*); Bookmark-Ziele meist abgelaufen

Sub-Task-Map

Bestehende Sub-Tasks bestätigt/präzisiert; 235 überarbeitet (SqlBase statt XML); zwei neue anzulegen.

Sub-TaskTitelDelta gegenüber erstem Wurf
P2503-227Datenmodell projektpartnerBestätigt; ADR-0052-Ref ergänzen, field_ppp_id explizit auf User
P2503-2283-stufiger Registrierungs-WizardPräzisiert: Webform-Wizard, Draft-Submission, atomarer Final-Handler
P2503-229Private Dokument-UploadsBestätigt; File-Handling via Webform-Draft → Profil umhängen
P2503-230Login mit E-MailBestätigt; login_emailusername bereits aktiv
P2503-231E-Mail-FlowsBestätigt; easy_email bereits aktiv
P2503-232Account-Self-Service: Profil bearbeitenPräzisiert: native Profile-Edit-Route
P2503-233Account-Löschung (DSGVO)Bestätigt; ApplicationPurger-Pattern, Profile-Cascade verifizieren
P2503-234Rollen-TrennungVereinfacht: fällt durch separate Profile-Route fast trivial
P2503-235Datenmigration Neos → DrupalÜberarbeitet: SqlBase direkt, koordinierte User→Profil-Migration, Doctrine-Array-Deserialisierung
P2503-237Suchagent / Projekt-AlertFeature + Migration der ~20k Kriterien (Vokabular-Mapping). Priorität hoch (gesetzt).
P2503-238Merkliste / BookmarksUpgrade der bestehenden Frontend-Merkliste (WatchlistController + watchlist.js, localStorage) auf backend-persistent für eingeloggte Partner; keine Neos-Migration
P2503-239Salesforce-Sync bei Profil-Änderung (per Mail)hook_ENTITY_TYPE_update + $entity->original-Diff → Queue → easy_email; Pattern wie SalesforceUrlWriteback
P2503-240Frontend-Test-Harness (FunctionalJavascript)Chromedriver in DDEV; WebDriverTestBase/DTT; deckt alle Formulare ab
P2503-241Bestandsnutzer-Aktivierung: Passwort-Policy + Willkommens-Mailpassword_policy_expiration (abgelaufenes PW → force reset) + Willkommens-Mail-Batch; neue Dependency drupal/password_policy

Abhängigkeiten

  • Composer: drupal/profile (1.14.0) + drupal/entity (1.6.0) hinzufügen. Sonstige Module (login_emailusername, easy_email, migrate_plus/tools, webform) bereits aktiv.
  • Form-Primitive (Figma ready-for-dev, SDC-gap): Inputfield P2503-123, Textarea P2503-124, Dropdown P2503-125, Upload field P2503-126 — Voraussetzung für die Portal-Formulare. Checkbox/Radio/Password fehlen ganz (Design-Lücke).
  • Projektliste (solcom_project_offer, Salesforce/RSM) — Voraussetzung für Suchagent-Matching und Bookmarks.
  • Neos-Dump als Migrations-Quelle (temporäre DB-Connection).

Implementierungs-Reihenfolge & Abhängigkeiten

Dependency-getriebene Tracer-Bullet-Reihenfolge. Detaillierte Slices im Implementation-Plan.

#SliceHängt ab von
0aDatenmodell (227): drupal/profile + Rolle + Felder + field_ppp_id— (Fundament, blockiert alles)
0bTest-Harness (TBD): Chromedriver in DDEV, FunctionalJavascript-Setup— (Querschnitt, früh; blockiert alle Formular-Tests)
0cForm-Primitive-SDCs (P2503-123…126): Inputfield, Textarea, Dropdown, Upload— (Theme-seitig, parallel zu 0a)
1Login (230)0a
2Private Uploads (229)0a
3Registrierungs-Wizard (228)0a, 0c, 2
4E-Mail-Flows (231): Verifizierung, Willkommen, Reset3
5Profil-Edit (232)0a, 0c
6Rollen-Trennung (234): Verifikation0a, 5
7Account-Löschung (233)0a, 2
8Migration (235): Neos → Drupal0a, 2 (Zielschema + private Files)
8bBestandsnutzer-Aktivierung (241): password_policy + Willkommens-Mail4, 8
9Salesforce-Sync (TBD): Profil-Diff → Mail0a, 5
10Suchagent (237) — Prio hoch0a, Projektliste (project_offer)
11Merkliste-Upgrade (238)0a, bestehende Merkliste, Projektliste

Kritischer Pfad: 0a → 2 → 3 → 4 (der Registrierungs-/Verifizierungs-Flow). Test-Harness (0b) und Form-Primitive (0c) laufen parallel zum Fundament. Migration (8) kann ab Slice 2 starten, muss aber vor Go-Live fertig sein. Suchagent (10) und Merkliste (11) hängen an der Projektliste und können nachgelagert laufen — der Suchagent ist aber gesetzt, nicht optional.

Offene Fragen

  • Migrations-Umfang — entschieden: alle ~37.700 Bestandspartner (ungefiltert); DSGVO-Retention-Nachbewertung nach Go-Live.
  • Skill-Vokabular — entschieden: field_skills als Taxonomie/Tags; Migration normalisiert Freitext-Skills (Fuzzy-Mapping + Review).
  • UI-Label nach Login — entschieden: „Mein Projektpartnerprofil".
  • SF-Sync-Empfänger — entschieden: Config-Platzhalter, Adresse vor Go-Live.
  • Offen (technisch): Webform-Profile-Handler D11-Stabilität + Theme-Integration der Profile-Edit-Form.

QA-Plan

Click-Pfade pro Akzeptanzkriterium — Quelle der Wahrheit für die Pre-PR-Acceptance-Stage des Ralph-Loops und für die Mensch-QA nach PR-Open. Format-Source: ADR-0037. Basis-URL https://solcom.ddev.site. Routen mit * sind in der Implementierung final zu bestätigen.

AK-#URL / PfadActionExpected
AK-1/projektpartnerportal/registrieren *Wizard öffnen, Seite 1 → 2 → 3 durchklicken, „Zurück" nutzenDrei Seiten (Kontakt&Unterlagen / Verfügbarkeit / Qualifikation), Progress-Anzeige, Vor/Zurück erhält bereits eingegebene Werte
AK-2/projektpartnerportal/registrieren *(a) Passwort ≠ Wiederholung absenden — (b) Consent-Checkboxen leer lassen — (c) korrekt ausfüllen(a) Match-Validierungsfehler — (b) Submit blockiert mit Pflicht-Hinweis Datenschutz + Nutzungserklärung — (c) Seite 1 akzeptiert
AK-3/projektpartnerportal/registrieren * + ddev drush user:information <mail>Vollständige Registrierung abschließenUser + projektpartner-Profil + Rolle projektpartner angelegt; Account-Status gesperrt (blocked) bis Verifizierung; Consent mit Timestamp+Version gespeichert
AK-4Test-Mailbox + Verifizierungs-LinkVerifizierungs-Mail öffnen, Aktivierungs-Link klickenMail im SOLCOM-Layout eingegangen; Klick aktiviert Account (Status aktiv); Willkommens-Mail folgt
AK-5/user/login(a) Login mit E-Mail + korrektem Passwort — (b) mit falschem Passwort(a) eingeloggt, Weiterleitung in den Account-Bereich — (b) verständliche Fehlermeldung; Standard-Login der Redakteure bleibt funktionsfähig
AK-6/user/password„Passwort vergessen" mit registrierter E-Mail auslösen, Reset-Link klickenReset-Mail via easy_email-Template eingegangen; Link führt zum Passwort-Setzen; neues Passwort funktioniert
AK-7/projektpartnerportal/registrieren * (DevTools)(a) bereits existierende E-Mail registrieren — (b) Honeypot-Feld via Console füllen + sofort absenden(a) Fehler „E-Mail bereits vergeben", kein zweiter Account — (b) Submit schein-erfolgreich, aber kein User/Profil angelegt
AK-8/user/{uid}/projektpartnerAls eingeloggter Partner alle Feldgruppen bearbeiten + speichernPerson/Kontakt/Verfügbarkeit/Qualifikation editierbar; Zeichenlimits (Anschreiben ≤2000, Schwerpunkte ≤500) greifen; Änderungen persistiert
AK-9Upload eines Dokuments + direkter File-URL private://ppp/<uid>/<file>(a) als Eigentümer abrufen — (b) als anderer eingeloggter Partner abrufen — (c) anonym abrufen(a) Datei wird ausgeliefert — (b) HTTP 403 — (c) HTTP 403; kein öffentlicher Pfad existiert
AK-10/user/{uid_fremd}/projektpartnerAls Partner A das Profil von Partner B aufrufenHTTP 403 — kein Lese-/Schreibzugriff auf fremde Profile
AK-11Account-Bereich → Löschen * + ddev exec ls private://ppp/<uid>/ + DB-CheckLöschung mit Bestätigungs-Schritt anstoßenUser-Account + projektpartner-Profil + alle privaten Dateien + Verzeichnis unwiderruflich entfernt; danach keine PII des Partners mehr auffindbar
AK-12/user/{uid}/edit als Redakteur (Rolle content_editor)Eigenes Account-Formular öffnenUnverändertes Standard-Drupal-Benutzerformular; keine projektpartner-Profilfelder; Registrierungs-Wizard für Redakteure nicht erreichbar
AK-13ddev drush migrate:import solcom_projektpartner_user,solcom_projektpartner_profileMigration gegen Dump-DB ausführenUser + projektpartner-Profil je Bestandspartner angelegt; field_ppp_id gesetzt; DC2Type:array-Felder (Sprachen) korrekt deserialisiert
AK-14ddev exec ls private://ppp/<uid>/ nach MigrationDatei-Migration prüfenBestands-Dokumente (aus userfile ⋈ persistentresource) im privaten Stream, dem richtigen Partner zugeordnet
AK-15/user/login als migrierter PartnerErstes Login eines migrierten AccountsErzwungener Passwort-Reset (Alt-Passwörter nicht migriert); nach Reset normaler Zugang
AK-16ddev drush migrate:import … --update + migrate:rollback + TrockenlaufMigration zweimal laufen lassen, rollback testenIdempotent (keine Duplikate via field_ppp_id); Rollback entfernt sauber; Trockenlauf-/Validierungsbericht liegt vor
AK-17Account-Bereich → Suchagent * + ddev drush cron + Test-MailboxSuchkriterien (Skills + Regionen) anlegen; neues passendes project_offer publizieren; CronBenachrichtigungs-Mail bei passendem Projekt; keine Mail bei nicht passendem
AK-18ddev drush migrate:import solcom_projektpartner_alertAlert-Migration ausführenMigrierte Suchagenten aktiv; Kriterien-Vokabular auf field_skills gemappt; pro Partner ein Alert
AK-19/projektportal/merkliste + Projektliste (anonym, dann eingeloggt)(a) Anonym Projekt merken → Browser-Tab wechseln. (b) Einloggen mit lokal gemerkten Projekten. (c) Auf zweitem Gerät/Browser einloggen.(a) localStorage-Merkliste bleibt (Bestandsverhalten). (b) Lokale Einträge werden in die persistente Merkliste des Partners übernommen. (c) Gemerkte Projekte sind geräteübergreifend da, ohne 5er-Limit
AK-20/user/{uid}/projektpartner + Test-Mailbox (SF-Sync-Empfänger)(a) Ein Profilfeld ändern + speichern. (b) Formular erneut speichern ohne Änderung.(a) Genau eine Diff-Mail an das konfigurierte SOLCOM-Postfach mit nur den geänderten Feldern (alt → neu); Queue-Item erzeugt und nach Cron-Run verarbeitet. (b) Keine Mail, kein Queue-Item
AK-21ddev exec ./vendor/bin/phpunit --testsuite functional-javascript (oder Modul-Pfad)Frontend-Test-Suite gegen Chromedriver in DDEV laufenChromedriver-Service via .ddev/docker-compose.testing.yaml aktiv; Wizard-FunctionalJavascript-Test (Mehrschritt-Navigation, Passwort-Match, Upload, Honeypot) grün; Smoke-Tests für contact_form / newsletter_signup / vacancy_application grün

Worklog

2026-06-16P2503-238 · Persistente Merkliste → Review clean

Ticket-spezifischer solcom-review für P2503-238 persistiert: P2503-238 Review. Standards clean und Spec clean: Projektpartner-Merkliste wird serverseitig persistiert, anonyme Nutzer behalten localStorage, Login-Merge läuft auch auf der leeren Merkliste-Seite, JSON-Mutationen sind rollen-/CSRF-begrenzt und Controller-Boundary-Validierung ist per Kernel-Test abgesichert.

2026-06-16P2503-237 · Suchagent / Projekt-Alert → Review clean

Ticket-spezifischer solcom-review für P2503-237 persistiert: P2503-237 Review. Standards clean und Spec clean für den finalen Alert-Aktivierungsdiff: Modul in Sync aktiviert, Projektpartner-Rolle berechtigt, Alert-Mail- und Migrationsconfig synchronisiert, Unique-Constraint auf Drupal-11-Attribute umgestellt und Mail-Platzhalterlogik per Kernel-Test abgedeckt. Restkontext: echter Neos-Dump noch nicht importiert; lokale Migration bleibt bis zur Dump-Bereitstellung synthetisch verifiziert.

2026-06-15P2503-229 · Private Dokument-Uploads → Standards Review

Privates, owner-only Upload-Feld field_documents (private://ppp/[current-user:uid]/, 10 MB, pdf/doc/docx/odt/txt/rtf/jpg/jpeg/png) auf dem projektpartner-Profil implementiert. hook_file_download-Gate delegiert die Zugriffsentscheidung an die Profile-Entity (Owner via „view own", Admins via „administer profile") und schließt verwaiste ppp/-Dateien fail-closed aus; self-contained PrivateFileUriItemOverride mit Canvas-Guard via class_exists. 9 Kernel-Tests grün (222 Assertions), PHPCS + PHPStan sauber. Lokaler Review: solcom-review (Standards+Spec) + codex-review — codex fand einen echten Real-Path-Bug (Admin-Download scheiterte an Core's deny-wins, da administer users keinen Profil-View gewährt) → Fix auf Profile::access('view'); zudem drupal:file-Dependency + per-User-Pfad ergänzt. Commit 5a3b0f3, PR #167365 (→ develop).

2026-06-15Grilling + Refinement

Story gegen Neos-Bestandssystem (MySQL-Dump db_10770solcom, ~37.700 User) und Drupal-Best-Practice gestresstet. Sieben Architektur-Achsen entschieden (Tabelle „Gegrillte Entscheidungen"). ADR-0052 (Datenmodell) geschrieben, customer-lens-reviewed, D11-Kompatibilität von drupal/profile empirisch per Composer-Dry-Run bestätigt. CONTEXT.md um Projektpartner:in / projektpartner-Profil / Suchagent erweitert, PPP-Definition geschärft. PRD erstellt. Scope: Suchagent + Bookmarks rein, Verfügbarkeits-Flow raus. Zwei neue Sub-Tasks (Suchagent, Bookmarks) anzulegen, 235 zu überarbeiten.