From fd8dd74d5f64eee311d2035f4790e88214aa67c1 Mon Sep 17 00:00:00 2001 From: Kevin Adametz Date: Wed, 7 Oct 2026 16:09:25 +0000 Subject: [PATCH] =?UTF-8?q?ops:=20Lokale=20Datenbank=20gegen=20fremde=20Te?= =?UTF-8?q?stl=C3=A4ufe=20absichern=20=E2=80=94=20DB=5F*=20nicht=20mehr=20?= =?UTF-8?q?als=20Container-Umgebung,=20Agenten-Regel,=20Testdatenbank-Pfli?= =?UTF-8?q?cht=20im=20Baukasten?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Am 07.10.2026 hat das RefreshDatabase eines frischen Demo-Projekts (Test der Vorlagen aus dev/git-deploy-monitoring) die lokale Datenbank `pressekonto` auf global-mysql vollständig geleert (Binärlog binlog.000009, Pos. 566161486). Ursache: docker-compose.yml setzte DB_* als Container-Umgebungsvariablen, die in Laravel Vorrang vor jeder .env haben; die phpunit.xml des Demo-Projekts erzwang kein SQLite. Die eigene Suite war nicht beteiligt (force="true" und Guard in tests/TestCase.php greifen; Gegenprobe mit MySQL-Variablen grün). - docker-compose.yml: DB_* entfernt (Werte identisch in .env), wirksam nach Neuerstellen des Containers. - Baukasten: „Testdatenbank absichern" (phpunit.xml mit force, Guard, Gegenprobe) als Pflicht vor RefreshDatabase. - .ai/rules/general.md und CLAUDE.md: fremde/frische Laravel-Projekte nur mit SQLite :memory: testen; migrate hier erst nach migrate:status. Co-Authored-By: Claude Opus 5.5 --- .ai/rules/general.md | 15 +++++++ .ai/rules/index.md | 7 +++ CLAUDE.md | 1 + .../02-fehlerprotokoll-glitchtip.md | 44 +++++++++++++++++++ .../04-checkliste-neues-projekt.md | 8 +++- docker-compose.yml | 15 +++---- 6 files changed, 81 insertions(+), 9 deletions(-) create mode 100644 .ai/rules/general.md create mode 100644 .ai/rules/index.md diff --git a/.ai/rules/general.md b/.ai/rules/general.md new file mode 100644 index 00000000..51b524f8 --- /dev/null +++ b/.ai/rules/general.md @@ -0,0 +1,15 @@ +--- +paths: + - '**/*' +--- + +# General + +## Befehle direkt im Dev-Container ausführen +Die Arbeitsumgebung /var/www/html liegt bereits im DEV-Container. PHP-/Artisan-, Composer- und Node-Befehle dort direkt ausführen (z. B. php artisan test --compact), ohne vendor/bin/sail davor. Eine Sail-Meldung über nicht laufendes Docker ist in diesem Container kein Nachweis, dass Docker auf dem Host gestoppt ist. Diese ausdrückliche Benutzeranweisung ersetzt die allgemeine Sail-Prefix-Vorgabe für diese Umgebung. + +## Fremde oder frische Laravel-Projekte nie gegen die lokale Datenbank testen +Auf `global-mysql` liegen die Datenbanken mehrerer Projekte, und Container-Umgebungsvariablen haben in Laravel Vorrang vor `.env` und nicht erzwungenen `phpunit.xml`-Werten. Ein frisches Laravel-Projekt hat die SQLite-Zeilen in `phpunit.xml` nur auskommentiert — `RefreshDatabase` führt dann `migrate:fresh` auf der Datenbank aus, die die Umgebung vorgibt (07.10.2026: so wurde `pressekonto` vollständig geleert). Deshalb: +- Tests, `migrate`, `migrate:fresh`, `db:wipe` oder Seeder eines anderen bzw. frisch angelegten Laravel-Projekts in diesem Container nur mit `DB_CONNECTION=sqlite DB_DATABASE=:memory: DB_URL=` davor ausführen, z. B. `DB_CONNECTION=sqlite DB_DATABASE=:memory: DB_URL= php artisan test`. +- Vorher prüfen, dass `phpunit.xml` dort SQLite `:memory:` mit `force="true"` setzt (siehe `dev/git-deploy-monitoring/02-fehlerprotokoll-glitchtip.md`, „Testdatenbank absichern“). +- `php artisan migrate` in diesem Projekt erst nach `php artisan migrate:status`: Stehen unerwartet viele Migrationen aus, ist die Datenbank nicht die erwartete — anhalten und nachfragen. diff --git a/.ai/rules/index.md b/.ai/rules/index.md new file mode 100644 index 00000000..f6afe6f7 --- /dev/null +++ b/.ai/rules/index.md @@ -0,0 +1,7 @@ +# Project Rules Index + +Before planning or editing, find the row whose globs match the file's path and read that rule file. + +| Applies to | Rule file | +| --- | --- | +| **/* | .ai/rules/general.md | diff --git a/CLAUDE.md b/CLAUDE.md index c25a5836..be02ff56 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -178,6 +178,7 @@ workflow and the privacy rules for error reporting. Monitoring decisions: - Configuration: `phpunit.xml` and `tests/Pest.php` - Test database: Uses `DB_DATABASE=testing` environment (configured in phpunit.xml) - Test directories: `tests/Feature/` (authentication, dashboard, settings) and `tests/Unit/` +- **Never run tests, migrations or seeders of another or freshly created Laravel project in this container against MySQL.** `global-mysql` holds several projects' databases and container env vars beat `.env`; a fresh project's `RefreshDatabase` wiped `pressekonto` on 07.10.2026. Prefix such runs with `DB_CONNECTION=sqlite DB_DATABASE=:memory: DB_URL=` and check `migrate:status` before `migrate` here (details: `.ai/rules/general.md`). ## Important Files & Configuration diff --git a/dev/git-deploy-monitoring/02-fehlerprotokoll-glitchtip.md b/dev/git-deploy-monitoring/02-fehlerprotokoll-glitchtip.md index 770b3db8..04aa6c2f 100644 --- a/dev/git-deploy-monitoring/02-fehlerprotokoll-glitchtip.md +++ b/dev/git-deploy-monitoring/02-fehlerprotokoll-glitchtip.md @@ -150,6 +150,50 @@ glitchtip“), `ErrorSignalsTest.php`, `BrowserErrorReportingTest.php`, Die Tests setzen `RefreshDatabase` voraus (in `tests/Pest.php` aktivieren) und eine `User`-Factory. +### Testdatenbank absichern (vor `RefreshDatabase`!) + +`RefreshDatabase` führt `migrate:fresh` aus und **löscht alle Tabellen** der +Datenbank, auf die die Tests zeigen. In einer frischen Laravel-Installation +sind die SQLite-Zeilen in `phpunit.xml` auskommentiert, und ohne `force="true"` +haben vorhandene Umgebungsvariablen (Docker-/Container-`environment`, CI) Vorrang +vor `phpunit.xml` und `.env`. So hat am 07.10.2026 das Testen dieser Vorlagen +in einem Demo-Projekt die lokale Datenbank eines anderen Projekts geleert, das +im selben Container lief. + +`phpunit.xml`, im ``-Block: + +```xml + + + + + + +``` + +Guard in `tests/TestCase.php` — `setUpTraits()` läuft vor jedem +Datenbank-Trait und bricht ab, bevor etwas geleert wird (auch bei einem +gecachten `bootstrap/cache/config.php`): + +```php +protected function setUpTraits(): array +{ + $default = (string) \Illuminate\Support\Facades\DB::getDefaultConnection(); + $connection = (array) config('database.connections.'.$default, []); + + if (! empty($connection['url']) + || ($connection['driver'] ?? null) !== 'sqlite' + || ($connection['database'] ?? null) !== ':memory:') { + throw new \RuntimeException("Tests laufen nicht gegen SQLite :memory: ({$default}) — abgebrochen, bevor RefreshDatabase etwas leert."); + } + + return parent::setUpTraits(); +} +``` + +Wer Vorlagen in einem Wegwerf-Projekt ausprobiert, startet die Tests +zusätzlich explizit mit `DB_CONNECTION=sqlite DB_DATABASE=:memory: php artisan test`. + --- ## 6. Regeln für den Code diff --git a/dev/git-deploy-monitoring/04-checkliste-neues-projekt.md b/dev/git-deploy-monitoring/04-checkliste-neues-projekt.md index ebf2ff90..63a87b99 100644 --- a/dev/git-deploy-monitoring/04-checkliste-neues-projekt.md +++ b/dev/git-deploy-monitoring/04-checkliste-neues-projekt.md @@ -32,7 +32,13 @@ Platzhalter: `meineapp` (Projektname), `meineapp.de` (Live-Domain), - [ ] `AppServiceProvider::boot()`: `Queue::failing` → `OperationalAlert`, `AboutCommand::add` - [ ] Vite-Eingang `resources/js/error-reporting.js`; `` in jedem Layout-`` - [ ] Basic Auth / `trustHosts`: `/health` ausgenommen bzw. erreichbar -- [ ] `phpunit.xml`: Sentry-DSNs leer (`force="true"`); `tests/Pest.php` mit `RefreshDatabase` +- [ ] **Vor** `RefreshDatabase`: Testdatenbank absichern (02 §5, „Testdatenbank absichern“): + `phpunit.xml` mit SQLite `:memory:` **und `force="true"`** (`DB_CONNECTION`, `DB_DATABASE`, `DB_URL` leer; + je als `` und ``), dazu der Guard in `tests/TestCase.php`. Eine frische Laravel-Installation + hat diese Zeilen nur auskommentiert — ohne `force` gewinnen vorhandene Umgebungsvariablen. +- [ ] Gegenprobe: `DB_CONNECTION=mysql DB_DATABASE=gibtsnicht php artisan test` muss trotzdem grün laufen + (bzw. der Guard laut abbrechen) — nie eine echte Datenbank leeren +- [ ] `phpunit.xml`: Sentry-DSNs leer (`force="true"`); danach `tests/Pest.php` mit `RefreshDatabase` - [ ] `.env.example` um `vorlagen/env-beispiel.env` ergänzt - [ ] Tests grün: `php artisan test --compact tests/Feature/Monitoring tests/Unit/Monitoring` (30 Tests) - [ ] Datenschutzerklärung: Fehlerprotokollierung (Kategorien, Frist, Rechtsgrundlage) diff --git a/docker-compose.yml b/docker-compose.yml index 8f5641ca..054843aa 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -21,14 +21,13 @@ services: IGNITION_LOCAL_SITES_PATH: '${PWD}' # --- Anbindung an das Mutterschiff --- - DB_CONNECTION: mysql - DB_HOST: global-mysql - DB_PORT: 3306 - # Hier definieren wir nur die Haupt-Datenbank für .env - # Die anderen beiden richtest du in Laravel ein - DB_DATABASE: pressekonto - DB_USERNAME: root - DB_PASSWORD: password + # Die Datenbank-Zugangsdaten (DB_*) stehen bewusst NUR in der .env, + # nicht hier: Container-Umgebungsvariablen haben in Laravel Vorrang + # vor jeder .env. Jedes andere Laravel-Projekt, das in diesem + # Container läuft (z. B. ein frisches Demo-Projekt), würde sonst + # automatisch auf `pressekonto` zeigen — am 07.10.2026 hat so das + # RefreshDatabase eines Demo-Projekts die lokale Datenbank geleert + # (dev/sicherheit/ENTWICKLUNGSPLAN-SICHERHEIT-2026-10-07.md). MAIL_HOST: global-mailpit MAIL_PORT: 1025 REDIS_HOST: global-redis