Merge branch 'develop'

This commit is contained in:
rene 2026-05-14 13:17:23 +02:00
commit 29e39ee14a
4 changed files with 81 additions and 13 deletions

View file

@ -406,7 +406,7 @@ async def serve_media(path: str, request: _Request):
raise _HE(404, "Nicht gefunden.")
return _media_response(filepath)
APP_VER = "940" # muss mit APP_VER in app.js übereinstimmen
APP_VER = "941" # muss mit APP_VER in app.js übereinstimmen
@app.get("/.well-known/assetlinks.json")
async def assetlinks():

View file

@ -1150,19 +1150,87 @@ async def fulfill_upgrade_request(req_id: int, user=Depends(require_admin)):
tier_labels = {"pro": "Ban Yaro Pro", "breeder": "Züchter"}
tier_label = tier_labels.get(req["tier"], req["tier"])
tier_price = {"pro": "29 €/Jahr", "breeder": "49 €/Jahr"}.get(req["tier"], "")
_features_pro = [
("users", "Mehrere Hunde", "Bis zu 10 Hunde mit getrennten Trainings-, Gesundheits- und Ernährungsdaten"),
("fork-knife", "Ernährung", "Kalorienbedarf-Rechner, BARF-Guide, vollständige Giftliste, KI-Ernährungsberater"),
("paw-print", "Gassi-Treffen", "Hundefotos & Rasse der Teilnehmer sichtbar, Fotos hochladen und teilen"),
("chat-circle-dots", "Direktnachrichten & Chat", "Schreibe direkt mit anderen Hundebesitzern"),
("handshake", "Playdate", "Spielkameraden in der Nähe finden und verabreden"),
("airplane", "Reise-Checkliste", "Editierbare Checkliste + EU-Länder-Einreiseregeln"),
("note-pencil", "Notizblock mit KI", "KI erkennt Muster in deinen Notizen und macht Vorschläge"),
("map-trifold", "Erweiterte Karten-Layer", "Regenradar, Temperatur-Layer und weitere Kartenmodi"),
]
_features_breeder = [
("check-circle", "Alle Pro-Features inklusive", "Mehrere Hunde, Ernährung, Gassi-Community, Chat, Playdate, Reise, Karten"),
("tree-structure", "Zuchtkartei", "Gesundheitstests (HD, ED, OCD, Augen, Herz, Patella, ZTP), Gentests (MDR1, PRA, DM, vWD), Titel"),
("notebook", "Wurfverwaltung", "Würfe und Welpen verwalten, Gewichtsverlauf, Fotos, Kaufvertrag automatisch ausfüllen"),
("list-bullets", "Warteliste", "Interessenten mit Präferenzen pro Zuchthündin verwalten"),
("thermometer", "Läufigkeit & Trächtigkeit", "Zykluskalender, Progesterontests, Deckdaten, automatische Meilensteinberechnung"),
("graph", "Stammbaum & IK-Rechner", "Stammbaum bis 4 Generationen, Inzuchtkoeffizient nach Wright, Probeverpaarung"),
("sparkle", "KI-Züchter-Assistent", "Wurfankündigungen schreiben, Genetik-Erklärung, Paarungsanalyse, Jahresbericht"),
("globe", "Öffentliches Züchter-Profil", "Visitenkarte unter banyaro.app/breeder/{zwingername} mit Hunden, Fotos und Gesundheitsstatistik"),
("download-simple", "Datenexport", "Vollständiger Export als HTML-Dossier und ODS-Tabelle (LibreOffice/Excel)"),
]
features = _features_breeder if req["tier"] == "breeder" else _features_pro
def _feature_row(icon, title, desc):
return f"""
<tr>
<td style="padding:10px 12px 10px 0;vertical-align:top;width:28px">
<div style="width:28px;height:28px;border-radius:8px;background:#fdf0e3;
display:flex;align-items:center;justify-content:center;font-size:14px">✓</div>
</td>
<td style="padding:10px 0;vertical-align:top">
<div style="font-weight:700;font-size:14px;color:#1a1a1a">{title}</div>
<div style="font-size:13px;color:#666;margin-top:2px;line-height:1.4">{desc}</div>
</td>
</tr>"""
feature_rows = "".join(_feature_row(i, t, d) for i, t, d in features)
try:
from mailer import send_email, email_html
import html as _html
name_esc = _html.escape(req["name"])
body_html = f"""
<p>Hallo {req['name']},</p>
<p>dein Account wurde soeben auf <strong>{tier_label}</strong> freigeschaltet.</p>
<p>Du kannst alle {tier_label}-Features ab sofort in der App nutzen.
Öffne Ban Yaro und lade die App einmal neu dann ist dein neuer Tarif aktiv.</p>
<p>Vielen Dank für dein Vertrauen!</p>
<p>Viele Grüße<br>René &amp; das Ban Yaro Team</p>"""
html = email_html(body_html, cta_url="https://banyaro.app", cta_label="Ban Yaro öffnen")
plain = (f"Hallo {req['name']},\n\ndein Account wurde auf {tier_label} freigeschaltet.\n"
f"Öffne Ban Yaro und lade die App neu.\n\nViele Grüße\nRené")
await send_email(req["email"], f"Dein {tier_label}-Zugang ist aktiv", html, plain)
<p style="margin:0 0 8px;font-size:22px;font-weight:800;color:#1a1a1a">
Herzlichen Glückwunsch, {name_esc}! 🎉
</p>
<p style="margin:0 0 20px;font-size:15px;color:#555">
Dein Account wurde soeben auf <strong style="color:#C4843A">{tier_label}</strong>
freigeschaltet. Vielen Dank für dein Vertrauen in Ban Yaro!
</p>
<div style="background:#fdf6ef;border-radius:10px;padding:16px 20px;margin-bottom:24px">
<div style="font-size:12px;font-weight:700;color:#C4843A;text-transform:uppercase;
letter-spacing:.06em;margin-bottom:4px">Dein Tarif</div>
<div style="font-size:18px;font-weight:800;color:#1a1a1a">{tier_label}
<span style="font-size:13px;font-weight:400;color:#888;margin-left:8px">{tier_price}</span>
</div>
</div>
<div style="font-size:13px;font-weight:700;color:#888;text-transform:uppercase;
letter-spacing:.06em;margin-bottom:12px">Deine neuen Features</div>
<table style="width:100%;border-collapse:collapse;margin-bottom:24px">
{feature_rows}
</table>
<div style="background:#f0f7ff;border-left:3px solid #C4843A;border-radius:0 8px 8px 0;
padding:12px 16px;margin-bottom:8px;font-size:13px;color:#444;line-height:1.5">
<strong>So aktivierst du deine Features:</strong><br>
Öffne Ban Yaro und lade die App einmal neu (Startseite antippen herunterziehen
oder App schließen und neu öffnen). Alle Features sind dann sofort verfügbar.
</div>"""
html = email_html(body_html, cta_url="https://banyaro.app", cta_label="Ban Yaro jetzt öffnen")
plain = (f"Herzlichen Glückwunsch, {req['name']}!\n\n"
f"Dein Account wurde auf {tier_label} ({tier_price}) freigeschaltet.\n\n"
f"Öffne Ban Yaro und lade die App neu — alle Features sind dann aktiv.\n\n"
f"Viele Grüße\nRené & das Ban Yaro Team")
await send_email(req["email"], f"🎉 Dein {tier_label}-Zugang ist aktiv!", html, plain)
except Exception as e:
import logging
logging.getLogger(__name__).warning(f"Bestätigungsmail fehlgeschlagen: {e}")

View file

@ -3,7 +3,7 @@
Router, State-Management, Navigation, Initialisierung.
============================================================ */
const APP_VER = '940'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
const APP_VER = '941'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
const APP_VERSION = '1.5.1'; // ← semantische Version, wird bei make release gesetzt
const IS_STAGING = location.hostname === 'staging.banyaro.app';
// Cache-Bust-Parameter nach Update-Reload sofort entfernen

View file

@ -3,7 +3,7 @@
Offline-Cache + Push Notifications + Tile-Cache
============================================================ */
const CACHE_VERSION = 'by-v940';
const CACHE_VERSION = 'by-v941';
const CACHE_STATIC = `${CACHE_VERSION}-static`;
const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten
const CACHE_API = 'ban-yaro-api-v1'; // API-Response-Cache