glanzlicht / Meinweimar_Tourguide

Intelligenter Tourguide für Weimar

Verified secure showcase
167 Files 833 KB Public size 12 Redacted Dart · Markdown · YAML · HTML · JSON · GITIGNORE

Project overview

Meinweimar_Tourguide is a verified code showcase with 167 visible project entries across 5 top-level modules. The primary detected language is Dart; protected files remain visible in the structure while their contents stay private.

README

MeinWeimar Tourguide

MeinWeimar Tourguide

Eine produktionsnahe Flutter-App fuer Stadtentdeckung, Tourplanung und Sprachlernen in Weimar. Die App verbindet eine responsive mobile und webfaehige Oberflaeche mit einer WordPress-REST-API und macht aus redaktionellen Inhalten konkrete Wege, Orte und Empfehlungen.

Dieses Repository zeigt neben der UI auch die technische Produktarbeit dahinter: API-Integration, Offline-tolerante Datenhaltung, Lokalisierung, Routing, Audio/TTS, Analytics, Deep Links und automatisierte Qualitaetssicherung.

App-Eindruecke

Start · Entdecken · Touren · Karte · Mehr

Produktumfang

  • Entdecken: POIs, Touren, Veranstaltungen, Partner und Themen mit Suche,
  • Filtern und fehlertoleranter Trefferlogik.

  • Unterwegs: Kartenansicht, Standort, Fussgaenger-Routing, Tourfortschritt,
  • Favoriten und eine persoenliche Route aus der eigenen Weimar-Liste.

  • Mehrsprachigkeit: UI und CMS-Inhalte in Deutsch, Englisch,
  • Niederlaendisch, Franzoesisch, Polnisch, Italienisch, Spanisch und Tschechisch.

  • Audio und Lernen: Guide-Audio, Flutter TTS sowie SprachGuide-Kurse und
  • Lern-Touren.

  • Redaktion und Betrieb: WordPress REST API, Oeffnungszeiten mit
  • Zeitzonenlogik, Kampagnen, Partnerplatzierungen, Deep Links und First-Party- Analytics.

  • Responsive UX: kleine Displays, grosse Systemschrift, dynamische
  • Kartenhoehen und versionierte Web-Releases ohne veraltete Service-Worker- Assets.

Technischer Steckbrief

BereichUmsetzung
FrameworkFlutter / Dart 3.4+
PlattformeniOS, Android und Web
DatenWordPress REST API, typisierte Models und Repositories
Kartenflutter_map, latlong2, Standort und Fussgaenger-Routing
Audiojust_audio, flutter_tts
Lokaler ZustandShared Preferences, begrenztes Caching und Analytics-Puffer
QualitaetFlutter Analyzer, Widget- und Service-Tests, Lokalisierungs- und API-Modelltests

Die Codebasis ist nach Verantwortlichkeiten gegliedert:

lib/
	core/          gemeinsame API-, Lokalisierungs- und Navigationslogik
	data/          Datenzugriff und DTO-nahe Strukturen
	features/      produktbezogene Screens und Flows
	models/        fachliche Modelle
	repositories/  Datenzugriff hinter stabilen Schnittstellen
	services/      Routing, Audio, Analytics und Plattformdienste
	widgets/       wiederverwendbare UI-Bausteine
test/            fokussierte Tests fuer Services, Modelle und Widgets

Lokal starten

Voraussetzungen: aktuelles Flutter SDK und das darin enthaltene Dart SDK.

flutter pub get
flutter analyze
flutter test
flutter run -d chrome

Die Anwendung verwendet standardmaessig die oeffentliche API: https://tour.meinweimar.de/wp-json/meinweimar/v1

Web-Release

Fuer einen Web-Release das versionierte Build-Skript verwenden:

./tool/build_web_release.sh

Das Skript legt den Runtime-Build unter build/web/releases/<release-id>/ ab. Launcher und Versionsendpunkt bleiben bewusst nicht cachebar, damit Browser nach einem Reload die aktuelle Version auflosen. Startup-Diagnostik ist nur mit ?mwdebug=1 aktiv.

Dokumentation

  • [Deep Links](DEEP_LINKS.md) - Web-Routen fuer Bereiche, Touren und POIs
  • [Projektstatus](PROJECT_STATE.md) - aktueller Funktions- und Integrationsstand
  • [Changelog](CHANGELOG.md) - nachvollziehbare Produkt- und UX-Iterationen
  • [API-Integration](docs/API_INTEGRATION.md) - technische Integrationsnotizen
tool/build_web_release.shShell
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")/.."
if [ ! -d web ]; then
flutter create . --platforms web
fi
VERSION="$(awk '/^version:/ {print $2; exit}' pubspec.yaml)"
RELEASE_ID="${VERSION//+/-}"
RELEASE_PATH="releases/${RELEASE_ID}/"
printf '{\n "version": "%s",\n "release_id": "%s",\n "release_path": "%s",\n "cache_policy": "always-current-launcher-versioned-runtime"\n}\n' \
"$VERSION" "$RELEASE_ID" "$RELEASE_PATH" > web/version.json
echo "Building MeinWeimar web $VERSION …"
echo "Runtime release path: $RELEASE_PATH"
# No Flutter PWA worker. Runtime files are isolated by release path.
flutter build web --release --pwa-strategy=none
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' EXIT
cp -a build/web/. "$TMP_DIR/"
rm -rf build/web
mkdir -p "build/web/$RELEASE_PATH"
cp -a "$TMP_DIR/." "build/web/$RELEASE_PATH"
# ---------------------------------------------------------------------------
# ALWAYS-CURRENT ROOT LAUNCHER
# ---------------------------------------------------------------------------
# index.html is intentionally a tiny stable trampoline. Even if a browser keeps
# an old copy of it, every invocation jumps to index.php with a unique query
# parameter. PHP then emits explicit no-store headers before serving the real
# launcher. This avoids depending on nginx/.htaccess cache behavior.
cat > build/web/index.html <<'HTML'
<!doctype html>
<html><head>
<meta charset="utf-8">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<meta name="robots" content="noindex">
<title>MeinWeimar TOURGUIDE</title>
<script>
(function () {
var target = new URL('index.php', window.location.href);
var current = new URL(window.location.href);
current.searchParams.forEach(function (value, key) {
if (key !== 'mwentry') target.searchParams.set(key, value);
});
target.searchParams.set('mwentry', Date.now().toString());
target.hash = current.hash;
window.location.replace(target.toString());
})();
</script>
</head><body></body></html>
HTML
# Real production launcher, served by PHP with headers that nginx cannot turn
# into a stale static HTML response. The HTML itself is Flutter's generated
# launcher, including MeinWeimar startup hardening.
{
cat <<'PHP'
<?php
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Pragma: no-cache');
header('Expires: 0');
header('X-MeinWeimar-Launcher: always-current');
?>
PHP
cat "$TMP_DIR/index.html"
} > build/web/index.php
# Authoritative release metadata via PHP = explicit no-store response headers.
cat > build/web/version.php <<PHP
<?php
header('Content-Type: application/json; charset=utf-8');
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Pragma: no-cache');
header('Expires: 0');
header('X-MeinWeimar-Version: ${VERSION}');
echo json_encode([
'version' => '${VERSION}',
'release_id' => '${RELEASE_ID}',
'release_path' => '${RELEASE_PATH}',
'cache_policy' => 'always-current-launcher-versioned-runtime',
], JSON_UNESCAPED_SLASHES);
PHP
# Static JSON remains for compatibility with older MeinWeimar launchers.
cp web/version.json build/web/version.json
cp web/update.html build/web/update.html
for item in manifest.json favicon.png icons; do
if [ -e "$TMP_DIR/$item" ]; then
cp -a "$TMP_DIR/$item" build/web/
fi
done
# Legacy Flutter service-worker killer. Old Flutter Web builds registered this
# exact URL. Browsers periodically check it for updates; once this script wins,
# it discards old Cache Storage and unregisters itself.
cat > build/web/flutter_service_worker.js <<'JS'
self.addEventListener('install', function () {
self.skipWaiting();
});
self.addEventListener('activate', function (event) {
event.waitUntil((async function () {
try {
var keys = await caches.keys();
await Promise.all(keys.map(function (key) { return caches.delete(key); }));
} catch (_) {}
try { await self.clients.claim(); } catch (_) {}
try { await self.registration.unregister(); } catch (_) {}
try {
var clients = await self.clients.matchAll({type: 'window', includeUncontrolled: true});
clients.forEach(function (client) { client.postMessage({type: 'MW_LEGACY_SW_REMOVED'}); });
} catch (_) {}
})());
});
self.addEventListener('fetch', function () {
// Deliberately no fetch interception. Network/browser cache handles assets.
});
JS
# Also cover a generic historical service-worker filename if one was ever used.
cp build/web/flutter_service_worker.js build/web/service-worker.js
# Optional Apache hardening for hosts that honor it. Correctness no longer
# depends on these rules because index.php/version.php emit their own headers.
cat > build/web/.htaccess <<'HT'
<IfModule mod_headers.c>
<FilesMatch "^(index\.html|index\.php|version\.json|version\.php|flutter_service_worker\.js|service-worker\.js)$">
Header always set Cache-Control "no-store, no-cache, must-revalidate, max-age=0"
Header always set Pragma "no-cache"
Header always set Expires "0"
</FilesMatch>
<FilesMatch "\.(?:js|mjs|json|wasm|woff2?|ttf|otf|png|jpe?g|webp|svg|ico)$">
Header set Cache-Control "public, max-age=31536000, immutable" "expr=%{REQUEST_URI} =~ m#^/releases/#"
</FilesMatch>
</IfModule>
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
HT
# Sanity checks.
test -f "build/web/$RELEASE_PATH/flutter_bootstrap.js"
test -f "build/web/$RELEASE_PATH/main.dart.js"
test -d "build/web/$RELEASE_PATH/assets"
test -f build/web/index.html
test -f build/web/index.php
test -f build/web/version.php
test -f build/web/flutter_service_worker.js
test ! -f build/web/main.dart.js
echo
echo "✓ build/web ready for COMPLETE upload"
echo " Version: $VERSION"
echo " Release path: $RELEASE_PATH"
echo " Root: stable index.html -> no-store index.php"
echo " Metadata: no-store version.php (+ version.json legacy fallback)"
echo " Legacy SW: active killer/unregister script"
echo
echo "Deploy the COMPLETE build/web directory."
echo "Normal reload path: / -> index.php?mwentry=<unique> -> version.php?cacheBust=<unique> -> $RELEASE_PATH"
echo "No user cache clearing is required for current MeinWeimar launchers."

Architecture

High-level modules detected from the verified public snapshot. Protected implementation details are intentionally omitted.

libmodule
testmodule
docsmodule
webmodule
toolmodule

Technology stack

DartMarkdownLOCKHTMLShellHTACCESSFlutter / Dart
Dart89.9%
Markdown3.9%
LOCK3.1%
HTML1.7%
Shell0.8%
HTACCESS0.2%
YAML0.1%
METADATA0.1%