6.0 KiB
Architecture
Entry points
| File | Purpose |
|---|---|
| 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 handler. Same autoloader. Session regeneration on first request, IP binding check (lines 28-33). Responses: echo json_encode(...); exit. |
| api.php | External API endpoints (~1350 lines). Uses RedBeanPHP. Helpers api_json_response() and api_validate_api_key(). |
| 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']:
- Apply
$route_aliasesmap (e.g./login→users/login_form). - Fallback:
/$seg0/$seg1→module=$seg0,action=$seg1. - Default:
campaigns/main_view. \controls\Site::route()instantiates\controls\{Module}and calls action method.
Layers
Controllers — autoload/controls/ (namespace \controls)
Static action methods. Pattern:
$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.Products.php, autoload/controls/class.Cron.php (~5,200 lines — see concerns.md).
Factories — autoload/factory/ (namespace \factory)
Static methods wrapping $mdb queries. Examples:
- autoload/factory/class.Campaigns.php (~400 lines)
- autoload/factory/class.Products.php (~1,540 lines)
- autoload/factory/class.Logs.php
Services — autoload/services/ (namespace \services)
External API integrations (see integrations.md).
Views — autoload/view/ (namespace \view)
Thin orchestrators. 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/ (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 storeclients— merchant accounts (Google Ads Customer ID, Merchant ID)campaigns,campaigns_history— campaign metadata + daily snapshotscron_sync_status— pipeline phase tracking (pending → fetch → aggregate_30 → done)campaign_alerts,campaign_search_terms_history,campaign_ad_groups,campaign_keywords,campaign_negative_keywordsproducts,products_aggregate,products_keyword_planner_terms,products_merchant_sync_loglogs— 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().