11 KiB
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:
matchexpressions (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
# 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
# Alternative
composer test
PHPUnit 9.6 via phpunit.phar. Bootstrap: tests/bootstrap.php. Config: phpunit.xml.
Current suite: 805 tests, 2253 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.
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:
autoload/{namespace}/class.{ClassName}.php(legacy)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 isadmin/(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-Keyheader vspp_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 (
$mdbglobal 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(singletonRedisConnection) - 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()afterget() - Config:
config.php($config['redis'])
Code Patterns
New code should follow DI pattern
// 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()returnsnullwhen no record, NOTfalse- After
$mdb->insert(), check$mdb->id()to confirm success
File naming
- New classes:
ClassName.php(noclass.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 conventionsdocs/PROJECT_STRUCTURE.md— current architecture, layers, cache, entry points, integrationsdocs/DATABASE_STRUCTURE.md— full database schemadocs/TESTING.md— test suite guide and structuredocs/FORM_EDIT_SYSTEM.md— form system architecturedocs/CHANGELOG.md— version historyapi-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