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)
5.3 KiB
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="...">, ohnetype="module") eingebunden, organisiert über einen gemeinsamen globalen Namespacewindow.EventMapstatt überimport/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 unterEventMap.*(keine versehentlichen Überschreibungen) und macht Abhängigkeiten weniger explizit alsimport-Statements – sie ergeben sich aus der Script-Reihenfolge inindex.html, die entsprechend sorgfältig gepflegt werden muss. - Behobenes Restrisiko: Ursprünglich lud
js/store/store.jsdie Beispieldaten perfetch('data/seed.json'), was unterfile://(insbesondere in Chrome/Chromium) von der Same-Origin-Policy blockiert wird. Die Seed-Daten wurden daher vondata/seed.jsonnachdata/seed.jsverschoben 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">+FileReadersind unproblematisch unterfile://, einfetch()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.