update
This commit is contained in:
109
.paul/codebase/architecture.md
Normal file
109
.paul/codebase/architecture.md
Normal file
@@ -0,0 +1,109 @@
|
||||
# Architecture
|
||||
|
||||
## Entry points
|
||||
|
||||
| File | Purpose |
|
||||
|---|---|
|
||||
| [index.php](index.php) | Main router. Autoloader (lines 3-12), session init, `$route_aliases` table (lines 40-59), URL-segment fallback (lines 70-79), auth via session or persistent cookie (lines 88-102), public-path whitelist for `/api/*`, `/cron/*`, `/login` (lines 106-118). Default module: `campaigns/main_view`. |
|
||||
| [ajax.php](ajax.php) | AJAX handler. Same autoloader. Session regeneration on first request, IP binding check (lines 28-33). Responses: `echo json_encode(...); exit`. |
|
||||
| [api.php](api.php) | External API endpoints (~1350 lines). Uses RedBeanPHP. Helpers `api_json_response()` and `api_validate_api_key()`. |
|
||||
| [cron.php](cron.php) | Legacy cron. Calls `\Cron::tasks_emails()` and `\Cron::recursive_tasks()`. |
|
||||
|
||||
Modern cron routes (dispatched through index.php → `\controls\Cron`):
|
||||
|
||||
| Route | Purpose |
|
||||
|---|---|
|
||||
| `/cron/cron_universal` | Google Ads campaigns + products daily snapshot |
|
||||
| `/cron/cron_campaigns_product_alerts_merchant` | Product alerts from Merchant Center |
|
||||
| `/cron/cron_products_urls` | Bulk fetch product URLs |
|
||||
| `/cron/cron_facebook_ads` | Facebook Ads sync (30-day window) |
|
||||
| `/cron/cron_xml_feed_import` | Import supplemental/product XML feeds |
|
||||
|
||||
## Routing
|
||||
|
||||
`index.php` builds a request URL into `$_GET['module']` and `$_GET['action']`:
|
||||
|
||||
1. Apply `$route_aliases` map (e.g. `/login` → `users/login_form`).
|
||||
2. Fallback: `/$seg0/$seg1` → `module=$seg0`, `action=$seg1`.
|
||||
3. Default: `campaigns/main_view`.
|
||||
4. `\controls\Site::route()` instantiates `\controls\{Module}` and calls action method.
|
||||
|
||||
## Layers
|
||||
|
||||
### Controllers — `autoload/controls/` (namespace `\controls`)
|
||||
|
||||
Static action methods. Pattern:
|
||||
|
||||
```php
|
||||
$id = (int) \S::get('client_id');
|
||||
$rows = \factory\Campaigns::get_campaigns_list($id);
|
||||
echo json_encode($rows); exit; // AJAX
|
||||
return \Tpl::view('campaigns/main_view', ['clients' => $rows]); // page
|
||||
```
|
||||
|
||||
Representative files: [autoload/controls/class.Campaigns.php](autoload/controls/class.Campaigns.php), [autoload/controls/class.Products.php](autoload/controls/class.Products.php), [autoload/controls/class.Cron.php](autoload/controls/class.Cron.php) (~5,200 lines — see [concerns.md](concerns.md)).
|
||||
|
||||
### Factories — `autoload/factory/` (namespace `\factory`)
|
||||
|
||||
Static methods wrapping `$mdb` queries. Examples:
|
||||
|
||||
- [autoload/factory/class.Campaigns.php](autoload/factory/class.Campaigns.php) (~400 lines)
|
||||
- [autoload/factory/class.Products.php](autoload/factory/class.Products.php) (~1,540 lines)
|
||||
- [autoload/factory/class.Logs.php](autoload/factory/class.Logs.php)
|
||||
|
||||
### Services — `autoload/services/` (namespace `\services`)
|
||||
|
||||
External API integrations (see [integrations.md](integrations.md)).
|
||||
|
||||
### Views — `autoload/view/` (namespace `\view`)
|
||||
|
||||
Thin orchestrators. [autoload/view/class.Site.php](autoload/view/class.Site.php) wraps controller output in `site/layout-logged.php`, injecting `campaign_alerts_count`, `user`, `current_module`, flash alerts.
|
||||
|
||||
### Templates — `templates/{module}/`
|
||||
|
||||
Rendered via `\Tpl::view('module/file', $data)`. Lookup order: `templates_user/` (override) → `templates/`. Data accessed in templates as `$this->varName` (magic `__get`). Output captured with `ob_start/ob_get_clean`.
|
||||
|
||||
## Modules
|
||||
|
||||
| Module | Controller | Purpose |
|
||||
|---|---|---|
|
||||
| campaigns | `\controls\Campaigns` | Google Ads campaign list, history, charts, alerts |
|
||||
| products | `\controls\Products` | Merchant Center product feed, AI title/desc suggestions |
|
||||
| clients | `\controls\Clients` | Merchant accounts (Google Ads ID, Merchant ID, settings) |
|
||||
| users | `\controls\Users` | Auth, settings, API key, cron status dashboard |
|
||||
| feeds | `\controls\Feeds` | Supplemental TSV feed generation |
|
||||
| logs | `\controls\Logs` | System event log viewer |
|
||||
| campaign_alerts | `\controls\CampaignAlerts` | AI-detected campaign issues |
|
||||
| campaign_terms | `\controls\CampaignTerms` | Search term aggregation, keyword suggestions |
|
||||
| facebook_ads | `\controls\FacebookAds` | Facebook Ads sync and tracking |
|
||||
| allegro | `\controls\Allegro` | Allegro.pl marketplace integration (legacy) |
|
||||
| cron | `\controls\Cron` | Cron execution dispatcher and status UI |
|
||||
| site | layout only | `layout-logged.php`, `layout-unlogged.php` |
|
||||
| html | components | Reusable form elements (input, textarea, select, etc.) |
|
||||
|
||||
## Database schema (selected)
|
||||
|
||||
Migrations in [migrations/](migrations/) (30+ files, e.g. `001_google_ads_settings.sql`). Tracked in `schema_migrations`. Run via `php install.php` (`--force`, `--with_demo`).
|
||||
|
||||
Key tables:
|
||||
|
||||
- `settings` — global key-value config store
|
||||
- `clients` — merchant accounts (Google Ads Customer ID, Merchant ID)
|
||||
- `campaigns`, `campaigns_history` — campaign metadata + daily snapshots
|
||||
- `cron_sync_status` — pipeline phase tracking (pending → fetch → aggregate_30 → done)
|
||||
- `campaign_alerts`, `campaign_search_terms_history`, `campaign_ad_groups`, `campaign_keywords`, `campaign_negative_keywords`
|
||||
- `products`, `products_aggregate`, `products_keyword_planner_terms`, `products_merchant_sync_log`
|
||||
- `logs` — structured event log (level/source/message/context JSON/client_id)
|
||||
- `facebook_campaigns`, `facebook_campaigns_history`, `facebook_ad_sets`, `facebook_ads`, `facebook_ads_history`
|
||||
|
||||
## Request flow
|
||||
|
||||
**Page (HTML):** request → `.htaccess` → `index.php` → routing → auth → `\view\Site::show()` → `\controls\Site::route()` → controller action → factory → `\Tpl::view(...)` → wrapped in `site/layout-logged.php` → response.
|
||||
|
||||
**AJAX (JSON):** POST/GET → `ajax.php` → session+IP check → controller action → `echo json_encode(...); exit`.
|
||||
|
||||
**Cron (JSON):** external GET → `index.php` (whitelisted) → `\controls\Cron::cron_universal()` → service API call → write to `*_history` + `cron_sync_status` → `self::output_cron_response([...])`.
|
||||
|
||||
## Auth
|
||||
|
||||
Session-based, with persistent cookie. Cookie stores JSON `{email, hash}` (salted). On revisit, `index.php` lines 92-102 verify and rehydrate session. AJAX adds IP binding (`$_SESSION['ip']` vs `$_SERVER['REMOTE_ADDR']`); mismatch → `session_destroy()`.
|
||||
Reference in New Issue
Block a user