# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview shopPRO is a PHP e-commerce platform with an admin panel and customer-facing storefront. It uses Medoo ORM (`$mdb`), Redis caching, and a Domain-Driven Design architecture with Dependency Injection (migration from legacy architecture complete). ## Zasady pisania kodu - Kod ma być czytelny „dla obcego”: jasne nazwy, mało magii - Brak „skrótów na szybko” typu logika w widokach, copy-paste, losowe helpery bez spójności - Każda funkcja/klasa ma mieć jedną odpowiedzialność, zwykle do 30–50 linii (jeśli dłuższe – dzielić) - max 3 poziomy zagnieżdżeń (if/foreach), reszta do osobnych metod - Nazewnictwo: - klasy: PascalCase - metody/zmienne: camelCase - stałe: UPPER_SNAKE_CASE - Zero „skrótologii” w nazwach (np. $d, $tmp, $x1) poza pętlami 2–3 linijki - medoo + prepared statements bez wyjątków (żadnego sklejania SQL stringiem) - XSS: escape w widokach (np. helper e()) - CSRF dla formularzy, sensowna obsługa sesji - Kod ma mieć komentarze tylko tam, gdzie wyjaśniają „dlaczego”, nie „co” ## PHP Version Constraint **Production runs PHP < 8.0.** Do NOT use: - `match` expressions (use ternary operators or if/else) - Named arguments - Union types (`int|string`) - `str_contains()`, `str_starts_with()`, `str_ends_with()` - Other PHP 8.0+ syntax `composer.json` requires `>=7.4`. ## Commands ### Running Tests ```bash # Full suite (recommended — PowerShell, auto-finds php) ./test.ps1 # Specific file ./test.ps1 tests/Unit/Domain/Product/ProductRepositoryTest.php # Specific test method ./test.ps1 --filter testGetQuantityReturnsCorrectValue # Alternatives composer test # standard ./test.bat # testdox (readable list) ./test-simple.bat # dots ./test-debug.bat # debug output ./test.sh # Git Bash ``` PHPUnit 9.6 via `phpunit.phar`. Bootstrap: `tests/bootstrap.php`. Config: `phpunit.xml`. Current suite: **820 tests, 2277 assertions**. ### Creating Updates See `docs/UPDATE_INSTRUCTIONS.md` for the full procedure. Updates are ZIP packages in `updates/0.XX/`. Never include `*.md` files, `updates/changelog.php`, or root `.htaccess` in update ZIPs. ZIP structure must start directly from project directories — no version subfolder inside the archive. ## Architecture ### Directory Structure ``` shopPRO/ ├── autoload/ # Autoloaded classes (core codebase) │ ├── Domain/ # Business logic repositories (\Domain\) │ ├── Shared/ # Shared utilities (\Shared\) │ │ ├── Cache/ # CacheHandler, RedisConnection │ │ ├── Email/ # Email (PHPMailer wrapper) │ │ ├── Helpers/ # Helpers (formerly class.S.php) │ │ ├── Html/ # Html utility │ │ ├── Image/ # ImageManipulator │ │ └── Tpl/ # Template engine │ ├── api/ # REST API layer (\api\) │ │ ├── ApiRouter.php # API router (\api\ApiRouter) │ │ └── Controllers/ # API controllers (\api\Controllers\) │ ├── admin/ # Admin panel layer │ │ ├── App.php # Admin router (\admin\App) │ │ ├── Controllers/ # DI controllers (\admin\Controllers\) — 28 controllers │ │ ├── Support/ # TableListRequestFactory, Forms/FormRequestHandler, Forms/FormFieldRenderer │ │ ├── Validation/ # FormValidator │ │ └── ViewModels/ # Forms/ (FormEditViewModel, FormField, FormTab, FormAction, FormFieldType), Common/ (PaginatedTableViewModel) │ └── front/ # Frontend layer │ ├── App.php # Frontend router (\front\App) │ ├── LayoutEngine.php # Layout engine (\front\LayoutEngine) │ ├── Controllers/ # DI controllers (\front\Controllers\) — 8 controllers │ └── Views/ # Static views (\front\Views\) — 11 view classes ├── admin/ # Admin panel │ ├── templates/ # Admin view templates │ └── layout/ # Admin CSS/JS/icons ├── templates/ # Frontend view templates ├── libraries/ # Third-party libraries (Medoo, RedBeanPHP, PHPMailer) ├── tests/ # PHPUnit tests │ ├── bootstrap.php │ ├── stubs/ # Test stubs (CacheHandler, Helpers, ShopProduct) │ └── Unit/ │ ├── Domain/ # Repository tests │ ├── admin/Controllers/ # Controller tests │ └── api/ # API tests ├── updates/ # Update packages for clients ├── docs/ # Technical documentation ├── config.php # Database/Redis config (not in repo) ├── index.php # Frontend entry point ├── ajax.php # Frontend AJAX handler ├── admin/index.php # Admin entry point ├── admin/ajax.php # Admin AJAX handler ├── cron.php # CRON jobs (Apilo sync) └── api.php # REST API (ordersPRO + Ekomi) ``` ### Autoloader Custom autoloader in each entry point (not Composer autoload at runtime). Tries two filename conventions: 1. `autoload/{namespace}/class.{ClassName}.php` (legacy) 2. `autoload/{namespace}/{ClassName}.php` (PSR-4 style, fallback) ### Namespace Conventions (case-sensitive on Linux!) - `\Domain\` → `autoload/Domain/` (uppercase D) - `\admin\Controllers\` → `autoload/admin/Controllers/` (lowercase a) - `\Shared\` → `autoload/Shared/` - `\api\` → `autoload/api/` - Do NOT use `\Admin\` (uppercase A) — the server directory is `admin/` (lowercase) - `\shop\` namespace is **deleted** — all 12 legacy classes migrated to `\Domain\`, `autoload/shop/` directory removed ### Domain-Driven Architecture (migration complete) All legacy directories (`admin/controls/`, `admin/factory/`, `admin/view/`, `front/controls/`, `front/view/`, `front/factory/`, `shop/`) have been deleted. All modules now use this pattern: **Domain Layer** (`autoload/Domain/{Module}/`): - `{Module}Repository.php` — data access, business logic, Redis caching - Constructor DI with `$db` (Medoo instance) - Methods serve both admin and frontend (shared Domain, no separate services) **Domain Modules**: Article, Attribute, Banner, Basket, Cache, Category, Client, Coupon, CronJob, Dashboard, Dictionaries, Integrations, Languages, Layouts, Newsletter, Order, Pages, PaymentMethod, Producer, Product, ProductSet, Promotion, Scontainers, Settings, ShopStatus, Transport, Update, User **Admin Controllers** (`autoload/admin/Controllers/`): - DI via constructor (repositories injected) - Wired in `admin\App::getControllerFactories()` **Frontend Controllers** (`autoload/front/Controllers/`): - DI via constructor - Wired in `front\App::getControllerFactories()` **Frontend Views** (`autoload/front/Views/`): - Static classes, no state, no DI — pure rendering **API Controllers** (`autoload/api/Controllers/`): - DI via constructor, stateless (no session) - Wired in `api\ApiRouter::getControllerFactories()` - Auth: `X-Api-Key` header vs `pp_settings.api_key` ### Key Classes | Class | Purpose | |-------|---------| | `\admin\App` | Admin router — maps URL segments to controllers | | `\front\App` | Frontend router — `route()`, `checkUrlParams()` | | `\front\LayoutEngine` | Frontend layout engine — `show()`, tag replacement | | `\Shared\Helpers\Helpers` | Utility methods (SEO, email, cache clearing) | | `\Shared\Tpl\Tpl` | Template engine — `render()`, `set()` | | `\Shared\Cache\CacheHandler` | Redis cache — `get()`, `set()`, `delete()`, `deletePattern()` | | `\api\ApiRouter` | REST API router — auth, routing, response helpers | ### Database - ORM: Medoo (`$mdb` global variable, injected via DI in new code) - Table prefix: `pp_` - Key tables: `pp_shop_products`, `pp_shop_orders`, `pp_shop_categories`, `pp_shop_clients` - Full schema: `docs/DATABASE_STRUCTURE.md` ### Form Edit System Universal form system for admin edit views. Docs: `docs/FORM_EDIT_SYSTEM.md`. - **ViewModels** (`admin\ViewModels\Forms\`): `FormEditViewModel`, `FormField`, `FormTab`, `FormAction`, `FormFieldType` - **Validation**: `admin\Validation\FormValidator` - **Rendering**: `admin\Support\Forms\FormFieldRenderer`, `admin\Support\Forms\FormRequestHandler` - **Template**: `admin/templates/components/form-edit.php` - **Table lists**: `admin\Support\TableListRequestFactory` + `admin\ViewModels\Common\PaginatedTableViewModel` ### Caching - Redis via `\Shared\Cache\CacheHandler` (singleton `RedisConnection`) - Key pattern for products: `shop\product:{id}:{lang}:{permutation_hash}` - Clear product cache: `\Shared\Helpers\Helpers::clear_product_cache($id)` - Pattern delete: `CacheHandler::deletePattern("shop\\product:{$id}:*")` - Default TTL: 86400 (24h) - Data is serialized — requires `unserialize()` after `get()` - Config: `config.php` (`$config['redis']`) ## Code Patterns ### New code should follow DI pattern ```php // Repository with constructor DI class ExampleRepository { private $db; public function __construct($db) { $this->db = $db; } public function find(int $id): ?array { return $this->db->get('pp_table', '*', ['id' => $id]); } } // Controller wiring (in admin\App or front\App) $repo = new \Domain\Example\ExampleRepository($mdb); $controller = new \admin\Controllers\ExampleController($repo); ``` ### Medoo ORM pitfalls - `$mdb->delete($table, $where)` takes **2 arguments**, NOT 3 — has caused bugs - `$mdb->get()` returns `null` when no record, NOT `false` - After `$mdb->insert()`, check `$mdb->id()` to confirm success ### File naming - New classes: `ClassName.php` (no `class.` prefix) - Legacy classes: `class.ClassName.php` (leave until migrated) ### Test conventions - Extend `PHPUnit\Framework\TestCase` - Mock Medoo: `$this->createMock(\medoo::class)` - AAA pattern: Arrange, Act, Assert - Tests mirror source structure: `tests/Unit/Domain/{Module}/{Class}Test.php` ## Workflow When user says **"KONIEC PRACY"**, run `/koniec-pracy` (see `.claude/commands/koniec-pracy.md`). Before starting implementation, review current state of docs. ## Key Documentation - `docs/MEMORY.md` — project memory: known issues, confirmed patterns, ORM pitfalls, caching conventions - `docs/PROJECT_STRUCTURE.md` — current architecture, layers, cache, entry points, integrations - `docs/DATABASE_STRUCTURE.md` — full database schema - `docs/TESTING.md` — test suite guide and structure - `docs/FORM_EDIT_SYSTEM.md` — form system architecture - `docs/CLASS_CATALOG.md` — full catalog of all classes with descriptions - `docs/TODO.md` — outstanding tasks and planned features - `docs/CRON_QUEUE_PLAN.md` — planned cron/queue architecture - `docs/CHANGELOG.md` — version history - `api-docs/api-reference.json` — REST API documentation (ordersPRO) - `api-docs/index.html` — REST API documentation (ordersPRO) - `docs/UPDATE_INSTRUCTIONS.md` — how to build client update packages ## Za każdym razem jak próbujesz sprawdzić jakiś plik z logami spróbuj go najpierw pobrać z serwera FTP ## Wszystkie pliki które tworzysz jako pomocnicze, np build_0330.ps1 czy build-update.ps1 twórz w folderze temp