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)
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user