4.9 KiB
Steuerkram – Entwicklungsregeln
Tech Stack
PHP 8.3+, MySQL, PSR-4 (Namespace Steuerkram\), Composer, kein Framework.
MVC: src/Controllers/, src/Models/, src/Services/, src/Views/.
Coding-Regeln
- Kein
var_dump, keindie()in Produktionscode. - Neue Libraries nur nach expliziter Rückfrage einbinden.
- Bestehenden Code-Stil beibehalten (declare strict_types, 4 Spaces).
- SQL ausschließlich über
Database::fetchAll/fetchOne/execute()mit Prepared Statements.
Tests
Regel: Jedes neue Feature bekommt einen eigenen Test.
Tests liegen in tests/ und folgen dem Namensschema NN_FunktionsnameTest.php.
Jede Testklasse erweitert TestCase und implementiert run().
docker compose exec -u www-data web php tests/run.php # alle Tests ausführen
./scripts/run-tests.sh # Tests + automatische Issue-Erstellung bei Fehlern
./scripts/run-tests.sh 42 # Tests; bei Fehlern Kommentar in Issue #42
Immer -u www-data: ohne die Option laufen die Tests als root und legen
unterhalb von data/ Dateien an, die Apache/PHP später nicht mehr beschreiben
kann – ein echter Beleg-Upload scheitert dann mit HTTP 500.
Neuen Test erstellen
- Datei
tests/NN_MeinFeatureTest.phpanlegen (NN = nächste freie Nummer) - Klasse
MeinFeatureTest extends TestCase protected string $testName = 'Test NN: Beschreibung';- Methode
public function run(): voidmit Assertions implementieren - Transaktions-Isolation ist automatisch (setUp/tearDown in TestCase)
- Dateien und Verzeichnisse immer über
TestCaseanlegen – der Rollback greift nur in der Datenbank, nicht im Dateisystem:
$pfad = $this->tempPath('.csv'); // Pfad in /tmp, wird aufgeräumt
$dir = $this->makeTempDir($basis . '/2026/BLG-...'); // Verzeichnis anlegen + aufräumen
$this->registerTempPath($schonVorhandenerPfad); // nachträglich anmelden
Bleibt trotzdem etwas liegen, meldet tests/run.php das am Ende des Laufs.
Assertion-Methoden
$this->assert(bool, 'Beschreibung');
$this->assertEquals($erwartet, $ist, 'Beschreibung');
$this->assertGreaterThan($min, $wert, 'Beschreibung');
$this->assertNotEmpty($wert, 'Beschreibung');
E2E-Tests (Browser)
Die PHP-Tests erreichen Routing, Views und Formular-JavaScript nicht. Dafür gibt
es Playwright-Tests in tests/e2e/, die im Container des e2e-runner laufen
(auf dem Host wird nichts installiert). Details: tests/e2e/README.md.
docker compose exec web php scripts/e2e-user.php # einmalig: Testnutzer anlegen
tests/e2e/run.sh # alle E2E-Tests
docker compose exec web php scripts/e2e-cleanup.php --force # Reste entfernen
Fehlt Docker, der Runner oder das Image, wird mit Exit 0 übersprungen.
Welche Ebene wofür: Rechen- und Model-Logik gehört in die PHP-Suite (schneller,
isoliert). In tests/e2e/ gehört nur, was einen Browser braucht: Formularabläufe,
Redirects, gerenderte Views, JavaScript-Umrechnungen, DOM-XSS.
Dokumentation aktuell halten
| Datei | Wann aktualisieren |
|---|---|
Changes.md |
Bei jedem Feature, Bugfix oder strukturellen Änderung (nicht bei reinen Test- oder Doku-Commits) |
README.md |
Wenn sich der Funktionsumfang oder der Tech Stack grundlegend ändert |
docs/funktionen.md |
Wenn ein neues Feature hinzukommt oder ein bestehendes wesentlich geändert wird |
docs/berechnungslogik.md |
Bei jeder Änderung an EuerCalculator.php oder UstvaCalculator.php (Zuordnungsregeln, neue Kennzahlen, geänderte Bedingungen) |
docs/anlagevermögen.md |
Bei Änderungen am Anlagevermögens-Workflow oder den Asset-Modellen |
Datenbankmigrationen
Schemaänderungen (neue Spalten, Tabellen, Kontenanpassungen) kommen ausschließlich als nummerierte Migrations-Datei in migrations/:
- Schema:
NNN_kurze_beschreibung.sql(NNN = nächste freie dreistellige Nummer, z.B.011_...) - Migrationen werden nie manuell eingespielt –
scripts/migrate.phperledigt das automatisch beim Container-Start - Jede Migration muss idempotent sein oder mit
IF NOT EXISTS/ON DUPLICATE KEYabgesichert werden
# Nächste freie Nummer ermitteln:
ls migrations/ | tail -1
# Migration manuell testen (ohne Neustart):
docker compose exec web php scripts/migrate.php
Geplante Aufgaben (Cron)
Alle planmäßigen Aufgaben (z.B. Ideenagent, Automatisierungen) laufen lokal über die System-Crontab des Nutzers. Für außerplanmäßige Ausführung das jeweilige Skript direkt aufrufen:
crontab -l # alle geplanten Jobs anzeigen
/home/fds/projects/Steuerkram/.claude/ideenagent-run.sh # Ideenagent manuell starten
/home/fds/projects/Steuerkram/.claude/automate-run.sh # Automatisierung manuell starten
Remote Triggers (claude.ai) oder Claude Code Cron-Jobs werden nicht verwendet.
Commits
Fix #NR: Kurze Beschreibung der Änderung
Keine Co-Authored-By-Zeile. Keine langen Commit-Messages.