Files
moneyfy/README.md
T
moneyfyandClaude Opus 5 0adf154049 feat(reports): Auswertungen, Kalender, Budgets und Export
Backend:
- Gemeinsame Bewegungsschicht flows(), auf der alle Berichte aufbauen; Plan und
  Ist bleiben dabei getrennt
- Forecast, Kategorien mit Drilldown, Abo-Übersicht, Jahresvergleich,
  Cashflow-Kalender, Budget-Ampel, Sparziel-Fortschritt, gebündeltes Dashboard
- Budgetübertrag über Monatsgrenzen, Budgets auf Oberkategorien schließen
  Unterkategorien ein
- Export als CSV (BOM, Semikolon, deutsches Dezimaltrennzeichen) und XLSX mit
  typisierten Beträgen

Frontend:
- Dashboard, Cashflow-Kalender mit Bestätigen direkt am Tag, Budget-, Sparziel-
  und Auswertungsseite
- Diagrammpalette gegen beide Flächen auf Kontrast und Farbfehlsichtigkeit
  geprüft; Grün/Rot als Serienpaar verworfen
- Einnahmen/Ausgaben und kumulierter Saldo in getrennten Diagrammen statt auf
  zwei Größenachsen
- Recharts in einen eigenen Chunk ausgelagert

27 neue Backend-Tests (235 gesamt), 16 neue Frontend-Tests (65 gesamt)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014e7t8UpmoVNMtWivY5LiSH
2026-09-09 16:50:22 +02:00

136 lines
5.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
```
In einem zweiten Terminal das Frontend, es leitet `/api` an das Backend weiter:
```bash
make fe-install
make fe-dev # http://localhost:5173
```
Nützliche Ziele: `make check` (alle Prüfungen), `make test`, `make lint`,
`make format`, `make fe-lint`, `make fe-test`, `make fe-build`.
## 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 |
## Diagramme
Die Serienfarben stammen aus einer Palette, die gegen die hellen und dunklen
Flächen der Anwendung auf Kontrast und Farbfehlsichtigkeit geprüft wurde; ihre
Reihenfolge ist Teil dieser Absicherung. Grün und Rot bleiben den Vorzeichen im
Text vorbehalten als Serienpaar wären sie bei Deuteranopie nicht zu
unterscheiden. Jedes Diagramm mit mehr als einer Serie führt eine Legende, und
zu den Balkendiagrammen lässt sich die Wertetabelle aufklappen.
Einnahmen, Ausgaben und der kumulierte Kontostand stehen bewusst in zwei
getrennten Diagrammen untereinander: eine gemeinsame Größenachse würde bei so
verschiedenen Größenordnungen einen Zusammenhang vortäuschen.
## 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)