# moneyfy Selbst gehostete Web-Anwendung zur Planung monatlicher Kosten und Einkünfte. Single-User, deutschsprachige Oberfläche, ausgelegt für den Betrieb im Homelab hinter einem Reverse Proxy. > **Status:** in Entwicklung. Siehe [CHANGELOG.md](CHANGELOG.md). ## Screenshots _Platzhalter – werden ergänzt, sobald die Oberfläche steht._ | Dashboard | Cashflow-Kalender | Firmen | |---|---|---| | _folgt_ | _folgt_ | _folgt_ | ## Funktionsumfang - Wiederkehrende Zahlungen und Einkünfte über vollständige RFC-5545-RRULEs, inklusive Werktagsverschiebung nach NRW-Feiertagen. - Preishistorie je Vertrag, sodass vergangene Monate betragstreu bleiben. - Verträge mit Mindestlaufzeit, Kündigungsfrist und automatischer Verlängerung. - Ratenzahlungen mit Restschuld- und Restratenberechnung. - Rücklagenbildung für nicht-monatliche Posten. - Firmenlogos und Markenfarben, lokal zwischengespeichert (siehe unten). - Auswertungen: Monatsübersicht, Cashflow-Kalender, 12-Monats-Forecast, Kategorien, Abo-Übersicht, Jahresvergleich, Budgets, Sparziele. - Benachrichtigungen per SMTP und Apprise. ## Technischer Stack | Bereich | Technologie | |---|---| | Backend | Python 3.12, FastAPI, SQLAlchemy 2 (async), Alembic, Pydantic v2 | | Datenbank | PostgreSQL 17 | | Scheduler | APScheduler (in-process) | | Frontend | React 18, TypeScript, Vite, TailwindCSS | | Charts | Recharts | | Tests | pytest + httpx, vitest + testing-library | ## Schnellstart (lokale Entwicklung) Voraussetzungen: Python 3.12, [uv](https://docs.astral.sh/uv/), Node 20+, eine erreichbare PostgreSQL-17-Instanz. ```bash git clone https://git.menzel.center/menzeljonas/moneyfy.git cd moneyfy cp .env.example backend/.env # DATABASE_URL und SECRET_KEY anpassen make install # Backend-Abhängigkeiten in backend/.venv make migrate # Schema anlegen make seed # Kategoriebaum und Standardregeln make dev # http://localhost:8000/api/docs ``` Nützliche Ziele: `make test`, `make lint`, `make format`, `make check`. ## Konfiguration Alle Einstellungen kommen aus Umgebungsvariablen; `.env.example` enthält die vollständige, kommentierte Liste. Die wichtigsten: | Variable | Standard | Bedeutung | |---|---|---| | `DATABASE_URL` | – | PostgreSQL-DSN, `postgresql://` wird auf asyncpg umgestellt | | `SECRET_KEY` | – | Signaturschlüssel für JWTs, mind. 32 Zeichen (`openssl rand -hex 32`) | | `MONEYFY_ADMIN_USER` / `MONEYFY_ADMIN_PASSWORD` | `admin` / – | Beim Erststart angelegter Benutzer | | `TIMEZONE` | `Europe/Berlin` | Zeitzone der gesamten Anwendung | | `HOLIDAY_REGION` | `DE-NW` | Feiertagsregion für Werktagsverschiebungen | | `LOGO_STORAGE_DIR` | `/data/logos` | Verzeichnis des Logo-Caches | | `LOGODEV_API_KEY` / `BRANDFETCH_API_KEY` | leer | Optionale Logo-Provider, ohne Schlüssel übersprungen | | `SMTP_*` | leer | Mailversand für Benachrichtigungen | | `APPRISE_URLS` | leer | Komma-separierte Apprise-Ziele | | `COOKIE_SECURE` | `true` | Hinter HTTPS `true`, für lokales HTTP `false` | | `SCHEDULER_ENABLED` | `true` | Täglicher Benachrichtigungslauf um 07:00 | ## Logos und Markenfarben Jede Firma bekommt ein Bild. Die Provider-Kette arbeitet der Reihe nach: 1. **simple-icons** – rund 3.500 Marken, im Repository unter `backend/app/assets/simple_icons.json.gz` mitgeliefert. Kein Schlüssel, kein Netzzugriff. Neu erzeugen mit `make vendor-icons`. 2. **logo.dev** – nur mit `LOGODEV_API_KEY`. 3. **Brandfetch** – nur mit `BRANDFETCH_API_KEY` und hinterlegter Domain. 4. **Favicon** – über den Google-Dienst, wenn eine Domain bekannt oder aus dem Namen ableitbar ist. 5. **Generierter Avatar** – Buchstaben-Monogramm mit fester Farbe aus dem Namens-Hash. Schlägt nie fehl. Findet die Kette einen eindeutigen Treffer im lokalen Katalog, unterbleiben die Anfragen nach außen vollständig – die Firmenliste verlässt den Server nicht. Im Auswahldialog (`POST /api/merchants/{id}/logo/search`) läuft dagegen bewusst die ganze Kette, damit Alternativen zur Wahl stehen. Ausgewählte Logos landen unter `LOGO_STORAGE_DIR`, benannt nach ihrem SHA-256-Hash, und werden nur über `GET /api/logos/{id}` ausgeliefert. Beim Seitenaufruf entsteht dadurch kein Zugriff auf fremde Dienste. Ein Upload oder eine bewusste Auswahl setzt den Status auf `manual` und wird von der Automatik nie überschrieben. ## Projektstruktur ``` backend/ FastAPI-Anwendung, Modelle, Services, Alembic-Migrationen, Tests frontend/ React-Oberfläche (Vite) docs/ Betriebs- und Runner-Dokumentation .gitea/ Gitea-Actions-Workflows ``` ## Lizenz [MIT](LICENSE)