listings

MCP serverDev tools

Live MCP for Immobilien Eichmann listings (Konstanz). Tools: search_listings, get_listing.

Available today. Use it from your connected AI after setup.

Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.

Then ask your AI: use listings to search listings

Install listings

The server’s own address, for the clients that take one directly. Or connect ahel once and every client you use reads it from one address, with the account kept on ahel rather than in each client’s config.

  • Claude Code

    claude mcp add --transport http --scope user listings 'https://immobilieneichmann.de/mcp'

    Run it once in your project, then open /mcp to approve any sign-in the server asks for.

  • Claude Desktop

    https://immobilieneichmann.de/mcp

    Add a custom connector in Settings, paste this address, and approve the sign-in.

  • Cursor

    cursor://anysphere.cursor-deeplink/mcp/install?name=listings&config=eyJ1cmwiOiJodHRwczovL2ltbW9iaWxpZW5laWNobWFubi5kZS9tY3AifQ==

    Open the link and Cursor adds the server at that address.

  • ChatGPT

    https://immobilieneichmann.de/mcp

    In Settings, enable Developer mode, create an MCP app, and paste this address. Your plan and workspace must allow custom apps.

  • Codex

    codex mcp add listings --url 'https://immobilieneichmann.de/mcp'

    Run it once, then sign in with codex mcp login listings if the server asks for an account.

From the project's README

As published by christianhohlfeld/eichmannimmobilien in README.md.

Listings SoT (SQLite)

  • Source of truth: SQLite on the droplet at /var/lib/eichmann/listings.db (not in git, not in the web root).
  • Origins: immowelt (inbound sync only) and eigen (own listings via unified /admin/#eigen).
  • Immowelt sync upserts/deactivates only origin=immowelt and never deletes origin=eigen.
  • Immowelt profile/account is read-only (no writes).
  • data/listings.json is an export/backup with "sot": "sqlite", not the SoT.
  • Publish: node scripts/publish-from-db.mjs writes JSON export + HTML from the DB.
  • Admin: https://immobilieneichmann.de/admin/ — Immowelt visibility + Eigen CRUD. Auth = email + password → HttpOnly cookie via /admin/api/ (localhost Node). No GitHub PAT.
  • Badge for eigen listings: „nur bei uns“.
  • Node on droplet: 20.x + better-sqlite3. App tooling: /var/lib/eichmann/app. Admin API unit: eichmann-admin-api.service.
  • Stabschef note: docs/STABSCHEF-admin-unified-2026-09-25.md

Immobilien Eichmann – technische Architektur und Betrieb

Statische Website für Immobilien Eichmann / Helmut Eichmann in Konstanz.

  • Produktion: https://immobilieneichmann.de/
  • Repository: ChristianHohlfeld/eichmannimmobilien
  • Branch für Produktion: main
  • Hosting: GitHub Pages
  • Formular-Backend: eigener, getrennter Gateway-Dienst auf dem bestehenden VPS
  • eigene Datenbank: keine
  • produktiver Node-Prozess für Formulare: dp-forms.service auf forms.digitalisierungsplanung.de

Stand dieser Dokumentation: 20.09.2026.


1. Architektur in einem Satz

Die öffentliche Website selbst besteht aus statischen HTML-, CSS-, JavaScript-, JSON- und Bilddateien auf GitHub Pages. Kontakt- und Exposé-Anfragen gehen an einen eigenen, technisch getrennten Formular-Gateway-Dienst unter forms.digitalisierungsplanung.de; weitere dynamische Abläufe laufen im Browser, über GitHub API / GitHub Actions oder über klar benannte Dienste wie Immowelt, Amazon SES und – nach Consent – Google Analytics.

Besucher
  |
  v
GitHub Pages / immobilieneichmann.de
  |
  +--> HTML + CSS + Vanilla JavaScript
  |
  +--> Kontakt-/Exposé-Anfrage
  |      Browser -> forms.digitalisierungsplanung.de -> Amazon SES -> info@immobilien-eichmann.com
  |
  +--> Analytics nur nach Consent
  |      Browser -> Google Analytics 4
  |
  +--> Externe Links
         -> Immowelt / Google Maps

Admin-Browser
  |
  +--> GitHub REST API mit Sitzungs-PAT
  |      -> data/listings.json
  |      -> assets/listings/*
  |
  +--> repository_dispatch / workflow_dispatch
         -> GitHub Actions
         -> Renderer
         -> generierte HTML-Seiten / Sitemap
         -> Commit auf main
         -> GitHub Pages Deployment

GitHub Actions Cron
  |
  +--> Playwright -> öffentliches Immowelt-Profil
         -> Merge in data/listings.json
         -> Bilder lokal spiegeln
         -> HTML / Sitemap neu rendern

Die Website-Dateien selbst laufen weiterhin ohne Application Server auf GitHub Pages. Für Formulare existiert bewusst ein kleiner separater Node-Dienst auf dem vorhandenen digitalisierungsplanung.de-VPS. Er hat eigene Runtime/Env, keine gemeinsame Produkt-DB oder Session und speichert keine Formularinhalte in einer eigenen Datenbank. GitHub-Actions-Runner bleiben kurzlebige Build-/Automationsmaschinen.


2. Frontend-Stack

Die Website ist bewusst ohne Frontend-Framework gebaut.

EbeneTechnik
MarkupHTML5
Stylingeine eigene CSS-Codebasis in css/styles.css
BrowserlogikVanilla JavaScript
Build-Bundlerkeiner
React/Vue/Angularkeiner
jQuerykeiner
CSS-Frameworkkeines
Webfontskeine externen Google Fonts; System-Font-Stacks
BilderJPG, WebP, PNG, SVG
SEOstatische Meta-Tags, Open Graph, Twitter Cards, JSON-LD, Sitemap
DeploymentGitHub Pages aus main

Die Browserlogik liegt hauptsächlich in:

  • js/main.js – Navigation, Kontakt-/Exposé-Formulare, Flyer, Gallery, Lightbox, URL-Prefills
  • js/cookie-consent.js – Consent-Speicherung und kontrolliertes Laden von Analytics
  • js/analytics.js – Google Analytics 4 / gtag.js, Measurement ID G-QVRRBPYNVM

Für Objektseiten unter /objekt/ wird über window.__eichmannJsBase sichergestellt, dass die gemeinsamen JavaScript-Dateien mit dem korrekten relativen Pfad geladen werden.


3. Node-/Build-Stack

Dieses Repository benötigt Node lokal und in GitHub Actions für Generierung, Scraping, Bildverarbeitung und Tests. Der separate Formular-Gateway läuft serverseitig als Node-Dienst im Repository ChristianHohlfeld/digitalisierungsplanung.de; er ist nicht Teil des statischen GitHub-Pages-Deployments dieses Repositories.

package.json verlangt Node >= 20.

Direkte Dependencies:

PaketVerwendungaktuell aufgelöst
playwrightBrowser-Automation: Immowelt-Import und Browser-Regressionsprüfungen1.63.0
sharpBildkonvertierung, Größenanpassung, Social-Share-Bilder0.33.5

Wichtige Befehle:

npm ci

npm run sync-immowelt
npm run sync-immowelt:render

npm run test:legal
npm run test:expose-form
npm run test:layout
npm run test:logo
npm run test:share
npm run test:jsonld
npm test

Für Playwright lokal:

npx playwright install chromium

4. Hosting, Domain und Serverfrage

Haben wir einen eigenen Server?

Für die statische Website nein; für Formulare ja.

GitHub Pages liefert die Website aus. Kontakt- und Exposé-POSTs gehen an den vorhandenen VPS unter forms.digitalisierungsplanung.de. Dort terminiert Nginx TLS und routet ausschließlich die Formularpfade an dp-forms.service auf Loopback-Port 8791. Es gibt weiterhin keine eigene Formular-Datenbank.

Wo liegt die Website?

Die Dateien liegen im GitHub-Repository und werden von GitHub Pages statisch ausgeliefert.

Die Datei:

CNAME

enthält:

immobilieneichmann.de

Damit ist die Custom Domain der GitHub-Pages-Site zugeordnet.

Die DNS-Konfiguration selbst liegt außerhalb dieses Repositories beim jeweiligen DNS-Provider. Das Repository enthält keine Zugangsdaten zum DNS-Provider.

Was passiert bei einem normalen Seitenaufruf?

  1. DNS löst immobilieneichmann.de auf GitHub Pages auf.
  2. GitHub Pages liefert fertige statische Dateien aus.
  3. Der Browser führt cookie-consent.js und main.js aus.
  4. Nur beim Absenden eines Kontakt-/Exposé-Formulars wird forms.digitalisierungsplanung.de aufgerufen.
  5. Drittanbieter werden nur für die jeweils beschriebenen Funktionen aufgerufen.

5. Verzeichnisstruktur

/
├── .github/workflows/       GitHub-Actions-Automation
├── admin/                   statisches Exposé-Admin
├── assets/
│   ├── flyer/               Flyerbilder
│   ├── listings/            lokal gespeicherte Objektbilder
│   ├── logo*                Marken-/Header-Assets
│   └── share-card*          Social-Preview-Bilder
├── css/styles.css           gesamtes Public Styling
├── data/listings.json       generierter lokaler Spiegel der Immowelt-Objektdaten
├── js/
│   ├── main.js
│   ├── cookie-consent.js
│   └── analytics.js
├── objekt/*.html            generierte Objekt-/Exposé-Seiten
├── partials/                generierte HTML-Fragmente
├── scripts/                 Generatoren, Importer und Tests
├── index.html               Startseite
├── kontakt.html             allgemeines Kontaktformular
├── impressum.html
├── datenschutz.html
├── widerrufsbelehrung.html
├── vertrag-widerrufen.html
├── sitemap.xml
├── robots.txt
├── llms.txt
├── CNAME
├── .nojekyll
├── package.json
└── package-lock.json

6. Single Source of Truth für Immobilien

Die fachliche Single Source of Truth ist Immowelt. Helmut pflegt dort Titel, Preis, Status, Referenznummern und Objektdaten.

data/listings.json ist ausschließlich der lokale, generierte Spiegel für Rendering und Website-Betrieb. Als lokale Abweichung ist nur site_hidden erlaubt: damit kann ein Immowelt-Objekt auf der eigenen Website ausgeblendet werden, ohne Immowelt zu verändern.

Top-Level-Struktur:

{
  "sot": "local",
  "source": "...",
  "immowelt_profile": "...",
  "scraped_at": "...",
  "listing_count": 13,
  "listings": []
}

Typische Felder eines Listings:

  • id
  • slug
  • local_url
  • title
  • price
  • location
  • rooms
  • living_area
  • plot_area
  • type
  • status
  • short_description
  • description
  • facts
  • expose_url
  • main_image_url
  • images
  • floor_plans
  • image_base
  • gallery_bases
  • floor_plan_bases
  • source
  • immowelt_id
  • sync_policy
  • missing_on_immowelt
  • active – steuert, ob ein Objekt öffentlich erscheint; false behält es intern, veröffentlicht es aber nicht
  • detail_page – false erlaubt einen öffentlichen Kontakt-Teaser ohne erfundene Exposé-Inhalte; nur true erzeugt Detailseite und Sitemap-Eintrag
  • optional manual_overrides

Die HTML-Seiten unter objekt/, die Karten auf Start-/Projektseite und die Objekt-URLs in sitemap.xml werden daraus erzeugt.


7. Immowelt-Import

Immowelt ist nur eine externe Inbound-Quelle.

Das Immowelt-Konto wird von dieser Codebasis niemals beschrieben.

Quelle:

https://www.immowelt.de/profil/3b18336c6a2e401da38e9cc20268270d

Importer:

scripts/sync-immowelt.mjs

Workflow:

.github/workflows/sync-immowelt.yml

Ablauf eines normalen Full-Syncs

  1. GitHub Actions startet einen kurzlebigen Ubuntu-Runner.
  2. Node 20 und Dependencies werden installiert.
  3. Playwright Chromium öffnet das öffentliche Immowelt-Profil.
  4. Öffentliche Objektinformationen werden gelesen.
  5. Soweit möglich werden Detailseiten für Beschreibung, Bilder, Grundrisse und Fakten angereichert.
  6. Neue Daten werden gegen data/listings.json gemerged.
  7. Objektbilder werden heruntergeladen.
  8. Sharp erzeugt lokale JPG-/WebP-Versionen.
  9. JSON wird aktualisiert.
  10. Karten, Exposé-Seiten und Sitemap werden neu gerendert.
  11. Geänderte Dateien werden auf main committed.
  12. GitHub Pages deployed den neuen Stand.

Zeitplan

Der Workflow läuft regulär:

0 */3 * * *

also alle drei Stunden nach UTC.

Zusätzlich kann er manuell gestartet werden.

Wenn scripts/sync-immowelt.mjs oder der Workflow selbst geändert wird, wird auf Push nur aus dem vorhandenen kanonischen JSON gerendert, damit Templateänderungen ohne erneuten Live-Scrape sofort auf alle Objektseiten kommen.

DataDome / Bot-Schutz

Immowelt kann automatisierte Browser mit DataDome/Captcha blockieren.

Darum ist der Import bewusst als Soft-Fail gebaut:

  • bei Scrape-Fehlern bleibt das zuletzt gültige JSON erhalten
  • die öffentliche Site wird nicht leergeräumt
  • kein Login und kein Captcha-Bypass
  • das Immowelt-Konto wird nicht verändert

Merge-Regeln

Standard:

sync_policy = independent

Bedeutung:

  • neue Immowelt-ID -> kann lokal ergänzt werden
  • vorhandene Objekte -> nur nicht manuell geschützte Felder werden aktualisiert
  • manual_overrides[field] = true schützt einen Wert vor Immowelt-Überschreiben
  • source: local ist lokal autoritativ
  • auf Immowelt verschwundene Objekte werden standardmäßig nicht automatisch gelöscht
  • stattdessen missing_on_immowelt: true
  • nur sync_policy: mirror erlaubt Auto-Entfernung eines verknüpften, dort verschwundenen Objekts

8. Bilder

Objektbilder liegen persistent im Git-Repository:

assets/listings/

Der Importer erzeugt in der Regel:

  • JPG für breite Kompatibilität
  • WebP für kleinere Übertragung
  • separate Gallery-Dateien
  • separate Grundriss-Dateien

Sharp übernimmt die Konvertierung.

Nicht mehr referenzierte, vom System verwaltete Objektbilder werden beim Rendern/Sync als Orphans erkannt und aufgeräumt.

Admin-Uploads werden zuerst per GitHub Contents API als Datei committed und danach in data/listings.json referenziert. Das ist ein zweistufiger Vorgang, keine Datenbanktransaktion.


9. Exposé-Anfrageflow

Referenz: bi-bodenseeimmo

Der öffentliche Exposé-Flow von:

https://www.bi-bodenseeimmo.de/

wurde am 20.09.2026 gegen aktuelle Objektseiten geprüft.

Die sichtbaren Personen-/Adressfelder des Eichmann-Exposé-Flows entsprechen diesem Referenzflow:

  1. Anrede* – Select
  2. Vorname*
  3. Name*
  4. Straße und Hausnummer*
  5. PLZ*
  6. Ort*
  7. Telefonnummer – optional
  8. E-Mail-Adresse*

Auf Eichmann-Exposé-Seiten gibt es bewusst kein zusätzliches Freitext-Nachrichtenfeld.

Die bi-bodenseeimmo-Seite zeigt zusätzlich eine Datenschutz-Einwilligungscheckbox. Diese wird hier bewusst nicht kopiert: die Eichmann-Site verwendet für die notwendige Anfragebearbeitung einen Datenschutzhinweis mit Link statt einer zusätzlichen Pflicht-Einwilligung.

Generiert wird der Flow zentral in:

scripts/sync-immowelt.mjs

Dadurch gelten Änderungen automatisch für alle erzeugten Objektseiten.

Versteckte technische Felder

Zusätzlich zu den sichtbaren Feldern werden Objektkontext und Mail-Metadaten mitgegeben:

  • anliegen = Exposé-Anfrage
  • objekt
  • objekt_url
  • ein Honeypot-Feld botcheck

Mail-Betreff und Empfänger werden serverseitig festgelegt; der Browser darf sie nicht frei bestimmen.

Validierung

js/main.js:

  1. trimmt Benutzereingaben
  2. nutzt die nativen HTML-required-/E-Mail-Regeln
  3. prüft mit form.checkValidity()
  4. zeigt Browserfehler via reportValidity()
  5. blockiert den clientseitigen Honeypot
  6. sendet erst dann

Damit ist eine komplett leere Exposé-Anfrage technisch nicht mehr möglich.

Regressionstest:

npm run test:expose-form

Der Test startet Chromium, lädt eine generierte Exposé-Seite, prüft Feldsatz, Reihenfolge, Required-Status, Payload und Success-UI und mockt ausschließlich die Netzwerkgrenze zum eigenen Formular-Gateway.

Serverseitige Trust-Grenze

Zusätzlich zur Browservalidierung validiert der Gateway die Pflichtfelder nochmals serverseitig. Er erzwingt Tenant, erlaubte Origins, feste Empfänger, feste Exposé-URL-Domain, Requestgrößen und Rate-Limits. Erfolg wird erst gemeldet, nachdem Amazon SES den Versand angenommen hat.


10. Allgemeines Kontaktformular

kontakt.html ist vom Exposé-Flow getrennt.

Pflichtfelder:

  • Name
  • E-Mail
  • Nachricht

Optional:

  • Telefon
  • Betreff/Anliegen-Auswahl

Auch hier:

  • Whitespace wird entfernt
  • native Validierung läuft
  • komplett leere Anfragen werden blockiert
  • kein Datenschutz-Pflicht-Haken
  • Datenschutzhinweis mit Link
  • Hinweis: durch Absenden kommt kein Maklervertrag zustande

11. Wie E-Mails tatsächlich verschickt werden

Produktiver Pfad:

Browser auf immobilieneichmann.de
  -> HTTPS JSON POST
  -> https://forms.digitalisierungsplanung.de/v1/immobilieneichmann/{contact|expose}
  -> Nginx
  -> dp-forms.service (127.0.0.1:8791)
  -> Amazon SES
  -> info@immobilien-eichmann.com

Der Gateway ist vom Hauptprodukt digitalisierungsplanung.de getrennt: eigener systemd-Dienst, eigener Linux-User, eigene Environment-Datei, eigener Loopback-Port, keine gemeinsame Account-Datenbank und keine Produktsession.

Bei Erfolg antwortet er mit:

{ "success": true, "requestId": "…" }

Bei Fehler zeigt die Website die bestehende Fehlerbox und den Mailto-Fallback. Die HTML-Formulare besitzen zusätzlich ein normales action auf denselben Gateway und method="POST" als einfachen No-JavaScript-Fallback.

Speicherung und Logs

Kontakt-/Exposé-Eingaben werden nicht in dieses GitHub-Repository, Local Storage, Session Storage oder eine eigene Formular-Datenbank geschrieben. Der Gateway verarbeitet sie im Arbeitsspeicher für Validierung und Mailversand. Seine technischen Logs enthalten Request-ID, Tenant, Flow, Status und Dauer, aber keine Formularinhalte oder Kontaktdaten. Danach liegt die Anfrage als E-Mail im Zielpostfach info@immobilien-eichmann.com, abhängig von dessen Aufbewahrungseinstellungen.

GitHub Pages hostet die Website, nicht das E-Mail-Postfach. Der Versand erfolgt über Amazon SES; die konkrete Mailbox-/MX-Infrastruktur von immobilien-eichmann.com wird weiterhin nicht in diesem Repository konfiguriert.

12. Datenschutz- und Consent-Runtime

Consent-Code:

js/cookie-consent.js

Browser-Key:

eichmann_cookie_consent_v1

Gespeichert wird in localStorage:

{
  "necessary": true,
  "analytics": false,
  "ts": 0
}

Es wird also nur die Consent-Entscheidung lokal im Browser gespeichert.

Google Analytics

Analytics wird nicht beim ersten Seitenaufruf automatisch geladen.

Nur wenn der Nutzer „Alle akzeptieren“ wählt:

  1. cookie-consent.js lädt js/analytics.js
  2. analytics.js lädt Googles gtag.js
  3. GA4 startet mit Measurement ID G-QVRRBPYNVM

Ohne Analytics-Consent wird googletagmanager.com von unserer Analytics-Logik nicht geladen.

Google Fonts

Keine externen Google Fonts.

Die Website verwendet lokale/System-Font-Stacks. Dadurch entsteht beim normalen Rendern kein Fonts-Request an Google.

Google Maps

Es gibt keinen automatisch geladenen Maps-Iframe.

Auf der Kontaktseite gibt es nur einen externen Link. Erst wenn der Nutzer ihn anklickt, wird Google Maps geöffnet.


13. Admin-System

URL:

https://immobilieneichmann.de/admin/

Unified UI (tabs: Immowelt | Eigen-Inserate). /admin/eigen/ redirects to /admin/#eigen.

Details: admin/README.md and docs/STABSCHEF-admin-unified-2026-09-25.md.

Login-Modus

admin/config.json:

auth_mode = password_session

Login benötigt:

  1. freigeschaltete E-Mail-Adresse
  2. Admin-Passwort

Kein GitHub-PAT. Der Browser ruft POST /admin/api/login auf; nginx proxyt auf 127.0.0.1:3847. Die API prüft Allowlist + password_sha256 und setzt ein HttpOnly Secure SameSite=Strict Cookie.

Speichern

Browser → /admin/api/{eigen|visibility|publish}
       → eichmann-admin-api (systemd)
       → SQLite SoT → publish-from-db → /var/www/…

Immowelt-Konto bleibt read-only. Immowelt-Import weiterhin über sync-immowelt.yml.

Entfernt (2026-09-25)

  • Sitzungs-PAT / sessionStorage Token
  • admin-eigen-save.yml (repository_dispatch → SSH upsert)
  • Standalone Eigen-UI (nur Redirect)

14. Admin-Speicherflow (Legacy / GitHub Contents — deprecated)

Deprecated 2026-09-25: Day-to-day CRUD uses /admin/api/ on the droplet. The flows below describe the old PAT + Contents API path and may still apply to leftover admin-save.yml tooling.

Objekt bearbeiten

Primärer Pfad:

Admin-Browser
  -> GET data/listings.json + SHA über GitHub Contents API
  -> Benutzer ändert Felder
  -> PUT data/listings.json mit bisherigem SHA
  -> GitHub Commit
  -> repository_dispatch admin_apply_render
  -> GitHub Action rendert
  -> Commit generierte Outputs
  -> GitHub Pages Deployment

Die Verwendung des aktuellen File-SHA ist eine einfache Form von Optimistic Concurrency: ein offensichtlich veralteter Stand kann von GitHub mit Konflikt abgewiesen werden.

Fallback

Wenn der direkte Contents-API-Save fehlschlägt:

repository_dispatch: admin_save_listings

Dann schreibt admin-save.yml die komplette vom Browser gesendete JSON-Datei und rendert anschließend.

Dieser Fallback ist funktional, aber keine transaktionale Multi-User-Datenbank. Gleichzeitiges Bearbeiten durch mehrere Admins sollte vermieden werden.

Neues Objekt

Das Admin erzeugt:

  • neue UUID
  • stabilen Slug
  • lokalen Datensatz
  • source: local
  • sync_policy: independent
  • manual_overrides für manuell gepflegte Felder

Eine optionale Immowelt-URL/UUID kann als Inbound-Verknüpfung hinterlegt werden.

Löschen

Löschen entfernt den Datensatz aus data/listings.json.

Der anschließende Render entfernt:

  • die nicht mehr benötigte objekt/{slug}.html
  • systemverwaltete orphaned Bilder, soweit sie nicht mehr referenziert sind
  • die Objekt-URL aus der Sitemap

Foto-Upload

  1. Browser liest die Datei als Base64.
  2. GitHub Contents API committed die Datei nach assets/listings/.
  3. Das Listing bekommt die neue Bildreferenz.
  4. data/listings.json wird committed.
  5. Render läuft.

Maximale vom Admin akzeptierte Uploadgröße: ungefähr 4,5 MB.

Erlaubte Dateitypen im aktuellen Adminpfad:

  • JPG/JPEG
  • PNG
  • WebP

15. Manuelle Overrides

Wird ein Feld im Admin manuell verändert, schreibt das Admin:

"manual_overrides": {
  "title": true,
  "price": true,
  "updated_at": "..."
}

Der Immowelt-Importer respektiert diese Locks.

Geschützte Feldgruppen umfassen unter anderem:

  • Titel
  • Preis
  • Ort
  • Zimmer
  • Wohn-/Grundstücksfläche
  • Typ
  • Status
  • Kurzbeschreibung
  • Beschreibung
  • Bilder/Gallery
  • Grundrisse
  • Fakten
  • Hauptbild

So bleibt lokal gepflegter Inhalt autoritativ.


16. GitHub-Actions-Pipelines

sync-immowelt.yml

Aufgabe:

  • regelmäßiger öffentlicher Immowelt-Import
  • manueller Sync
  • Render-only
  • Generatoränderungen auf Push neu ausrollen

Schreibziel:

  • data/listings.json
  • assets/listings/
  • partials/listings-grid.html
  • index.html
  • projekte.html
  • objekt/
  • sitemap.xml

admin-save.yml

Aufgabe:

  • Admin-repository_dispatch empfangen
  • JSON speichern oder nur rendern
  • generierte Outputs committen
  • optional Immowelt-Workflow anstoßen

Events:

  • admin_save_listings
  • admin_apply_render
  • admin_trigger_sync

apply-legal-baseline.yml

Wird ausgeführt, wenn die Legal-Baseline selbst geändert wird.

Ablauf:

  1. Baseline anwenden
  2. Legal-/Privacy-Regressionsprüfung
  3. Dependencies installieren
  4. Playwright installieren
  5. Layout prüfen
  6. Änderungen gegebenenfalls committen

layout-regression.yml

Hard Gate für relevante Frontendänderungen.

Prüft:

  • Legal-/Privacy-Baseline
  • Exposé-Formular-Feldsatz und Payload
  • Desktop-Layout
  • Mobile-Layout
  • Horizontal Overflow
  • Header/Logo
  • Flyer-Geometrie
  • Kontaktformular kann leer nicht absenden

Screenshots werden als GitHub-Actions-Artefakt hochgeladen.

logo-consistency.yml

Prüft Logo-Dateien, Versionierung und bekannte Fehlerbilder.

Der Logo-Test selbst läuft aktuell standardmäßig soft; die Header-Logo-Sicherheitsversion ist:

assets/logo-header.svg?v=header-safe-v1

Der zusätzliche rechte SVG-Viewport verhindert, dass das letzte N im Header wieder abgeschnitten wird.

share-card.yml

Auf jedem Push/PR:

npm run test:share

Prüft unter anderem:

  • 1200 × 630
  • JPEG
  • Dateigröße
  • korrekte OG-/Twitter-Referenzen
  • keine Abweichung vom freigegebenen Plain-Bild

refresh-share-card.yml

Nur bei Änderungen am Refresh-Script/Workflow.

Lädt das freigegebene Immobilienbild, erzeugt 1200 × 630 und schreibt:

  • share-card-source-plain-v2.jpg
  • share-card-plain-v2.jpg
  • Legacy-Dateien

Es werden kein Text und kein Logo-Overlay hinzugefügt.

GitHub Pages Deployment

Das Pages-Build-/Deploy ist ein GitHub-eigener Workflow und liegt deshalb nicht zwingend als eigene YAML-Datei in diesem Verzeichnis.

Jeder relevante Commit auf main wird anschließend über GitHub Pages veröffentlicht.


17. Tests

Gesamtsuite

npm test

Einzeltests

npm run test:share
npm run test:logo
npm run test:jsonld
npm run test:legal
npm run test:layout
npm run test:expose-form

Legal-/Privacy-Test

scripts/test-legal-baseline.mjs prüft unter anderem:

  • keine externen Google Fonts
  • kein automatisch eingebettetes Google Maps
  • keine ausgeschaltete native Formvalidierung
  • keine Legal-Platzhalter
  • keine unnötige Datenschutz-Pflichtcheckbox
  • Impressumsbehörde vorhanden
  • Datenschutz nennt reale eingesetzte Dienste
  • Widerruf enthält 14-Tage-Regel und keine alte 30-Tage-Fassung
  • generierte Objektseiten nutzen Consent-Gate
  • Header-Logo-Sicherheitsversion bleibt erhalten

Exposé-Flow-Test

Shortened here. Read the whole README on GitHub.

Tools it offers (5)

What this server listed when ahel dialed its public endpoint in Oct 2026, with no key and no account of yours. The names are the server’s own.

  • search_listings
  • get_listing
  • get_flyer
  • get_contact
  • submit_inquiry

Signals

Last commit
Oct 2026
Advanced
Delivery
listings MCP server → your ahel connector (mcp.ahel.ai) → your AI.
Item type
mcp-server
Key
de-immobilieneichmann-listings
Source
github.com/christianhohlfeld/eichmannimmobilien
Hosted endpoint
https://immobilieneichmann.de/mcp