Files
putzliga/README.md
2026-04-13 08:32:28 +02:00

8.6 KiB

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 PushSubscriptions
  • CLI-Kommandos für Archivierung und serverseitig triggerbare Benachrichtigungen
  • Cloudron-/Container-tauglicher Start mit start.sh, Dockerfile und CloudronManifest.json

Projektstruktur

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

python3 -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt

2. Umgebungsvariablen setzen

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:

python scripts/generate_assets.py

4. Datenbank und Seed-Daten anlegen

flask --app app.py init-db
python seed.py

Demo-Logins:

  • anna@putzliga.local / putzliga123
  • ben@putzliga.local / putzliga123

5. Entwicklungsserver starten

flask --app app.py run --debug

oder produktionsnah:

./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 TaskInstances 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:

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

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

Produktiver Betrieb

Auf Cloudron oder einem anderen Server solltest du diese Kommandos regelmäßig per Cronjob oder Task ausführen, zum Beispiel:

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

./start.sh

Hilfsskripte

VAPID-Schlüssel generieren:

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:

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