Legacy-Crawler-Feeds: 1:1-Neos-Parity statt bereinigter Struktur
/asp/robots/… und /rss/… werden in Drupal zeichengenau so ausgeliefert, wie Neos sie heute rendert — inklusive bewusster Altlasten wie dem Label-Tippfehler Zusätzliche Infomationen:, dem HTML-4.0-Doctype, dem Copy-Paste-Fehler mode=FREELANCERCHECK im Freelance-Feed und dem Städtenamen Magedeburg im Xing-Region-Mapping. Diese Entscheidung revidiert die „strukturtreu, bereinigt"-Linie aus P2503-113/P2503-226 für den GULP-Feed. Alle Feed-URLs und alle Link-Ziele in den Feed-Bodies bleiben wörtlich erhalten; die Legacy-Detailseiten-URLs (detail.asp, detail.aspx, detail-xing.asp, detail-xing.aspx) rendern eine eigenständige Parallelwelt-Detailseite — den 1:1-Port der Neos-Seite Api/ProjectDetail.html mit den originalen Neos-Assets, unabhängig vom Drupal-Theme — mit lfdNr-Lookup, weil die heute auf gulp.de geschalteten Anzeigen RSM-Nummern tragen. Wer einen der konservierten Fehler „fixt", bricht potenziell einen externen Crawler-Parser.
Kontext
Zum Cutover am 08.07.2026 übernimmt die Drupal-Site die Domain www.solcom.de vom Neos-Altsystem. Externe Job-Portal-Crawler (GULP, freelance.de, Jooble, Trovit, Xing, Projektwerk u. a.) rufen seit Jahren wörtliche Legacy-URLs ab — historisch aus der Classic-ASP-Ära, von Neos per Flow-Routen weiterbedient — und importieren die dort publizierten Projektangebote in ihre Portale. Das Parsing-Verhalten dieser Crawler ist unbekannt und nicht beeinflussbar; einzelne werten mutmaßlich Label-Strings, URL-Muster (mode=GULP&id=…) und die RSM-lfdNr aus.
Die frühere Implementierung (P2503-113, P2503-169/170, P2503-226) hatte den GULP-Feed unter /asp/robots/gulplist.aspx bereits gebaut, dabei aber „1:1" als strukturtreu, bereinigt interpretiert: HTML5-Doctype, kanonische Drupal-URLs statt detail.aspx-Links, Salesforce-Id statt lfdNr, korrigierter Tippfehler, zusätzliches (m/w/d)-Suffix. Zudem hingen alle Feed-Gates an Salesforce-Feldern (field_sf_channel_gulp), während die RSM-Migration das Neos-Freigabe-Flag <GULPRobot> gar nicht importierte — bei RSM-geführtem Betrieb (der aktuellen Realität, 659 von 870 Nodes) wäre der Feed praktisch leer geblieben.
Die Inventur des Neos-Dumps (temp/web54_extracted) ergab: 17 Feed-Templates, davon 13 aktiv verdrahtet (9 RSM-Projekt-Feeds + Projectfeed-RSS, 2 Personio-Vacancy-Feeds, 1 News-RSS). Indeed ist in Neos selbst deaktiviert (itemCollection = null), Kununu ein 17-Byte-Leertemplate, und für 7 weitere Settings-URLs existiert kein Template mehr. Der Live-Output ist nicht direkt abrufbar (Cloudflare-Geo/Bot-403); Source-of-truth sind die Fluid-Templates plus deren Rendering-Semantik (ViewHelper, Fusion-Prototypen).
Entscheidung
1. Output-Parity-Kontrakt inklusive konservierter Fehler
Jeder der 13 Feeds reproduziert den Neos-Output zeichengenau (Elemente, Attribute, Labels, URL-Muster, Escaping-Semantik, CDATA-Wrapping, Gate-Logik); Whitespace ist best-effort. Konserviert werden ausdrücklich: der Tippfehler Zusätzliche Infomationen: (gulplist), mode=FREELANCERCHECK samt utm_source=freelancercheck.de im Freelance-Feed, Magedeburg im StateCapitalForRegion-Mapping, der HTML-4.0-Transitional-Doctype mit <html id="tagHTML">, nacktes & in href-Attributen sowie der Verzicht auf das nachträgliche (m/w/d)-Suffix (die RSM-Titel tragen es bereits). Semantik der Quellfelder: Job-Nr./id = RSM-lfdNr, Ort: = RSM-Region (nicht Ort-Freitext), Start = Rohtext (z. B. „01.07.2026, spätestens 01.08.2026").
2. URLs bleiben wörtlich — Feeds, Link-Ziele und Parallelwelt-Detailseite
Alle Feed-URLs bleiben unter den Legacy-Pfaden (inkl. Zweitrouten: gulplist.asp und gulplist.aspx, projektwerk.xml und projektwerk.xml.aspx). Die Link-Ziele in den Feed-Bodies bleiben ebenfalls byte-gleich; Drupal bedient sie: detail.asp/detail.aspx/detail-xing.asp/detail-xing.aspx rendern eine eigenständige Legacy-Detailseite — den 1:1-Port von Neos Api/ProjectDetail.html (LegacyProjectDetailController + vendored Neos-Assets unter assets/project-detail/: CSS, Header-Bild, ScalaSans-Fonts, Hyphenator.js), komplett am Drupal-Theme vorbei. Der Lookup läuft ausschließlich über field_rsm_lfd_nr (Neos findOneById kannte nur numerische RSM-Nummern; der field_sf_id-Fallback des zwischenzeitlichen 301-Redirects entfällt) und ohne Status-Filter, damit offline genommene Angebote nicht ins Leere laufen. Fehlende/ungültige Parameter und unbekannte Nummern antworten wie Neos mit 303 auf /de/404. Damit funktionieren die heute auf gulp.de geschalteten Anzeigen nach dem Cutover weiter — und sehen für den Bewerber exakt so aus wie heute. Bewusste Abweichungen der Detailseite: Asset-URLs zeigen auf den Modulpfad statt /_Resources/Static/… (der Neos-Ressourcen-Router existiert nach dem Cutover nicht mehr); der Bewerben-Fallback ohne FreelancerLink nutzt die Feed-Konvention bewerbung_<lfdNr> statt der Neos-Plugin-Query-URL (das Ziel-Plugin existiert nach dem Cutover nicht, das utm_source=undefined-Rewriting-Script bleibt 1:1); drei der sechs Award-Bilder behalten ihre /_Resources/Persistent/…-Original-URLs (heute schon live 404 = aktueller Live-Zustand), die drei im Dump vorhandenen werden lokal ausgeliefert.
3. Architektur: eine Feed-Klasse pro Feed, am Theme vorbei
LegacyFeedBase + je Feed eine Klasse unter solcom_project_offer_feeds/src/Feed/ mit eigenem Twig-Template und eigenem Kernel-Test — self-contained Responses ohne Theme-Beteiligung. Die bestehenden Drupal-nativen Vendor-Feeds unter /feeds/*.xml bleiben unverändert parallel bestehen. Drupal-Core, Contrib und composer.json werden nicht angefasst; alles liegt additiv in web/modules/custom/** und config/sync/**.
4. RSM-Migration liefert die Parity-Daten
Die RSM-Migration wird um die bislang verworfenen OpenPos-Elemente erweitert: GULPRobot → field_sf_channel_gulp (Feed-Gate), keinePortale → field_rsm_no_portal, Anforderungen → field_sf_requirements, Zusatz → field_rsm_zusatz, Start-Rohtext → field_rsm_start_raw, aktiviert_am → field_rsm_activated, tags → field_rsm_tags. Feed-Werte lesen RSM-Felder mit Per-Feld-Fallback auf die SF-Pendants — Parity heute, kein Bruch bei späterer Salesforce-Umschaltung.
5. Tote Feeds werden nicht nachgebaut
Indeed, Kununu und die 7 template-losen Settings-URLs liefern auch in Neos nichts Sinnvolles; sie werden bewusst nicht reproduziert.
Abgelehnte Alternativen
- „Strukturtreu, bereinigt" beibehalten (Status quo aus P2503-226): gleiche Tabellenstruktur, aber kanonische URLs, SF-Id, korrigierte Labels. Abgelehnt, weil das Parsing-Verhalten der Crawler unbekannt ist — jede Abweichung vom heutigen Output ist ein unkalkulierbares Risiko, und die Feeds sind ausschließlich crawler-facing (kein menschliches Publikum, das von „sauberem" Markup profitieren würde).
- Redirects von Alt-URLs auf die
/feeds/-Formate: Alte Crawler folgen Redirects nicht zuverlässig, und die/feeds/-Wire-Formate weichen inhaltlich ab (Minggo-Apply-URLs, SF-Ids, anderes Escaping). - Alle ~20 Settings-URLs blind nachbauen: Tote Feeds kosten Umsetzungs- und Verifikationsaufwand ohne Nutzen; was in Neos schon nichts lieferte, braucht keine Parity.
- Live-Output-Scraping als Referenz: Cloudflare blockt externe Abrufe (403, Geo/Bot-Gate). Die Fluid-Templates im Neos-Dump plus ViewHelper-/Fusion-Semantik sind die verlässlichere und versionierbare Source-of-truth.
Konsequenzen
- Konservierte Fehler sind Kontrakt. Wer
Infomationen,Magedeburgodermode=FREELANCERCHECK„fixt", ändert den Feed-Output und riskiert Crawler-Brüche. Refactoring-/Cleanup-Skills und Reviewer müssen diese Stellen unangetastet lassen; die Templates tragen entsprechende Hinweis-Kommentare. - Dokumentierte, bewusste Abweichungen vom Literal-Output: (a)
xing-projects <url>nutzt den kanonischen Drupal-Alias statt des historischen/de/projektportal/projektangebote/{uriPathSegment}-Pfads — der alte Pfad wäre auf der neuen Site ein 404, und die historischen Slugs sind aus dem Dump nicht rekonstruierbar; (b) der Newsfeed rendert die Kategorie konstant alsNachricht, bis dasblog-Bundle ein Kategorie-Feld erhält; (c) der Video-Content-Zweig der Xing-Personio-Feeds entfällt, weil das Signal (Embed-Erkennung in Personio-Sections) die Vacancy-Migration nicht überlebt; (d) die XSLT-Stylesheet-PI inprojectfeed.xmlreferenziert die historische absolute URL (für RSS-Parser bedeutungslos). - Feld-Redundanz bleibt: RSM-Werte landen teils in
field_sf_*-Feldern (etabliertes Muster, geteilt mit dem SF-Sync), teils in neuenfield_rsm_*-Feldern. Die Zuordnung dokumentiert die Migrations-YML. - Cutover-Abhängigkeit außerhalb Drupals: Der GULP-Crawler passiert heute eine Cloudflare-Whitelist. Diese Freischaltung muss auf die neue Infrastruktur übertragen und der Abruf nach dem Cutover aktiv verifiziert werden — sonst ist der Feed perfekt und trotzdem unerreichbar.
- Wartungsanker: Der Neos-Dump unter
temp/web54_extractedbleibt die Referenz für Parity-Fragen; die Kernel-Tests kodieren die kritischen Kontrakt-Details (Labels, URL-Muster, Escaping) als Regressionsschutz.
Offene Punkte
- Cloudflare-/WAF-Whitelist des GULP-Crawlers für die Mittwald-Infrastruktur klären (Stakeholder/Ops, vor dem 08.07.2026).
- Nach dem Cutover: tatsächlichen GULP-Abruf und Anzeigen-Aktualisierung auf gulp.de verifizieren.
- Kategorie-Feld für das
blog-Bundle (Newsfeed-Paritycat1/cat2/cat3) — Stakeholder-Frage, ob der Aufwand für 4 Bestandsnodes lohnt.