# Technology Stack & Integrations ## Languages | Language | Version | Notes | |----------|---------|-------| | PHP | 7.4 – <8.0 | Production constraint — no PHP 8.0+ syntax | | JavaScript | ES5 + jQuery 2.1.3 | No modern framework | | CSS | Bootstrap 4.x (pre-compiled SCSS) | No build pipeline | **PHP 8.0+ features explicitly forbidden:** - `match` expressions → use ternary / if-else - Named arguments - Union types (`int|string`) → use single type + docblock - `str_contains()`, `str_starts_with()`, `str_ends_with()` → use `strpos()` ## Core Libraries | Library | Version | Location | Purpose | |---------|---------|----------|---------| | Medoo | 1.7.10 | `libraries/medoo/medoo.php` | Database ORM | | PHPMailer | classic | `libraries/phpmailer/` | Email sending | | RedBeanPHP | — | `libraries/rb.php` | Legacy ORM — **unused, candidate for removal** | ## Frontend Libraries | Library | Location | Purpose | |---------|----------|---------| | jQuery | 2.1.3 | DOM / AJAX | | jQuery Migrate | 1.0.0 | Backward compat | | Bootstrap | 4.1.3 / 4.5.2 | `libraries/bootstrap*/` | | CKEditor | 4.x | `libraries/ckeditor/` | Rich text editor | | ApexCharts | — | `libraries/apexcharts/` | Admin charts | | FancyBox | 2 + 3 | `libraries/fancyBox/`, `fancybox3/` | Lightbox | | Plupload | — | `libraries/plupload/` | File uploads | | Selectize.js | — | — | Select dropdowns | | Lozad.js | — | — | Lazy loading | | Swiper | — | — | Carousel/slider | | CodeMirror | — | `libraries/codemirror/` | Code editor | | Font Awesome | 5.7.0 | `libraries/fontawesome-5.7.0/` | Icons | | File Manager | 9.14.1 & 9.14.2 | `libraries/filemanager-9.14.*/` | File browsing | ## Database - **ORM**: Medoo 1.7.10 (custom-extended with Redis support) - **Engine**: MySQL - **Table prefix**: `pp_` - **Connection**: `new medoo([...])` in each entry point via credentials from `config.php` - **Key tables**: `pp_shop_products`, `pp_shop_orders`, `pp_shop_categories`, `pp_shop_clients` ## Caching - **Technology**: Redis - **PHP extension**: Native `Redis` class - **Wrapper**: `\Shared\Cache\CacheHandler` (singleton via `RedisConnection`) - **Config**: `config.php` → `$config['redis']['host/port/password']` - **Serialization**: PHP `serialize()` / `unserialize()` - **Default TTL**: 86400 seconds (24h) - **Key patterns**: - `shop\product:{id}:{lang_id}:{hash}` — product details - `ProductRepository::getProductPermutationQuantityOptions:v2:{id}:*` - `pp_routes:all` — URL routing patterns - `pp_settings_cache` — shop settings ## Email - **Library**: PHPMailer (classic, not v6) - **Config**: `config.php` (host, port, login, password) - **Helpers**: - `\Shared\Helpers\Helpers::send_email($to, $subject, $text, $reply, $file)` - `\Shared\Email\Email::send(...)` — newsletter / template-based - **Issue**: Duplicate PHPMailer logic in both classes — should be unified ## HTTP Client - **Technology**: Native PHP cURL (`curl_init`, `curl_setopt`, `curl_exec`) - **No abstraction library** (no Guzzle, Symfony HTTP Client) - **Used in**: `IntegrationsRepository.php` (Apilo calls), `cron.php` (image downloads) ## Dev & Build Tools | Tool | Purpose | |------|---------| | Composer | PHP dependency management | | PHPUnit 9.6 | Testing (`phpunit.phar`) | | PowerShell `test.ps1` | Recommended test runner | | No webpack/Vite/Gulp | SCSS pre-compiled, assets served as-is | ## External Integrations ### Apilo (ERP/WMS) - **Auth**: OAuth 2.0 Bearer token (client_id + client_secret from `pp_shop_apilo_settings`) - **Base URL**: `https://projectpro.apilo.com/rest/api/` - **Sync operations**: order sending, payment sync, status polling, product qty/price sync, pricelist sync - **Code**: `autoload/Domain/Integrations/IntegrationsRepository.php` - **Cron jobs**: `APILO_SEND_ORDER`, `APILO_SYNC_PAYMENT`, `APILO_STATUS_POLL`, `APILO_PRODUCT_SYNC`, `APILO_PRICELIST_SYNC` - **Logging**: `\Domain\Integrations\ApiloLogger` → `pp_log` table ### Ekomi (Reviews) - **Type**: CSV export - **Code**: `api.php` → generates `/ekomi/ekomi-{date}.csv` ### TrustMate (Review Invitations) - **Type**: Browser-based (requires JS execution) - **Code**: `cron.php` (line ~741), `cron-trustmate.php` - **Config**: `$config['trustmate']['enabled']` ### Google Shopping Feed - **Type**: XML feed generation - **Cron job**: `GOOGLE_XML_FEED` - **Code**: `cron.php` → `ProductRepository::generateGoogleFeedXml()` ### shopPRO Product Import - **Type**: Direct MySQL connection to remote shopPRO instance - **Config**: `pp_shop_shoppro_settings` (domain, db credentials) - **Code**: `IntegrationsRepository.php` (lines 668–850) - **Logs**: `/logs/shoppro-import-debug.log` ### REST API (ordersPRO — outbound) - **Auth**: `X-Api-Key` header - **Endpoints**: orders (list/get/status/paid), products (list/get), dictionaries, categories - **Code**: `api.php` → `autoload/api/ApiRouter.php` → `autoload/api/Controllers/` ## Cron Job System | Job Type | Purpose | |----------|---------| | `APILO_TOKEN_KEEPALIVE` | OAuth token refresh | | `APILO_SEND_ORDER` | Sync orders to Apilo (priority 40) | | `APILO_SYNC_PAYMENT` | Sync payment status | | `APILO_STATUS_POLL` | Poll order status changes | | `APILO_PRODUCT_SYNC` | Update product qty & prices | | `APILO_PRICELIST_SYNC` | Update pricelist | | `PRICE_HISTORY` | Record price history | | `ORDER_ANALYSIS` | Order/product correlation | | `TRUSTMATE_INVITATION` | Review invitations | | `GOOGLE_XML_FEED` | Google Shopping XML | - **Priority levels**: CRITICAL(10), HIGH(50), NORMAL(100), LOW(200) - **Backoff**: Exponential on failure (60s → 3600s max) - **Storage**: `pp_cron_jobs` table