Files
eventmap/docs/adr/0001-vanilla-esm.md
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

99 lines
5.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.