# 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`, kein `die()` 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()`. ```bash 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 1. Datei `tests/NN_MeinFeatureTest.php` anlegen (NN = nächste freie Nummer) 2. Klasse `MeinFeatureTest extends TestCase` 3. `protected string $testName = 'Test NN: Beschreibung';` 4. Methode `public function run(): void` mit Assertions implementieren 5. Transaktions-Isolation ist automatisch (setUp/tearDown in TestCase) 6. Dateien und Verzeichnisse **immer** über `TestCase` anlegen – der Rollback greift nur in der Datenbank, nicht im Dateisystem: ```php $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 ```php $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`. ```bash 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.php` erledigt das automatisch beim Container-Start - Jede Migration muss idempotent sein oder mit `IF NOT EXISTS` / `ON DUPLICATE KEY` abgesichert werden ```bash # 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: ```bash 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.