Files
orderPRO/.paul/codebase/ARCHITECTURE.md
Jacek Pyziak 4c3daf69b7 docs: add codebase map to .paul/codebase/
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>
2026-03-12 21:42:24 +01:00

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 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

Repositories:

  • OrderStatusRepository — CRUD + reorder for order_status_groups and order_statuses
  • AllegroIntegrationRepository — reads/writes allegro_integration_settings; encrypts secrets via IntegrationSecretCipher
  • AllegroStatusMappingRepositoryallegro_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
  • ShopproStatusMappingRepositoryorder_status_mappings per shopPRO integration
  • ShopproDeliveryMethodMappingRepositoryshoppro_delivery_method_mappings
  • CarrierDeliveryMethodMappingRepositorycarrier_delivery_method_mappings (unified, cross-source)
  • CompanySettingsRepositorycompany_settings single-row config
  • AllegroDeliveryMethodMappingRepository — Allegro-specific delivery method mappings (legacy, superseded by carrier table)

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)

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))

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 system
  • integration_id — FK to integrations.id
  • internal_order_numberOPXXXXXXXXX (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_mappingsallegro_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