# Putzliga Putzliga ist eine moderne, leichte Haushaltsaufgaben-Web-App mit spielerischem Charakter. Version 1 setzt auf Flask, SQLite, Jinja-Templates, responsives CSS, minimales JavaScript und eine saubere PWA-/Web-Push-Basis. Die App ist für mehrere Nutzer ausgelegt, läuft lokal sehr unkompliziert und ist so vorbereitet, dass sie auf Cloudron direkt als Container-App betrieben werden kann. ## Features - Mehrere Nutzer mit Login, Registrierung und Profil-/Avatar-Einstellungen - Trennung zwischen `TaskTemplate` und `TaskInstance` - Aufgaben anlegen, bearbeiten, zuweisen und erledigen - Wiederholungen für einmalig, alle X Tage, alle X Wochen und alle X Monate - Saubere Erledigungslogik für fremd zugewiesene Aufgaben mit Auswahl, wer wirklich erledigt hat - Statuslogik für offen, bald fällig, überfällig und erledigt - `Meine Aufgaben`, `Alle Aufgaben`, `Aufgabe erstellen`, `Kalender/Liste`, `Highscoreboard`, `Optionen` - Monats-Highscore mit Badge-Boni und Balkendarstellung - Monatsarchiv über `MonthlyScoreSnapshot` - PWA mit `manifest.json`, Service Worker, App-Icons und iOS-freundlicher Installationsbasis - Echte Web-Push-Architektur mit gespeicherten `PushSubscription`s - CLI-Kommandos für Archivierung und serverseitig triggerbare Benachrichtigungen - Cloudron-/Container-tauglicher Start mit `start.sh`, `Dockerfile` und `CloudronManifest.json` ## Projektstruktur ```text app/ routes/ services/ static/ css/ fonts/ icons/ images/ js/ manifest.json service-worker.js templates/ auth/ partials/ scoreboard/ settings/ tasks/ app.py config.py seed.py start.sh Dockerfile CloudronManifest.json requirements.txt .env.example scripts/ data/ ``` ## Lokale Daten vs. Cloudron-Inhalte Die App ist jetzt so vorbereitet, dass lokale Entwicklungsdaten nicht versehentlich mit nach Cloudron wandern: - `data/` ist in `.gitignore` ausgeschlossen und wird nicht committed - `data/` ist zusätzlich in `.dockerignore` ausgeschlossen und landet nicht im Docker-Build-Kontext - Uploads liegen standardmäßig ebenfalls unter `data/uploads` und bleiben damit lokal bzw. im persistenten Cloudron-Storage - Beim ersten Cloudron-Start wird keine lokale Entwicklungsdatenbank ins Image kopiert Damit kannst du lokal mit Seed-Daten entwickeln und online unabhängig davon echte Inhalte pflegen. ## Lokales Setup ### 1. Abhängigkeiten installieren ```bash python3 -m venv .venv . .venv/bin/activate pip install -r requirements.txt ``` ### 2. Umgebungsvariablen setzen ```bash cp .env.example .env ``` Wichtige Variablen: - `SECRET_KEY`: Flask Secret Key - `DATA_DIR`: Persistentes Datenverzeichnis - `DATABASE_PATH`: SQLite-Datei - `UPLOAD_FOLDER`: Upload-Verzeichnis für Avatare - `APP_BASE_URL`: Vollständige Basis-URL der App, wichtig für Push-Links - `APP_TIMEZONE`: Standardmäßig `Europe/Berlin` - `VAPID_PUBLIC_KEY` / `VAPID_PRIVATE_KEY`: Web-Push-Schlüssel - `VAPID_CLAIMS_SUBJECT`: Kontaktadresse für VAPID ### 3. App-Icons erzeugen Die Raster-Icons liegen als generierte Dateien im Projekt. Falls du sie neu erzeugen willst: ```bash python scripts/generate_assets.py ``` ### 4. Datenbank und Seed-Daten anlegen ```bash flask --app app.py init-db python seed.py ``` Demo-Logins: - `anna@putzliga.local` / `putzliga123` - `ben@putzliga.local` / `putzliga123` ### 5. Entwicklungsserver starten ```bash flask --app app.py run --debug ``` oder produktionsnah: ```bash ./start.sh ``` ## Seed-Daten Die Seed-Datei erzeugt: - 2 Beispielnutzer - wiederkehrende und einmalige Vorlagen - offene, bald fällige, überfällige und erledigte Aufgaben - Punkte im aktuellen Monat - erledigte Aufgaben aus dem Vormonat, damit das Archiv direkt sichtbar ist - Standard-Badges für Frühstarter, Serien und Monatsmenge ## Datenmodell Umgesetzt sind die Kernmodelle: - `User` - `TaskTemplate` - `TaskInstance` - `MonthlyScoreSnapshot` - `PushSubscription` - `NotificationLog` Zusätzlich für Version 1: - `BadgeDefinition` für pflegbare Badge-Regeln in den Optionen Wichtig: `TaskTemplate` beschreibt die wiederverwendbare Vorlage, `TaskInstance` die konkrete Aufgabe mit Fälligkeit, Status und tatsächlicher Erledigung. ## Monatsarchivierung Putzliga speichert keine monatlichen Punktetotale als Live-Zähler. Stattdessen wird der Monatsstand aus erledigten `TaskInstance`s berechnet. Dadurch startet jeder neue Monat automatisch bei 0, weil nur Aufgaben des aktuellen Monats zählen. Die Archivierung funktioniert so: - Vor Requests wird geprüft, ob bis zum Vormonat Archive fehlen - Fehlende Monate werden als `MonthlyScoreSnapshot` erzeugt - Archivwerte enthalten erledigte Aufgaben und Badge-Boni des jeweiligen Monats - Frühere Monate bleiben dauerhaft sichtbar Zusätzlicher CLI-Trigger: ```bash flask --app app.py archive-months ``` ## Push-Benachrichtigungen Putzliga nutzt echte Web-Push-Benachrichtigungen mit Service Worker und VAPID. ### Architektur - Browser registriert Service Worker - Subscription wird pro Nutzer in `PushSubscription` gespeichert - Server versendet über `pywebpush` - Versand ist getrennt in Prüf- und Ausführungslogik - Logs werden in `NotificationLog` dedupliziert ### Verfügbare Trigger ```bash flask --app app.py notify-due flask --app app.py notify-monthly-winner ``` `notify-due`: - prüft offene Aufgaben, die heute oder morgen fällig sind - berücksichtigt die Nutzeroption `notification_task_due_enabled` `notify-monthly-winner`: - sendet am 1. des Monats ab 09:00 Uhr - verweist auf das Scoreboard/Archiv des letzten Monats - berücksichtigt `notification_monthly_winner_enabled` Für iPhone/iPad muss zusätzlich sichergestellt sein, dass der Server ausgehend Apple Web Push erreichen kann. Laut WebKit sollten dafür Verbindungen zu `*.push.apple.com` möglich sein. ### Produktiver Betrieb Auf Cloudron oder einem anderen Server solltest du diese Kommandos regelmäßig per Cronjob oder Task ausführen, zum Beispiel: ```bash flask --app /app/app.py notify-due flask --app /app/app.py notify-monthly-winner ``` ### iPhone-/iOS-Hinweis Web-Push auf iPhone/iPad funktioniert nur in neueren iOS-/iPadOS-Versionen, wenn die Web-App über Safari zum Home-Bildschirm hinzugefügt wurde. Innerhalb eines normalen Safari-Tabs stehen Push-Berechtigungen nicht zuverlässig zur Verfügung. ## PWA Enthalten sind: - `app/static/manifest.json` - `app/static/service-worker.js` - `app/static/images/pwa-icon-192.png` - `app/static/images/pwa-icon-512.png` - `app/static/images/apple-touch-icon.png` - `app/static/images/pwa-badge.png` Der Service Worker cached die App-Shell und Assets pragmatisch für eine stabile Basis. Für Version 1 ist das bewusst schlank gehalten. ## Branding und Assets aus `heinz.marketing` Aus `../heinz.marketing` wurden bewusst nur verwertbare Grundlagen übernommen: - `Inter` und `Space Grotesk` aus `css/fonts/` - ausgewählte lokale SVG-Icons aus `css/fontawesome-pro-plus-7.0.0-web/svgs-full/chisel-regular/` Diese Assets wurden nicht unverändert als fertiges Branding übernommen. Putzliga nutzt darauf aufbauend: - eine eigene helle, iOS-nahe Farbwelt - ein neues App-Logo (`app/static/images/logo.svg`) - ein eigenes Favicon (`app/static/images/favicon.svg`) - eigene generierte PWA-Raster-Icons (`scripts/generate_assets.py`) ## Cloudron Cloudron-Dateien im Projekt: - `Dockerfile` - `start.sh` - `CloudronManifest.json` Die Manifest- und Docker-Struktur orientiert sich an der aktuellen Cloudron-Dokumentation für Docker-/Container-Apps: https://docs.cloudron.io/docker/ ### Wichtige Punkte für Cloudron - App hört auf `PORT` und standardmäßig auf `8000` - `DATA_DIR` und `UPLOAD_FOLDER` sollten im persistenten Storage liegen - SQLite-Datei liegt standardmäßig unter `/app/data/putzliga.db` - `start.sh` initialisiert die DB und startet Gunicorn - `APP_BASE_URL` kann auf Cloudron über `CLOUDRON_APP_ORIGIN` gesetzt oder daraus abgeleitet werden - Lokale Testdaten aus `data/` werden weder committed noch in das Docker-Image gepackt ### Beispielstart in Cloudron-/Container-Umgebungen ```bash ./start.sh ``` ## Hilfsskripte VAPID-Schlüssel generieren: ```bash python scripts/generate_vapid_keys.py ``` Der ausgegebene `VAPID_PRIVATE_KEY` ist bereits `.env`-freundlich mit escaped Newlines formatiert. `config.py` wandelt `\\n` beim Start automatisch in echte Zeilenumbrüche zurück. Icons neu generieren: ```bash python scripts/generate_assets.py ``` ## Hinweise für spätere Erweiterungen - Maluslogik für verspätete Erledigungen kann an `compute_monthly_scores()` und `TaskInstance` ergänzt werden - echte Admin-/Rollenrechte können ergänzt werden, aktuell dürfen bewusst alle Nutzer Aufgaben pflegen - Scheduler kann auf Cloudron später als separater Task sauber ausgelagert werden - Badge-Awards könnten in einer eigenen Tabelle historisiert werden, falls spätere Regeln rückwirkungsfrei versioniert werden sollen