| Browser (Multipart-Form-Upload) |
rein → |
- file binary (PDF/DOC/DOCX)
- filename
- MIME type
- file size
- CSRF token
|
ApiController::uploadTempFileAction() — anonymer Gast-Upload während Registrierungsformular (vor Account-Aktivierung) |
Web-Request (synchron) |
HTTP-REST multipart/form-data via $_FILES['file'] |
Drupal-Äquivalent: managed_file field + file.module; PII-relevant (Lebenslauf/Zertifikate von Freelancern). Im Drupal-Nachbau als temporäres verwaltetes File anlegen (file_save_upload), anschließend in eigener Tabelle als 'temporary file' vorhalten bis Registrierung abgeschlossen. |
| Browser (Multipart-Form-Upload, Registrierungsformular) |
rein → |
- file binary (PDF/DOC/DOCX)
- filename
- MIME type
- file size
- file error code
|
AccountController::registerAction() — Gast lädt Dokumente während der Registrierung hoch (mehrteiliges Formular, vor Account-Aktivierung) |
Web-Request (synchron) |
HTTP-REST multipart/form-data via $_FILES['--contenance_solcom-portal_account_register']['tmp_name']['uploads'] |
In Drupal: Webform- oder Custom-Form mit managed_file Widget; Upload im Registrierungs-Flow speichern und nach E-Mail-Bestätigung an Account koppeln. Zwischenzustand (nicht aktivierter Account) muss in Drupal explizit abgebildet werden. |
| Browser (Multipart-Form-Upload, authentifizierter Nutzer) |
rein → |
- file binary (PDF/DOC/DOCX)
- filename
- MIME type
- file size
|
AccountController::userProfileUploadAction() — eingeloggter Projektpartner lädt Profildokument hoch (max. 5 Dateien) |
Web-Request (synchron) |
HTTP-REST multipart/form-data via $_FILES['input_file_name'] |
Gleiches Muster wie Gast-Upload, aber an authentifizierten User gebunden. Drupal-Nachbau: CSRF-geschützter AJAX-Endpoint mit file_validate_extensions() + file_validate_size(); Ergebnis direkt als managed file an User-Profil-Entity hängen. |
| Browser-Cookie ('info') — Referer-Tracking |
rein → |
- url_full (Base64-encoded, max. 252 Zeichen — Herkunfts-URL des Bewerbers)
|
CareerPersonioController::jobApplicationSendAction() — liest Cookie bei Bewerbungs-Submit; wird als custom_attribute_2722693 und custom_attribute_2722695 an Personio weitergegeben |
Web-Request (synchron, on-demand) |
Cookie |
In Drupal: Cookie 'info' muss beim Bewerbungsformular-Submit ausgelesen werden. Domain-Mapping-Logik (40+ Job-Portale) aus CareerPersonioController::jobApplicationSendAction() Zeilen 752-805 muss eins zu eins übernommen werden — sie bestimmt den Kanal-Label-Wert für Personio-Reporting. PII-Relevanz: MITTEL — URL kann personenbezogene Query-Parameter enthalten. |
| Browser-Cookie / Session (inbound read) |
rein → |
- searchParameter (JSON-Array)
- location (JSON-Array)
- business (JSON-Array)
- zip (JSON-Array, gefiltert auf nicht-leere Einträge)
|
BookmarkController::indexAction() — GET-Request auf Bookmark-Übersichtsseite; Cookies werden gelesen und als Template-Variablen übergeben (Sidebar-Suchparameter wiederherstellen) |
Web-Request (synchron) |
Cookie (HTTP Cookie-Header, gelesen via CookieService::getCookie, JSON-dekodiert) |
Lücke: Drupal-Rebuild muss diese vier Cookies lesen und an den Bookmark-View übergeben; wahrscheinlich werden diese Cookies von einem separaten Suchformular-Controller gesetzt (nicht in diesen drei Dateien); Suchparameter-Cookie-Persistenz muss ebenfalls implementiert werden |
| Mailingwork (login.mailingwork.de/webservice/webservice/json/) |
rein → |
- email
- listId '1'
- result (0=nicht in Liste, 1=in Liste)
|
AccountController::profileAction() — beim Laden der Profilseite wird geprüft, ob die E-Mail des eingeloggten Nutzers in der Mailingwork-Liste steht (isemailinlist), um den Subscribe/Unsubscribe-Toggle korrekt darzustellen |
Web-Request (synchron, bei jedem Profilseitenaufruf) |
HTTP-REST (cURL POST) |
Leicht redundant mit user.field_magazine_option. Drupal-Nachbau kann auf das lokale Feld zurückgreifen, statt Mailingwork live abzufragen — Performance-Vorteil. Lücke: Konsistenz zwischen lokalem Flag und Mailingwork-Stand sicherstellen (bei externem Unsubscribe). |
| Personio XML Feed (https://solcom-gmbh.jobs.personio.de/xml) |
rein → |
- id
- office
- department
- recruitingCategory
- name
- subcompany
- jobDescriptions
- employmentType
- seniority
- schedule
- yearsOfExperience
- occupation
- occupationCategory
- createdAt
|
PersonioCommandController::importCommand() — CLI-Command `./flow personio:import` |
Cron (Intervall nicht in Code festgelegt; muss in Cron-Tab konfiguriert werden) |
HTTP-REST (cURL GET, Accept: text/xml) — curlPersonioProjects() in PersonioService |
Entspricht dem geplanten Drupal-Modul für Stellenanzeigen-Import. Noch nicht vorhanden. Benötigt: Drupal Migrate-Source oder Custom-Service, der den XML-Feed pollt und in eine lokale Entity (Node-Type 'job_posting' o.ä.) persistiert. PII-Relevanz: keine in den Stellendaten. |
| SOLCOM-Website (https://www.solcom.de/asp/robots/projectReferences.xml) |
rein → |
- ID
- Headline
- Name (Kundenname)
- Industry
- ProjectDescription
- Tags
|
CLI-Befehl `referenceProject:import` (ReferenceProjectCommandController::importCommand) holt XML via HTTP GET curl |
Cron (on-demand; Intervall nicht im Paket definiert) |
HTTP-REST (curl GET, SSL-Verifikation deaktiviert) |
Referenzprojekte (Kundenprojekte, nicht Freelancer-Angebote) sind ein separater Content-Typ. Im Drupal-Nachbau als `reference_project`-Node-Typ oder via Migration zu behandeln. Kein direktes Äquivalent in solcom_project_offer — eigenes Migrate-Modul erforderlich. Kein PII, aber Kundennamen sind potentiell vertraulich. |
| Salesforce/RMS (via Filesystem-Drop: OpenPos.xml) |
rein → |
- lfdNr (Projekt-ID)
- Titel
- Beschreibung
- Start
- Dauer
- Ort
- Stellentyp
- Bearbeiter
- Aktiv
- Anforderungen
- Zusatz
- GULPRobot
- aktiviert_am
- deaktiviert_am
- LastModified
- LastModifiedBearbeiter
- Region
- Unternehmensbereich (enthält 'Salesforce' als Wert)
- Branche
- keinePortale
- skills
- tags
- FreelancerLink (minggo.io-URL)
- AgencyLink (minggo.io-URL)
|
CLI-Befehl `project:import` (ProjectCommandController::importCommand) liest die Datei Resources/Private/Import/OpenPos.xml via simplexml_load_file() |
Cron (on-demand / scheduled, kein Crontab im Paket gefunden; Intervall liegt außerhalb des Pakets) |
Dateisystem (XML-Datei, UTF-16 codiert, Filesystem-Drop durch externen Prozess — vermutlich Salesforce-Export) |
Im Drupal-Nachbau (solcom_project_offer) übernimmt ein Migrate-Sync-Modul diese Rolle. Die Datei OpenPos.xml entspricht dem Feed `field_sf_*`-Feldern auf dem node type `project_offer`. PII-relevant: Bearbeiter-E-Mail (z.B. a.peeke l@solcom.de) steckt im XML-Feld und landet in `contact`. |
| Flow PersistentResource / Filesystem (FLOW_PATH_DATA/Persistent/Resources/<sha1[0]>/<sha1[1]>/<sha1[2]>/<sha1[3]>/<sha1>) |
⛁ intern |
- file binary (SHA1-adressiert)
- sanitisierter Dateiname (alphanum + _.-)
- MIME type
- Dateigröße
- creationDate
|
ResourceManager::importUploadedResource() — aufgerufen aus UploadService::uploadFile(), AccountController::registerAction() und AccountController::userProfileUploadAction() |
Web-Request (synchron), on-demand |
Dateisystem (PHP file_get_contents / Stream-API) |
Flow speichert Binärdaten als SHA1-Content-Addressed-Files unter Data/Persistent/Resources/. In Drupal: public:// oder private:// managed files (sites/default/files/). PII-kritisch: Lebensläufe/Zertifikate müssen in private:// liegen, nicht public://. Entspricht Drupal FileInterface + ManagedFile-Widget. |
| Flow-Session (PHP-Session-Storage) |
⛁ intern |
- projects (array von Projekt-IDs/Strings — Lesezeichen des anonymen/eingeloggten Besuchers)
|
Bookmark::addProject() — aufgerufen bei Klick auf Merken-Button; @Flow\Session(autoStart=true) |
Web-Request (synchron) |
Session |
Bookmark ist @Flow\Scope('session') — kein Doctrine-Entity, kein DB-Persist; im Drupal-Rebuild als PHP-Session oder Drupal-TempStore abgebildet; für angemeldete User im Drupal-Rebuild per Watchlist-Node-Reference persistiert |
| Flow-Session (server-side) |
⛁ intern |
- Bookmark.projects (Array von Project-UUIDs, max. 7 Einträge)
|
BookmarkController::addAction() / removeAction() / removeAllAction() — AJAX-Requests vom Browser; Bookmark-Model ist @Flow\Scope('session'), wird server-seitig in Flow-Session persistiert |
Web-Request (synchron, on-demand per AJAX) |
Session (Neos Flow Session-Storage, server-seitig; Client hat nur Session-Cookie-ID) |
In Drupal: $_SESSION oder tempstore (PrivateTempStore) für anonyme/authentifizierte User; max. 7 Bookmarks ist Business-Regel die übernommen werden muss |
| MySQL-Tabelle: contenance_solcom_domain_model_accountchangeflow |
⛁ intern |
- oldEmail
- newEmail
- activationToken (30-Zeichen-Zufallsstring)
- activationTokenValidUntil (datetime)
- creationDate (datetime)
|
E-Mail-Adresse-Ändern-Formular-Submit (zweistufige Bestätigung) |
Web-Request (synchron) |
DB-Doctrine |
Im Drupal-Rebuild als solcom_projektpartner AccountChangeFlow abgebildet (bereits implementiert in P2503-230); speichert old+new E-Mail transient bis Bestätigung — PII-Retention-Window beachten |
| MySQL-Tabelle: contenance_solcom_domain_model_availability |
⛁ intern |
- staffId (PersonalNr des SOLCOM-Mitarbeiters)
- projectPartner (Projektnummer/RMS-Referenz)
- type (Mailtyp integer)
- email (E-Mail-Adresse des Projektpartners)
- salutation (Anredezeile)
- staff (Name SOLCOM-Mitarbeiter)
- editor (Bearbeiter-Name)
- hash
- creationDate
- status (1=Mail gesendet, 2=PP hat geantwortet)
|
Verfügbarkeitsabfrage durch SOLCOM-Mitarbeiter (CRM-seitig initiiert) |
Web-Request (synchron) / on-demand |
DB-Doctrine |
Kein direktes Äquivalent im aktuellen Drupal-Rebuild erkennbar; enthält PII beider Seiten (PP-E-Mail + Mitarbeiter-Name/ID); bei Migration prüfen ob als Custom-Entity oder als Webform-Submission abzubilden |
| MySQL-Tabelle: contenance_solcom_domain_model_donation |
⛁ intern |
- salutation
- personalAddress
- title
- firstname
- lastname
- email (Empfänger/Projektpartner)
- salesPersonalAddress
- salesName (Name des SOLCOM-Sales-Mitarbeiters)
- salesEmail (E-Mail des SOLCOM-Sales-Mitarbeiters)
- mailStatus (0–4 Fortschritts-Integer)
- donationStatus (bool)
- creationDate
- spendDate
- donationOrganisation FK
|
Spendenformular-Submit (SOLCOM-internes Kampagnen-Feature) |
Web-Request (synchron) |
DB-Doctrine |
Einmaliges Kampagnen-Feature; kein Äquivalent im aktuellen Drupal-MVP; enthält PII beider Seiten (Projektpartner + Sales-Mitarbeiter); bei Drupal-Migration: Post-MVP oder als Webform-Submission mit Consent-Flag; salesEmail ist interne Mitarbeiter-E-Mail |
| MySQL-Tabelle: contenance_solcom_domain_model_lead2faform |
⛁ intern |
- token (Zufalls-Token — verknüpft Lead mit 2FA-Opt-in)
- accepted (bool)
- acceptedDate (datetime, nullable)
|
2FA-/Lead-Formular-Consent-Klick |
Web-Request (synchron) |
DB-Doctrine |
Kein direktes Äquivalent erkennbar; token allein ist kein PII, aber Verknüpfung zum Lead impliziert personenbezogenen Kontext; im Drupal-Rebuild als Consent-Log-Feld am User-Profil oder als Webform-Submission abzubilden |
| MySQL-Tabelle: contenance_solcom_domain_model_projectalert |
⛁ intern |
- tags (array — Suchfilter-Kriterien)
- noTags (array — Ausschluss-Tags)
- states (array — Projektstatus-Filter)
- hash
- active (bool)
- user FK → contenance_solcom_domain_model_user (nullable)
- guest FK → contenance_solcom_domain_model_projectalertguest (nullable, cascade all)
|
Projektbenachrichtigung-Einrichten durch registrierten User oder Gast |
Web-Request (synchron); Benachrichtigungs-Versand via Cron |
DB-Doctrine |
Im Drupal-Rebuild als solcom_project_offer Watchlist-Modul abgedeckt; user-FK ist PII-Verknüpfung; guest-Zweig enthält eigenständige PII (→ ProjectAlertGuest-Kante) |
| MySQL-Tabelle: contenance_solcom_domain_model_projectalertguest |
⛁ intern |
- gender
- firstName
- lastName
- email
|
Projektbenachrichtigung-Einrichten durch nicht-registrierten Gast |
Web-Request (synchron) |
DB-Doctrine |
Gast-PII ohne Account-Binding; im Drupal-Rebuild prüfen ob als anonyme Webform-Submission oder eigene Entity abzubilden; DSGVO-Lösch-Mechanismus fehlt in Neos-Quelle |
| MySQL-Tabelle: contenance_solcom_domain_model_registrationflow |
⛁ intern |
- email
- encryptedPassword (bcrypt-Hash)
- notified (bool)
- attributes (json_array — enthält firstName, lastName und weitere Registrierungsfelder)
- activationToken (30-Zeichen-Zufallsstring)
- activationTokenValidUntil (datetime)
|
Registrierungs-Formular-Submit (vor Account-Aktivierung) |
Web-Request (synchron) |
DB-Doctrine |
In Drupal durch solcom_projektpartner ProjektpartnerRegistrationSubmitter ersetzt; kein persistenter Flow-Zwischenspeicher — Token-basierte Aktivierung per E-Mail; Lücke: attributes-JSON enthält Registrierungsdaten, die im Drupal-Rebuild explizit gemappt werden müssen |
| MySQL-Tabelle: contenance_solcom_domain_model_resetpasswordflow |
⛁ intern |
- email
- resetPasswordToken (30-Zeichen-Zufallsstring)
- resetPasswordTokenValidUntil (datetime)
|
Passwort-vergessen-Formular-Submit |
Web-Request (synchron) |
DB-Doctrine |
In Drupal durch Core-eigenen Passwort-Reset-Flow (user/password) abgedeckt; kein Custom-Entity nötig |
| MySQL-Tabelle: contenance_solcom_domain_model_sommerfestperson |
⛁ intern |
- gender
- firstname
- lastname
- email
- qrCode
- identification
- status (0=kein Eintrag, 1=Eintrag vorhanden)
- creationDate
- submitDate
|
Sommerfest-Anmeldeformular-Submit |
Web-Request (synchron) |
DB-Doctrine |
Einmaliges Event-Feature; kein Äquivalent im aktuellen Drupal-MVP geplant; enthält vollständige personenbezogene Kontaktdaten inkl. QR-Code-Verknüpfung; bei Migration auf Post-MVP schieben oder als Webform-Modul-Submission abbilden |
| MySQL-Tabelle: contenance_solcom_domain_model_user |
⛁ intern |
- email (NotNull, unique via account FK)
- title
- salutation
- gender
- firstName
- lastName
- hourlyrate
- birthday
- company
- phone
- mobile
- website
- streetAndNumber
- zip
- city
- country
- countryAll
- countryA
- countryCh
- countryDe
- countryInternational
- available
- location
- networkGulpId
- networkFreelancer
- networkXing
- networkFreelancermap
- professionalEmphases
- magazine
- skills (text, max 1000)
- applicationText (text, max 2500)
- rmsNumber
- languages (array/json)
- bookmarks (array/json)
- policyOption (bool)
- magazineOption (bool)
- lastAccountEditDate (datetime)
- account FK → neos_flow_security_account
|
Registrierung, Profil-Update, Account-Anlage |
Web-Request (synchron) |
DB-Doctrine |
Drupal-Entsprechung: user-Entity + zugehörige Profilfelder als Custom-Fields (field_rms_number, field_skills, field_available etc.); PII-Felder vollständig vorhanden laut NeosProjektpartnerUser-Migration; bookmarks-Array im Drupal-Watchlist-Modul als eigene Entität gelöst |
| MySQL/Doctrine ORM (Neos-Datenbank, Tabelle contenance_solcom_domain_model_project) |
⛁ intern |
- id (lfdNr)
- nodeId
- creationDate
- title
- description
- start
- duration
- location
- type
- contact
- active
- requirements
- additional
- gulp
- activated
- deactivated
- modified
- modifiedContact
- state
- division
- business
- noPortal
- skills
- tags
- freelancerLink
- agencyLink
|
ProjectCommandController::createProject() bei neuer lfdNr; ::updateProject() wenn LastModified im XML neuer als in DB; ::removeProject() bei fehlender lfdNr im aktuellen XML-Lauf |
Cron (synchron mit import-Command) |
DB-Doctrine (Neos Flow PersistenceManager::persistAll()) |
Drupal-Äquivalent: node type `project_offer` mit Feldern field_sf_lfd_nr, field_sf_title, etc. (bereits implementiert in solcom_project_offer). Lücke: `noPortal`-Flag (keinePortale) steuert, ob ein Projekt im Portal erscheint — muss als Boolean-Feld (field_sf_no_portal) im Drupal-Node vorhanden sein und im View-Query ausgewertet werden. |
| MySQL/Doctrine ORM (Tabelle contenance_solcom_domain_model_rms) |
⛁ intern |
- counter (Integer, autoinkrement bei jeder Neuregistrierung)
|
FlowUserCreationService::createUserFromRegistrationFlow() bei erfolgreicher Registrierung eines neuen Projektpartners; UtilityCommandController::setCounterCommand() / createCounterCommand() / setCounterToUsersCommand() für Admin-Operationen |
Web-Request (Registrierung) + on-demand CLI |
DB-Doctrine (Neos Flow PersistenceManager) |
Im Drupal-Nachbau (solcom_projektpartner) bereits als `field_rms_number` auf dem User-Entity implementiert. Der Counter selbst muss als Singleton-Config (State-Tabelle oder Drupal State API) migriert werden. Startwert laut Code: 121212. PII-Relevanz: RMS-Nummer ist interner Identifier, aber indirekt personenbezogen (verknüpft mit User-Account). |
| MySQL/Doctrine ORM (Tabelle contenance_solcom_domain_model_user, Feld rms_number) |
⛁ intern |
- rmsNumber (String, entspricht dem aktuellen RMS-Counter-Wert zum Zeitpunkt der Registrierung)
|
FlowUserCreationService::createUserFromRegistrationFlow() — direkt nach Anlage des User-Objekts wird der aktuelle Counter-Wert als rmsNumber gesetzt und der Counter inkrementiert |
Web-Request (einmalig bei Nutzer-Registrierung) |
DB-Doctrine |
Bereits in Drupal migriert als `field_rms_number` (solcom_projektpartner-Modul). Wichtig: die Zuweisung ist atomar (read-then-increment) — bei parallelen Requests Race-Condition-Risiko in der Legacy-Implementierung; im Drupal-Rebuild via Database-Transaction oder Sequence absichern. |
| MySQL/Doctrine ORM — lokale PersonioProject-Entity (Cache-Tabelle) |
⛁ intern |
- id (Personio-ID)
- subcompany
- office
- department
- recruitingCategory
- name
- jobDescriptions (JSON/Array)
- employmentType
- seniority
- schedule
- yearsOfExperience
- occupation
- occupationCategory
- createdAt
- nodeId (Neos-Content-Repository-UUID)
- creationDate
|
PersonioCommandController::importCommand() — create/modify/remove je nach Diff gegen Live-Feed |
Cron (sync mit XML-Fetch) |
DB-Doctrine (PersonioProjectRepository add/update/remove) |
In Drupal: node-basierte oder custom-entity-basierte lokale Cache-Tabelle für Personio-Stellenanzeigen. Schlüssel-Feld ist die numerische Personio-ID ('id'). jobDescriptions ist ein Array (serialisiert), in Drupal als JSON-Feld oder Paragraph-Entity abzubilden. nodeId-Äquivalent entfällt (Neos-spezifisch). |
| MySQL/Doctrine — Tabelle contenance_solcom_domain_model_temporaryfile |
⛁ intern |
- UUID (identifier)
- type ('guest')
- creationDate (DateTime)
- originalResource FK → neos_flow_resourcemanagement_persistentresource
|
UploadService::uploadFile() — nach erfolgreichem importUploadedResource(); Lifecycle: bleibt bis zum manuellen Cleanup über SolcomResourcesCommandController::cleanCommand() |
Web-Request (synchron) beim Upload; Cleanup on-demand (Cron/manuell) |
DB-Doctrine (Neos Flow ORM) |
Kein direktes Drupal-Core-Äquivalent für 'temporäre Datei mit explizitem DB-Record'. In Drupal: status=0 in file_managed (temporäre Dateien werden nach 6h von file_cron() gelöscht). Lücke: Legacy hält TemporaryFile unbegrenzt — Drupal-Nachbau braucht expliziten Cleanup-Cron (hook_cron) oder temporäre Files mit TTL. |
| MySQL/Doctrine — Tabelle contenance_solcom_domain_model_userfile (JOINED Inheritance) |
⛁ intern |
- UUID (identifier)
- title (sanitisierter Dateiname)
- creationDate (DateTime)
- shouldNotSendAsNotification (bool)
- originalResource FK
- user FK → User (nullable)
- registrationFlow FK → RegistrationFlow (nullable)
|
AccountController::registerAction() (Registrierung, FK auf RegistrationFlow), AccountController::userProfileUploadAction() (eingeloggter Nutzer, FK auf User). Max. 5 Dateien pro User. |
Web-Request (synchron) |
DB-Doctrine (Neos Flow ORM) |
In Drupal als eigenes Content Entity 'user_document' oder als field_file auf einem Custom-Profile-Entity modellieren. Wichtig: shouldNotSendAsNotification muss als Boolean-Feld erhalten bleiben (steuert tägliche Notification-E-Mail). FK auf RegistrationFlow wird nach Account-Aktivierung auf User umgeschrieben — in Drupal entsprechend im Hook nach Account-Aktivierung migrieren. PII: Lebensläufe, Zertifikate. |
| MySQL/Doctrine — neos_flow_resourcemanagement_persistentresource (Flow Core-Tabelle) |
⛁ intern |
- sha1 (Content-Hash)
- filename (sanitisiert)
- mediaType
- collectionName
- fileSize
|
ResourceManager::importUploadedResource() — wird von UploadService und AccountController aufgerufen; PersistentResource ist das zentrale Binär-Registry-Objekt, auf das UserFile und TemporaryFile per FK zeigen |
Web-Request (synchron) beim Upload; Cleanup via SolcomResourcesCommandController::cleanCommand() (on-demand/manuell) |
DB-Doctrine (Neos Flow ORM) |
Entspricht Drupal-Kern-Tabelle file_managed (fid, uri, filename, filemime, filesize, status). Cascade-Delete: UserFile hat cascade={'all'} auf originalResource — beim Löschen eines UserFile wird auch der PersistentResource-Eintrag und die Datei auf dem Filesystem entfernt. In Drupal: file_usage_delete() + file_delete() korrekt aufrufen. |
| Neos Content Repository (NodeData, Workspace 'live') |
⛁ intern |
- title
- titleOverride
- metaDescription
- contentForSearch (description+requirements+skills+tags)
- uriPathSegment (title-lfdNr)
- canonicalLink
- openGraphType
- openGraphTitle
- openGraphDescription
- openGraphImage
- projectid (Doctrine UUID des Project-Objekts)
- NodeType: Contenance.Solcom:Document.Portal.Project
|
ProjectCommandController::createProjectNode() bei Neuanlage; removeProjectNode() bei Löschung; updateProjectNode() ist implementiert aber auskommentiert (nicht aktiv) |
Cron (synchron mit import-Command) |
DB-Doctrine (Neos ContentRepository NodeDataRepository) |
Im Drupal-Nachbau keine 1:1-Entsprechung nötig: Drupal-Nodes sind bereits die kanonischen Entitäten. `contentForSearch` (Volltextfeld) wird in Drupal durch Search-API-Indexierung ersetzt. `projectid`-Referenz entfällt (Node = Entity). Relevant: `uriPathSegment`-Logik → Drupal pathauto mit Muster `/fuer-freiberufler/projektliste/[title]-[lfdNr]`. |
| Neos Content Repository (NodeData, Workspace 'live', NodeType Contenance.Solcom:Document.ReferenceProject) |
⛁ intern |
- title (Headline)
- titleOverride
- metaDescription
- uriPathSegment (Headline-ID)
- description (ProjectDescription, nl2br)
- customer (Name)
- branche (Industry)
- words (Tags)
- NodeType: Contenance.Solcom:Document.ReferenceProject
|
ReferenceProjectCommandController::createNodes() nach erfolgreichem XML-Fetch; pruneCommand() löscht alle bestehenden Nodes vor Re-Import |
Cron (synchron mit referenceProject:import) |
DB-Doctrine (Neos ContentRepository) |
Im Drupal-Nachbau eigener Node-Typ nötig. Wichtig: pruneCommand + createNodes ist ein vollständiger Replace-Zyklus (kein Delta-Import) — im Drupal-Rebuild als Truncate+Reimport oder via Migrate-Rollback+Run abbilden. |
| Settings.Solcom.yaml (interne Konfiguration) |
⛁ intern |
- mailingworks.username ('Geopard')
- mailingworks.password ('Ben1ist_Super!')
- mailingworks.listId ('1')
|
Applikationsstart / Service-Injection (injectSettings) |
einmalig (pro Request-Lifecycle) |
Dateisystem (Flow-Settings-Injection) |
Credentials NICHT in VCS übernehmen. Drupal-Nachbau: settings.php / .env mit MAILINGWORK_USERNAME, MAILINGWORK_PASSWORD, MAILINGWORK_LIST_ID. listId='1' entspricht Liste 'SOLCOM Freiberufler Magazin' — diese ID im Drupal-Config-Objekt hinterlegen. |
| Browser (authentifizierter Download / Inline-Anzeige) |
→ raus |
- file binary (via SHA1)
- filename
- MIME type
- Content-Length
|
ApiController::getpersistentfileAction() — eingeloggter Nutzer ruft /api/getpersistentfile?file=<sha1/path> auf; Authentifizierung wird vor Auslieferung geprüft |
Web-Request (synchron) |
HTTP (header() + echo; kein Framework-Response-Objekt — direktes PHP-Streaming) |
Sicherheitslücke im Legacy-Code: sha1 wird aus URL-Parameter extrahiert, jede bekannte SHA1 ist abrufbar (kein User-Scope-Check). Drupal-Nachbau muss private:// + hook_file_download() mit explizitem Owner/Role-Check implementieren. PII-kritisch. |
| Browser-Cookie |
→ raus |
- info.time
- info.url_full (base64-encoded HTTP_REFERER or utm_source value)
|
SolcomComponent::handle() — jeder eingehende HTTP-Request auf karriere.solcom.de mit gesetztem HTTP_REFERER oder utm_source-Query-Param; externer Referrer überschreibt bestehenden Cookie nur wenn er nicht von solcom.de-Domains stammt |
Web-Request (synchron, jeder Page-Load) |
Cookie (Set-Cookie HTTP-Header, Laufzeit +1 Tag, JSON-codiert) |
Lücke: Drupal hat keinen Äquivalent; muss als custom EventSubscriber (KernelEvents::REQUEST) oder Middleware neu gebaut werden; PII-Relevant: URL kann personenbezogene Suchanfragen enthalten |
| Browser-Cookie |
→ raus |
- utm_time.time
- utm_time.utm_source
- utm_time.utm_sourcename
- utm_time.utm_medium
|
SolcomComponent::handle() — Request mit utm_source + utm_medium + utm_campaign=Jobposting Query-Params; bekannte utm_source (freelancercheck.de, gulp.de, jooble.org, xing.com, projektwerk.com, job.trovit.com); Cookie wird nach 24h gelöscht |
Web-Request (synchron) |
Cookie (Set-Cookie, Laufzeit +1 Tag, JSON-codiert) |
Lücke: kein Äquivalent; custom Middleware oder EventSubscriber nötig; utm_sourcename ist normalisierter Plattformname (Enum-artiger Wert), muss Mapping aus getUtmSourceName() übernommen werden |
| Browser-Cookie |
→ raus |
- utm_measurement.time
- utm_measurement.utm_source
- utm_measurement.utm_medium
- utm_measurement.utm_campaign (optional)
|
SolcomComponent::handle() — Request mit utm_source + utm_medium Query-Params (unabhängig von utm_campaign); @deprecated laut Code-Kommentar; Cookie wird nach 24h gelöscht |
Web-Request (synchron) |
Cookie (Set-Cookie, Laufzeit +1 Tag, JSON-codiert) |
Deprecated in Legacy — für Drupal-Rebuild evaluieren ob Measurement Protocol noch aktiv genutzt wird; wenn ja: custom Middleware; wenn nein: weglassen |
| Browser-Cookie |
→ raus |
- utm_ads.time
- utm_ads.utm_campaign (444=XING, 555=LinkedIn, 666=Bing, 333=Google)
|
SolcomComponent::handle() — Request mit utm_campaign in {444,555,666} ODER gid=googleadsfreelancer Query-Param; Cookie wird nach 24h gelöscht |
Web-Request (synchron) |
Cookie (Set-Cookie, Laufzeit +1 Tag, JSON-codiert) |
Lücke: Werbeplattform-Tracking-Cookie; custom Middleware; Kampagnen-ID-Mapping (numerische Codes → Plattformnamen) muss ins Drupal-Äquivalent übernommen werden |
| Browser-Cookie |
→ raus |
- sol_act (AES-128-CBC-verschlüsselt, base64): time, msclkid (Microsoft Ads Click-ID), gclid (Google Ads Click-ID)
|
SolcomComponent::handle() — Request mit msclkid oder gclid Query-Param (Enhanced Conversion Tracking); Cookie wird nach 24h gelöscht; Verschlüsselungskey '«redigiert»' hardcoded |
Web-Request (synchron) |
Cookie (Set-Cookie, Laufzeit +1 Tag, AES-128-CBC-verschlüsselt + base64) |
PII-kritisch: msclkid/gclid sind nutzerbezogene Ad-Click-IDs; hardcodierter Schlüssel muss in Drupal-Config/Secrets-Management; Drupal-Rebuild als custom EventSubscriber; Verschlüsselung beibehalten oder durch httpOnly+Secure-Cookie ersetzen |
| Google Analytics Measurement Protocol (UA-17264541-1 / UA-17264541-4) |
→ raus |
- v (protocol version=1)
- t (hit type: event)
- tid (UA-17264541-1 Projektportal / UA-17264541-4 Karriere)
- cid (timestamp als Client-ID)
- ec (event category: Projektbewerbung / Karriere Bewerbung / B2B Anfrage / Account Manager Karriere Bewerbung / MP-Variante)
- ea (event action: Bewerbungsart + guestOrUser)
- el (Protocol - transactionId)
- ti (transaction ID, inkrementeller Zähler aus Statistics-Entity)
- pa (product action: purchase)
- pr1id / pr2id... (project.getId())
- pr1nm / pr2nm... (project.getTitle())
- pr1ca / pr2ca... (Projektportal / Karriere/<office>)
- geoid (DE)
- cs / cm / cn (utm_source, utm_medium, utm_campaign aus utm_measurement-Cookie)
|
ProjectController->sendAction (Bewerbung abschicken), CareerPersonioController->sendAction (Karrierebewerbung abschicken), FormsController->sendForm (B2B Kontaktformular), LandingpageFinisher->executeFinisher (Landingpage-Formular) |
Web-Request (synchron, server-side cURL im Request-Thread) |
HTTP-REST (cURL POST zu http://www.google-analytics.com/collect) |
Lücke — noch nicht implementiert. In Drupal: Measurement Protocol Calls oder serverseitiges GA4 Event API bei Bewerbungs-Submission; UTM-Cookie-Auslesen via custom Service. PII-Relevanz: transactionId, projectId/-name, UTM-Daten. UA ist deprecated → auf GA4 Measurement Protocol migrieren. |
| Google Fonts (fonts.googleapis.com) |
→ raus |
- Font-Familie: Open+Sans (300,400,600,700)
- Font-Familie: Lato (300,300italic,400,400italic,700,700italic,900) — nur ACP-Vendor-Asset
- Font-Familie: Raleway (300,400,600) — nur Dashboard-Template
|
Jeder Seitenaufruf (HTML <link rel=stylesheet> im <head>) |
Web-Request (synchron, beim Seitenload) |
HTTP-REST (CSS-Request an fonts.googleapis.com, nachfolgende Font-Datei-Requests an fonts.gstatic.com) |
Bekannt und abgedeckt — in Drupal-Neuaufbau prüfen ob Fonts self-hosted werden sollen (DSGVO-konform) oder ob der CDN-Link beibehalten wird. byte_theme nutzt ggf. bereits eigene Font-Einbindung. Kein API-Key erforderlich. |
| Google Maps JavaScript API (key: AIzaSyBz3SQLqUNyB_nvdm4E1FortzlH3oWRId8) |
→ raus |
- API Key: AIzaSyBz3SQLqUNyB_nvdm4E1FortzlH3oWRId8
- lat (Breitengrad aus Neos-Node-Property)
- lng (Längengrad aus Neos-Node-Property)
- title (Marker-Titel aus Neos-Node-Property)
- node.identifier (Map-Container-ID)
|
Seitenaufruf einer Seite mit Contenance.Solcom:Map-ContentElement, NACHDEM der Benutzer Google-Maps-Cookies im Cookie-Consent-Banner akzeptiert hat; Cookie-Consent-Callback lädt maps.google.com/maps/api/js dynamisch nach |
Web-Request (on-demand, client-side nach Cookie-Consent) |
HTTP-REST (dynamisch geladenes JS-Bundle von maps.google.com) |
Lücke — Google Maps API Key muss in Drupal-Konfiguration (Umgebungsvariable / settings.php) hinterlegt werden. Cookie-Consent-Integration mit Drupal EU Cookie Compliance oder ähnlichem Modul. API Key ist im Legacy-Code im Klartext in Script.js — in Drupal als Config-Secret ablegen. PII-Relevanz: IP-Adresse wird an Google übermittelt. |
| Google Tag Manager (GTM-ND5SFNH) / Google Analytics (client-side dataLayer) |
→ raus |
- GTM-Container-ID: GTM-ND5SFNH
- dataLayer events: Pageview, Impression, productClick, addToCart, checkout, transaction, purchase, begin_checkout, view_item
- projekt-id (Projekt-Nummer aus DOM)
- projektname, projectcategory, projectposition, projectlist
- Bewerbungsart (User / Gast)
- transactionId (inkrementeller Zähler)
- Karriere-Felder: item_standort, item_anstellung, item_starttermin, item_erfahrung
- Kontaktformular-Felder: sha256_email_address, sha256_phone_number, msclkid, gclid (aus data-Attributen im HTML)
- Events: Anmeldung Projektalert, Nutzerregistrierung durchgeführt, Userlogin, B2B Anfrage abgeschickt, Karriere Lead, Rückruf Anfrage, Projektsuche durchgeführt + Suchbegriff + Trefferzahl
|
Jeder Seitenaufruf (Pageview/Impression automatisch); Click-Events auf Bewerbungs-CTA, Projektdetail-Links; Form-Submission-Success-Pages (DOM-Flag-Klassen wie .dataLayerPurchase, .dataLayerTransactionCareer, .contactformsendsucc) |
Web-Request (client-side JavaScript, synchron beim Seitenload / on-demand bei User-Interaktion) |
HTTP-REST (GTM JS-Snippet lädt gtm.js von googletagmanager.com; dataLayer-Pushes werden von GTM an GA/Ads weitergeleitet) |
Lücke — GTM-Snippet und dataLayer-Pushes müssen 1:1 in Drupal reproduziert werden. Kandidaten: Drupal Google Tag-Modul (contrib) für GTM-Snippet; custom JS in byte_theme für dataLayer-Pushes auf Projekt-/Karriere-Seiten. sha256_email/phone sind PII-relevant. msclkid/gclid = Conversion-Tracking für Ads. |
| Mailingwork (login.mailingwork.de/webservice/webservice/json/) |
→ raus |
- title (Herr/Frau)
- lastName
- firstName
- email
- optinSetupId (=listId '1', list: 'SOLCOM Freiberufler Magazin')
|
AccountController::registerAction() — Nutzer registriert sich und setzt magazine='true' im Registrierungsformular (Double-Opt-In via optinrecipient-Endpoint) |
Web-Request (synchron) |
HTTP-REST (cURL POST, application/x-www-form-urlencoded), credentials username='Geopard'/password in Settings.Solcom.yaml |
PII-relevant (Vorname, Nachname, E-Mail). Im Drupal-Nachbau: ProjektpartnerRegistrationSubmitter oder entsprechender EventSubscriber nach erfolgreicher Registrierung; Opt-In-Checkbox im Registrierungsformular muss erhalten bleiben. Mailingwork-Credentials in .env / Drupal-Config (nicht in VCS). Lücke: Double-Opt-In-Flow (optinrecipient) muss nachgebaut werden. |
| Mailingwork (login.mailingwork.de/webservice/webservice/json/) |
→ raus |
- title (Herr/Frau)
- lastName
- firstName
- email
- optinSetupId (=listId '1')
|
AccountController::addMagazineAction() — eingeloggter Nutzer abonniert nachträglich das Freiberufler-Magazin über die Profilseite |
Web-Request (synchron) |
HTTP-REST (cURL POST) |
PII-relevant. Drupal-Nachbau: eigener Route/Controller-Action im Projektpartner-Profil. Nach erfolgreichem API-Call: user.field_magazine_option = TRUE setzen (analog User::setMagazineOption). Vorhanden als ProjektpartnerMailManager-Modul — Mailingwork-Subscribe-Methode fehlt noch. |
| Mailingwork (login.mailingwork.de/webservice/webservice/json/) |
→ raus |
- email
- listId '1'
- recipientId (intern via getrecipientidbyemail lookup)
|
AccountController::removeMagazineAction() — eingeloggter Nutzer kündigt Magazin-Abo über die Profilseite (deleterecipientbyid nach ID-Lookup) |
Web-Request (synchron) |
HTTP-REST (cURL POST, zwei sequenzielle Calls: getrecipientidbyemail + deleterecipientbyid) |
PII-relevant (Löschung). Drupal-Nachbau muss zwei API-Calls kapseln. Nach Erfolg: user.field_magazine_option = FALSE. Lücke: kein Unsubscribe-Flow im aktuellen solcom_projektpartner-Modul. |
| Mailingwork (login.mailingwork.de/webservice/webservice/json/) |
→ raus |
- title (Herr/Frau)
- lastName
- firstName
- email
- optinSetupId (=listId '1')
|
ProjectAlertController::projectAlertSendAction() — Nutzer (eingeloggt oder Gast) legt Projekt-Alert an und setzt newsletter='1' im Formular |
Web-Request (synchron) |
HTTP-REST (cURL POST) |
PII-relevant. Drupal-Nachbau: beim Erstellen eines Projekt-Alerts (WatchlistController oder dedizierter ProjectAlertController) Newsletter-Checkbox auswerten und ggf. subscribe aufrufen. Eingeloggte Nutzer erhalten zusätzlich user.field_magazine_option = TRUE. |
| Mailingwork (login.mailingwork.de/webservice/webservice/json/) |
→ raus |
- title (salutation)
- lastName (lastname)
- firstName (firstname)
- email
- optinSetupId (=listId '1')
|
EmailFinisher::executeInternal() — Neos-Form-Finisher; wird nach Absenden eines beliebigen Neos-Forms (vermutlich Lead-Formular / Kontaktformular) ausgeführt, das mit diesem Finisher konfiguriert ist |
Web-Request (synchron) |
HTTP-REST (cURL POST) |
PII-relevant. Drupal-Nachbau: Webform-Handler oder Custom Submit Handler für das entsprechende Lead-/Kontaktformular. Kein magazine-Guard — jeder Form-Submit trägt ein. Prüfen, ob das Formular im Drupal-Rebuild existiert (Lead-Formular via Webform-Modul?). Lücke: unklar, welche Neos-Form-Instanzen diesen Finisher nutzen — alle betroffenen Formulare inventarisieren. |
| Mailingwork (login.mailingwork.de/webservice/webservice/json/) |
→ raus |
- title (Herr/Frau)
- lastName (formFields.lastname)
- firstName (formFields.firstname)
- email (formFields.email)
- optinSetupId (=listId '1')
|
ProjectController::jobApplicationSendAction() — Nutzer bewirbt sich auf ein Projekt und setzt magazine='true' im Bewerbungsformular |
Web-Request (synchron) |
HTTP-REST (cURL POST) |
PII-relevant. Drupal-Nachbau: beim Einreichen einer Projektbewerbung (falls nachgebaut) Newsletter-Checkbox mitführen. Bewerbungsformular ist im aktuellen Drupal-Scope (solcom_project_offer) nicht vollständig vorhanden — Lücke erfassen. |
| MySQL-Tabelle / Doctrine-Entity (User) |
→ raus |
- user.bookmarks (Array von Project-UUIDs — Sync aus Session bei Login)
|
BookmarkController::addAction() — wenn $account vorhanden (eingeloggter User): Session-Bookmarks werden in user.bookmarks geschrieben + persistenceManager->persistAll() |
Web-Request (synchron, on-demand per AJAX) |
DB-Doctrine (Neos Flow PersistenceManager::persistAll) |
Gast-zu-Login-Migration: Session-Bookmarks werden bei addAction eines eingeloggten Users in die DB migriert; Drupal-Rebuild muss diesen Sync-Trigger in der Watchlist-Implementierung abbilden (bei Login: Session-Watchlist → user field_bookmarks); PII: Project-UUIDs ohne direkten Personenbezug, aber über User-Entity verknüpft |
| MySQL-Tabelle / Doctrine-Entity (User) |
→ raus |
- user.bookmarks (aktualisiertes Array nach Entfernen eines Projekts)
|
BookmarkController::removeAction() — wenn $account vorhanden: Bookmark-UUID wird aus user.bookmarks entfernt + persistenceManager->persistAll() |
Web-Request (synchron, on-demand per AJAX) |
DB-Doctrine (Neos Flow PersistenceManager::persistAll) |
Symmetrisch zu addAction; Drupal-Rebuild: removeAction auf Watchlist-Entity; Session und DB werden synchron gehalten |
| MySQL-Tabelle / Doctrine-Entity (User) |
→ raus |
- user.bookmarks = [] (leeres Array)
|
BookmarkController::removeAllAction() — wenn $account vorhanden: alle Bookmarks aus user.bookmarks gelöscht + persistenceManager->persistAll() |
Web-Request (synchron, on-demand per AJAX) |
DB-Doctrine (Neos Flow PersistenceManager::persistAll) |
Bulk-Clear; Drupal: deleteAll auf Watchlist-Einträge für den User; Session wird ebenfalls geleert (bookmark.removeAllProjects()) |
| Personio API Auth (https://api.personio.de/v1/auth) |
→ raus |
|
PersonioService::personioApiAuth() — OAuth-Token-Beschaffung (Methode existiert, aber im aktuellen Code-Pfad nicht aufgerufen; recruitingApiKey wird direkt genutzt) |
on-demand (latent/unused im aktuellen Flow) |
HTTP-REST (cURL POST, X-Personio-App-ID: SOLCOM_CAREER_PORTAL) |
Auth-Methode vorhanden, wird im aktuellen Code jedoch nicht im Bewerbungs-Flow verwendet (Bearer-Token hardcoded aus Settings). In Drupal-Rebuild dokumentieren aber nicht aktiv implementieren, solange recruitingApiKey ausreicht. Config: clientid NTUwNjg3YWI5MGE2OTYxYmU5Yjc5NmQ2, secret NTYyNGIzNjI0NDFjY2ZmNDIwZmNlOTFlOTExNDFjMWVlNTBj. |
| Personio Recruiting API (https://api.personio.de/v1/recruiting/applications) |
→ raus |
- job_position_id (Personio-ID)
- first_name
- last_name
- email
- application_date
- attributes[gender]
- attributes[phone]
- attributes[available_from]
- attributes[salary_expectations]
- attributes[custom_attribute_2722696] (Talentpool-Opt-in: Ja/Nein)
- attributes[custom_attribute_2722693] (Referer-URL/Herkunft)
- attributes[custom_attribute_2722695] (Kanal-Label aus Domain-Mapping)
- files[uuid, original_filename, category]
|
CareerPersonioController::jobApplicationSendAction() — Bewerbungsformular-Submit durch Bewerber (nach erfolgreichem Datei-Upload) |
Web-Request (synchron, on-demand) |
HTTP-REST (cURL POST application/json, Authorization: Bearer recruitingApiKey, X-Personio-App-ID: SOLCOM_CAREER_PORTAL, X-Company-ID: 78231) |
Kern-Outbound-Edge. In Drupal: nach Webform-Submit gegen personioApiSendApplication() posten. PII-Relevanz: KRITISCH — Bewerberdaten (Name, E-Mail, Telefon, Gehaltswunsch, Verfügbarkeitsdatum, Gender). Referer-URL aus 'info'-Cookie wird als Herkunfts-Tracking mitgeschickt (custom_attribute_2722693/2722695). API-Key identisch mit Upload-Endpoint. |
| Personio Recruiting API (https://api.personio.de/v1/recruiting/applications/documents) |
→ raus |
- file (Binary/multipart)
- original_filename
- uuid (response)
- mimetype
- extension
- size (response)
|
CareerPersonioController::jobApplicationSendAction() — Bewerbungsformular-Submit durch Bewerber; handleUploads() pro Datei (max. 3 Dateien: cv, cover-letter, certificate, other) |
Web-Request (synchron, on-demand) |
HTTP-REST (cURL POST multipart/form-data, Authorization: Bearer recruitingApiKey, X-Personio-App-ID: SOLCOM_CAREER_PORTAL, X-Company-ID: 78231) |
In Drupal: Bewerbungsformular (Webform oder Custom Form) muss Datei-Upload-Felder (bis zu 3) gegen diesen Endpoint senden. API-Key aus Settings.yaml (recruitingApiKey: c1510ffd84a8d1356b70). PII-Relevanz: HOCH — Bewerber-Dokumente (Lebenslauf, Anschreiben, Arbeitszeugnis). Temporäre Dateien werden in der TemporaryFile-Entity zwischengespeichert, vor dem API-Upload lokal gehalten. |
| SMTP/Mail-Empfänger (bewerbung@solcom.de) |
→ raus |
- file binary als Swift_Attachment
- filename
- MIME type
- alle UserFile-Binaries des Users
|
AccountController (privat): sendMailToSolcom() — beim Abschluss der Registrierung (Account-Aktivierung); alle UserFiles des Users werden als E-Mail-Anhänge mitgesendet |
Web-Request (synchron, bei Account-Aktivierung) |
SMTP via Neos\SwiftMailer\Message (Swift_Attachment::newInstance + getStream()) |
Drupal-Nachbau: hook_user_insert / HookEventSubscriber auf AccountEvents::ACCOUNT_ACTIVATED; alle managed files des Users als E-Mail-Anhang via \Drupal\Core\Mail\MailManager. PII: Lebensläufe gehen an interne SOLCOM-Adresse. |
| SMTP/Mail-Empfänger (bewerbung@solcom.de) — tägliche Änderungs-Notification |
→ raus |
- file binary als Swift_Attachment (nur Dateien von gestern, shouldNotSendAsNotification=false)
- filename
- MIME type
|
UserNotificationCommandController::notifyCommand() — Cron-Job sendet täglich E-Mail an bewerbung@solcom.de für jeden User mit Profil-Änderungen; neue Dokumente (creationDate = gestern, shouldNotSendAsNotification=false) werden als Anhänge mitgesendet |
Cron (täglich) |
SMTP via Neos\SwiftMailer\Message (Swift_Attachment::newInstance + stream_get_contents($resource->getStream())) |
Drupal-Nachbau: Drupal Queue + hook_cron oder Scheduled Task (Ultimate Cron); shouldNotSendAsNotification als Boolean auf dem user_document-Entity. Datumsprüfung creationDate=gestern muss beibehalten werden (verhindert Doppel-Versand). PII: Neu-Uploads gehen täglich raus. |
| SMTP/Mail-Empfänger: Bewerber (formFields.email) + BCC: bewerbung@solcom.de |
→ raus |
- formFields.firstname
- formFields.lastname
- projectObj.id (mehrere möglich)
- signature=info@solcom.de
|
ProjectController::jobApplicationSendAction — Eingangsbestätigung nach erfolgreichem Versand der Bewerbungsmail |
Web-Request (synchron) |
SMTP (Neos\SwiftMailer\Message) |
Template Mail/ApplicationConfirmation.html; Betreff: 'Eingangsbestätigung / Projekt-Nummer: [IDs]'; From: no-reply@solcom.de; Lücke in Drupal WatchlistController: Bestätigungs-Mail noch nicht implementiert; PII: E-Mail + Name |
| SMTP/Mail-Empfänger: Entwickler/Admins (rehme@geopard-digital.de + admin@mxp.de + solcom.de-Mitarbeiter) |
→ raus |
- errorInModuleName
- bodyText
- now (Zeitstempel)
|
MailerService::sendAlert — wird aus beliebigem Service/Controller bei kritischem Fehler aufgerufen |
Web-Request (synchron) oder Cron (on-demand bei Fehler) |
SMTP (Neos\SwiftMailer\Message) |
Template Mail/Error/GeneralError.html; Betreff: '***CRITICAL*** / ***INFO*** SOLCOM Webseiten - Error: [Modul]'; From: no-reply@solcom.de; Drupal: Watchdog / Alert-Modul statt Custom-Mailer; hardcodierte Empfängerliste enthält externe Dienstleister-Adressen |
| SMTP/Mail-Empfänger: Formular-Absender (formValues.email) — Allgemeine Formulare |
→ raus |
- formValues.lastname (für Anrede)
- currentDate
- sessionid
|
NormalEmailFinisher::executeInternal — beliebiges Neos-Form mit NormalEmailFinisher-Konfiguration wird abgesendet |
Web-Request (synchron) |
SMTP (Neos\SwiftMailer\Message über MailerService) |
Template Mail/Forms/ThanksForEmailSubmission.html; Betreff: 'Bestätigung: Wir haben Ihre Anfrage erhalten.'; From: no-reply@solcom.de; generischer Dankeschön-Flow, in Drupal über Webform-Bestätigungs-E-Mail abbildbar; PII: E-Mail + Name |
| SMTP/Mail-Empfänger: Nutzer (accountChangeFlow.newEmail + accountChangeFlow.oldEmail) — zwei separate Mails |
→ raus |
- accountChangeFlow.newEmail
- accountChangeFlow.oldEmail
- user.fullName
- signature=info@solcom.de
|
AccountController::activationChangeAccountEmailAction — Nutzer klickt Bestätigungslink für E-Mail-Änderung |
Web-Request (synchron) |
SMTP (Neos\SwiftMailer\Message) |
Templates Mail/Account/AccountChangeSuccessMailtoUser.html (an neue Adresse) + AccountChangeSuccessMailtoUserOld.html (an alte Adresse); Betreff jeweils: 'Bestätigung: Ihre Login-E-Mail-Adresse im SOLCOM Projektportal wurde geändert'; Lücke in Drupal; PII: beide E-Mail-Adressen |
| SMTP/Mail-Empfänger: Nutzer (accountChangeFlow.newEmail) |
→ raus |
- accountChangeFlow.newEmail
- accountChangeFlow.activationToken
- activationUrl
- user.fullName
- signature=info@solcom.de
|
AccountController::editAccountSendAction — Nutzer beantragt E-Mail-Änderung im Profil |
Web-Request (synchron) |
SMTP (Neos\SwiftMailer\Message) |
Template Mail/Account/AccountChangeMailtoUser.html; Betreff: 'Änderung Ihrer Login-E-Mail-Adresse im SOLCOM Projektportal'; Lücke in Drupal-Rebuild: dieser Flow fehlt noch (P2503-226 scope); PII: alte + neue E-Mail |
| SMTP/Mail-Empfänger: Nutzer (accountEmailAddress) |
→ raus |
- user.firstName
- user.lastName
- signature=info@solcom.de
|
AccountController::deleteAction — gleichzeitig mit der internen Lösch-Benachrichtigung |
Web-Request (synchron) |
SMTP (Neos\SwiftMailer\Message) |
Template Mail/Account/DeleteNoticeForPP.html; Betreff: 'Bestätigung: Löschung SOLCOM Nutzerkonto'; From: no-reply@solcom.de; PII: Name + E-Mail |
| SMTP/Mail-Empfänger: Nutzer (availability.email) |
→ raus |
- availability.firstName
- availability.lastName
- availability.email
- availability.staffId
- pppid
- signature=projektpartner@solcom.de
|
AvailabilityController::sendAction — Eingangsbestätigung nach erfolgreichem Versand der Verfügbarkeits-Mail |
Web-Request (synchron) |
SMTP (Neos\SwiftMailer\Message) |
Template Mail/Availability/Confirmation.html; Betreff: 'Eingangsbestätigung'; From: no-reply@solcom.de; Drupal-Lücke: Verfügbarkeits-Formular-Bestätigung fehlt; PII: E-Mail + Name + RMS-Nr. |
| SMTP/Mail-Empfänger: Nutzer (registrationFlow.email) |
→ raus |
- activationToken
- activationUrl
- salutation
- lastName
- title
- signature=info@solcom.de
|
AccountController::registerAction — Nutzer füllt Registrierungsformular aus und klickt Absenden |
Web-Request (synchron) |
SMTP (Neos\SwiftMailer\Message) |
Entspricht ProjektpartnerMailManager::sendRegistrationMail() in solcom_projektpartner; Template Mail/Account/Registration.html → Drupal-Template noch anlegen; From: no-reply@solcom.de, To: Nutzer-E-Mail, Betreff: 'Bestätigung Ihrer Registrierung im SOLCOM Projektportal'; PII: E-Mail + Name |
| SMTP/Mail-Empfänger: Nutzer (registrationFlow.email) — Bewerbung mit Kontoanlage |
→ raus |
- activationToken
- activationUrl
- lastName
- salutation
- title
- signature=info@solcom.de
|
ProjectController::jobApplicationSendAction — Gast bewirbt sich und legt dabei gleichzeitig Konto an |
Web-Request (synchron) |
SMTP (Neos\SwiftMailer\Message) |
Template Mail/Account/Registration.html (gleicher Template-Typ wie Standalone-Registrierung); Betreff: 'Bestätigung Ihrer Registrierung'; Drupal: kombinierter Flow (Bewerbung + Registrierung) fehlt noch; PII: E-Mail + Name |
| SMTP/Mail-Empfänger: Nutzer (registrationFlow.email) — Token abgelaufen, Erneut-Senden |
→ raus |
- activationToken
- activationUrl
- salutation
- lastName
- title
- signature=info@solcom.de
|
AccountController::reActivationAction — Nutzer ruft Aktivierungs-URL mit abgelaufenem Token auf |
Web-Request (synchron) |
SMTP (Neos\SwiftMailer\Message) |
Gleicher Mail-Typ wie Registrierungs-E-Mail; Template Mail/Account/Registration.html; Drupal: ProjektpartnerMailManager – resend-Pfad; PII: E-Mail + Name |
| SMTP/Mail-Empfänger: Nutzer (resetPasswordFlow.email) |
→ raus |
- resetPasswordToken
- resetPasswordUrl
- signature=info@solcom.de
|
AccountController::passwordForgottenSendAction — Nutzer sendet Passwort-vergessen-Formular |
Web-Request (synchron) |
SMTP (Neos\SwiftMailer\Message) |
Template Mail/Account/PasswordForgotten.html; Betreff: 'Zurücksetzen Ihres Passwortes / SOLCOM Projektportal'; Drupal: solcom_projektpartner hat eigenen ProjektpartnerMailManager::sendPasswordResetMail(); PII: E-Mail + Token |
| SMTP/Mail-Empfänger: Nutzer (user.email) |
→ raus |
- user.firstName
- user.lastName
- signature=info@solcom.de
|
AccountController::activationAction — direkt nach Account-Anlage (gleicher Web-Request) |
Web-Request (synchron) |
SMTP (Neos\SwiftMailer\Message) |
Template Mail/Account/RegistrationUserNotification.html; From: no-reply@solcom.de, Betreff: 'Ihre Aktivierung war erfolgreich'; Drupal-Pendant: ProjektpartnerMailManager::sendActivationSuccessMail(); PII: E-Mail + Name |
| SMTP/Mail-Empfänger: Nutzer (user.email) |
→ raus |
- user.firstName
- user.lastName
- signature=info@solcom.de
|
AccountController::editAccountSendAction — Nutzer ändert Passwort im Profil |
Web-Request (synchron) |
SMTP (Neos\SwiftMailer\Message) |
Template Mail/Account/AccountChangePasswordMailtoUser.html; Betreff: 'Ihre Passwortänderung im SOLCOM Projektportal'; From: no-reply@solcom.de; Drupal-Pendant in solcom_projektpartner vorhanden (P2503-230); PII: Name + E-Mail |
| SMTP/Mail-Empfänger: Nutzer/Gast (user.email / guest.email) — Projekt-Alert |
→ raus |
- user.firstName
- user.lastName
- tags
- states
- projects (Liste: title, link)
- hash
- projectAlert.id
- unsubscribeLink
- signature=projektalert@solcom.de
|
ProjectAlertCommandController::sendCommand — Cron-Job sendet neue Projekt-Matches an alle aktiven Alert-Abonnenten |
Cron (täglich, Intervall per Cron-Konfiguration) |
SMTP (Neos\SwiftMailer\Message über MailerService) |
Template Mail/ProjectAlert/ProjectAlert.html; Betreff: 'SOLCOM Projekt Alert'; From: no-reply@solcom.de; Drupal-Lücke: ProjectAlert-Cron-Flow noch nicht in solcom_project_offer abgebildet (F-scope offen); PII: E-Mail + Name + Suchkritierien |
| SMTP/Mail-Empfänger: bewerbung@solcom.de |
→ raus |
- formFields (alle Registrierungsattribute)
- formattedSkills
- rmsNumber (pppid)
- currentDate
- sessionid
- filenames
- file-Attachments (UserFiles)
|
AccountController::activationAction — Nutzer klickt Aktivierungs-Link im E-Mail-Postfach, Token gültig, Account wird angelegt |
Web-Request (synchron) |
SMTP (Neos\SwiftMailer\Message) |
Template Mail/Account/RegistrationNotification.html (20 KB, vollständiges Bewerbungsprofil); To: bewerbung@solcom.de; Anhänge = hochgeladene Profilunterlagen; entspricht dem internen Benachrichtigungs-Flow in solcom_projektpartner ProjektpartnerRegistrationSubmitter; PII hoch |
| SMTP/Mail-Empfänger: bewerbung@solcom.de |
→ raus |
- user.firstName
- user.lastName
- user.email
- loginemail
- signature
|
AccountController::deleteAction — Nutzer löscht sein Konto selbst |
Web-Request (synchron) |
SMTP (Neos\SwiftMailer\Message) |
Template Mail/Account/Delete.html; Betreff: 'Nutzerkonto Löschung'; From: info@solcom.de; In Drupal abgebildet in solcom_projektpartner (P2503-233 Account-Löschung); PII: Name + E-Mail |
| SMTP/Mail-Empfänger: bewerbung@solcom.de (+ CC: projectObj.contact) |
→ raus |
- formFields (salutation, firstname, lastname, email, phone, mobile, birthday, company, street, zip, city, country, hourlyrate, availability, skills, applicationText, languages, gulp, freelancer, xing, freelancermap)
- projectObj.id
- projectObj.title
- filenames
- file-Attachments
- pppid
- accountCreated
- currentDate
- utm_sourcename/utm_campaign
|
ProjectController::jobApplicationSendAction — Nutzer/Gast sendet Projektbewerbung; eine Mail pro Projekt |
Web-Request (synchron) |
SMTP (Neos\SwiftMailer\Message) |
Template Mail/Application.html; Betreff: 'Bewerbung über [Quelle] / Projekt-Nummer: [ID] / [Titel]'; From: no-reply@solcom.de; In Drupal: WatchlistController / solcom_project_offer; PII hoch (vollständiges Bewerberprofil + Dokumente) |
| SMTP/Mail-Empfänger: bewerbung@solcom.de (ACP-Admin-Bereich) |
→ raus |
- user.firstName
- user.lastName
- user.email
- acpUser
- currentDate
- sessionid
|
AcpController::removeUserAction — ACP-Administrator löscht Nutzerkonto manuell |
Web-Request (synchron) |
SMTP (Neos\SwiftMailer\Message) |
Template Mail/Acp/AccountDelete.html; Betreff: 'SOLCOM Konsole - Account-Löschung durchgeführt'; From: no-reply@solcom.de; Drupal: kein direktes Äquivalent (ACP = Admin-Interface, in Drupal über Standard-Admin gelöst); PII: Name + E-Mail |
| SMTP/Mail-Empfänger: bewerbung@solcom.de — Profil-Aktualisierungen |
→ raus |
- user.rmsNumber
- user.firstName
- user.lastName
- changes (propertyName, old, new)
- filenames
- file-Attachments (neu hochgeladene Dokumente vom Vortag)
|
UserNotificationCommandController::sendCommand — Cron-Job aggregiert alle Profil-Änderungen und sendet täglich eine Sammlung |
Cron (täglich) |
SMTP (Neos\SwiftMailer\Message) |
Template Mail/UserNotification/Notification.html; Betreff: 'SOLCOM PPP-ID [RMS-Nr.] hat seine Daten aktualisiert'; From: no-reply@solcom.de; Drupal-Lücke: kein Äquivalent in solcom_projektpartner – Profil-Änderungs-Benachrichtigung per Cron fehlt; PII hoch |
| SMTP/Mail-Empfänger: crm@solcom.de + BCC: K.Staritz@solcom.de, info@solcom.de |
→ raus |
- formValues (Anfrage-Felder: name, company, email, phone, message)
- currentDate
- sessionid
- file-Attachments
|
FormsController::sendMailtoSolcom — Nutzer sendet Anfrageformular (Projektanfrage CRM) |
Web-Request (synchron) |
SMTP (Neos\SwiftMailer\Message) |
Template Mail/Forms/SendProject.html; Betreff: 'Anfrageformular - Anfrage übermitteln'; From: no-reply@solcom.de; PII: Name + E-Mail + Projektdaten |
| SMTP/Mail-Empfänger: crm@solcom.de — 2FA-Bestätigung |
→ raus |
|
FormsController::activate2faAction — Nutzer klickt 2FA-Bestätigungslink in E-Mail |
Web-Request (synchron) |
SMTP (Neos\SwiftMailer\Message über MailerService) |
Template Mail/2FA/Accept.html (Pfad im Code: Mail/Lead2faForm/Accept.html); Betreff: 'AVV Bestätigung ([E-Mail])'; From: no-reply@solcom.de; Drupal-Lücke: 2FA-Flow für AVV-Bestätigung fehlt; PII: E-Mail |
| SMTP/Mail-Empfänger: karriere@solcom.de |
→ raus |
- formValues (firstname, lastname, email, phone, company, message, utm-/performance-Cookies)
- currentDate
- sessionid
- file-Attachment (Bewerbungsunterlage)
|
FormsController::sendCareerLandingpageMailtoSolcom — Nutzer sendet Karriere-Landingpage-Bewerbungsformular |
Web-Request (synchron) |
SMTP (Neos\SwiftMailer\Message) |
Template Mail/Forms/SendCareerLandingpage.html; Betreff: 'Karriere Bewerbungsformular - Bewerbung'; From: no-reply@solcom.de; Kein Portal-Scope (Karriereseite); PII: Name + E-Mail + Datei |
| SMTP/Mail-Empfänger: karriere@solcom.de |
→ raus |
- formValues (firstname, lastname, email, message, Termin-Felder)
- currentDate
- sessionid
|
FormsController::sendCareerApplicationMailtoSolcom — Nutzer sendet Karriere-Terminbestätigungs-Formular |
Web-Request (synchron) |
SMTP (Neos\SwiftMailer\Message) |
Template Mail/Forms/SendCareerApplication.html; Betreff: 'Terminbestätigung von [Vorname] [Nachname]'; From: no-reply@solcom.de; Kein Portal-Scope; PII: Name + E-Mail |
| SMTP/Mail-Empfänger: projektpartner@solcom.de |
→ raus |
- availability.staffId
- availability.projectPartner
- date
- availability (alle Felder)
- sessionid
- message
- file-Attachments (bis zu 4 Dokumente)
|
AvailabilityController::sendAction — eingeloggter/nicht eingeloggter PP sendet Verfügbarkeits-Formular |
Web-Request (synchron) |
SMTP (Neos\SwiftMailer\Message) |
Template Mail/Availability/Solcom.html; Betreff: 'Aktualisierung RMS Nr. [ID] – [Name] / Verfügbar ab: [Datum]'; From: no-reply@solcom.de; Kein direktes Drupal-Äquivalent (Verfügbarkeits-Flow = eigener Scope); PII: Name + RMS-Nr. + Verfügbarkeitsdatum |
| SMTP/Mail-Empfänger: recipientAddress (aus Form-Config) — Allgemeine Formulare |
→ raus |
- subject (aus Form-Config)
- recipientAddress
- senderAddress
- replyToAddress
- carbonCopyAddress
- blindCarbonCopyAddress
- formValues (alle Felder)
- performanceCodeGoogle
- performanceCodeBing
|
NormalEmailFinisher::executeInternal — zweite Mail (an SOLCOM-Empfänger) nach der Nutzer-Bestätigung |
Web-Request (synchron) |
SMTP (Neos\SwiftMailer\Message) |
Template konfigurierbar (templatePathAndFilename in Form-YAML); Empfänger je nach Form-Konfiguration; Drupal: Webform-EmailHandler; PII abhängig von Formular-Feldern |
| Twitter/X API (OAuth 1.0a) |
→ raus |
- consumerKey: xYJ2EoFMMjL5n1Eu6oc9g (hardcoded)
- consumerSecret: s1qtbwFCZvNOQWndSBG7BrQI9Sz00ZckHcBYldraI (hardcoded)
- accessToken: 492335992-anrUvaAzb39l4p1YdHVEmfNAsB7YobjpPryZCkzI (hardcoded)
- accessTokenSecret: VylvKsOtoUoGKMUnpua7igPZm6C87sXxj9rCj7xMFI (hardcoded)
- Tweet-Text: project.getTitle() + Ort: project.getState() + Start: project.getStart() + project.getType() + project.getBusiness() + #Job #Stellenangebot #beruf + https://solcom.de/t/<project.getId()>
|
Cron-Command project:importAndProcess (ProjectCommandController->importAndProcessCommand) — AUSKOMMENTIERT: $this->twitterService->tweetProject() ist im Code vorhanden aber commented out; kein aktiver Aufruf in Produktion |
Cron (war vorgesehen bei Projekt-Import; aktuell deaktiviert) |
HTTP-REST (DG\Twitter\Twitter-Library, OAuth 1.0a POST zu api.twitter.com/1.1/statuses/update.json) |
Niedrige Priorität — Twitter-Integration war bereits deaktiviert (auskommentiert). Im Drupal-Neuaufbau nicht zwingend zu implementieren. Falls doch: Twitter/X API v2 (OAuth 2.0), keine Legacy-Credentials übernehmen. Credentials im Klartext im Code sind ein Sicherheitsproblem — müssen rotiert werden. Kein PII im Tweet-Text. |