Files
eventmap/docs/adr/0001-vanilla-esm.md
T
dapelza ee55fb1cf9 Phase 0+1: Scaffold, Datenmodell, Karte und Liste
Reines HTML5/CSS3/JavaScript ohne Build-Tooling, lauffaehig direkt per
Doppelklick auf index.html (file://, kein Server noetig):

- Datenmodell fuer Ausflugsziele mit allen Feldern aus der Anforderung,
  15 feste Kategorien inkl. Farbe/Icon
- Zentraler Pub/Sub-Store mit LocalStorage-Persistenz und
  Migrations-Grundgeruest
- Interaktive Karte (Leaflet + Leaflet.markercluster, lokal vendored)
  mit kategoriefarbenen Markern, Clustering, Popups, Geolocation-Button
- Kartengrundlage ueber CARTO-Basemaps statt tile.openstreetmap.org, da
  dessen Referer-Pflicht file://-Aufrufe blockiert
- Seed-Daten als eingebettetes Script (data/seed.js) statt JSON-Datei,
  da fetch() auf lokale Dateien unter file:// nicht zuverlaessig
  funktioniert
- Ergebnisliste mit 10 Beispiel-Ausflugszielen, sicher gerendert ueber
  textContent/DOM-APIs statt innerHTML (Vorbereitung fuer spaeteren
  KI-JSON-Import mit Fremddaten)
- Responsives Layout (Desktop nebeneinander, Mobile gestapelt)
2026-07-24 11:24:47 +02:00

5.3 KiB
Raw Blame History

ADR 0001: Kein Build-Tooling, klassische Scripts mit globalem Namespace, Leaflet lokal vendored

Status

Akzeptiert (überarbeitet siehe "Revision" unten; ursprüngliche Entscheidung für native ES-Module wurde revidiert)

Kontext

anforderung.md fordert explizit "möglichst einfache und gut verständliche Technologien" (HTML5, CSS3, JavaScript, eine Open-Source-Kartenbibliothek, LocalStorage) und stellt keinen Backend-Zwang für die erste Version. Die Anwendung soll außerdem vollständig responsiv sein und ohne größere Infrastruktur betrieben und gewartet werden können.

Die tatsächliche Zielumgebung des Nutzers wurde präzisiert: Die App wird per Doppelklick auf index.html direkt aus einem lokal synchronisierten Nextcloud-Ordner geöffnet (file://...). Es steht kein lokaler HTTP-Server zur Verfügung und ein solcher soll vom Endnutzer auch nicht manuell gestartet werden müssen Priorität hat maximale Einfachheit für den Endnutzer, nicht Entwicklerkomfort.

Revision (2026-07-24)

Die ursprüngliche Entscheidung, JavaScript als native ES-Module (<script type="module"> mit import/export) umzusetzen, war für diesen Anwendungsfall falsch: Browser blockieren das Nachladen von ES-Modulen über file:// per CORS-Policy (Access to script ... has been blocked by CORS policy). Die App ließ sich damit nur über einen lokalen HTTP-Server starten was der Anforderung "Doppelklick, kein Server" widerspricht.

Neue Entscheidung: Alle JavaScript-Dateien wurden von ES-Modulen auf klassische, nicht-modulare <script>-Tags umgebaut. Statt import/export hängt jede Datei ihre öffentliche API an ein einziges globales Namespace-Objekt window.EventMap (mit Sub-Namespaces utils, config, models, store, map, ui) an. Jede Datei kapselt ihre internen Hilfsvariablen weiterhin in einer IIFE ((function () { ... })();), sodass nur das explizit an EventMap.* angehängte gemeinsam genutzt wird. Die Ladereihenfolge in index.html (Utils → Config → Models → Store → Map → UI → main.js) stellt sicher, dass jede Datei beim Ausführen bereits auf die Namespaces ihrer Abhängigkeiten zugreifen kann.

Entscheidung

  • Es wird kein Build-Tooling (kein Bundler wie Webpack/Vite, kein Transpiler, kein Package-Manager-Setup für die App selbst) eingesetzt.
  • JavaScript wird als klassische Scripts (<script src="...">, ohne type="module") eingebunden, organisiert über einen gemeinsamen globalen Namespace window.EventMap statt über import/export. Jede Datei ist in eine IIFE gekapselt.
  • Leaflet und Leaflet.markercluster werden lokal vendored unter vendor/leaflet/ bzw. vendor/leaflet.markercluster/ (JS, CSS und Marker-Bildassets), nicht per CDN eingebunden.

Begründung

  • Entspricht direkt der Anforderung nach einfachen, gut verständlichen Technologien ohne zusätzliche Lernkurve (kein Framework, kein Build-Schritt).
  • Ermöglicht das Öffnen der App per Doppelklick aus dem synchronisierten Ordner heraus, ohne dass der Endnutzer einen Server starten oder irgendetwas installieren muss das ist für die Zielgruppe wichtiger als natives Modul-Tooling.
  • Lokal vendorte Bibliotheken machen die App offline-fähig und unabhängig von der Verfügbarkeit externer CDNs; das passt zum Offline-First-Ansatz der LocalStorage-Datenhaltung.
  • Geringere Angriffsfläche/Komplexität: keine Abhängigkeit von Node-Toolchain- Versionen, keine Build-Artefakte, die aktuell gehalten werden müssten.

Konsequenzen

  • Trade-off gegenüber ES-Modulen: Es gibt kein natives Modul-Scoping mehr. Stattdessen dient der globale window.EventMap-Namespace plus IIFE-Kapselung pro Datei als Ersatz. Das erfordert Disziplin beim Vergeben von Namen unter EventMap.* (keine versehentlichen Überschreibungen) und macht Abhängigkeiten weniger explizit als import-Statements sie ergeben sich aus der Script-Reihenfolge in index.html, die entsprechend sorgfältig gepflegt werden muss.
  • Behobenes Restrisiko: Ursprünglich lud js/store/store.js die Beispieldaten per fetch('data/seed.json'), was unter file:// (insbesondere in Chrome/Chromium) von der Same-Origin-Policy blockiert wird. Die Seed-Daten wurden daher von data/seed.json nach data/seed.js verschoben und liegen dort als eingebettetes <script>-Objekt (EventMap.data.SEED_PLACES), das wie jede andere JS-Datei klassisch eingebunden wird. initStore() ist dadurch wieder synchron; fetch() kommt aktuell an keiner Stelle der Anwendung mehr vor. Für spätere Phasen (z.B. KI-JSON-Import) ist zu beachten: Datei-Uploads über <input type="file"> + FileReader sind unproblematisch unter file://, ein fetch() auf lokale Dateien dagegen nicht.
  • Es gibt keinen automatischen Minify-/Tree-Shaking-Schritt; die Dateigröße im Produktivbetrieb ist etwas größer als mit Bundler, was für den Umfang dieser Anwendung akzeptabel ist.
  • Updates der vendorten Bibliotheken müssen manuell durchgeführt werden (Dateien in vendor/ austauschen), es gibt keinen automatisierten Dependency-Update-Mechanismus (z.B. Dependabot) für diese Assets.
  • Sollte die Anwendung später deutlich wachsen (z.B. TypeScript, größere Testinfrastruktur, Bereitstellung über einen echten Webserver), kann diese Entscheidung revidiert und zurück auf ES-Module umgestellt werden.