diff --git a/backend/static/js/pages/onboarding.js b/backend/static/js/pages/onboarding.js
new file mode 100644
index 0000000..6cfda8b
--- /dev/null
+++ b/backend/static/js/pages/onboarding.js
@@ -0,0 +1,461 @@
+/* ============================================================
+ BAN YARO — Onboarding-Wizard
+ 3-Schritt-Wizard für neue User ohne Hund.
+ ============================================================ */
+
+window.Page_onboarding = (() => {
+
+ let _container = null;
+ let _appState = null;
+ let _step = 1; // 1 = Willkommen, 2 = Hund anlegen, 3 = Fertig
+
+ // ----------------------------------------------------------
+ // INIT
+ // ----------------------------------------------------------
+ async function init(container, appState) {
+ _container = container;
+ _appState = appState;
+ _step = 1;
+ _render();
+ }
+
+ function refresh() {
+ // Wenn User nach Abschluss zurücknavigiert und schon fertig ist → Tagebuch
+ if (localStorage.getItem('by_onboarding_done')) {
+ App.navigate('diary');
+ return;
+ }
+ _render();
+ }
+
+ function onDogChange() {}
+
+ // ----------------------------------------------------------
+ // RENDER
+ // ----------------------------------------------------------
+ function _render() {
+ _container.innerHTML = `
+
+
+
+
+ ${[1, 2, 3].map(n => `
+
+
+ ${n < _step
+ ? ` `
+ : n}
+
+ ${n < 3 ? `
` : ''}
+
+ `).join('')}
+
+
+
+
+ ${_stepContent()}
+
+
+
+ `;
+
+ _bindEvents();
+ }
+
+ function _stepContent() {
+ if (_step === 1) return _step1();
+ if (_step === 2) return _step2();
+ if (_step === 3) return _step3();
+ return '';
+ }
+
+ // ----------------------------------------------------------
+ // SCHRITT 1 — Willkommen
+ // ----------------------------------------------------------
+ function _step1() {
+ return `
+
+
+
+
+
+
+
+
+
+ Willkommen bei Ban Yaro!
+
+
+
+
+ Ban Yaro ist dein digitaler Begleiter für alles rund um deinen Hund —
+ Tagebuch, Gesundheit, Karte und Community in einer App.
+
+
+ In nur zwei Schritten richtest du dein Profil ein und bist sofort startklar.
+
+
+
+
+ ${[
+ ['book-open', 'Tagebuch', 'Momente & Fotos'],
+ ['syringe', 'Gesundheit', 'Impfungen & Arzt'],
+ ['map-trifold', 'Karte', 'Orte & Routen'],
+ ['users', 'Community', 'Freunde & Treffen'],
+ ].map(([icon, title, desc]) => `
+
+ `).join('')}
+
+
+
+
+
+
+ Los geht's
+
+
+ Überspringen
+
+
+
+
+ `;
+ }
+
+ // ----------------------------------------------------------
+ // SCHRITT 2 — Hund anlegen
+ // ----------------------------------------------------------
+ function _step2() {
+ const today = new Date().toISOString().slice(0, 10);
+ return `
+
+
+
+
+
+
+
+
+
+
+ Dein erster Hund
+
+
+ Nur der Name ist Pflicht — alles andere kannst du später ergänzen.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hund anlegen
+
+
+
+
+ Ohne Hund fortfahren
+
+
+
+
+ `;
+ }
+
+ // ----------------------------------------------------------
+ // SCHRITT 3 — Fertig
+ // ----------------------------------------------------------
+ function _step3() {
+ const dogName = _appState.activeDog?.name;
+ return `
+
+
+
+
+
+
+
+ Dein Profil ist bereit!
+
+ ${dogName ? `
+
+ ${_esc(dogName)} ist jetzt in Ban Yaro.
+ Du kannst jetzt Einträge im Tagebuch anlegen, die Gesundheit pflegen
+ und viele weitere Funktionen nutzen.
+
+ ` : `
+
+ Ban Yaro ist bereit. Du kannst jetzt die Karte, das Wiki und viele
+ weitere Funktionen erkunden.
+
+ `}
+
+ Du kannst dein Hundeprofil jederzeit unter
+ Mein Hund bearbeiten und ergänzen.
+
+
+
+
+
+
+ Zum Tagebuch
+
+ ${dogName ? `
+
+
+ Profil vervollständigen
+
+ ` : ''}
+
+
+
+ `;
+ }
+
+ // ----------------------------------------------------------
+ // EVENTS
+ // ----------------------------------------------------------
+ function _bindEvents() {
+ // Weiter-Button (Schritt 1)
+ _container.querySelector('#ob-next-btn')?.addEventListener('click', () => {
+ _step = 2;
+ _render();
+ });
+
+ // Zurück-Button (Schritt 2)
+ _container.querySelector('#ob-back-btn')?.addEventListener('click', () => {
+ _step = 1;
+ _render();
+ });
+
+ // Überspringen
+ _container.querySelector('#ob-skip-btn')?.addEventListener('click', () => {
+ _finish();
+ });
+
+ // Foto-Vorschau
+ _container.querySelector('#ob-photo-input')?.addEventListener('change', e => {
+ const file = e.target.files?.[0];
+ if (!file) return;
+ const url = URL.createObjectURL(file);
+ const preview = _container.querySelector('#ob-photo-preview');
+ const img = _container.querySelector('#ob-photo-img');
+ const label = _container.querySelector('#ob-photo-label');
+ if (preview) preview.style.display = '';
+ if (img) img.src = url;
+ if (label) label.textContent = file.name.length > 20
+ ? file.name.slice(0, 17) + '...'
+ : file.name;
+ });
+
+ // Formular abschicken (Schritt 2)
+ _container.querySelector('#ob-dog-form')?.addEventListener('submit', async e => {
+ e.preventDefault();
+ await _saveDog(e.target);
+ });
+
+ // Zu Tagebuch (Schritt 3)
+ _container.querySelector('#ob-diary-btn')?.addEventListener('click', () => {
+ App.navigate('diary');
+ });
+
+ // Zu Hund-Profil (Schritt 3)
+ _container.querySelector('#ob-profile-btn')?.addEventListener('click', () => {
+ App.navigate('dog-profile');
+ });
+ }
+
+ // ----------------------------------------------------------
+ // HUND SPEICHERN
+ // ----------------------------------------------------------
+ async function _saveDog(form) {
+ const saveBtn = _container.querySelector('#ob-save-btn');
+ if (saveBtn) {
+ saveBtn.disabled = true;
+ saveBtn.innerHTML = `
+
+ Wird angelegt…
+ `;
+ }
+
+ try {
+ const data = new FormData(form);
+ const payload = {
+ name: data.get('name')?.trim(),
+ rasse: data.get('rasse')?.trim() || null,
+ geburtstag: data.get('geburtstag') || null,
+ };
+
+ if (!payload.name) {
+ UI.toast.error('Bitte gib einen Namen ein.');
+ return;
+ }
+
+ // Hund anlegen
+ const dog = await API.dogs.create(payload);
+
+ // Foto hochladen (falls vorhanden)
+ const fotoFile = data.get('foto');
+ if (fotoFile && fotoFile.size > 0) {
+ try {
+ const fd = new FormData();
+ fd.append('file', fotoFile);
+ await API.dogs.uploadPhoto(dog.id, fd);
+ } catch {
+ // Foto-Upload-Fehler ist nicht kritisch
+ UI.toast.warning('Hund angelegt, Foto konnte nicht hochgeladen werden.');
+ }
+ }
+
+ // State aktualisieren
+ const dogs = await API.dogs.list();
+ _appState.dogs = dogs;
+ const newDog = dogs.find(d => d.id === dog.id) || dogs[0];
+ _appState.activeDog = newDog;
+ if (newDog) {
+ localStorage.setItem('by_active_dog', String(newDog.id));
+ }
+ App.renderDogSwitcher();
+
+ UI.toast.success(`${_esc(dog.name)} wurde angelegt!`);
+
+ _step = 3;
+ _render();
+
+ } catch (err) {
+ UI.toast.error(err.message || 'Hund konnte nicht angelegt werden.');
+ } finally {
+ if (saveBtn) {
+ saveBtn.disabled = false;
+ saveBtn.innerHTML = `
+
+ Hund anlegen
+ `;
+ }
+ }
+ }
+
+ // ----------------------------------------------------------
+ // ABSCHLUSS
+ // ----------------------------------------------------------
+ function _finish() {
+ localStorage.setItem('by_onboarding_done', '1');
+ if (_appState.dogs.length > 0) {
+ App.navigate('diary');
+ } else {
+ App.navigate('map');
+ }
+ }
+
+ // ----------------------------------------------------------
+ // HELPER
+ // ----------------------------------------------------------
+ function _esc(s) {
+ return UI.escape(s || '');
+ }
+
+ // ----------------------------------------------------------
+ // PUBLIC
+ // ----------------------------------------------------------
+ return { init, refresh, onDogChange };
+
+})();