# Architecture & Structure

## Directory Layout

```
shopPRO/
├── autoload/                   # Core application code (custom autoloader)
│   ├── Domain/                 # Business logic — 29 modules
│   ├── Shared/                 # Cross-cutting utilities
│   │   ├── Cache/              # CacheHandler, RedisConnection
│   │   ├── Email/              # Email (PHPMailer wrapper)
│   │   ├── Helpers/            # Static utility methods
│   │   ├── Html/               # HTML escaping/generation
│   │   ├── Image/              # ImageManipulator
│   │   └── Tpl/                # Template engine
│   ├── admin/                  # Admin panel layer
│   │   ├── App.php             # Router & DI factory
│   │   ├── Controllers/        # 28 DI controllers
│   │   ├── Support/            # Forms, TableListRequestFactory
│   │   ├── Validation/         # FormValidator
│   │   └── ViewModels/         # Forms/, Common/
│   ├── front/                  # Frontend layer
│   │   ├── App.php             # Router & DI factory
│   │   ├── LayoutEngine.php    # Placeholder-based layout engine
│   │   ├── Controllers/        # 8 DI controllers
│   │   └── Views/              # 11 static view classes
│   └── api/                    # REST API layer
│       ├── ApiRouter.php       # Auth + routing
│       └── Controllers/        # 4 DI controllers
├── admin/
│   ├── index.php               # Admin entry point
│   ├── ajax.php                # Admin AJAX handler
│   ├── templates/              # Admin view templates
│   └── layout/                 # Admin CSS/JS/icons
├── templates/                  # Frontend view templates
├── libraries/                  # Third-party libraries
├── tests/                      # PHPUnit test suite
├── docs/                       # Technical documentation
├── index.php                   # Frontend entry point
├── ajax.php                    # Frontend AJAX handler
├── api.php                     # REST API entry point
├── cron.php                    # Background job processor
└── config.php                  # DB/Redis config (NOT in repo)
```

## Autoloader

Custom autoloader in each entry point — tries two conventions:
1. `autoload/{namespace}/class.{ClassName}.php` (legacy)
2. `autoload/{namespace}/{ClassName}.php` (PSR-4 style, preferred)

**Namespace → directory mapping (case-sensitive on Linux):**
- `\Domain\` → `autoload/Domain/`
- `\admin\` → `autoload/admin/` (**lowercase a** — never `\Admin\`)
- `\front\` → `autoload/front/`
- `\api\` → `autoload/api/`
- `\Shared\` → `autoload/Shared/`

## Dependency Injection

Manual factory pattern in router classes. Each entry point wires dependencies once:

```php
// Example from admin\App::getControllerFactories()
'ShopProduct' => function() {
    global $mdb;
    return new \admin\Controllers\ShopProductController(
        new \Domain\Product\ProductRepository($mdb),
        new \Domain\Integrations\IntegrationsRepository($mdb),
        new \Domain\Languages\LanguagesRepository($mdb)
    );
}
```

DI wiring locations:
- Admin: `autoload/admin/App.php` → `getControllerFactories()`
- Frontend: `autoload/front/App.php` → `getControllerFactories()`
- API: `autoload/api/ApiRouter.php` → `getControllerFactories()`

## Routing

### Admin (`\admin\App`)
- URL: `/admin/?module=shop_product&action=view_list`
- `module` → PascalCase (`shop_product` → `ShopProduct`) → controller lookup
- `action` → method call on controller
- Auth checked before routing; 2FA supported

### Frontend (`\front\App`)
- Routes stored in `pp_routes` table (regex patterns, cached in Redis as `pp_routes:all`)
- Match URI → extract destination params → merge with `$_GET`
- Special params: `?product=ID`, `?category=ID`, `?article=ID`
- Controller dispatch via `getControllerFactories()`
- Unmatched → static page content

### API (`\api\ApiRouter`)
- URL: `/api.php?endpoint=orders&action=getOrders`
- Stateless — auth via `X-Api-Key` header (`hash_equals()`)
- `endpoint` → controller, `action` → method

## Request Lifecycle (Frontend)

```
HTTP GET /produkt/nazwa-produktu
  → index.php (autoload, init Medoo, session, language)
  → Fetch pp_routes from Redis (or DB)
  → Regex match → extract ?product=123
  → front\LayoutEngine::show()
    → Determine layout (pp_layouts)
    → Replace placeholders [MENU:ID], [BANER_STRONA_GLOWNA], etc.
    → Call view classes / repositories for each placeholder
  → Output HTML (with GTM, meta OG, WebP, lazy loading)
```

## Request Lifecycle (Admin)

```
HTTP GET /admin/?module=shop_order&action=view_list
  → admin/index.php (IP check, session, auth cookie check)
  → admin\App::update() (run pending DB migrations)
  → admin\App::special_actions() (handle s-action=user-logon etc.)
  → admin\App::render()
    → Auth check → if not logged in, show login form
    → admin\App::route()
      → 'shop_order' → ShopOrder → factory()
      → new ShopOrderController(OrderAdminService, ProductRepository)
      → ShopOrderController::viewList()
      → Tpl::view('shop-order/orders-list', [...])
    → Tpl::render('site/main-layout', ['content' => $html])
  → Output admin HTML
```

## Domain Modules (29)

All in `autoload/Domain/{Module}/{Module}Repository.php`:

| Module | Repository | Notes |
|--------|-----------|-------|
| Article | ArticleRepository | Blog/news |
| Attribute | AttributeRepository | Product attributes (color, size) |
| Banner | BannerRepository | Promo banners |
| Basket | (static) | Cart calculations |
| Cache | (utilities) | Cache key constants |
| Category | CategoryRepository | Category tree |
| Client | ClientRepository | Customer accounts |
| Coupon | CouponRepository | Discount codes |
| CronJob | CronJobRepository, CronJobProcessor | Job queue |
| Dashboard | DashboardRepository | Admin stats |
| Dictionaries | DictionariesRepository | Units, enums |
| Integrations | IntegrationsRepository | Apilo, Ekomi (**875 lines — too large**) |
| Languages | LanguagesRepository | i18n translations |
| Layouts | LayoutsRepository | Page templates |
| Newsletter | NewsletterRepository, NewsletterPreviewRenderer | Email campaigns |
| Order | OrderRepository, OrderAdminService | Orders, status |
| Pages | PagesRepository | Static pages |
| PaymentMethod | PaymentMethodRepository | Payment gateways |
| Producer | ProducerRepository | Brands |
| Product | ProductRepository | Core catalog (**3583 lines — too large**) |
| ProductSet | ProductSetRepository | Bundles |
| Promotion | PromotionRepository | Special offers |
| Scontainers | ScontainersRepository | Content blocks |
| Settings | SettingsRepository | Shop config |
| ShopStatus | ShopStatusRepository | Order statuses |
| Transport | TransportRepository | Shipping |
| Update | UpdateRepository | DB migrations |
| User | UserRepository | Admin users, 2FA |

## Admin Controllers (28)

All in `autoload/admin/Controllers/`:
`ArticlesController`, `ArticlesArchiveController`, `BannerController`, `DashboardController`, `DictionariesController`, `FilemanagerController`, `IntegrationsController`, `LanguagesController`, `LayoutsController`, `NewsletterController`, `PagesController`, `ProductArchiveController`, `ScontainersController`, `SettingsController`, `ShopAttributeController`, `ShopCategoryController`, `ShopClientsController`, `ShopCouponController`, `ShopOrderController`, `ShopPaymentMethodController`, `ShopProducerController`, `ShopProductController` (1199 lines), `ShopProductSetsController`, `ShopPromotionController`, `ShopStatusesController`, `ShopTransportController`, `UpdateController`, `UsersController`

## Frontend Controllers (8)

`autoload/front/Controllers/`: `NewsletterController`, `SearchController`, `ShopBasketController`, `ShopClientController`, `ShopCouponController`, `ShopOrderController`, `ShopProducerController`, `ShopProductController`

## Frontend Views (11, static)

`autoload/front/Views/`: `Articles`, `Banners`, `Languages`, `Menu`, `Newsletter`, `Scontainers`, `ShopCategory`, `ShopClient`, `ShopPaymentMethod`, `ShopProduct`, `ShopSearch`

## API Controllers (4)

`autoload/api/Controllers/`: `OrdersApiController`, `ProductsApiController`, `CategoriesApiController`, `DictionariesApiController`

## Template System

### Tpl Engine (`\Shared\Tpl\Tpl`)
```php
// Controller
return \Shared\Tpl\Tpl::view('shop-category/category-edit', [
    'category' => $data,
    'languages' => $langs,
]);

// Template (templates/shop-category/category-edit.php)
<h1><?= $this->category['name'] ?></h1>
```

Search order: `templates_user/`, `templates/`, `../templates_user/`, `../templates/`

### Frontend Layout Engine (`\front\LayoutEngine`)
Replaces placeholders in layout HTML loaded from `pp_layouts.html`:
- `[MENU:ID]`, `[KONTENER:ID]`, `[LANG:key]`
- `[PROMOWANE_PRODUKTY:limit]`, `[PRODUKTY_TOP:limit]`, `[PRODUKTY_NEW:limit]`
- `[BANER_STRONA_GLOWNA]`, `[BANERY]`, `[COPYRIGHT]`
- `[AKTUALNOSCI:layout_id:limit]`, `[PRODUKTY_KATEGORIA:cat_id:limit]`

## Admin Form System

Universal form system for CRUD views. Full docs: `docs/FORM_EDIT_SYSTEM.md`.

| Component | Class | Location |
|-----------|-------|----------|
| View model | `FormEditViewModel` | `autoload/admin/ViewModels/Forms/` |
| Field definition | `FormField` | same |
| Field type enum | `FormFieldType` | same |
| Tab | `FormTab` | same |
| Action | `FormAction` | same |
| Validation | `FormValidator` | `autoload/admin/Validation/` |
| POST parsing | `FormRequestHandler` | `autoload/admin/Support/Forms/` |
| Rendering | `FormFieldRenderer` | `autoload/admin/Support/Forms/` |
| Template | `form-edit.php` | `admin/templates/components/` |

## Authentication

### Admin
- Session: `$_SESSION['user']` after successful login
- 2FA: 6-digit code sent by email; `twofa_pending` in session during verification
- Remember Me: 14-day HMAC-SHA256 signed cookie

### API
- Stateless; `X-Api-Key` header vs `pp_settings.api_key` via `hash_equals()`

### Frontend
- Customer session in `$_SESSION['client']`
- IP validation on every request (`$_SESSION['ip']` vs `REMOTE_ADDR`)
