# Architecture ## Request Flow ``` HTTP Request → public/index.php → bootstrap/app.php (loads config, registers PDO, services) → Application::boot() (loads routes/web.php) → Router::dispatch(Request) (matches URL, runs middleware pipeline) → [Middleware] (AuthMiddleware, ApiKeyMiddleware) → Controller::method() (parse input → call repository/service → render) → Template::render() (PHP native, layout composition) → Response::send() ``` ## Layer Map | Layer | Location | Responsibility | |-------|----------|----------------| | Entry | `public/index.php` | Bootstrap only | | Routes | `routes/web.php` (581 lines) | All ~80 routes; manual DI wiring | | Core | `src/Core/` (25 files) | Framework infrastructure | | Controllers | `src/Modules/*/Controller.php` | Request parsing → response | | Services | `src/Modules/*/Service.php` | Business logic | | Repositories | `src/Modules/*/Repository.php` | PDO data access (34+ repos) | | Views | `resources/views/` | PHP templates with `$e()` / `$t()` | | Components | `resources/views/components/` | Reusable UI blocks | | Frontend modules | `public/assets/js/modules/` | Small vanilla JS enhancements loaded by layout | ## Module Inventory (`src/Modules/`) | Module | Files | Key Classes | Purpose | |--------|-------|-------------|---------| | **Auth** | 3 | `AuthController`, `AuthMiddleware`, `AuthService` | Login/logout, session | | **Users** | 2 | `UserController`, `UserRepository` | User CRUD | | **Orders** | 3 | `OrdersController` (1187 LOC), `OrdersRepository` (1221 LOC) | Order list, detail, status, payment, correlated subquery for return-risk | | **Shipments** | 17 | `ShipmentController`, provider services + tracking services | Shipment creation, label download, tracking polling | | **Accounting** | 5 | `AccountingController`, `ReceiptService`, `ReceiptRepository` | Receipts, invoices, PDF, Excel export | | **Email** | 3 | `EmailSendingService`, `VariableResolver`, `AttachmentGenerator` | Template-based email with PDF attachments | | **Automation** | 6 | `AutomationService` (834 LOC), `AutomationRepository`, `AutomationExecutionLogRepository` | Event→condition→action rules, email triggers | | **Settings** | 54+ | Integration controllers, OAuth clients, API clients (Fakturownia incl.), mappers | Allegro/shopPRO/Apaczka/InPost/Fakturownia config, status mappings | | **Sms** | 3 | `SmsMessageRepository`, `SmsConversationService`, `SmsplanetWebhookController` | SMSPLANET outbound order SMS, inbound webhook parsing, order matching | | **Notifications** | 3 | `NotificationRepository`, `NotificationController`, `NotificationApiController` | Global notification history, unread polling API, mark-read actions | | **Cron** | 12 | `CronRepository`, `CronHandlerFactory`, handler classes | Scheduled imports, syncs, token refresh | | **Printing** | 4 | `PrintApiController`, `PrintJobRepository`, `ApiKeyMiddleware` | REST API for Windows print client | | **Statistics** | 3 | `OrdersStatisticsController`, `OrdersStatisticsRepository`, `statistics-summary-charts.js` | Daily order statistics and monthly summary charts | | **Info** | 1 | `InfoController` | Health check | ## Frontend Enhancement Modules ### Checkbox Multiselect (`public/assets/js/modules/checkbox-multiselect.js`) - Loaded globally from `resources/views/layouts/app.php`. - Enhances native `` z opcja domyslna + aktywne szablony (renderowany tylko gdy `$smsTemplatesList !== []`). - Textarea ma teraz `id="js-sms-message"` — JS target. ### Frontend module `public/assets/js/modules/sms-template-picker.js` - Vanilla JS, idempotent guard `window.__smsTemplatePickerBound` + per-element `dataset.smsPickerBound`. - Na `change` selecta: fetch `/orders/{id}/sms/template?template_id=N`, podstaw body do textarea, fire `input` event. - Gdy textarea ma juz tresc -> `OrderProAlerts.confirm({...})` options-object API (Phase 114 pattern). Po zatwierdzeniu nadpisuje, po anulowaniu resetuje select. Fallback na natywny `confirm()`. - Ladowany globalnie z `layouts/app.php` (linia po `notifications.js`). ### Wspolny resolver — wiring DI (`routes/web.php`) - `$smsVariableResolver = new SmsVariableResolver($shipmentPackageRepositoryForOrders);` - `$variableResolver = new VariableResolver($shipmentPackageRepositoryForOrders, $smsVariableResolver);` (drugi argument opcjonalny dla BC). - `$smsTemplateRepository = new SmsTemplateRepository($app->db());` - `$smsTemplateController = new SmsTemplateController($template, $translator, $auth, $smsTemplateRepository);` - `$ordersController` rozszerzony o 3 trailing params (smsTemplateRepository, smsVariableResolver, companySettingsRepository). ### SCSS — `_sms-templates.scss` - Nowy partial `resources/scss/modules/_sms-templates.scss` z klasami `.sms-template-*` (active label, counter, body grid) oraz `.sms-var-panel/.sms-var-group/.sms-var-item` dla palety zmiennych. - Import w `app.scss` po `customer-risk-alert`. ### Stopka — preserved Phase 122 contract - Szablony SMS NIE zawieraja `default_footer` — operator wpisuje sama tresc. - `SmsConversationService::buildFinalOutboundBody()` dokleja stopke raz przy `sendFromOrder()` (po wstawieniu szablonu i ewentualnej edycji przez operatora). Walidacja `MAX_SMS_LENGTH = 918` obowiazuje na finalnej tresci. ### BREAKING / migration - Migracja `20260512_000112_create_sms_templates.sql` — `CREATE TABLE IF NOT EXISTS sms_templates` (DDL, brak SELECT no-op). - Brak innych zmian schematu. `OrdersController` ctor: 3 NEW optional params (default null) — backwards compatible.