Auto-generated by paul:map-codebase — 4 parallel analysis agents. Covers stack, architecture, conventions, and concerns. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
22 KiB
Architecture
Analysis Date: 2026-03-12
1. Directory Structure
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
→ 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)
4. Module Organization
Auth (src/Modules/Auth/)
| 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 |
Orders (src/Modules/Orders/)
| 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) |
Settings (src/Modules/Settings/)
Large module covering all configuration:
Controllers:
SettingsController— statuses, status groups, DB migrationsAllegroIntegrationController— Allegro OAuth2, import, status mappings, delivery mappingsApaczkaIntegrationController— Apaczka API configInpostIntegrationController— InPost ShipX configShopproIntegrationsController— shopPRO multi-instance management (statuses, delivery, sync)IntegrationsHubController— overview hub listing all provider instancesCronSettingsController— cron schedule UICompanySettingsController— company/sender details
Repositories:
OrderStatusRepository— CRUD + reorder fororder_status_groupsandorder_statusesAllegroIntegrationRepository— reads/writesallegro_integration_settings; encrypts secrets viaIntegrationSecretCipherAllegroStatusMappingRepository—allegro_order_status_mappingsCRUDAllegroOrderSyncStateRepository— cursor state for Allegro sync (integration_order_sync_state)ApaczkaIntegrationRepository— reads/writesapaczka_integration_settingsInpostIntegrationRepository— reads/writesinpost_integration_settingsIntegrationsRepository— baseintegrationstable queries (hub listing)ShopproIntegrationsRepository— multi-instance CRUD forintegrationswheretype=shopproShopproStatusMappingRepository—order_status_mappingsper shopPRO integrationShopproDeliveryMethodMappingRepository—shoppro_delivery_method_mappingsCarrierDeliveryMethodMappingRepository—carrier_delivery_method_mappings(unified, cross-source)CompanySettingsRepository—company_settingssingle-row configAllegroDeliveryMethodMappingRepository— Allegro-specific delivery method mappings (legacy, superseded by carrier table)
API Clients (HTTP adapters):
AllegroOAuthClient— builds OAuth2 authorize URL, exchanges code for tokens, refreshes tokensAllegroApiClient— 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)
Services:
AllegroOrderImportService— maps single Allegro checkout-form to neutral order aggregate, callsOrderImportRepository::upsertOrderAggregate()AllegroOrdersSyncService— paginates Allegro checkout-forms list and imports new/changed orders; maintains sync cursorAllegroStatusSyncService— syncs statuses between Allegro and orderPRO based on configured directionAllegroStatusDiscoveryService— fetches live status list from Allegro API and seedsallegro_order_status_mappingsShopproOrdersSyncService— fetches shopPRO orders, maps to neutral aggregate, handles paczkomat/pickup points, mediaShopproStatusSyncService— orchestrates shopPRO→orderPRO status synchronisationShopproPaymentStatusSyncService— polls shopPROpaidflag and updatesorders.payment_statusIntegrationSecretCipher— AES-256-CBC encryption with HMAC-SHA256 authentication (v1:base64(iv+mac+cipher))
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:
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;
}
| 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 |
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:
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, ...)
Key orders columns:
source— origin system (allegro,shoppro)source_order_id— external ID in source systemintegration_id— FK tointegrations.idinternal_order_number—OPXXXXXXXXX(unique internal identifier, e.g.OP000000001)external_status_id/external_status_code— last known status from sourcepayment_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_codeorder_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.
Applicationholds the core singletons (PDO, AuthService, OrdersRepository, etc.) and exposes them via typed getters ($app->db(),$app->orders(),$app->auth(), etc.).routes/web.phpis 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 topublic/assets/css/. - Scripts: JS in
resources/modules/(e.g.jquery-alerts), compiled topublic/assets/js/modules/. - Alerts/confirms:
window.OrderProAlerts.confirm(...)frompublic/assets/js/modules/jquery-alerts.js. Nativealert()/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.phpwith sidebar nav. SidebaractiveMenuandactiveSettingsvariables control highlighted state.
Full architecture analysis: 2026-03-12