Der Pull nennt Remote und Branch ausdrücklich (origin main, HTTP/1.1), damit kein Tracking-Branch nötig ist. Quelle ist der Fork, solange es nur die Entwicklungsumgebung gibt; für eine spätere Produktion gibt es UPDATE_REMOTE=upstream. Das Skript bricht bei unverändertem Code nicht mehr ab, sodass Migrationen eines von Hand gezogenen Stands nachgeholt werden. Doku (CLAUDE.md, PLAN.md, README.md, Changes.md) angepasst. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
120 lines
4.7 KiB
Markdown
120 lines
4.7 KiB
Markdown
# Finanzmanager – Entwicklungsregeln
|
||
|
||
## Tech Stack
|
||
PHP 8.3+, MariaDB, PSR-4 (Namespace `Finanzmanager\`), Composer, kein Framework.
|
||
MVC: `src/Controllers/`, `src/Models/`, `src/Services/`, `src/Views/`.
|
||
Webserver: **nginx + php-fpm**, alles in Docker Compose.
|
||
|
||
## Betriebsregeln
|
||
|
||
- **Keine lokale Installation ohne Rückfrage.** Kein PHP, kein Composer, kein MariaDB
|
||
auf dem Host – alles läuft in Containern.
|
||
- Lokal erreichbar unter **http://localhost:8000**.
|
||
- Es gibt derzeit **nur die Entwicklungsumgebung**, keinen getrennten Produktionsserver.
|
||
`scripts/update.sh` zieht deshalb aus dem **Fork** (`origin`, Branch `main`); der
|
||
Upstream dient als Backup und zur Veröffentlichung. Kommt später eine isolierte
|
||
Produktion (kein Zugriff von außen, kein Zugriff durch Claude Code), zieht sie aus dem
|
||
Upstream: `UPDATE_REMOTE=upstream ./scripts/update.sh`.
|
||
|
||
```bash
|
||
docker compose up -d # starten
|
||
docker compose exec -u www-data php php tests/run.php # Tests
|
||
./scripts/run-tests.sh # dasselbe, kürzer
|
||
./scripts/update.sh # Update aus dem Fork
|
||
./scripts/backup.sh # Backup mit Rotation
|
||
```
|
||
|
||
## Coding-Regeln
|
||
|
||
- Kein `var_dump`, kein `die()` in Produktionscode.
|
||
- **Neue Libraries nur nach expliziter Rückfrage.** Wenn eine Bibliothek wirklich
|
||
Arbeit spart, wird sie auf Codeberg geforkt und über ein VCS-Repository eingebunden –
|
||
keine Abhängigkeit von fremden Update-Zyklen.
|
||
- `declare(strict_types=1)`, 4 Leerzeichen Einrückung.
|
||
- SQL ausschließlich über `Database::fetchAll/fetchOne/fetchValue/execute()` mit
|
||
Prepared Statements.
|
||
- Bezeichner und Oberflächentexte auf Deutsch.
|
||
|
||
## Begrifflichkeiten – nicht abweichen
|
||
|
||
Die Partnerin nutzt weiterhin den Lexware FinanzManager. Alle fachlichen Begriffe
|
||
bleiben deshalb identisch:
|
||
|
||
Kategorie · Klasse · Splitbuchung · Umbuchung · Kontengruppe · Kontoblatt ·
|
||
Budgetplaner · Monatsabschluss · Auswertung · Buchungsvorlage · Regelmäßige Buchung ·
|
||
Zahlungsverkehr · Cockpit · Kontenübersicht · Umbuchungskonto
|
||
|
||
Keine eigenen Wortschöpfungen, keine englischen Entsprechungen.
|
||
|
||
## Tests
|
||
|
||
**Regel: Jedes neue Feature bekommt einen eigenen Test.**
|
||
|
||
Tests liegen in `tests/` nach dem Schema `NN_NameTest.php`, jede Klasse erweitert
|
||
`TestCase` und implementiert `run()`. Transaktions-Isolation ist automatisch.
|
||
|
||
```php
|
||
$this->assert(bool, 'Beschreibung');
|
||
$this->assertEquals($erwartet, $ist, 'Beschreibung');
|
||
$this->assertNotEmpty($wert, 'Beschreibung');
|
||
$this->assertNull($wert, 'Beschreibung');
|
||
$this->assertGreaterThan($minimum, $wert, 'Beschreibung');
|
||
```
|
||
|
||
Dateien und Verzeichnisse immer über `$this->tempPfad()` bzw.
|
||
`$this->registriereTempPfad()` anlegen – der Rollback greift nur in der Datenbank.
|
||
|
||
**Immer `-u www-data`:** sonst laufen die Tests als root und legen unter `data/`
|
||
Dateien an, die php-fpm später nicht mehr beschreiben kann.
|
||
|
||
### E2E-Tests
|
||
|
||
Browser-Abläufe gehören nach `tests/e2e/` (Playwright über das Projekt `e2e-runner`,
|
||
läuft im Container – auf dem Host wird nichts installiert). Rechen- und Model-Logik
|
||
gehört in die PHP-Suite: schneller und isoliert.
|
||
|
||
```bash
|
||
tests/e2e/run.sh
|
||
```
|
||
|
||
## Datenbankmigrationen
|
||
|
||
Schemaänderungen kommen **ausschließlich** als nummerierte Datei nach `migrations/`:
|
||
|
||
- `NNN_kurze_beschreibung.sql` (nächste freie dreistellige Nummer)
|
||
- Nie manuell einspielen – `scripts/migrate.php` erledigt das beim Containerstart
|
||
- Jede Migration idempotent (`IF NOT EXISTS`, `ON DUPLICATE KEY`)
|
||
|
||
```bash
|
||
ls migrations/ | tail -1 # nächste freie Nummer
|
||
docker compose exec php php scripts/migrate.php # manuell testen
|
||
```
|
||
|
||
## Diagnose
|
||
|
||
Das Debug-Log wird im Einstellungsdialog unter *Diagnose* eingeschaltet (oder über
|
||
`DEBUG_LOG=1`). Es schreibt nach `data/logs/debug-JJJJ-MM-TT.log` und maskiert PINs,
|
||
Passwörter, TANs und API-Keys. Im Normalbetrieb ausgeschaltet lassen.
|
||
|
||
Neue Einstellungen gehören in den **zentralen Einstellungsdialog** (ein Reiter je
|
||
Bereich aus `Einstellung::BEREICHE`), nicht in eigene Dialoge.
|
||
|
||
## Dokumentation aktuell halten
|
||
|
||
| Datei | Wann aktualisieren |
|
||
|---|---|
|
||
| `Changes.md` | Bei jedem Feature, Bugfix oder strukturellen Änderung |
|
||
| `PLAN.md` | Wenn sich Phasenzuschnitt oder Grundentscheidungen ändern |
|
||
| `README.md` | Bei Änderungen an Funktionsumfang oder Tech Stack |
|
||
| `docs/` | Wenn ein Modul hinzukommt oder sich wesentlich ändert |
|
||
|
||
## Git
|
||
|
||
Codeberg, nicht GitHub. Upstream = persönlicher Account, Fork = BOT-Account
|
||
(`CODEBERG_BOT_TOKEN`). Keine Feature-Branches, direkt auf `main` im Fork.
|
||
Ein Feature = ein PR. **Vor jedem Commit prüfen, ob upstream noch ein offener PR
|
||
vom Fork existiert** – sonst vermischen sich Features.
|
||
|
||
```
|
||
Fix #NR: Kurze Beschreibung der Änderung
|
||
```
|