Commit graph

94 commits

Author SHA1 Message Date
9394bab1fb Big Sweep: Security + Race-Conditions + Tests + DSGVO + A11y, SW by-v1095
SECURITY (auth.py, routes/auth.py, database.py, main.py)
- JWT bekommt jti; Logout trägt in neue jwt_blacklist-Tabelle ein,
  decode_token() prüft → server-side Invalidierung
- JWT-Expiry default 30 → 7 Tage (ENV JWT_EXPIRY_DAYS überschreibt)
- Sliding-Refresh-Middleware: erneuert Cookie wenn >50% verbraucht
  (Schwelle via JWT_REFRESH_FRACTION, Default 2)
- Login-Lockout in DB-Tabelle login_attempts (5 Versuche / 15 Min,
  überlebt Container-Restart) — alte In-Memory-Lockouts ersetzt
- SMTP-Versand: alle 'except: pass' durch logger.exception ersetzt;
  Fehlversuche landen in failed_emails-Tabelle für späteres Retry
- Referral-Counter Race gefixt: UPDATE partner_codes SET uses=uses+1
  ... WHERE uses<max_uses RETURNING — atomar statt SELECT+UPDATE

RACE CONDITIONS (routes/invoices.py, database.py)
- Neue invoice_counters-Tabelle für atomare Nummernvergabe
- _next_invoice_number nutzt BEGIN IMMEDIATE + atomares UPDATE
- Funktioniert für RG- und ST-Prefixe (Stornorechnungen)
- Race-Test verifiziert (5 Threads × 20 Calls = 100 eindeutige Nummern)

VERSION + TESTS + ERROR-DIGEST (VERSION, Makefile, tests/, scheduler.py)
- Neue VERSION-Datei (Single Source of Truth) — main.py liest beim
  Startup
- Makefile-Target 'make bump' propagiert in sw.js, app.js, index.html
- Makefile-Target 'make test' setzt venv auf, läuft pytest
- 19 Smoke-Tests in tests/ (health, auth, diary, invoice) — alle grün
- Scheduler: täglicher _job_error_digest um 06:30 → schickt Error-
  Zusammenfassung an ADMIN_EMAIL (still wenn keine Errors)

DSGVO + A11Y + ERSTE-HILFE
- landing.html: 'HTML und ODS' → 'JSON' (tatsächlich implementiert)
- datenschutz.js: Sektion Account-Löschung erweitert (sofort gelöscht /
  anonymisiert / 10 Jahre für Rechnungen)
- erste-hilfe.js: prominentes Warning-Banner oben (ersetzt keine
  Tierarzt-Beratung); Notfallnummern gruppiert nach Land, TODO-Platz-
  halter für AT-Uni-Klinik, CH Tox Info Suisse, CH Tierspital Zürich
- ui.js Modal: ESC schließt, Focus-Trap, Auto-Focus erstes Element,
  Restore Focus auf vorigen Caller
- impressum.js Kontaktformular: Labels mit for=cf-name etc.

NEUE DB-TABELLEN (idempotent via CREATE TABLE IF NOT EXISTS)
- jwt_blacklist, login_attempts, failed_emails, invoice_counters

NEUE ENV-VARS
- JWT_REFRESH_FRACTION (Default 2)
- JWT_EXPIRY_DAYS Default geändert (30 → 7)
2026-05-26 20:12:01 +02:00
c03884cb81 Perf: 9 Performance-Fixes — SW by-v1072
Backend:
- DB: 3 neue Indizes (forum_posts thread+user, routes user) — Forum/Routen-Queries
- Caching: cache.py (TTL-Cache ohne neue Dependency) für 5 statische Listen
  (training_exercises, pflege_tipps, wiki_stats, wiki_gruppen, help_articles)
- diary.py + breeder_photos.py: Bildverarbeitung (ffmpeg/PIL/EXIF) per
  run_in_executor → blockiert Event-Loop nicht mehr
- scheduler.py: 11 kollidierende Jobs auf 5-Min-Intervalle gestaggert, coalesce=True
- social.py: ORDER BY RANDOM() ohne LIMIT in 2 Stellen gefixt
- alerts.py: Haversine-Loop bekommt SQL-Bounding-Box-Vorfilter

Frontend:
- sw.js: Tile-Cache mit LRU-Eviction (max 500 Einträge)
- admin.js: Event-Listener-Leak — Tab-Klicks per Delegation statt N Listener
- api.js: compressImage() Helper — Client-seitiges Resize auf max 2000px
  (HEIC/Videos/<500KB unverändert), integriert in 8 Upload-Stellen
  (diary, dog-profile×2, walks, poison, lost, health×2)

Bump APP_VER 1071 → 1072 (sw.js, app.js, main.py, index.html)
2026-05-26 06:30:36 +02:00
f0cf0f2243 Fix: users.geburtstag Migration robuster (PRAGMA table_info Check)
Statt try/except mit pass: PRAGMA table_info prüft ob Spalte existiert,
loggt explizit ob hinzugefügt oder bereits vorhanden.
SW by-v1032, APP_VER 1032
2026-05-16 12:18:48 +02:00
b54d9fda99 Fix: users.geburtstag Migration + Format TT.MM statt MM-DD
- database.py: ALTER TABLE users ADD COLUMN geburtstag TEXT (fehlte!)
- profile.py: Validierung auf \d{2}\.\d{2} (TT.MM Format)
- settings.js: Placeholder/Pattern auf TT.MM geändert
- worlds.js: Birthday-Check auf DD.MM Format angepasst
SW by-v1029, APP_VER 1029
2026-05-16 12:02:52 +02:00
0a466ef6ce Feat: Rechnungsadresse — Profil, Upgrade-Modal Hinweis, Rechnung-erstellen-Button in Upgrade-Cards (SW by-v967) 2026-05-15 10:59:12 +02:00
b68a12587a Feature: Rechnungs-System (invoices) — Backend komplett
- DB-Migration: invoices + invoice_items Tabellen inkl. Indizes
- routes/invoices.py: vollständiger Admin-Router (prefix /api/admin/invoices)
  - CRUD: Liste, Detail, Erstellen, Senden, Bezahlen, Stornieren
  - PDF-Generierung via fpdf2 mit §14-UStG-Pflichtangaben (Kleinunternehmer-Hinweis)
  - Cashflow-Übersicht und Quartalsbericht
  - PDF-Download-Endpunkt
  - Speicherung in /scaninput + optionaler Paperless-Upload
- mailer.py: send_email() + Backends um optionale PDF-Anhänge erweitert
  (Brevo: base64, SMTP: MIMEApplication)
- main.py: invoices_router registriert
- docker-compose.yml: /volume1/scaninput:/scaninput Volume hinzugefügt
2026-05-15 10:04:23 +02:00
1ea8127aaf Fix: needs_dog_selection TEXT '0' war truthy — INTEGER + === 1 Check (SW by-v946) 2026-05-14 14:02:17 +02:00
3b666c545f Feature: Abo-Kündigung + Ablaufdatum + Dog-Auswahl nach Downgrade (SW by-v945) 2026-05-14 13:56:55 +02:00
f6b37717b4 Feature: Upgrade-Anfragen-System — User-Flow + Admin-Panel (SW by-v920)
- DB: upgrade_requests-Tabelle (user_id, tier, message, fulfilled_at)
- POST /api/upgrade-request: Anfrage speichern + Admin-Benachrichtigungsmail
- GET/POST /api/admin/upgrade-requests[/{id}/fulfill]: Admin-Endpunkte
  — fulfill setzt subscription_tier + sendet Bestätigungsmail an User
- action-items: upgrades_pending zählt offene Anfragen → Badge im Admin
- Admin-Tab "Upgrades": Tabelle offener/erledigter Anfragen, Freischalten-Button
  mit Confirm-Modal, automatischer Tier-Setzung und Bestätigungsmail
- Settings: Upgrade-Modal sendet echte API-Anfrage statt nur mailto
  — doppelte Anfrage wird erkannt (already:true → Toast statt Fehler)
- api.js: API.auth.upgradeRequest(tier, message) hinzugefügt
- SW by-v920, APP_VER 920
2026-05-14 09:59:11 +02:00
65811720f5 Fix: wurf_rang/wurf_name ALTER TABLE außerhalb executescript (SW by-v912) 2026-05-13 20:01:34 +02:00
53f0cb37d6 Feature: Wurf-Buchstabe (A–Z) + Wurf-Name — DB, Backend, Formular, Kartenanzeige (SW by-v912) 2026-05-13 19:58:50 +02:00
f3308a6a94 Feature: Läufigkeit & Trächtigkeit — Zyklen, Progesterontests, Deckdaten, Meilensteine (SW by-v894) 2026-05-13 17:09:02 +02:00
67e68bbe2d Feature: Warteliste pro Wurf — CRUD, Status-Flow, Formular (SW by-v891) 2026-05-13 16:45:46 +02:00
44ba51cd38 Feature: Gassi-Hundefotos bei Teilnehmern + Fotos nach dem Treffen (SW by-v878) 2026-05-12 17:04:43 +02:00
b818f85f36 Feature: Aktive Erinnerungen, Versicherung, Verhaltensprotokoll, Hundefreundliche Orte (SW by-v874) 2026-05-11 22:24:42 +02:00
83034c0db0 Feature: Widerristhöhe im Hundeprofil + Ausweis-Fix (SW by-v873) 2026-05-11 21:30:07 +02:00
bda61a0e40 Feature: Trauer-Feature, Futter-Verträglichkeit, Multi-Hund-Fixes, Wetter-Ort (Sprint 47)
- dog-profile.js: Verstorben-Button, Gedenkseite, KI-Abschiedstext
- database.py: futter_eintraege/reaktionen, route_dogs, exercise_progress.dog_id
- routes/ernaehrung.py: Futter-Verträglichkeit mit 20 Reaktionstypen + Analyse
- routes/routen.py: route_dogs Many-to-Many, Routen editierbar
- routes/training.py: exercise_progress per dog_id
- routes/ki.py: /ki/abschied Trauer-KI
- weather.py: Nominatim Ortsname parallel geladen
- ui.js: dogChip/bindDogChip, visualViewport-Modal
- api.js: gedenken, gedenkseite, futter-Methoden, route_dogs
- worlds.js: Ortsname im Wetter-Chip
- uebungen.js: _progressLoaded-Flag, dog-spezifischer Fortschritt
- trainingsplaene.js: dog_id Unterstützung
- diary.js/health.js: P-Badge Cleanup
- map.js: Wetter-Ort-Anzeige entfernt
- wetter.js: Ort in Wetter-Detail
2026-05-11 19:28:38 +02:00
891e11df65 Fix: ki_health_reports ALTER TABLE user_id Migration, INSERT try/catch, Bericht immer zurückgeben (SW by-v807) 2026-05-09 21:31:05 +02:00
e8cf742911 Feature: App-Einstellungen in DB (preferred_theme neu, notes_ki+gassi_stunde schon drin) — geräteübergreifend sync (SW by-v785) 2026-05-08 19:06:29 +02:00
9ebd40aaae Feature: Geburtstags-KI — 2 Modi (morgen: Ideen, heute: Hundeperspektive), DB-Cache, Abend-Tagebuch-Hinweis (SW by-v780) 2026-05-08 18:24:27 +02:00
71f29dcce0 Feature: Subscription-Tier-System (standard/pro/breeder + _test), has_pro_access(), Admin-Tier-UI (SW by-v734) 2026-05-06 18:39:27 +02:00
05ecf3b94a Feature: Hilfe/FAQ, Übungen-Content, Navigation-Fixes (SW by-v727)
Hilfe & FAQ:
- Neue Seite /hilfe mit Akkordeon + Live-Suche (6 Kategorien, 25 Artikel)
- DB-Tabelle help_articles — Inhalte admin-seitig ohne Deploy änderbar
- Admin-Tab Hilfe/FAQ zum Bearbeiten aller Artikel
- Link in Einstellungen (unter Welten einrichten, über Abmelden)
- routes/help.py: GET (public), POST/PATCH/DELETE (Admin)

Übungen:
- 110 Übungen: beschreibung (kurz), schritte (JSON 4-6 Schritte), tipp — gutes Deutsch mit Umlauten
- Admin-Tab Übungen: Inline-Editor für alle drei Felder
- PUT /training/exercises/{id} (Admin) neu
- Übung-des-Tages Chip → scrollt jetzt korrekt zur Übung (exercise_id-Feldname-Fix)

Welten-Navigation:
- hide() stellt app-header + bottom-nav wieder her (worlds-hidden wurde nie entfernt)
- init() mit _setupDone-Guard (keine doppelten Event-Listener)
- Login ruft Worlds.init(_appState) statt show() — _state war null → falscher Render
- X-Button in Welten-Konfiguration: 30×30px, Icon 17px, besser sichtbar

Wetter:
- Motivation bei blockiertem Standort: 6-Schritte-iOS-Anleitung + Flugmodus-Tipp
- Auto-locate bleibt (kein Button-Only mehr)

achievements.py:
- my_achievements(): d.user_id → JOIN dogs (zweite Funktion war noch kaputt)
2026-05-05 21:46:16 +02:00
40de0f38aa Feature: Tierarzt-Bewertungen — Sterne-Rating pro Praxis mit Detail-Modal (SW by-v700) 2026-05-04 21:02:49 +02:00
6e4bf25581 Feature: Hundeernährungs-Feature — Kalorien-Rechner, Futter-Guide, Giftliste, KI-Berater (SW by-v698) 2026-05-04 20:51:45 +02:00
af1508c0de Feature: Fell-Typ Einstellung am Hundeprofil — personalisierte Wetter-Hinweise (SW by-v693)
- DB-Migration: dogs.fell_typ (kurz|mittel|lang|drahtaar|doppel|nackt)
- Hund-Profil Formular: Dropdown "Felltyp" mit 6 Optionen, wird via PATCH /api/dogs/{id} gespeichert
- Wetter: _dogWeatherLabel(d, felltyp) mit fell-spezifischen Hitze-/Kälteschwellen
- Wetter: Fell-spezifische Hinweise (doppel + Hitze, nackt + Kälte, kurz + Frost)
2026-05-04 20:21:02 +02:00
9103c7950f Feature: Generische Seiten-Hilfe (UI.pageInfo), POI Multi-Select, Tagessprüche-DB (SW by-v654)
- UI.pageInfo(): generische Hilfe-Funktion — erstes Öffnen zeigt Info-Banner, danach ? Button oben rechts; CSS-Klassen pinfo-*
- Übungen-Seite nutzt UI.pageInfo() als erstes Beispiel
- Karte POI: Mehrfachauswahl (außer Giftköder), Kombi-Typen entfernt, type als comma-separated im Backend
- daily_quotes Tabelle in DB (346 Einträge via import_quotes.py importiert)
- GET /widget/quote — deterministischer Tagesspruch (wechselt täglich)
2026-05-03 20:10:01 +02:00
1fdba57365 Feature: UX-Fixes — Zahnrad weg, POI-Kombi-Typen, exp-fab-Position, Welten-Config in DB (SW by-v653)
- worlds-settings Zahnrad komplett entfernt (war auf Mobile sichtbar, auf Desktop schon hidden)
- exp-fab: bottom jetzt calc(--nav-bottom-height + --safe-bottom + --space-2) — kein Overlap mit worlds-back auf iPhone
- Karte POI: neue Typen bank, bank_kotbeutel, bank_kotbeutel_abfall, kotbeutel_abfall (Backend + Frontend)
- Welten-Chip-Config: GET/PUT /profile/world-config, Spalte users.world_config TEXT (Migration), Sync bei Init + Speichern
2026-05-03 19:50:04 +02:00
747c353444 Chore: Sprint32-36 Zwischenstand — alle Änderungen aus dieser Session committen 2026-05-03 11:09:39 +02:00
798289ae5a Feature: Daueraufträge in Ausgaben — monatlich/quartalsweise/jährlich, Scheduler, SW by-v605 2026-05-02 10:51:28 +02:00
742ad189e8 Feature: Sprint31 — 9 Features merged (Streak, Ausgaben, KI-Tierarzt, Rückrufe, Adoption, Vet+Befunde, Hundepass, Playdate, Rassenerkennung)
- Trainings-Streak: streak.py, DB training_streaks, Scheduler 19:00, Widget in welcome.js, Ping in uebungen.js
- Ausgaben-Tracker: expenses.py, expenses.js, DB expenses-Tabelle
- KI-Tierarztfragen: ki.py /tierarzt, health.js Button+Modal, DB ki_tierarzt_log
- Rückruf-Alarm: recalls.py, recalls.js, DB feed_recalls, Scheduler 08:00 RASFF
- Adoption: adoption.py, adoption.js, DB adoption_cache
- Tierarzt-Favorit + Befunde: tieraerzte.py /my-favorite+/favorite, health_docs.py, health.js, api.js, DB favorite_vets+health_documents
- Digitaler Hundepass: passport.py, dog-profile.js, main.py /pass/{token}, DB vaccinations+medications+dog_passport_meta+passport_shares, requirements.txt fpdf2
- Playdate-Matching: playdate.py, playdate.js, DB playdate_listings+playdate_requests
- Rassen-Erkennung: ki.py /rasse-erkennung (Claude Vision), dog-profile.js+wiki.js, CSS .rasse-result-card, DB ki_rasse_log
2026-05-02 09:29:48 +02:00
ea2a83b29e Feature: Filme-Suche, HdM ins Forum + Gewinner-Badge im Profil, SW by-v594
- Filme-Seite: Suchfeld (filtert live nach Titel, Rasse, Genre, Beschreibung)
- Filme-Seite: Tab "Hund des Monats" entfernt
- Forum: kompakte HdM-Kachel über der Suche (Sieger + Stimmen), Klick öffnet Abstimmungs-Modal
- Hundeprofil: goldene Badges für jeden gewonnenen Monat (🏆 Mai 2026 …)
- DB: Tabelle hund_des_monats_wins (dauerhaft, dog_id + monat + stimmen)
- Scheduler: Job am 1. des Monats 00:05 — schreibt Vormonats-Sieger, Push an Besitzer
- Dogs-API: liefert hdm_wins[] pro Hund mit
2026-05-02 08:12:29 +02:00
87039994ce Feature: Moderation History — Log für alle 4 Bereiche, resolved_by/at Migration, SW by-v590 2026-05-01 19:44:59 +02:00
b6fdb23292 Cleanup: Influencer-Runde-2-Vorlagen aus Migration entfernt (bereits versendet) 2026-05-01 18:15:30 +02:00
37ad20a096 Outreach: 7 personalisierte Influencer-Mail-Vorlagen (Runde 2)
@nami.and.tommy, @brina.explores, @heimatherzen, @pfotentick,
@flummis_diary, @verwolft, @babybearyuki — INSERT OR IGNORE Migration
2026-05-01 17:34:20 +02:00
f378edab5d Jobs: Bewerbungssystem für Social-Media-Manager/in
Backend:
- job_applications + job_application_docs Tabellen in DB
- luna_trial_until Spalte in users (Migration)
- routes/jobs.py: POST /apply (FormData + Datei-Upload, max 3×10MB),
  GET /my-application, GET /luna-trial-status
- Admin: GET/PATCH /admin/applications, GET /admin/applications/{id}/docs/{doc_id}
- Bei Bewerbung: 14-Tage Luna-Probezugang automatisch aktiviert
- Bei Annahme: is_social_media=1 + Gründer-Status gesetzt
- Status-Mails (pending/reviewing/accepted/rejected) via email_html-Template
- auth.py: require_social_media prüft auch luna_trial_until

Frontend:
- pages/jobs.js: Stellenausschreibung + Bewerbungsformular
  (Name, E-Mail, Hund, Social-Handle, Motivation, Datei-Upload)
- Luna-Probezugang Teaser mit Countdown wenn aktiv
- Bestehende Bewerbung: Status-Screen statt Formular
- app.js: 'jobs' Seite registriert
- admin.js: neuer Tab 'Bewerbungen' (filtert nach Status,
  Statuswechsel per Dropdown, Detailansicht mit Anhang-Download,
  Admin-Notiz-Feld)
- admin.js: Tab 'Jobs' → 'Scheduler' umbenannt
2026-05-01 09:30:05 +02:00
59856e61a1 Filme: DB-Migration, 68 Einträge, Sort + Typ-Filter
- movies-Tabelle in SQLite (statt hardcoded Liste)
- seed_movies(): 68 Filme/Serien/Dokus beim ersten Start
- Felder: titel, originaltitel, jahr, genre, typ, hund_rasse,
  stirbt_der_hund, beschreibung, bild_emoji, imdb_rating, streaming
- GET /api/movies/filme?sort=&typ= — serverseitig sortiert
  Sort: default | titel | jahr_desc | jahr_asc | imdb | bewertung
  Typ: alle | film | serie | doku
- Admin-CRUD: POST/PATCH/DELETE /api/movies/filme
- Frontend: Sort-Dropdown, Typ-Filter-Buttons (Filme/Serien/Dokus),
  Zähler, IMDb-Rating + Streaming auf der Karte
- Promis ebenfalls erweitert (10 statt 6 Einträge)
2026-05-01 08:50:01 +02:00
526ff42215 Security: Passwort-Minimum, Rate Limits, Headers, Passwort-vergessen, email_verified
- Passwort-Minimum 8 Zeichen bei Register + Reset
- Rate Limit auf /resend-verification (3/h) und /forgot-password (3/h)
- Security-Headers: X-Frame-Options, X-Content-Type-Options, Referrer-Policy etc.
- email_verified in get_current_user SELECT ergänzt
- Forum: create_thread + create_post erfordern email_verified
- POST /auth/forgot-password + /auth/reset-password (2h-Token, via support@)
- DB-Migration: password_reset_token + password_reset_expires
- Frontend: Passwort-vergessen-Modal im Login, Reset-Formular mit Passphrase-Generator
- SW by-v576, APP_VER 553
2026-04-30 20:23:43 +02:00
b9ee67b8dd Feature: E-Mail-Verifikation + Forum öffentlich lesbar + Launch-Vorbereitung
- Forum ohne requiresAuth: öffentlich lesbar, Schreiben weiter via API-Guard
- E-Mail-Verifikation: Token bei Registrierung, support@-Mail, /verify-email/{token}
- Verifikations-Banner (orange, dismissible) wenn email_verified=0
- Grüner Haken / "Nicht bestätigt"-Chip in Settings
- POST /auth/resend-verification für Chip und Banner
- DB-Migration: users.verification_token TEXT
- SW by-v575, APP_VER 552
2026-04-30 19:51:07 +02:00
e79290edb7 Feature: Mailing — Template-Manager, zwei SMTP-Accounts (partner/support)
- email_templates Tabelle (CRUD), Startwert-Vorlage wird einmalig geseedet
- outreach_log.from_account Spalte ergänzt
- Admin-UI: Template-Liste mit Laden/Bearbeiten/Löschen + Modal zum Anlegen
- Compose mit Absender-Auswahl (partner@/support@)
- send_support_mail() intern aufrufbar für Moderations-Trigger
- SW by-v574, APP_VER 551
2026-04-30 19:41:58 +02:00
b6258db6bc Feature: Admin Outreach — E-Mail-Versand via Hetzner SMTP, Vorlagen, Log, SW by-v567 2026-04-30 19:10:54 +02:00
230455c250 Feature: Gründer-Aktivierung nach Hunde-Profil mit Plausibilitätsprüfung
- is_founder_pending: bei Registrierung mit Code gesetzt (statt sofort is_founder)
- dogs.py: erstes Hunde-Profil → Plausibilitätsprüfung → is_founder aktivieren
- Prüfung: Name min. 2 Zeichen + Buchstaben, Rasse gültig, Geburtsjahr realistisch
- Settings: gelbes 'Gründer-Platz reserviert' Badge mit Link zu Hunde-Profil
- Onboarding-Toast informiert über nötiges Hunde-Profil
- SW by-v566, APP_VER 543
2026-04-30 18:59:20 +02:00
ab41af470d Feature: 100 Gründer-Challenge — Leaderboard, Ranking, founder_number
- users.founder_number: sequentielle Nummer #1-#100 (bei Registrierung mit Code oder Admin-Grant)
- Globaler Cap: max. 100 Gründer über alle Partner-Codes zusammen
- GET /api/partner/founders/stats: öffentlich — Slots, Partner-Ranking nach uses, Gründer-Galerie
- Öffentliche Seite /gruender: Fortschrittsbalken, Partner-Challenge-Leaderboard (🥇🥈🥉), Gründer-Grid
- Forum: "Gründer #42"-Badge (lila) neben Autorenname bei Threads + Antworten
- Settings: Badge zeigt "Gründer #N" statt nur "Gründer", klickbar zur /gruender-Seite
- Sidebar: "🏆 100 Gründer"-Link im Footer
- Admin-Grant: Vergabe von founder_number beim manuellen is_founder=1-Setzen
- SW by-v516, APP_VER 493
2026-04-29 21:30:52 +02:00
e57c6db013 Feature: Partner-Codes + Gründer-Lizenz-System für Influencer-Kooperationen
- partner_codes Tabelle: Code, Label, max_uses, grants_founder, uses-Counter
- users: is_founder + is_partner Flags (DB-Migration + auth.py SELECT)
- Registrierung: Partner-Code löst Gründer-Lizenz aus (vor User-Referral geprüft)
- API: GET/POST/DELETE /api/admin/partner/codes, POST /api/admin/partner/users/{id}/grant
- API: GET /api/partner/codes/{code}/info (öffentlich, für Registrierungsvalidierung)
- API: GET /api/admin/users/search (Name-Suche für Admin-UI)
- Admin-Tab "Partner & Codes": Code anlegen, Stats, User-Status vergeben
- Registrierungsformular: Einladungscode-Feld mit Live-Validierung
- Settings: Gründer (lila) + Partner (blau) Badge neben Kostenlos/Plus
- SW by-v515, APP_VER 492
2026-04-29 21:20:16 +02:00
27d847ce31 Fix: direct_messages Migration-Reihenfolge für frische DBs; Staging produktionsbereit — SW by-v513, APP_VER 490 2026-04-29 20:12:09 +02:00
ad3b73d687 Cleanup: training_exercises.js_exercise_id — ID-Mismatch bereinigt, JOIN mit exercise_progress, Fuß-Umbenennung — SW by-v508, APP_VER 485 2026-04-29 19:00:53 +02:00
9832cd24d8 Feature: KI-Jahresberichte speichern + Archiv + Download — SW by-v505, APP_VER 482 2026-04-29 17:03:49 +02:00
81ee1a063e Feature: Übungs-Suche, fehlende Legacy-Übungen nachmigriert (110 gesamt) — SW by-v495, APP_VER 472 2026-04-29 12:26:32 +02:00
392359df45 Feature: ORS-Stats im Admin-Panel — Tagesverbrauch/2000, 30-Tage-Sparkline, Top-Nutzer — SW by-v485, APP_VER 462 2026-04-29 10:10:59 +02:00
7048499624 Feature: ORS-Wochenlimit (20/Woche), Tages-Cache, Privilegien-Bypass, Datenschutz-Update — SW by-v480, APP_VER 457 2026-04-29 08:23:55 +02:00
c8ae514c01 Feature: Tierschutz-Check, KI-Züchter-Features, Export, SEO-Update
Tierschutz-System (immer aktiv, nicht abschaltbar):
- welfare_check.py: regelbasierte Prüfung IK, Alter, Deckpause, Wurfanzahl, Genetik
- Grün/Gelb/Rot-Modal bei Wurf anlegen + Probeverpaarung
- Bei kritischem Befund + "Trotzdem fortfahren" → automatische Admin-Mail
- Tierschutz-Check nie durch Nutzer deaktivierbar

KI-Züchter-Features (pro User an/abschaltbar außer Tierschutz):
- routes/zucht_ki.py: 5 Endpunkte — Wurfankündigung, Genetik-Erklärung,
  Paarungsanalyse, Hund-Beschreibung, Jahresbericht
- Toggles in Einstellungen (ki_zucht_* Felder)
- KI-Buttons in litters.js + zuchthunde.js

KI-Routing: Privilegierte Rollen (Admin, Züchter, Moderator, Manager)
nutzen Claude Sonnet primär, lokales LLM als Fallback

Datenexport: routes/breeder_export.py — ZIP mit HTML-Dossier + ODS
(odfpy hinzugefügt in requirements.txt)

Admin-Profil: POST /admin/breeder/create-profile für Schnellprofil ohne
Antragsprozess; Admin-Rolle bleibt erhalten

Wurfformular: Dropdown aus Zuchtkartei für Vater/Mutter mit Auto-Fill;
litters.vater_id + mutter_id als FK auf zucht_hunde

Probeverpaarung: heart-fill Icon + Welfare-Block im Ergebnis

Landing Page: Züchter-Section + Feature-Gruppe, Meta-Tags, JSON-LD,
keywords, softwareVersion 2.1

SEO: llms.txt vollständig überarbeitet, robots.txt Züchter-Pfade,
sitemap.xml um Wurfbörse + Züchter-Profile erweitert

SW by-v474, APP_VER 451
2026-04-28 19:49:54 +02:00