phase 2 dev
This commit is contained in:
parent
5a7478907e
commit
ba48745809
59 changed files with 2692 additions and 1994 deletions
|
|
@ -1,8 +1,10 @@
|
|||
# Umsetzung: Neustrukturierung Customer / Lead / Booking
|
||||
|
||||
**Status:** Phase 1 auf Testsystem abgeschlossen — Contacts-Modul live; **Phase-2-App-Code vorbereitet (deploy-bereit)**
|
||||
**Status:** Phase 1 auf **Live** abgeschlossen (2026-04-17); Phase 2 auf **Test** erfolgreich migriert und verifiziert — bereit für Live-Deploy.
|
||||
**Erstellt:** April 2025
|
||||
**Konzept:** [konzept.md](konzept.md)
|
||||
**Letzte Aktualisierung:** 2026-04-17
|
||||
**Konzept:** [konzept.md](konzept.md)
|
||||
**Deploy-Handbücher:** [phase-1-live-deploy.md](phase-1-live-deploy.md) · [phase-2-live-deploy.md](phase-2-live-deploy.md)
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -10,12 +12,70 @@
|
|||
|
||||
| Phase | Status | Deployed auf Test? | Deployed auf Live? |
|
||||
|-------|--------|-------------------|-------------------|
|
||||
| Phase 1 — Contact-Deduplizierung | ✅ Abgeschlossen | ✅ Ja | ⬜ Nein |
|
||||
| Phase 1 — Contacts-Modul (neuer Code) | ✅ Abgeschlossen | ✅ Ja | ⬜ Nein |
|
||||
| Phase 2 — App-Code (Models/Repos/Controller/Views auf `contacts`/`inquiries`/`inquiry_id`) | ✅ Abgeschlossen | ⬜ Nein | ⬜ Nein |
|
||||
| Phase 2 — Tabellen-Migrationen (3 Migrationsdateien) | ⬜ Ausstehend (Code ist deploy-ready) | ⬜ Nein | ⬜ Nein |
|
||||
| Phase 3 — Participants konsolidieren | ⬜ Ausstehend | ⬜ Nein | ⬜ Nein |
|
||||
| Phase 4 — Communications / Notices / Attachments | ⬜ Ausstehend | ⬜ Nein | ⬜ Nein |
|
||||
| Phase 1 — Contact-Deduplizierung | ✅ Abgeschlossen | ✅ Ja | ✅ **2026-04-17** |
|
||||
| Phase 1 — Contacts-Modul (neuer Code) | ✅ Abgeschlossen | ✅ Ja | ✅ **2026-04-17** |
|
||||
| Phase 2 — App-Code (Models/Repos/Controller/Views auf `contacts`/`inquiries`/`inquiry_id`) | ✅ Abgeschlossen | ✅ Ja | ⬜ Nein (Deploy-Handbuch fertig) |
|
||||
| Phase 2 — Tabellen-Migrationen (3 Migrationsdateien) | ✅ Abgeschlossen | ✅ **Ja, Batch 27–29** | ⬜ Nein (Deploy-Handbuch fertig) |
|
||||
| Phase 2 — Smoke-Test-Fixes 2026-04-17 (`Lead::bookings()` FK; `orderColumn`-SQL in 4 Controllern; Blade-Column-`name:` in `contact/index.blade.php`) | ✅ Abgeschlossen | ✅ Ja | ⬜ Nein (in Phase-2-Deploy gebündelt) |
|
||||
| Phase-1-Hotfix — nullable Parameter (`?int $mailDirId`, `?string $subdir`) in 3 Service-Klassen (Mail-Dialoge mit NULL-Werten) | ✅ Abgeschlossen | ✅ Ja | ⬜ Nein (in Phase-2-Deploy gebündelt, siehe Handbuch) |
|
||||
| Phase 3 — Participants konsolidieren | ⬜ Ausstehend (Migrationen geschrieben, Code noch nicht) | ⬜ Nein | ⬜ Nein |
|
||||
| Phase 4 — Communications / Notices / Attachments | ⬜ Ausstehend (Migrationen geschrieben, Code noch nicht) | ⬜ Nein | ⬜ Nein |
|
||||
|
||||
### Verifikation Phase 2 auf Test (2026-04-17)
|
||||
|
||||
Smoke-Queries nach erfolgter Migration:
|
||||
|
||||
```
|
||||
Tabellen:
|
||||
customer NOT FOUND ← umbenannt ✓
|
||||
contacts EXISTS ← neu ✓
|
||||
lead NOT FOUND ← umbenannt ✓
|
||||
inquiries EXISTS ← neu ✓
|
||||
booking EXISTS ✓
|
||||
|
||||
booking-Spalten:
|
||||
lead_id NOT FOUND ← umbenannt ✓
|
||||
inquiry_id EXISTS ← neu ✓
|
||||
|
||||
Eloquent-Queries:
|
||||
Contact::count() = 19.156 (ohne merged)
|
||||
Customer::count() = 22.283 (alle, inkl. merged — Legacy-Model)
|
||||
Lead::count() = 19.543
|
||||
Booking::count() = 10.648
|
||||
Booking->inquiry_id funktioniert
|
||||
Booking->lead() Relation mit expl. FK inquiry_id funktioniert
|
||||
```
|
||||
|
||||
### Smoke-Test-Findings 2026-04-17 (Test-Durchlauf nach Phase-2-Restore)
|
||||
|
||||
Während der UI-Smoke-Tests auf `mein.sterntours.test` traten drei unterschiedliche Bug-Klassen auf, alle auf Test gefixt und in die Phase-2-Deploy-Liste aufgenommen.
|
||||
|
||||
**1. Eloquent-Relation ohne expliziten FK — `Lead::bookings()`**
|
||||
- Fehler: `/leads` → `Column not found: 'booking.lead_id'`.
|
||||
- Ursache: `$this->hasMany(Booking::class)` ohne 2. Argument ⇒ Laravel leitet den FK aus dem Model-Namen ab (`Lead` → `lead_id`), der nach dem Rename nicht mehr existiert.
|
||||
- Fix: `app/Models/Lead.php` Zeile 249–253: `$this->hasMany(Booking::class, 'inquiry_id')`.
|
||||
|
||||
**2. Hartcodierte Tabellenqualifier in `orderColumn`-SQL-Strings + Blade-Column-`name:`**
|
||||
- Fehler A: `/contacts` → `Column not found: 'customer.id' in 'order clause'`. Behoben durch SQL-Umstellung im Controller — blieb aber bestehen, weil Yajra bei fehlendem `orderColumn`-Match den `name:`-String aus der Blade-Column-Definition als raw SQL verwendet.
|
||||
- Fehler B (gleiche Ursache, 2. Runde): `/contacts` → derselbe Fehler trotz Controller-Fix. Root Cause: In `resources/views/contact/index.blade.php` Zeile 188 stand `name: 'customer.id'`. Yajra matched `orderColumn()` auf diesen `name:`-String — mein erster Fix mit `orderColumn('id', …)` hat also nicht getroffen.
|
||||
- Ursache zusammengefasst: Yajra-DataTables-`orderColumn()` bekommt als 2. Argument eine Raw-SQL-Expression; **und** der `name:`-Wert einer DataTable-Column muss exakt zum 1. Argument von `orderColumn()` / `filterColumn()` passen — sonst fällt Yajra zurück auf "Name wörtlich als SQL einsetzen".
|
||||
- Fix in 5 Dateien:
|
||||
- `app/Http/Controllers/ContactController.php` — `orderColumn('contacts.id' / 'deleted_at', …)`, `filterColumn('contacts.id', …)`
|
||||
- `resources/views/contact/index.blade.php` — Column-Name `customer.id` → `contacts.id`
|
||||
- `app/Http/Controllers/Admin/ReportController.php` — 2 Blöcke (`customer.firstname $1` → `contacts.firstname $1` etc.)
|
||||
- `app/Http/Controllers/Admin/ReportBookingController.php` — 2 Blöcke
|
||||
- `app/Http/Controllers/Admin/ReportLeadsController.php` — `$orderByNum`-Array
|
||||
- Bewusst nicht angefasst: die 1. Argumente von `addColumn` / `rawColumns` (`customer.fullName`, `lead.status_id`) — das sind reine DataTables-Frontend-Identifier, die Yajra über den Eloquent-Relation-Mechanismus auflöst (Model `Customer`/`Lead` → `$table = 'contacts'`/`'inquiries'`), und die 3-teiligen `booking.customer.firstname`-Strings in `ReportController.php` und `ReportProviderController.php` (Yajra-Relation-Notation bzw. seit jeher kein gültiges SQL, durch Phase 2 nicht schlimmer).
|
||||
|
||||
**3. Strict-Type-Regression aus Phase 1 (Laravel-10/PHP-8) — zwei Varianten**
|
||||
- Fehler A: `App\Services\Booking::getCustomerMailName(): Argument #2 ($mailDirId) must be of type int, null given` in `modal-show-mail-inner.blade.php` Zeile 92.
|
||||
- Fehler B: `App\Services\Booking::setOutputDirs(): Argument #2 ($subdir) must be of type string, null given` in derselben kompilierten View, Zeile 101.
|
||||
- Ursache: Blade-Views übergeben `$mail_dir_id` bzw. `$mail_sdir_id` direkt aus DB-Feldern, die nullable sein können (Entwurfs-Mails, Top-Level-Ordner, Mails ohne Subdir). Unter Laravel 8 / PHP 7 wurde `null` stillschweigend zu `0` / `""` gecastet; PHP 8 strict types verweigern das.
|
||||
- Fix in drei Dateien:
|
||||
- `app/Services/Booking.php` — `getCustomerMailName()`, `getCustomerMailEmails()`: `int $mailDirId` → `?int`; `setOutputDirs()`: `string $subdir` → `?string`.
|
||||
- `app/Services/Lead.php` — identische Änderungen (symmetrische API).
|
||||
- `app/Services/MailDirService.php` — `getCustomerMailName()`, `getCustomerMailEmails()`, `resolveModel()` auf `?int`; `setOutputDir()` auf `?string`; in `resolveModel()` zusätzlich ein früher `return null`-Guard.
|
||||
- Das ist **fachlich ein Phase-1-Bug**, der nichts mit Customer→Contacts zu tun hat. Wir deployen ihn trotzdem zusammen mit Phase 2, weil die Services keine DB-Abhängigkeit haben und ein separates Wartungsfenster unnötig wäre.
|
||||
|
||||
### Was in Phase 1 umgesetzt wurde
|
||||
|
||||
|
|
@ -178,33 +238,46 @@ php artisan migrate:rollback --path=database/migrations/2025_04_15_100001_phase1
|
|||
- Routen-Namen (`lead_detail`, `lead_index`) — bleiben als Aliase, um Links in Views/Mails/Logs nicht zu brechen.
|
||||
|
||||
### Schritt 1: Migrationen einspielen
|
||||
|
||||
**Auf Test (2026-04-17 erfolgreich durchgeführt, Batch 27–29):**
|
||||
```bash
|
||||
# Backup erstellen!
|
||||
php artisan migrate --path=database/migrations/2025_04_15_200001_phase2_rename_customer_to_contacts.php
|
||||
php artisan migrate --path=database/migrations/2025_04_15_200002_phase2_rename_lead_to_inquiries.php
|
||||
php artisan migrate --path=database/migrations/2025_04_15_200003_phase2_rename_booking_lead_id_to_inquiry_id.php
|
||||
php artisan migrate --path=database/migrations/2025_04_15_200001_phase2_rename_customer_to_contacts.php --force
|
||||
php artisan migrate --path=database/migrations/2025_04_15_200002_phase2_rename_lead_to_inquiries.php --force
|
||||
php artisan migrate --path=database/migrations/2025_04_15_200003_phase2_rename_booking_lead_id_to_inquiry_id.php --force
|
||||
```
|
||||
|
||||
> **Wichtig — `--path` verwenden!** Ohne `--path` würde `php artisan migrate` auch die noch im Workspace liegenden Phase-3-, Phase-4- und Offers-Migrationen ausführen, die noch nicht deployreif sind. Einzeln per `--path` hält den Deploy auf exakt diese drei Dateien beschränkt.
|
||||
|
||||
**Auf Live:** Ablauf siehe [phase-2-live-deploy.md](phase-2-live-deploy.md). Der Live-Deploy muss innerhalb eines Wartungsfensters passieren, weil DB und Code atomar zusammengehen müssen.
|
||||
|
||||
### Ergebnis-Prüfung
|
||||
```sql
|
||||
-- Tabellen vorhanden?
|
||||
SHOW TABLES LIKE 'contacts';
|
||||
SHOW TABLES LIKE 'inquiries';
|
||||
-- Spalte umbenannt?
|
||||
SHOW COLUMNS FROM booking LIKE 'inquiry_id';
|
||||
-- FK vorhanden?
|
||||
SELECT * FROM information_schema.KEY_COLUMN_USAGE
|
||||
WHERE TABLE_NAME = 'booking' AND COLUMN_NAME = 'inquiry_id';
|
||||
```
|
||||
|
||||
Oder via Laravel-Tinker:
|
||||
```bash
|
||||
php artisan tinker --execute="
|
||||
echo Schema::hasTable('contacts') ? 'contacts OK' : 'contacts FEHLT'; echo PHP_EOL;
|
||||
echo Schema::hasTable('inquiries') ? 'inquiries OK' : 'inquiries FEHLT'; echo PHP_EOL;
|
||||
echo Schema::hasColumn('booking', 'inquiry_id') ? 'booking.inquiry_id OK' : 'FEHLT'; echo PHP_EOL;
|
||||
"
|
||||
```
|
||||
|
||||
### Rollback Phase 2
|
||||
```bash
|
||||
# In umgekehrter Reihenfolge
|
||||
php artisan migrate:rollback --path=database/migrations/2025_04_15_200003_phase2_rename_booking_lead_id_to_inquiry_id.php
|
||||
php artisan migrate:rollback --path=database/migrations/2025_04_15_200002_phase2_rename_lead_to_inquiries.php
|
||||
php artisan migrate:rollback --path=database/migrations/2025_04_15_200001_phase2_rename_customer_to_contacts.php
|
||||
php artisan migrate:rollback --path=database/migrations/2025_04_15_200003_phase2_rename_booking_lead_id_to_inquiry_id.php --force
|
||||
php artisan migrate:rollback --path=database/migrations/2025_04_15_200002_phase2_rename_lead_to_inquiries.php --force
|
||||
php artisan migrate:rollback --path=database/migrations/2025_04_15_200001_phase2_rename_customer_to_contacts.php --force
|
||||
```
|
||||
|
||||
> **Wichtig:** Rollback MUSS zusammen mit Code-Revert passieren (Code erwartet sonst die falschen Tabellennamen). Details im [phase-2-live-deploy.md](phase-2-live-deploy.md#rollback-plan-falls-phase-2-auf-live-scheitert).
|
||||
|
||||
---
|
||||
|
||||
## Phase 3 — Participants konsolidieren
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue