# 01 – Legacy-Analyse Detailliertes Inventar des Symfony-1.4-Backends in `/_businessportal24.com/`. Das `presseecho`-Projekt ist code-identisch. --- ## 1. Projektstruktur (Top-Level) ``` _businessportal24.com/ ├── apps/ │ ├── backend/ ← Admin-App (Routing, Config, Templates). Modules liegen in Plugins. │ └── frontend/ ← Public/Frontend-App (wird NICHT migriert – neue Frontends existieren) ├── config/ ← Globale Config (Datenbanken, Projekt, i18n) ├── lib/ ← Global genutzte Klassen (Models liegen aber in Plugin) ├── plugins/ ← Fachliche Logik – der Hauptteil! │ ├── PressePortalPlugin ★ Kern-Plugin (Entities, Modules, Forms) │ ├── sfDoctrineGuardPlugin ← Auth │ ├── sfDoctrineGuardPaymentPlugin ★ Payment, Invoice, Coupon │ ├── sfDoctrineApplyPlugin ← Registrierung │ ├── sfFormExtraPlugin ← Form-Widgets │ ├── sfImageTransformPlugin ← Image-Thumbnailing │ ├── sfImageTransformExtraPlugin │ ├── sfCaptchaGDPlugin ← Captcha │ ├── sfCsvPlugin ← CSV-Export │ ├── isicsWidgetFormTinyMCEPlugin← WYSIWYG │ ├── tnHttpErrorPlugin ← HTTP-Error-Handling │ └── tnStrategicTesterResponsePlugin ├── symfony-1.4/ ← Framework (Vendor) ├── data/ ← Fixtures ├── web/ ← DocRoot, Public Assets └── cron_script_{local,server}.sh ``` --- ## 2. Admin-Module (`PressePortalPlugin/modules/`) ### 2.1 Verwaltung / CRUD | Modul | Entität | Admin-URL | Migrations-Target | |---|---|---|---| | `adminCenter` | Dashboard / Navigationshub | `/` | Livewire `admin.dashboard` (existiert) | | `adminSfGuardAuth` | Login/Logout | `/login`, `/logout` | Fortify (existiert) | | `adminSfGuardUser` (über Routing) | User | `/sf_guard_user` | `admin.users.*` (existiert) | | `adminSfGuardGroup` | Rollen | `/sf_guard_group` | Spatie Roles → `admin.roles.*` (existiert) | | `adminSfGuardPermission` | Permissions | `/sf_guard_permission` | Spatie Permissions | | `adminSalutation` | Anreden | `/salutation` | → Config (`config/salutations.php`) | | `adminCountry` | Länder | `/country` | → Config (`config/countries.php`) | | `adminCategory` | Kategorien (i18n) | `/category` | `admin.categories.*` (existiert) | | `adminCompany` | Firmen/Agenturen | `/company` | `admin.companies.*` (existiert) | | `adminContact` | Ansprechpartner | `/contact` | `admin.contacts.*` (existiert) | | `adminPressrelease` | Pressemitteilungen | `/pressrelease` | `admin.press-releases.*` (existiert) | | `adminPressreleaseimage` | Bilder zu PMs | `/pressreleaseimage` | Teil von PressRelease | | `adminPromotionlink` | Werbeplätze/Links | `/promotionlink` | **Scope-Entscheidung nötig** | | `adminFootercode` | Custom Footer-HTML | `/footercode` | **Scope-Entscheidung nötig** | | `adminBlacklist` | Wort-Blacklist | `/blacklist` | `admin.blacklist.*` (neu) | | `adminNewslettersubscription` | Newsletter-Subscriber | `/newslettersubscription` | `admin.newsletter.subscribers` (existiert) | | `sfpCouponAdmin` | Gutscheine | `/coupon` | `admin.coupons.*` (existiert) | | `sfpInvoiceAdmin` | Rechnungen | `/invoice` | `admin.invoices.*` (existiert) | | `sfpInvoiceBillingAddressAdmin` | Rechn.-Adressen | `/invoice_billing_address` | Teil von Invoice | | `sfpUserBillingAddressAdmin` | User-Rechn.-Adressen | `/user_billing_address` | Teil von User | | `sfpUserPaymentOptionAdmin` | User-Abos/Payment | `/user_payment_option` | `admin.payments.*` (existiert) | ### 2.2 Service-/System-Module | Modul | Zweck | Migrations-Target | |---|---|---| | `sfpCron` | HTTP-Trigger für Cron-Scripts | Laravel Scheduler (`routes/console.php`) | | `sfpStore` | Abo-/Bestell-Flow | Stripe Checkout + Domain-Service | | `sfpInvoicePdf` | PDF-Generation | `barryvdh/laravel-dompdf` + Blade-Template | | `sfpUserBilling` | User-seitige Rechn.-Übersicht | Frontend-/Kundencenter-Views | | `import` | CSV-/Daten-Import | **Neu als `php artisan` Command(s)** | | `ajax` | Autocompletion für Admin-Forms | Livewire `wire:model`-Suche | | `tnHttpError` | Error-Views | Laravel's Standard-Error-Pages | ### 2.3 Frontend-Module (werden NICHT migriert) | Modul | Zweck | |---|---| | `company`, `customercenter`, `page`, `pressrelease`, `pressreleaseimage`, `category`, `profile`, `newsletter`, `presscontact`, `sfApply`, `sfGuardAuth`, `sfGuardUser` | Altes Symfony-Frontend. Wird ersetzt durch bestehendes `resources/views/web/*` und das neue Backend-API | --- ## 3. Datenmodell (aus `PressePortalPlugin/config/doctrine/schema.yml`) ### 3.1 Entitäten (Kern) | Doctrine-Entität | Zeilen in Schema | Fachlicher Zweck | |---|---|---| | `Salutation` | 4–18 | Anrede (Herr/Frau, i18n) | | `Country` | 23–32 | Länder | | `sfGuardUser` | 38–84 | User | | `sfGuardUserProfile` | 92–191 | User-Profil (Name, Adresse, Tel, E-Mail, API-Key, Tax-ID …) | | `Company` | 197–278 | Firma (inkl. Logo, Login, Footer-Code-Disable) | | `Agency` | 280–297 | Column-Aggregation-Inheritance von Company (ctype='agency') | | `CompanyUser` | 300–318 | User ↔ Company Pivot | | `ApiUser` | 321–339 | API-Only User-Markierung | | `ResponsibleCompanyUser` | 342–360 | Verantwortliche User pro Company | | `Contact` | 365–411 | Ansprechpartner einer Firma | | `NewsletterSubscription` | 418–469 | Newsletter-Anmeldungen | | `Category` | 476–494 | Kategorien (i18n, sluggable) | | `PressRelease` | 500–575 | Pressemitteilungen (mit Teaser-Range, Status, SEO) | | `PressReleaseContact` | 583–601 | PM ↔ Contact Pivot | | `PressReleaseImage` | 608–644 | Bilder zu PMs | | `PromotionLink` | 650–684 | Werbelinks | | `PromotionLinkCategory` | 687–705 | PromotionLink ↔ Category Pivot | | `FooterCode` | 707–733 | Custom Footer-HTML pro Kategorie/Sprache | | `CategoryFooterCode` | 735–753 | Pivot | | `Blacklist` | 755–768 | Worte für Spam-Check | | `UserBillingAddress` | 771–807 | Rechn.-Adresse am User | | `InvoiceBillingAddress` | 809–841 | Rechn.-Adresse auf Rechnung (Snapshot) | | `UserPaymentOptionCompany` | 854–874 | Abo ↔ Firma | ### 3.2 Entitäten aus `sfDoctrineGuardPaymentPlugin` | Entität | Zweck | |---|---| | `PaymentOption` | Produkt-Definition (Preis, Typ: recurring/onetime/single) | | `PaymentOptionReference` | Self-referencing, Parent→Child (z. B. Aufpreispakete) | | `PaymentOptionExcludeGroup` | Gruppen, die Option NICHT buchen dürfen | | `PaymentOptionAccessGroup` | Gruppen, die durch Option Zugriff erhalten | | `UserPaymentOption` | Gebuchtes Abo (User ↔ Produkt), Status, Laufzeit | | `UserPaymentOptionReference` | Self-referencing | | `UserPayment` | Zahlungsdatensatz | | `Invoice` | Rechnung (mit Mahnungen, Fälligkeit) | | `UserBillingAddress` | (hier nochmal definiert) | | `InvoiceBillingAddress` | (hier nochmal definiert) | | `Coupon` | Gutschein | ### 3.3 sfGuard-Tabellen `sfGuardUser`, `sfGuardGroup`, `sfGuardPermission`, `sfGuardUserGroup`, `sfGuardGroupPermission`, `sfGuardUserPermission`, `sfGuardRememberKey` → Mapping auf Laravel `users` + Spatie `roles`/`permissions`/`model_has_*`. ### 3.4 Besondere Doctrine-Features | Feature | Verwendung | Laravel-Äquivalent | |---|---|---| | `actAs: Timestampable` | auf fast allen Entitäten | `created_at`/`updated_at` (Standard) | | `actAs: I18n` | `Salutation`, `Category`, `PaymentOption` | Translation-Tabellen oder `spatie/laravel-translatable` | | `actAs: Sluggable` | `Company`, `Category`, `PressRelease`, `PressReleaseImage` | `spatie/laravel-sluggable` | | `inheritance: column_aggregation` | `Agency extends Company` | Entweder gemeinsames Model mit `type`-Scope, oder Parent+Child-Model mit globalem Scope | | `relations refClass` | viele M:N | Pivot-Tabellen, `belongsToMany` | --- ## 4. Routing (`apps/backend/config/routing.yml`) Auszug – **15 `sfDoctrineRouteCollection`** (auto-generated REST für alle CRUD-Entitäten) + folgende Custom-Routes: | Route | URL | Ziel | |---|---|---| | `homepage` | `/` | `adminCenter::index` | | `change` | `/mychange` | `adminCenter::change` | | `sf_guard_signin` | `/login` | Login | | `sf_guard_signout` | `/logout` | Logout | | `sf_guard_password` | `/request_password` | Password-Reset | | `usercp` | `/usercp` | User-CP | | `masterdata` | `/masterdata` | Stammdaten | | `portalcp` | `/portalcp` | Portal-CP | | `promotioncp` | `/promotioncp` | Promotion | | `pressrelease_company_autocomplete` | `/pressrelease/companyautocomplete` | AJAX | | `company_user_autocomplete` | `/company/userautocomplete` | AJAX | | `press_release_autocomplete_url` | `/ajax/press_release_autocomplete` | AJAX | | `sf_image` | `/thumbnails/sf_image/:format/:filepath.:sf_format` | Thumbnails | | `slug_image` | `/thumbnails/:type/:format/:path/:slug-:id.:sf_format` | Thumbnails (Slug) | → Abbildung auf `routes/admin.php` (bereits zu 80 % vorhanden) + ein paar Livewire-Aktionen. --- ## 5. Admin-Menü (`config/adminMenu/hnav.yml`) ``` Home ├─ Master data │ ├─ Countries │ ├─ Salutations │ └─ Blacklists ├─ User CP │ ├─ Users │ ├─ Groups │ ├─ Permissions │ └─ Newsletter subscription ├─ Billing │ ├─ Payment options │ ├─ Coupons │ └─ Invoices ├─ Portal CP │ ├─ Press releases │ ├─ Press release images │ ├─ Categories │ ├─ Companies │ └─ Contacts └─ Promotions ├─ Promotion links └─ Footer code ``` → Diese Struktur ist im neuen Laravel-Projekt bereits in der `sidebar.blade.php`-Navigation abgebildet. --- ## 6. Cron-Scripts (`cron_script_server.sh`) ```bash php symfony sfp:user-payment-create --application=frontend php symfony sfp:invoice-create --application=frontend --culture=de php symfony sfp:invoice-reminder --application=frontend --culture=de # php symfony sfp:user-paymentoption-expire --application=frontend (deaktiviert) ``` Dazu `sfpCron::index` (HTTP-getriggert, sehr unsicher: Shared-Secret als URL-Parameter). **Ziel-Mapping:** | Legacy-Task | Neu | |---|---| | `sfp:user-payment-create` | Job `CreateRecurringPayments` (daily) | | `sfp:invoice-create` | Job `GenerateInvoices` (daily) | | `sfp:invoice-reminder` | Job `SendInvoiceReminders` (daily) | | `sfp:user-paymentoption-expire` | Job `ExpirePaymentOptions` (daily) | Alles über Laravel Scheduler → `routes/console.php`. --- ## 7. API (aus `lib/ApiActions.class.php` + Frontend-Modulen) - **Auth**: Statischer `api_key` im User-Profil (String, SHA1-base64). - **CSRF**: Für API-Requests in `prepareForm()` deaktiviert. - **Endpoints** (exakte Liste siehe [`07-API-MIGRATION.md`](./07-API-MIGRATION.md)): - `POST /pressrelease/create` – neue PM anlegen - `POST /pressreleaseimage/upload` – Bild hochladen - `GET /pressrelease/list` – PMs des Users - `GET /company/list` - `POST /newsletter/subscribe` - … --- ## 8. Mailer (`lib/bpMailer.class.php`) - Templating via `get_partial()` in Symfony. - Versand via SwiftMailer. → Ersetzt durch: - Laravel `Mailable` + Blade-Templates - Queues (`mail` queue) --- ## 9. Frontend-Assets / Thumbnails - URL-Format: `/thumbnails/pressreleaseimage/thumb_200/pr/-.jpg` - Generator: `sfImageTransformPlugin` - Pfade referenzieren Slugs → bei Slug-Änderung Broken-Links → Ersatz: `intervention/image` + `/storage/images/...` + `public/thumbnails/...`. Für alte URLs **302-Redirect-Middleware**. --- ## 10. Vorarbeiten im Repository (nicht verlieren!) 1. **`_businessportal24.com/dev/`** – Bereits extrahiertes Core-Package mit DTOs, Enums, Value Objects, Domain-Events. Inhalte prüfen + dort wo sinnvoll in Laravel-App übernehmen. 2. **`_businessportal24.com/dev/migration/`** – Vorhandene Migrations-Doku (CHECKLIST, IMPLEMENTATION etc.) – als Referenz nutzen, aber **nicht mehr pflegen**. 3. **`dev/_old/Models/`** & **`dev/_old/migrations/`** – Früher automatisch erzeugte Eloquent-Modelle/-Migrations aus dem alten Schema (2024). Wert: Nützliches Mapping der Spalten-/Typ-Namen. **NICHT** 1:1 übernehmen – Schema wird modernisiert. --- ## 11. „Kritische" Stellen (Achtung bei Migration) | Datei / Ort | Problem | |---|---| | `PressePortalPlugin/lib/helper/PaypalCredentialsHelper.php` (oder vergleichbar) | Hart-kodierte PayPal-Credentials → entfällt (nur Stripe) | | `sfpCron/actions/actions.class.php` | Shared Secret `G8ZvEbnP8fEPfnWX4L` in URL; `exec()`-Call → entfällt | | `sfGuardUser.password`-Feld | `sha1($salt.$password)` → Laravel bcrypt, Legacy-Hasher nötig | | `Company.ctype` enum | Inheritance-Feld; bei Migration entscheiden, ob `type enum('agency','company')` oder Single-Table | | `sfGuardUserProfile.api_key` | Wird von API-Clients genutzt → Umwandlung nach Sanctum + Keep-Alive | | `PressRelease.text` | `string(40000)` – in MySQL 8 auf `TEXT` oder `MEDIUMTEXT` mappen | | Thumbnails mit `/slug-id.ext` | Bei Slug-Änderung 404; neues Schema sollte `id` primär nutzen, Slug redirectbar | | Mehrsprachigkeit `I18n` behavior | Aktuell `de` + `en` Daten in `*_translation`-Tabellen – siehe [`04-DATA-MODEL.md`](./04-DATA-MODEL.md) |