chore: generate codebase map in .paul/codebase/
INDEX, STACK, ARCHITECTURE, CONVENTIONS, TESTING, INTEGRATIONS, CONCERNS
This commit is contained in:
@@ -1,286 +1,71 @@
|
||||
# Technology Stack
|
||||
|
||||
**Analysis Date:** 2026-03-12
|
||||
## Runtime
|
||||
|
||||
---
|
||||
| Layer | Technology | Version | Notes |
|
||||
|-------|-----------|---------|-------|
|
||||
| PHP | PHP | ^8.4 | `declare(strict_types=1)` in all files |
|
||||
| Web server | Apache | XAMPP (local) | `public/.htaccess` handles routing |
|
||||
| Database | MySQL | InnoDB | utf8mb4_unicode_ci |
|
||||
| Node.js | npm | dev only | Sass build tool only, no runtime JS bundler |
|
||||
|
||||
## Languages
|
||||
## PHP Dependencies (`composer.json`)
|
||||
|
||||
**Primary:**
|
||||
- PHP 8.4 — all backend logic, routing, controllers, repositories, CLI scripts
|
||||
- SQL — raw migration files, all database queries via PDO prepared statements
|
||||
|
||||
**Secondary:**
|
||||
- SCSS — compiled to CSS for frontend styling (`resources/scss/`)
|
||||
- JavaScript — custom jQuery-based UI alert/confirm module (`resources/modules/jquery-alerts/`)
|
||||
|
||||
---
|
||||
|
||||
## Runtime & Server
|
||||
|
||||
**PHP:**
|
||||
- Version: `^8.4` (strict, declared via `declare(strict_types=1)` in every file)
|
||||
- Extensions required: `pdo_mysql`, `openssl`, `curl`, `hash`, `mbstring`, `session`
|
||||
- Dev server: `php -S localhost:8000 -t public public/index.php` (via `composer serve`)
|
||||
- Production: any standard PHP-FPM + Apache/Nginx setup targeting `public/` as document root
|
||||
|
||||
**Entry point:**
|
||||
- `public/index.php` — bootstraps the application
|
||||
- `index.php` (root) — likely a redirect or secondary entry
|
||||
|
||||
**CLI scripts (in `bin/`):**
|
||||
- `bin/migrate.php` — runs database migrations (`composer migrate`)
|
||||
- `bin/cron.php` — executes scheduled cron jobs (`composer cron`)
|
||||
|
||||
---
|
||||
| Package | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| `dompdf/dompdf` | ^3.1 | PDF generation (receipts, labels) |
|
||||
| `phpoffice/phpspreadsheet` | ^5.5 | Excel/XLSX export (accounting) |
|
||||
| `phpmailer/phpmailer` | ^7.0 | SMTP email sending |
|
||||
| `phpunit/phpunit` | ^11.5 (dev) | Unit testing |
|
||||
| `dg/bypass-finals` | ^1.9 (dev) | Mock final classes in tests |
|
||||
|
||||
## Framework
|
||||
|
||||
**No third-party framework.** The application uses a fully custom, hand-rolled framework located in `src/Core/`:
|
||||
**Custom lightweight framework** — no Laravel/Symfony.
|
||||
|
||||
| Component | Class | File |
|
||||
|---|---|---|
|
||||
| Application container | `App\Core\Application` | `src/Core/Application.php` |
|
||||
| HTTP Router | `App\Core\Routing\Router` | `src/Core/Routing/Router.php` |
|
||||
| HTTP Request | `App\Core\Http\Request` | `src/Core/Http/Request.php` |
|
||||
| HTTP Response | `App\Core\Http\Response` | `src/Core/Http/Response.php` |
|
||||
| Template engine | `App\Core\View\Template` | `src/Core/View/Template.php` |
|
||||
| Database factory | `App\Core\Database\ConnectionFactory` | `src/Core/Database/ConnectionFactory.php` |
|
||||
| Migrator | `App\Core\Database\Migrator` | `src/Core/Database/Migrator.php` |
|
||||
| Session | `App\Core\Support\Session` | `src/Core/Support/Session.php` |
|
||||
| Logger | `App\Core\Support\Logger` | `src/Core/Support/Logger.php` |
|
||||
| CSRF protection | `App\Core\Security\Csrf` | `src/Core/Security/Csrf.php` |
|
||||
| Translator (i18n) | `App\Core\I18n\Translator` | `src/Core/I18n/Translator.php` |
|
||||
| Env helper | `App\Core\Support\Env` | `src/Core/Support/Env.php` |
|
||||
| Component | File |
|
||||
|-----------|------|
|
||||
| Application bootstrap | `src/Core/Application.php` |
|
||||
| Router | `src/Core/Routing/Router.php` |
|
||||
| Request / Response | `src/Core/Http/Request.php`, `Response.php` |
|
||||
| Template engine | `src/Core/View/Template.php` (PHP-native, `$e()` + `$t()` helpers) |
|
||||
| Session | `src/Core/Support/Session.php` |
|
||||
| Logger | `src/Core/Support/Logger.php` → `storage/logs/app.log` |
|
||||
| CSRF | `src/Core/Security/Csrf.php` |
|
||||
| i18n | `src/Core/I18n/Translator.php` (Polish primary: `resources/lang/pl/`) |
|
||||
| DB connection | `src/Core/Database/ConnectionFactory.php` (PDO, no ORM, no medoo) |
|
||||
| Migrator | `src/Core/Database/Migrator.php` (custom SQL runner, `migrations` table) |
|
||||
| SSL resolver | `src/Core/Http/SslCertificateResolver.php` (env: `CURL_CA_BUNDLE_PATH`) |
|
||||
|
||||
**Routing style:** `GET`/`POST` registration with path-param support (`{id}`) and per-route middleware pipeline. Routes defined in `routes/web.php`.
|
||||
## Frontend
|
||||
|
||||
**Template engine:** PHP native `require` with `ob_start()`/`ob_get_clean()`. Views live in `resources/views/`. Layout support via a second render pass. XSS helper `$e()` exposed to every view via `htmlspecialchars`. Translation helper `$t()` also injected.
|
||||
- **No CSS framework** — custom SCSS design tokens
|
||||
- **jQuery** — used only for `jquery-alerts` module (`resources/modules/jquery-alerts/`)
|
||||
- **No JS bundler** — files served directly from `public/assets/js/`
|
||||
- **Build**: `npm run build:assets` (Sass → compressed CSS + JS copy)
|
||||
|
||||
**i18n:** Single-locale PHP array file. Currently Polish only: `resources/lang/pl.php`.
|
||||
## Build Scripts
|
||||
|
||||
---
|
||||
|
||||
## Database
|
||||
|
||||
**Engine:** MySQL (only supported driver — enforced with `RuntimeException` in `ConnectionFactory`)
|
||||
**Default port:** 3306
|
||||
**Charset:** `utf8mb4`
|
||||
**Client:** PHP PDO with `ERRMODE_EXCEPTION`, `FETCH_ASSOC`, `EMULATE_PREPARES = false`
|
||||
**ORM:** None — raw PDO prepared statements everywhere
|
||||
|
||||
**Migrations:**
|
||||
- Plain SQL files in `database/migrations/`, named `YYYYMMDD_NNNNNN_description.sql`
|
||||
- Run via `bin/migrate.php` / `composer migrate`
|
||||
- 46 migrations present (as of analysis date), dating from 2026-02-21
|
||||
|
||||
**Config file:** `config/database.php`
|
||||
|
||||
---
|
||||
|
||||
## Package Manager & Build Tools
|
||||
|
||||
**PHP dependencies (Composer):**
|
||||
- `composer.json` — PSR-4 autoload: `App\` → `src/`, `Tests\` → `tests/`
|
||||
- No runtime Composer packages — zero third-party PHP libraries
|
||||
- Dev only: `phpunit/phpunit ^11.5`
|
||||
- Lockfile: `composer.lock` (present)
|
||||
|
||||
**Node / Frontend (npm):**
|
||||
- `package.json` — `devDependencies` only
|
||||
- `sass ^1.97.3` — SCSS compiler (Dart Sass CLI)
|
||||
- Lockfile: `package-lock.json` (present)
|
||||
|
||||
**Build commands (npm scripts):**
|
||||
|
||||
```bash
|
||||
npm run build:css # Compile app.scss + login.scss → public/assets/css/
|
||||
npm run build:modules # Compile jquery-alerts.scss + copy jquery-alerts.js → public/assets/
|
||||
npm run build:assets # Full build (build:css + build:modules)
|
||||
npm run watch:css # Watch mode for SCSS development
|
||||
```json
|
||||
"build:css" → sass --style=compressed resources/scss/app.scss → public/assets/css/app.css
|
||||
"build:modules"→ sass jquery-alerts.scss + copy jquery-alerts.js
|
||||
"build:assets" → build:css && build:modules
|
||||
"watch:css" → sass --watch (development)
|
||||
```
|
||||
|
||||
**Output paths:**
|
||||
- `public/assets/css/app.css` — main application styles
|
||||
- `public/assets/css/login.css` — login page styles
|
||||
- `public/assets/css/modules/jquery-alerts.css` — alert/confirm modal styles
|
||||
- `public/assets/js/modules/jquery-alerts.js` — alert/confirm module JS
|
||||
```json
|
||||
"serve" → php -S localhost:8000 -t public public/index.php
|
||||
"migrate" → php bin/migrate.php
|
||||
"cron" → php bin/cron.php
|
||||
"test" → vendor/bin/phpunit -c phpunit.xml --testdox
|
||||
```
|
||||
|
||||
**SCSS sources:**
|
||||
- `resources/scss/app.scss` — main stylesheet
|
||||
- `resources/scss/login.scss` — login page stylesheet
|
||||
- `resources/scss/shared/_ui-components.scss` — shared component partials
|
||||
- `resources/modules/jquery-alerts/jquery-alerts.scss` — module source
|
||||
## Environment Variables (`.env.example`)
|
||||
|
||||
---
|
||||
|
||||
## Testing
|
||||
|
||||
**Framework:** PHPUnit `^11.5`
|
||||
**Config:** `phpunit.xml`
|
||||
**Run command:** `composer test` → `vendor/bin/phpunit -c phpunit.xml --testdox`
|
||||
**Test root:** `tests/` (`Tests\` namespace)
|
||||
**Bootstrap:** `tests/bootstrap.php`
|
||||
**Cache dir:** `storage/cache/phpunit`
|
||||
**Coverage source:** `src/`
|
||||
|
||||
---
|
||||
|
||||
## Security
|
||||
|
||||
**CSRF:** Session-based token via `App\Core\Security\Csrf` (`src/Core/Security/Csrf.php`) — `hash_equals()` comparison
|
||||
|
||||
**Credential encryption (integration API keys):** AES-256-CBC + HMAC-SHA256 via `App\Modules\Settings\IntegrationSecretCipher` (`src/Modules/Settings/IntegrationSecretCipher.php`)
|
||||
- Encryption key and HMAC key are both derived from `INTEGRATIONS_SECRET` env var using `hash('sha256', 'enc|...')` / `hash('sha256', 'auth|...')`
|
||||
- Encrypted values stored in DB as `v1:<base64>` format
|
||||
|
||||
**XSS:** `htmlspecialchars()` via `$e()` helper injected into every view by `Template::renderFile()`
|
||||
|
||||
**SQL injection:** PDO prepared statements enforced throughout all repositories
|
||||
|
||||
---
|
||||
|
||||
## External Integrations
|
||||
|
||||
### Allegro (Polish marketplace)
|
||||
|
||||
- **OAuth 2.0 client:** `App\Modules\Settings\AllegroOAuthClient` (`src/Modules/Settings/AllegroOAuthClient.php`)
|
||||
- Authorization code + refresh token flow
|
||||
- Environments: `production` (`https://allegro.pl`) and `sandbox` (`https://allegro.pl.allegrosandbox.pl`)
|
||||
- Scopes: `allegro:api:orders:read`, `allegro:api:sale:offers:read`, `allegro:api:shipments:read`, `allegro:api:shipments:write`
|
||||
- **REST API client:** `App\Modules\Settings\AllegroApiClient` (`src/Modules/Settings/AllegroApiClient.php`)
|
||||
- Endpoints used: checkout forms (order list/detail), shipments, delivery services, product offers, shipment labels (binary PDF)
|
||||
- Accept header: `application/vnd.allegro.public.v1+json`
|
||||
- HTTP transport: native PHP `curl`
|
||||
- **Sync services:**
|
||||
- `AllegroOrdersSyncService` — order import from Allegro
|
||||
- `AllegroStatusSyncService` — order status synchronization
|
||||
- `AllegroOrderImportService` — individual order import
|
||||
- **Cron handlers:** `AllegroOrdersImportHandler`, `AllegroStatusSyncHandler`, `AllegroTokenRefreshHandler`
|
||||
- **Credentials stored:** in DB `integrations` table, API key encrypted with `IntegrationSecretCipher`
|
||||
|
||||
### shopPRO (Polish e-commerce platform)
|
||||
|
||||
- **REST API client:** `App\Modules\Settings\ShopproApiClient` (`src/Modules/Settings/ShopproApiClient.php`)
|
||||
- Endpoint pattern: `{baseUrl}/api.php?endpoint=orders&action=list`
|
||||
- Auth: `X-Api-Key` HTTP header
|
||||
- Supports: order list (paginated), order by ID, product by ID
|
||||
- **Sync services:**
|
||||
- `ShopproOrdersSyncService` — order import from shopPRO
|
||||
- `ShopproStatusSyncService` — order status sync
|
||||
- `ShopproPaymentStatusSyncService` — payment status sync
|
||||
- **Cron handlers:** `ShopproOrdersImportHandler`, `ShopproStatusSyncHandler`, `ShopproPaymentStatusSyncHandler`
|
||||
|
||||
### Apaczka (Polish shipping aggregator)
|
||||
|
||||
- **REST API client:** `App\Modules\Settings\ApaczkaApiClient` (`src/Modules/Settings/ApaczkaApiClient.php`)
|
||||
- Base URL: `https://www.apaczka.pl/api/v2`
|
||||
- Auth: HMAC-SHA256 signature (`app_id:route:requestJson:expires` + `appSecret`)
|
||||
- Signature variant fallback: tries multiple formats to handle Apaczka API quirks
|
||||
- Endpoints: `service_structure`, `order_send`, `order/{id}`, `waybill/{id}`, `points/{type}`
|
||||
- **Shipment provider:** `App\Modules\Shipments\ApaczkaShipmentService` (`src/Modules/Shipments/ApaczkaShipmentService.php`)
|
||||
- **Settings repo:** `ApaczkaIntegrationRepository`, `ApaczkaIntegrationController`
|
||||
|
||||
### InPost ShipX
|
||||
|
||||
- **API base URL:** `https://api-shipx-pl.easypack24.net`
|
||||
- **Auth:** Bearer token (stored encrypted in DB)
|
||||
- **Settings repo:** `App\Modules\Settings\InpostIntegrationRepository` (`src/Modules/Settings/InpostIntegrationRepository.php`)
|
||||
- **Shipment provider:** `App\Modules\Shipments\AllegroShipmentService` also covers InPost services through Allegro's shipment management API
|
||||
- **Config stored:** `inpost_integration_settings` DB table
|
||||
- **Features:** sandbox/production toggle, dispatch method, locker size, dimensions, label format (PDF/ZPL/EPL), weekend delivery, multi-parcel
|
||||
|
||||
### GS1 (product barcode data)
|
||||
|
||||
- Referenced in `bin/test_gs1_api.php` and `bin/fix_gs1_brand.php`
|
||||
- Settings stored in `app_settings` table (GS1 API key, GLN, etc.)
|
||||
|
||||
---
|
||||
|
||||
## Shipment Provider Abstraction
|
||||
|
||||
Interface: `App\Modules\Shipments\ShipmentProviderInterface` (`src/Modules/Shipments/ShipmentProviderInterface.php`)
|
||||
|
||||
Methods:
|
||||
- `code(): string`
|
||||
- `getDeliveryServices(): array`
|
||||
- `createShipment(int $orderId, array $formData): array`
|
||||
- `checkCreationStatus(int $packageId): array`
|
||||
- `downloadLabel(int $packageId, string $storagePath): array`
|
||||
|
||||
Registry: `App\Modules\Shipments\ShipmentProviderRegistry` (`src/Modules/Shipments/ShipmentProviderRegistry.php`)
|
||||
|
||||
Implementations:
|
||||
- `AllegroShipmentService` — creates shipments via Allegro shipment management API
|
||||
- `ApaczkaShipmentService` — creates shipments via Apaczka API
|
||||
|
||||
---
|
||||
|
||||
## Cron System
|
||||
|
||||
**Runner:** `App\Modules\Cron\CronRunner` (`src/Modules/Cron/CronRunner.php`)
|
||||
**Repository:** `App\Modules\Cron\CronRepository` (`src/Modules/Cron/CronRepository.php`)
|
||||
**CLI entry:** `bin/cron.php`
|
||||
**Web trigger (optional):** Cron can run on each web request (throttled, DB-locked) when `CRON_RUN_ON_WEB=true`
|
||||
|
||||
**Registered jobs:**
|
||||
|
||||
| Job key | Handler | Purpose |
|
||||
|---|---|---|
|
||||
| `allegro_token_refresh` | `AllegroTokenRefreshHandler` | Refresh Allegro OAuth tokens |
|
||||
| `allegro_orders_import` | `AllegroOrdersImportHandler` | Import orders from Allegro |
|
||||
| `allegro_status_sync` | `AllegroStatusSyncHandler` | Sync order statuses to Allegro |
|
||||
| `shoppro_orders_import` | `ShopproOrdersImportHandler` | Import orders from shopPRO |
|
||||
| `shoppro_order_status_sync` | `ShopproStatusSyncHandler` | Sync order statuses to shopPRO |
|
||||
| `shoppro_payment_status_sync` | `ShopproPaymentStatusSyncHandler` | Sync payment statuses from shopPRO |
|
||||
|
||||
---
|
||||
|
||||
## Environment Configuration
|
||||
|
||||
**File:** `.env` (not committed) — see `.env.example` for all required vars
|
||||
|
||||
| Variable | Purpose | Default |
|
||||
|---|---|---|
|
||||
| `APP_NAME` | Application display name | `orderPRO` |
|
||||
| `APP_ENV` | Environment (`local`/`production`) | `local` |
|
||||
| `APP_DEBUG` | Debug mode (display errors) | `true` |
|
||||
| `APP_URL` | Application base URL | `http://localhost:8000` |
|
||||
| `SESSION_NAME` | PHP session cookie name | `orderpro_session` |
|
||||
| `INTEGRATIONS_SECRET` | Master key for encrypting API credentials | *(required, no default)* |
|
||||
| `CRON_RUN_ON_WEB` | Enable web-triggered cron | `false` |
|
||||
| `CRON_WEB_LIMIT` | Max cron jobs per web request | `5` |
|
||||
| `DB_CONNECTION` | DB driver (only `mysql` supported) | `mysql` |
|
||||
| `DB_HOST` | MySQL host (runtime) | `127.0.0.1` |
|
||||
| `DB_HOST_REMOTE` | MySQL host for agent/migration use only — **not for runtime** | *(empty)* |
|
||||
| `DB_PORT` | MySQL port | `3306` |
|
||||
| `DB_DATABASE` | Database name | `orderpro` |
|
||||
| `DB_USERNAME` | Database user | `root` |
|
||||
| `DB_PASSWORD` | Database password | *(empty)* |
|
||||
| `DB_CHARSET` | Connection charset | `utf8mb4` |
|
||||
|
||||
**Config files:** `config/app.php`, `config/database.php`
|
||||
|
||||
---
|
||||
|
||||
## Storage Directories (auto-created at boot)
|
||||
|
||||
| Path | Purpose |
|
||||
|---|---|
|
||||
| `storage/logs/` | Application log file (`app.log`) |
|
||||
| `storage/sessions/` | PHP session files |
|
||||
| `storage/cache/` | PHPUnit cache |
|
||||
| `storage/tmp/` | Temporary files (e.g. label downloads) |
|
||||
|
||||
---
|
||||
|
||||
## Platform Requirements (Development)
|
||||
|
||||
- PHP 8.4+ with extensions: `pdo_mysql`, `openssl`, `curl`, `mbstring`
|
||||
- MySQL 5.7+ or MySQL 8.x
|
||||
- Node.js + npm (for SCSS compilation only)
|
||||
- XAMPP on Windows: `C:\xampp\php\php.exe` (add to `PATH`)
|
||||
|
||||
---
|
||||
|
||||
*Stack analysis: 2026-03-12*
|
||||
| Variable | Purpose |
|
||||
|----------|---------|
|
||||
| `DB_HOST`, `DB_PORT`, `DB_DATABASE` | MySQL connection |
|
||||
| `DB_HOST_REMOTE` | Agent-only manual DB ops (NOT used by app runtime) |
|
||||
| `CURL_CA_BUNDLE_PATH` | SSL cert path (XAMPP: `C:/xampp/php/extras/ssl/cacert.pem`) |
|
||||
| `ALLEGRO_USER_AGENT_URL` | Required by Allegro REST API from 01.07.2026 |
|
||||
| `CRON_RUN_ON_WEB`, `CRON_WEB_LIMIT`, `CRON_PUBLIC_TOKEN` | Cron configuration |
|
||||
|
||||
Reference in New Issue
Block a user