chore: generate codebase map in .paul/codebase/
INDEX, STACK, ARCHITECTURE, CONVENTIONS, TESTING, INTEGRATIONS, CONCERNS
This commit is contained in:
@@ -1,434 +1,126 @@
|
||||
# Architecture
|
||||
|
||||
**Analysis Date:** 2026-03-12
|
||||
|
||||
---
|
||||
|
||||
## 1. Directory Structure
|
||||
## Request Flow
|
||||
|
||||
```
|
||||
orderPRO/ # Project root
|
||||
├── bin/ # CLI scripts (cron, migrations, data tools)
|
||||
├── bootstrap/
|
||||
│ └── app.php # Application bootstrap: autoload, env, config, DI wiring
|
||||
├── config/
|
||||
│ ├── app.php # Application config (name, debug, locale, paths, cron, secrets)
|
||||
│ └── database.php # DB connection params
|
||||
├── database/
|
||||
│ ├── migrations/ # SQL migration files (47 files, named YYYYMMDD_NNNNNN_description.sql)
|
||||
│ └── drafts/ # Non-active schema drafts
|
||||
├── DOCS/
|
||||
│ ├── ARCHITECTURE.md # Existing architecture notes (Polish, incremental)
|
||||
│ ├── DB_SCHEMA.md # Table-level schema reference
|
||||
│ ├── TECH_CHANGELOG.md # Chronological technical changelog
|
||||
│ └── todo.md # Work backlog
|
||||
├── public/
|
||||
│ ├── index.php # Single HTTP entry point
|
||||
│ └── assets/ # Compiled CSS, JS, images (served directly)
|
||||
├── resources/
|
||||
│ ├── lang/ # Translation files (PL locale)
|
||||
│ ├── modules/ # Frontend JS/CSS modules (e.g. jquery-alerts)
|
||||
│ ├── scss/ # SCSS source → compiled to public/assets/css/
|
||||
│ └── views/ # PHP template files (plain PHP, no engine)
|
||||
├── routes/
|
||||
│ └── web.php # All route definitions (returns closure)
|
||||
├── src/
|
||||
│ ├── Core/ # Framework kernel (router, DB, HTTP, security, i18n, views)
|
||||
│ └── Modules/ # Feature modules (Auth, Orders, Settings, Cron, Shipments, Users)
|
||||
├── storage/
|
||||
│ ├── cache/ # File cache
|
||||
│ ├── logs/ # app.log
|
||||
│ ├── sessions/ # PHP session files
|
||||
│ └── tmp/ # Temp files (e.g. downloaded labels)
|
||||
└── tests/
|
||||
└── Unit/ # Unit tests (currently empty)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Application Layers
|
||||
|
||||
### Layer 1 — Kernel (`src/Core/`)
|
||||
|
||||
Framework infrastructure. No business logic.
|
||||
|
||||
| Class | File | Responsibility |
|
||||
|---|---|---|
|
||||
| `Application` | `src/Core/Application.php` | Root service locator. Wires all dependencies, boots session, registers error handlers, runs cron on web. |
|
||||
| `Router` | `src/Core/Routing/Router.php` | Pattern-matching router for GET/POST. Supports `{param}` segments and middleware pipeline. |
|
||||
| `Request` | `src/Core/Http/Request.php` | Immutable wrapper around `$_GET`, `$_POST`, `$_FILES`, `$_SERVER`. |
|
||||
| `Response` | `src/Core/Http/Response.php` | Fluent response builder (`html()`, `json()`, `redirect()`). |
|
||||
| `Template` | `src/Core/View/Template.php` | Output-buffer PHP view renderer. Injects `$e()` (XSS escape) and `$t()` (translation) helpers. Supports layout wrapping. |
|
||||
| `ConnectionFactory` | `src/Core/Database/ConnectionFactory.php` | Creates PDO connection from config array. |
|
||||
| `Migrator` | `src/Core/Database/Migrator.php` | Applies pending `.sql` files from `database/migrations/`. Uses DB lock (`GET_LOCK`) to prevent concurrent runs. |
|
||||
| `Csrf` | `src/Core/Security/Csrf.php` | Session-based CSRF token generate/validate using `hash_equals`. |
|
||||
| `Session` | `src/Core/Support/Session.php` | Thin wrapper around PHP sessions. |
|
||||
| `Flash` | `src/Core/Support/Flash.php` | Single-request flash messages stored in `$_SESSION`. |
|
||||
| `Logger` | `src/Core/Support/Logger.php` | Appends `[LEVEL] message {context_json}` lines to `storage/logs/app.log`. |
|
||||
| `Env` | `src/Core/Support/Env.php` | Parses `.env` file; `get()`, `bool()` helpers. |
|
||||
| `Translator` | `src/Core/I18n/Translator.php` | Loads language files from `resources/lang/`; `get($key, $replace)`. |
|
||||
|
||||
### Layer 2 — Modules (`src/Modules/`)
|
||||
|
||||
Feature slices. Each module owns its controllers, repositories and services.
|
||||
|
||||
| Module | Path | Active Modules |
|
||||
|---|---|---|
|
||||
| Auth | `src/Modules/Auth/` | Login/logout, session-based auth |
|
||||
| Orders | `src/Modules/Orders/` | Order list/detail, status change, import |
|
||||
| Settings | `src/Modules/Settings/` | Statuses, integrations (Allegro/Apaczka/InPost/shopPRO), DB, cron, company |
|
||||
| Cron | `src/Modules/Cron/` | Job scheduling, execution, handlers per job type |
|
||||
| Shipments | `src/Modules/Shipments/` | Provider-agnostic shipment creation, label download |
|
||||
| Users | `src/Modules/Users/` | User management (list, create) |
|
||||
|
||||
### Layer 3 — Views (`resources/views/`)
|
||||
|
||||
Plain PHP templates. No Blade, no Twig.
|
||||
|
||||
| Path | Renders for |
|
||||
|---|---|
|
||||
| `layouts/app.php` | Main authenticated shell (sidebar nav) |
|
||||
| `layouts/auth.php` | Login page shell |
|
||||
| `orders/list.php` | Order list page |
|
||||
| `orders/show.php` | Order detail page |
|
||||
| `settings/allegro.php` | Allegro integration settings |
|
||||
| `settings/apaczka.php` | Apaczka integration settings |
|
||||
| `settings/inpost.php` | InPost integration settings |
|
||||
| `settings/shoppro.php` | shopPRO integration settings (multi-instance) |
|
||||
| `settings/statuses.php` | Status groups & statuses management |
|
||||
| `settings/cron.php` | Cron scheduler UI |
|
||||
| `settings/integrations.php` | Integrations hub |
|
||||
| `settings/database.php` | Migrations UI |
|
||||
| `settings/company.php` | Company/sender settings |
|
||||
| `shipments/prepare.php` | Shipment creation form |
|
||||
| `users/index.php` | Users list |
|
||||
| `auth/login.php` | Login form |
|
||||
| `components/table-list.php` | Reusable paginated table component |
|
||||
| `components/order-status-panel.php` | Reusable order status panel |
|
||||
|
||||
---
|
||||
|
||||
## 3. Bootstrap and Request Flow
|
||||
|
||||
### Bootstrap sequence
|
||||
|
||||
```
|
||||
public/index.php
|
||||
└─ bootstrap/app.php
|
||||
├─ autoload (vendor/autoload.php or spl_autoload from src/)
|
||||
├─ Env::load('.env')
|
||||
├─ load config/app.php + config/database.php
|
||||
├─ new Application($basePath, $config)
|
||||
│ ├─ new Router
|
||||
│ ├─ new Translator
|
||||
│ ├─ new Template
|
||||
│ ├─ ConnectionFactory::make → PDO
|
||||
│ ├─ new UserRepository, OrdersRepository, OrderStatusRepository
|
||||
│ ├─ new Migrator
|
||||
│ └─ new AuthService, Logger
|
||||
└─ $app->boot()
|
||||
├─ prepareDirectories (storage/*)
|
||||
├─ configureSession
|
||||
├─ registerErrorHandlers
|
||||
└─ require routes/web.php → $routes($app)
|
||||
(instantiates all controllers, repositories, services and registers routes)
|
||||
```
|
||||
|
||||
### Per-request flow
|
||||
|
||||
```
|
||||
HTTP request
|
||||
HTTP Request
|
||||
→ public/index.php
|
||||
→ $app->run()
|
||||
├─ Request::capture() (wraps $_GET/$_POST/$_FILES/$_SERVER)
|
||||
├─ maybeRunCronOnWeb() (if cron_run_on_web=1, throttled, DB-locked)
|
||||
└─ Router::dispatch($request)
|
||||
├─ find route by method + path (exact match first, then {param} patterns)
|
||||
├─ attach URL params to $request via withAttributes()
|
||||
├─ build middleware pipeline (array_reduce, reversed)
|
||||
│ └─ AuthMiddleware::handle() (most routes)
|
||||
│ └─ redirect /login if not authenticated
|
||||
└─ call controller method($request): Response
|
||||
├─ reads input via $request->input()
|
||||
├─ validates CSRF via Csrf::validate()
|
||||
├─ calls repository/service methods
|
||||
└─ returns Response::html($template->render(...))
|
||||
or Response::redirect(...)
|
||||
or Response::json(...)
|
||||
→ Response::send() (sets headers, echoes body)
|
||||
→ 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
|
||||
|
||||
## 4. Module Organization
|
||||
| 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 |
|
||||
|
||||
### Auth (`src/Modules/Auth/`)
|
||||
## Module Inventory (`src/Modules/`)
|
||||
|
||||
| Class | Responsibility |
|
||||
|---|---|
|
||||
| `AuthController` | `GET /login`, `POST /login`, `POST /logout` |
|
||||
| `AuthService` | `check()`, `user()`, `attempt(email, password)`, `logout()` backed by session |
|
||||
| `AuthMiddleware` | `handle(Request, callable $next)` — redirects to `/login` if session unauthenticated |
|
||||
| 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** | 51+ | Integration controllers, OAuth clients, API clients, mappers | Allegro/shopPRO/Apaczka/InPost config, status mappings |
|
||||
| **Cron** | 12 | `CronRepository`, `CronHandlerFactory`, handler classes | Scheduled imports, syncs, token refresh |
|
||||
| **Printing** | 4 | `PrintApiController`, `PrintJobRepository`, `ApiKeyMiddleware` | REST API for Windows print client |
|
||||
| **Statistics** | 2 | `OrdersStatisticsController`, `OrdersStatisticsRepository` | Dashboard aggregates |
|
||||
| **Info** | 1 | `InfoController` | Health check |
|
||||
|
||||
### Orders (`src/Modules/Orders/`)
|
||||
## Key Data Flows
|
||||
|
||||
| Class | Responsibility |
|
||||
|---|---|
|
||||
| `OrdersController` | `index` (list), `show` (detail), `updateStatus` — builds view data, delegates DB to repos |
|
||||
| `OrdersRepository` | `paginate()`, `findDetails()`, `statusCounts()`, `statusPanelConfig()`, `sourceOptions()`, `updateOrderStatus()`, `recordActivity()` |
|
||||
| `OrderImportRepository` | `upsertOrderAggregate()` — transactional upsert of the full order aggregate (order + addresses + items + payments + shipments + notes + status history) |
|
||||
### Order Lifecycle
|
||||
1. **Import** — Cron handler → API client → `OrderImportService` → `OrdersRepository::insertOrder()` → `AutomationService::executeForNewOrder()`
|
||||
2. **Status update** — `OrdersController::updateStatus()` → `OrdersRepository::updateStatus()` → automation check
|
||||
3. **Status sync** — Cron → `AllegroStatusSyncService` / `ShopproStatusSyncService` → carrier API
|
||||
|
||||
### Settings (`src/Modules/Settings/`)
|
||||
### Shipment Flow
|
||||
1. **Create** — `ShipmentController::create()` → `ShipmentProviderRegistry` → carrier `ShipmentService::createShipment()` → `ShipmentPackageRepository::insert()`
|
||||
2. **Track** — Cron `ShipmentTrackingHandler` → `ShipmentTrackingRegistry` → carrier tracking API → `ShipmentPackageRepository::updateDeliveryStatus()`
|
||||
|
||||
Large module covering all configuration:
|
||||
### Receipt / Invoice
|
||||
1. **Generate** — `ReceiptController::store()` → `ReceiptService::generateReceipt()` → `ReceiptRepository::insert()` + Dompdf PDF
|
||||
2. **Email** — `EmailSendingService::send()` → `VariableResolver::resolve()` → `AttachmentGenerator::generatePdf()` → PHPMailer SMTP
|
||||
|
||||
**Controllers:**
|
||||
- `SettingsController` — statuses, status groups, DB migrations
|
||||
- `AllegroIntegrationController` — Allegro OAuth2, import, status mappings, delivery mappings
|
||||
- `ApaczkaIntegrationController` — Apaczka API config
|
||||
- `InpostIntegrationController` — InPost ShipX config
|
||||
- `ShopproIntegrationsController` — shopPRO multi-instance management (statuses, delivery, sync)
|
||||
- `IntegrationsHubController` — overview hub listing all provider instances
|
||||
- `CronSettingsController` — cron schedule UI
|
||||
- `CompanySettingsController` — company/sender details
|
||||
### Automation Rules
|
||||
1. **Setup** — `AutomationController` → `AutomationRepository::insertRule()`
|
||||
2. **Trigger** — `AutomationService::executeForOrder()` → evaluates trigger (`order_status_changed`, `order_status_aged`) → runs action (send email, update status)
|
||||
3. **Log** — `AutomationExecutionLogRepository` tracks every run
|
||||
|
||||
**Repositories:**
|
||||
- `OrderStatusRepository` — CRUD + reorder for `order_status_groups` and `order_statuses`
|
||||
- `AllegroIntegrationRepository` — reads/writes `allegro_integration_settings`; encrypts secrets via `IntegrationSecretCipher`
|
||||
- `AllegroStatusMappingRepository` — `allegro_order_status_mappings` CRUD
|
||||
- `AllegroOrderSyncStateRepository` — cursor state for Allegro sync (`integration_order_sync_state`)
|
||||
- `ApaczkaIntegrationRepository` — reads/writes `apaczka_integration_settings`
|
||||
- `InpostIntegrationRepository` — reads/writes `inpost_integration_settings`
|
||||
- `IntegrationsRepository` — base `integrations` table queries (hub listing)
|
||||
- `ShopproIntegrationsRepository` — multi-instance CRUD for `integrations` where `type=shoppro`
|
||||
- `ShopproStatusMappingRepository` — `order_status_mappings` per shopPRO integration
|
||||
- `ShopproDeliveryMethodMappingRepository` — `shoppro_delivery_method_mappings`
|
||||
- `CarrierDeliveryMethodMappingRepository` — `carrier_delivery_method_mappings` (unified, cross-source)
|
||||
- `CompanySettingsRepository` — `company_settings` single-row config
|
||||
- `AllegroDeliveryMethodMappingRepository` — Allegro-specific delivery method mappings (legacy, superseded by carrier table)
|
||||
### Cron Jobs
|
||||
|
||||
**API Clients (HTTP adapters):**
|
||||
- `AllegroOAuthClient` — builds OAuth2 authorize URL, exchanges code for tokens, refreshes tokens
|
||||
- `AllegroApiClient` — calls Allegro REST API (`/order/checkout-forms`, `/sale/product-offers`, `/delivery-services`, etc.)
|
||||
- `ApaczkaApiClient` — calls Apaczka REST API (services, create shipment, label, points)
|
||||
- `ShopproApiClient` — calls shopPRO REST API (orders, products, dictionaries, statuses)
|
||||
| Handler | Task |
|
||||
|---------|------|
|
||||
| `AllegroOrdersImportHandler` | Fetch new Allegro orders |
|
||||
| `AllegroStatusSyncHandler` | Push status changes to Allegro |
|
||||
| `AllegroTokenRefreshHandler` | OAuth token refresh (24h expiry) |
|
||||
| `ShopproOrdersImportHandler` | Fetch new shopPRO orders |
|
||||
| `ShopproStatusSyncHandler` | Push status to shopPRO |
|
||||
| `ShopproPaymentStatusSyncHandler` | Sync payment statuses |
|
||||
| `ShipmentTrackingHandler` | Poll carrier tracking APIs |
|
||||
| `OrderStatusAgedHandler` | Trigger automation for stuck statuses |
|
||||
| `AutomationHistoryCleanupHandler` | Purge old automation logs |
|
||||
|
||||
**Services:**
|
||||
- `AllegroOrderImportService` — maps single Allegro checkout-form to neutral order aggregate, calls `OrderImportRepository::upsertOrderAggregate()`
|
||||
- `AllegroOrdersSyncService` — paginates Allegro checkout-forms list and imports new/changed orders; maintains sync cursor
|
||||
- `AllegroStatusSyncService` — syncs statuses between Allegro and orderPRO based on configured direction
|
||||
- `AllegroStatusDiscoveryService` — fetches live status list from Allegro API and seeds `allegro_order_status_mappings`
|
||||
- `ShopproOrdersSyncService` — fetches shopPRO orders, maps to neutral aggregate, handles paczkomat/pickup points, media
|
||||
- `ShopproStatusSyncService` — orchestrates shopPRO→orderPRO status synchronisation
|
||||
- `ShopproPaymentStatusSyncService` — polls shopPRO `paid` flag and updates `orders.payment_status`
|
||||
- `IntegrationSecretCipher` — AES-256-CBC encryption with HMAC-SHA256 authentication (`v1:base64(iv+mac+cipher)`)
|
||||
## Dependency Injection
|
||||
|
||||
### Cron (`src/Modules/Cron/`)
|
||||
|
||||
| Class | Responsibility |
|
||||
|---|---|
|
||||
| `CronRunner` | Dispatches due schedules to `cron_jobs` queue; processes pending jobs up to `$limit`; delegates to typed handlers |
|
||||
| `CronRepository` | `findDueSchedules()`, `claimNextPendingJob()`, `markJobCompleted()`, `markJobFailed()`, `enqueueJobFromSchedule()`, `getBoolSetting()`, `getIntSetting()` |
|
||||
| `AllegroTokenRefreshHandler` | `handle()` → refreshes Allegro OAuth token before expiry |
|
||||
| `AllegroOrdersImportHandler` | `handle()` → calls `AllegroOrdersSyncService::sync()` |
|
||||
| `AllegroStatusSyncHandler` | `handle()` → calls `AllegroStatusSyncService::sync()` |
|
||||
| `ShopproOrdersImportHandler` | `handle()` → calls `ShopproOrdersSyncService::syncAll()` |
|
||||
| `ShopproStatusSyncHandler` | `handle()` → calls `ShopproStatusSyncService::syncAll()` |
|
||||
| `ShopproPaymentStatusSyncHandler` | `handle()` → calls `ShopproPaymentStatusSyncService::syncAll()` |
|
||||
|
||||
Cron is also triggerable via CLI (`bin/cron.php`) and optionally runs on each HTTP request when `cron_run_on_web=1` (throttled with session timer + DB advisory lock `orderpro_web_cron_lock`).
|
||||
|
||||
### Shipments (`src/Modules/Shipments/`)
|
||||
|
||||
Provider-agnostic shipment layer built around `ShipmentProviderInterface`:
|
||||
Manual constructor injection in `routes/web.php` — no DI container library. Example:
|
||||
|
||||
```php
|
||||
interface ShipmentProviderInterface {
|
||||
public function code(): string;
|
||||
public function getDeliveryServices(): array;
|
||||
public function createShipment(int $orderId, array $formData): array;
|
||||
public function checkCreationStatus(int $packageId): array;
|
||||
public function downloadLabel(int $packageId, string $storagePath): array;
|
||||
}
|
||||
$ordersController = new OrdersController(
|
||||
$template, $translator, $auth,
|
||||
$app->orders(), $shipmentPackageRepository,
|
||||
$receiptRepository, $receiptConfigRepository, ...
|
||||
);
|
||||
```
|
||||
|
||||
| Class | Provider Code | Responsibility |
|
||||
|---|---|---|
|
||||
| `AllegroShipmentService` | `allegro_wza` | Allegro WZA carrier integration |
|
||||
| `ApaczkaShipmentService` | `apaczka` | Apaczka carrier API: wycena, create, label, points fallback for pickup addresses |
|
||||
| `ShipmentProviderRegistry` | — | Map of `code → ShipmentProviderInterface`; resolved by `ShipmentController` |
|
||||
| `ShipmentController` | — | `prepare` (form), `create`, `checkStatus`, `label` endpoints |
|
||||
| `ShipmentPackageRepository` | — | CRUD for `shipment_packages` table |
|
||||
All production classes are `final` — prevents accidental inheritance.
|
||||
|
||||
### Users (`src/Modules/Users/`)
|
||||
|
||||
| Class | Responsibility |
|
||||
|---|---|
|
||||
| `UsersController` | List users, create user |
|
||||
| `UserRepository` | Find by email, list, insert/update |
|
||||
|
||||
---
|
||||
|
||||
## 5. Core Domain Concepts
|
||||
|
||||
### Order Aggregate
|
||||
|
||||
The order domain is provider-neutral. All external orders (Allegro, shopPRO) are normalised into the same tables:
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
orders ← main record (source, integration_id, statuses, totals, flags)
|
||||
├─ order_addresses ← 1:N (type: customer | delivery | invoice)
|
||||
├─ order_items ← 1:N (products, quantities, media_url)
|
||||
├─ order_payments ← 1:N (payment method, amounts)
|
||||
├─ order_shipments ← 1:N (tracking numbers, provider info)
|
||||
├─ order_documents ← 1:N (invoices, etc.)
|
||||
├─ order_notes ← 1:N (internal notes)
|
||||
├─ order_status_history ← 1:N (status transitions with timestamps)
|
||||
└─ order_activity_log ← 1:N (universal event log: status_change, payment, shipment, import, note, ...)
|
||||
bootstrap/ app.php (service wiring, config loading)
|
||||
bin/ migrate.php, cron.php (CLI entry points)
|
||||
config/ app.php, database.php
|
||||
database/
|
||||
migrations/ 84 SQL files (YYYYMMDD_NNNNNN_description.sql)
|
||||
drafts/ WIP migrations
|
||||
public/
|
||||
index.php HTTP entry point
|
||||
.htaccess Apache rewrite rules
|
||||
assets/css/ Compiled CSS (app.css, login.css, modules/)
|
||||
assets/js/ jquery-alerts.js, global-search.js, automation-form.js
|
||||
resources/
|
||||
views/ PHP templates by module + components/ layouts/
|
||||
scss/ SCSS sources (app.scss, login.scss, modules/_*.scss)
|
||||
modules/ jquery-alerts JS+SCSS source
|
||||
lang/pl/ Polish translations
|
||||
routes/
|
||||
web.php All routes (581 lines)
|
||||
src/
|
||||
Core/ Framework (25 files)
|
||||
Modules/ 13 feature modules (~200+ PHP files)
|
||||
storage/
|
||||
logs/ app.log
|
||||
sessions/ PHP session files
|
||||
cache/ PHPUnit cache, etc.
|
||||
tests/
|
||||
Unit/ PHPUnit tests (7+ service test files)
|
||||
bootstrap.php PSR-4 autoloader for tests
|
||||
```
|
||||
|
||||
Key `orders` columns:
|
||||
- `source` — origin system (`allegro`, `shoppro`)
|
||||
- `source_order_id` — external ID in source system
|
||||
- `integration_id` — FK to `integrations.id`
|
||||
- `internal_order_number` — `OPXXXXXXXXX` (unique internal identifier, e.g. `OP000000001`)
|
||||
- `external_status_id` / `external_status_code` — last known status from source
|
||||
- `payment_status` — payment state (`0`=unpaid, `2`=paid, etc.)
|
||||
- `ordered_at` / `source_created_at` / `source_updated_at` / `fetched_at` — date fallback chain
|
||||
|
||||
### Integration Registry (`integrations` table)
|
||||
|
||||
Single base table for all integration instances. Specific settings are in satellite tables linked by `integration_id`:
|
||||
|
||||
```
|
||||
integrations (type, name, is_active, api_key_encrypted, orders_fetch_enabled, ...)
|
||||
├─ allegro_integration_settings (1:1, environment, OAuth tokens, token_expires_at)
|
||||
├─ apaczka_integration_settings (1:1, app_id, app_secret_encrypted)
|
||||
└─ inpost_integration_settings (1:1, api_token, organization_id, defaults)
|
||||
|
||||
integrations (type=shoppro, multi-instance)
|
||||
├─ order_status_mappings (1:N, shoppro_status_code → orderpro_status_code)
|
||||
└─ shoppro_delivery_method_mappings (1:N, delivery method → carrier service)
|
||||
```
|
||||
|
||||
### Status Configuration
|
||||
|
||||
```
|
||||
order_status_groups (name, code, color_hex, sort_order, is_active)
|
||||
└─ order_statuses (1:N, name, code, sort_order, is_active)
|
||||
```
|
||||
|
||||
Status codes in `orders` (`external_status_code`) are mapped to human labels via join with `order_statuses`. Fallback group "Pozostale" catches unmapped codes.
|
||||
|
||||
External status mappings per provider:
|
||||
- `allegro_order_status_mappings` — `allegro_status_code → orderpro_status_code`
|
||||
- `order_status_mappings` — generic per-integration mapping (`shoppro_status_code → orderpro_status_code`)
|
||||
|
||||
### Carrier / Delivery Method Mappings
|
||||
|
||||
```
|
||||
carrier_delivery_method_mappings
|
||||
source_system + source_integration_id + order_delivery_method
|
||||
→ provider + provider_service_id + provider_account_id
|
||||
```
|
||||
|
||||
This is the unified resolution table used by `ShipmentController` to auto-select the carrier service when preparing a shipment.
|
||||
|
||||
### Cron Scheduling Tables
|
||||
|
||||
```
|
||||
cron_schedules (job_type, interval_seconds, priority, is_active, next_run_at)
|
||||
→ cron_jobs (job_type, payload, status, priority, scheduled_at, result_json, ...)
|
||||
```
|
||||
|
||||
`CronRunner` reads due schedules, enqueues jobs, then claims and processes pending jobs up to the configured limit.
|
||||
|
||||
---
|
||||
|
||||
## 6. Dependency Injection Pattern
|
||||
|
||||
The application does not use a DI container. All dependencies are wired manually in `routes/web.php` (for HTTP) and in `Application::maybeRunCronOnWeb()` (for web cron). This means:
|
||||
|
||||
- Every controller receives its dependencies via constructor injection.
|
||||
- `Application` holds the core singletons (PDO, AuthService, OrdersRepository, etc.) and exposes them via typed getters (`$app->db()`, `$app->orders()`, `$app->auth()`, etc.).
|
||||
- `routes/web.php` is the composition root for the web context.
|
||||
|
||||
---
|
||||
|
||||
## 7. Security Architecture
|
||||
|
||||
| Concern | Mechanism |
|
||||
|---|---|
|
||||
| Authentication | Session-based. `AuthService::check()` reads `$_SESSION`. `AuthMiddleware` guards all protected routes. |
|
||||
| CSRF | `Csrf::token()` / `Csrf::validate()` — single session token, validated on all POST handlers before any mutation. |
|
||||
| Secret storage | API keys and OAuth tokens encrypted at-rest using `IntegrationSecretCipher` (AES-256-CBC + HMAC-SHA256). Secret key comes from `INTEGRATIONS_SECRET` env var. |
|
||||
| XSS | Template helper `$e()` wraps `htmlspecialchars()` with `ENT_QUOTES`. |
|
||||
| SQL injection | All queries use PDO prepared statements (medoo-style named params). No raw string concatenation. |
|
||||
| DB locks | `GET_LOCK` used for migrations (`orderpro_migrations_lock`) and web cron (`orderpro_web_cron_lock`) to prevent concurrent execution. |
|
||||
|
||||
---
|
||||
|
||||
## 8. Database Design Summary
|
||||
|
||||
**Migration system:** SQL files in `database/migrations/` named `YYYYMMDD_NNNNNN_description.sql`, sorted alphabetically and tracked in `migrations` table. Applied via `Migrator::runPending()` from UI or CLI (`bin/migrate.php`).
|
||||
|
||||
**Core tables:**
|
||||
|
||||
| Table | Purpose |
|
||||
|---|---|
|
||||
| `users` | Panel users (email, password_hash) |
|
||||
| `orders` | Master order record |
|
||||
| `order_addresses` | Typed addresses per order (customer/delivery/invoice) |
|
||||
| `order_items` | Order line items with media_url |
|
||||
| `order_payments` | Payment records per order |
|
||||
| `order_shipments` | Shipment/tracking records from source system |
|
||||
| `order_documents` | Document references (invoices etc.) |
|
||||
| `order_notes` | Internal notes |
|
||||
| `order_status_history` | Full status transition history |
|
||||
| `order_activity_log` | Universal event log (status_change, payment, shipment, import, note, document, message) |
|
||||
| `order_status_groups` | Configurable status groups (with color, sort) |
|
||||
| `order_statuses` | Statuses within groups |
|
||||
| `order_status_mappings` | External status → orderPRO status per integration (generic) |
|
||||
| `allegro_order_status_mappings` | Allegro-specific status mappings |
|
||||
| `integrations` | Base table for all integration instances (allegro, apaczka, inpost, shoppro) |
|
||||
| `allegro_integration_settings` | Allegro OAuth2 credentials and tokens (1:1 with integrations) |
|
||||
| `apaczka_integration_settings` | Apaczka app_id + secrets (1:1 with integrations) |
|
||||
| `inpost_integration_settings` | InPost ShipX config and defaults (1:1 with integrations) |
|
||||
| `integration_order_sync_state` | Import cursor per integration (last synced order, timestamps) |
|
||||
| `carrier_delivery_method_mappings` | Unified: order delivery method → shipment provider service |
|
||||
| `shoppro_delivery_method_mappings` | shopPRO-specific delivery mappings (legacy, superseded by carrier table) |
|
||||
| `shipment_packages` | Packages created via shipment providers (status, tracking, label path) |
|
||||
| `company_settings` | Single-row sender company config (address, contact_person, package defaults) |
|
||||
| `cron_schedules` | Named job schedules with intervals and priorities |
|
||||
| `cron_jobs` | Job queue: pending, running, completed, failed |
|
||||
| `app_settings` | Key-value settings store (cron_run_on_web, allegro_status_sync_direction, etc.) |
|
||||
| `migrations` | Applied migration filenames (Migrator tracking) |
|
||||
|
||||
---
|
||||
|
||||
## 9. CLI Scripts (`bin/`)
|
||||
|
||||
| Script | Purpose |
|
||||
|---|---|
|
||||
| `bin/cron.php` | CLI cron runner; loads app and calls `CronRunner::run($limit)` |
|
||||
| `bin/migrate.php` | CLI migration runner; calls `Migrator::runPending()` |
|
||||
| `bin/deploy_and_seed_orders.php` | Applies order schema draft + seeds test data (`--count`, `--append`, `--profile=default\|realistic`) |
|
||||
| `bin/fix_status_codes.php` | Repairs status group/status codes (PL→ASCII transliteration, `--dry-run`) |
|
||||
| `bin/fill_order_item_images.php` | Backfills `order_items.media_url` from integration APIs |
|
||||
| `bin/randomize_order_statuses.php` | Dev utility to randomize order statuses |
|
||||
| `bin/fix_gs1_brand.php` | Fixes GS1 brand data |
|
||||
| `bin/test_gs1_api.php` | Tests GS1 API connectivity |
|
||||
|
||||
---
|
||||
|
||||
## 10. Frontend Architecture
|
||||
|
||||
- **Styles:** SCSS source in `resources/scss/`, compiled to `public/assets/css/`.
|
||||
- **Scripts:** JS in `resources/modules/` (e.g. `jquery-alerts`), compiled to `public/assets/js/modules/`.
|
||||
- **Alerts/confirms:** `window.OrderProAlerts.confirm(...)` from `public/assets/js/modules/jquery-alerts.js`. Native `alert()`/`confirm()` are forbidden.
|
||||
- **Views:** Plain PHP; no JS framework. Inline JS kept minimal, page-level only in view files.
|
||||
- **Layout:** Single shell `resources/views/layouts/app.php` with sidebar nav. Sidebar `activeMenu` and `activeSettings` variables control highlighted state.
|
||||
|
||||
---
|
||||
|
||||
*Full architecture analysis: 2026-03-12*
|
||||
|
||||
Reference in New Issue
Block a user