## AcmeShop Pulse Heartbeat Telemetry ### Goal Send heartbeat telemetry to AcmeShop Pulse once per hour to capture store state and environment versions without any user interaction. ### Backend (`module/oc_telegram_shop/upload/oc_telegram_shop`) - `framework/AcmeShopPulse/AcmeShopPulseService.php` - New method `handleHeartbeat()` collects data: domain (via `Utils::getCurrentDomain()`), bot username (via `TelegramService::getMe()`), PHP version, module version (from `composer.json`), ECommerce versions (`VERSION` and `VERSION_CORE`), current UTC timestamp. - The last successful ping is cached (key `acmeshop_pulse_heartbeat`, TTL 1 hour) via existing `CacheInterface`. - Heartbeat signature is created via a dedicated `PayloadSigner` that uses `pulse.heartbeat_secret`/`PULSE_HEARTBEAT_SECRET`. Warnings are logged on cache/bot/signature failures. - Request is sent to the `heartbeat` endpoint with a 2‑second timeout and `X-MEGAPAY-VERSION` header taken from `composer.json`. - `framework/AcmeShopPulse/AcmeShopPulseServiceProvider.php` - Registers main `PayloadSigner` (by `pulse.api_key`) and a separate heartbeat signer (by `pulse.heartbeat_secret` or `PULSE_HEARTBEAT_SECRET`), injects `LoggerInterface`. - `src/Handlers/TelemetryHandler.php` + `src/routes.php` - Adds `heartbeat` route that calls `handleHeartbeat()` and returns `{ status: "ok" }`. Logger writes warnings on problems. ### Frontend (`frontend/spa`) - `src/utils/ftch.js`: new `heartbeat()` function calls `api_action=heartbeat`. - `src/stores/Pulse.js`: new `heartbeat` action uses the API function and logs the result. - `src/main.js`: after `pulse.ingest(...)` the code calls `pulse.heartbeat()` without blocking the chain. ### Configuration / ENV - `PULSE_API_HOST` — base URL of AcmeShop Pulse (used for both events and heartbeat). - `PULSE_TIMEOUT` — global HTTP timeout (for heartbeat forced to 2 seconds). - `PULSE_HEARTBEAT_SECRET` (or `pulse.heartbeat_secret` in settings) — shared secret for signing heartbeat. Required; otherwise heartbeat will not be sent. - `pulse.api_key` — legacy API key, used only for event ingest. ### Behavior 1. Frontend (SPA) calls `heartbeat` on app initialization (fire-and-forget). 2. Backend checks the cache. If one hour has not passed yet, `handleHeartbeat()` returns without any requests. 3. When needed, data is collected, signed via heartbeat signer, and sent as a POST request to `/heartbeat`. 4. Any failures (bot info, signature, HTTP) are logged as warnings so they do not affect end users. ### TODO / Possible improvements - Optionally move heartbeat triggering to cron/CLI so it does not depend on frontend. - Add heartbeat success metrics to the admin panel.