# KPI_READINESS

## Table of Contents
- KPI Definitions
- Current Measurement Coverage
- Event Coverage vs KPIs
- Sample Queries
- Gaps and Instrumentation Plan

## KPI Definitions
- p80 AI latency: 80th percentile end-to-end for `/api/ai/respond` per module.
- CTR (Opportunities): `clicked_cta / delivered` from push_logs within window.
- Saved ≥10%: `saved_ads / delivered` for pushed items.
- Activation D1: user performs ≥3 distinct actions within 24h (e.g., Start, ViewDeal, PriceCheck, SaveDeal, ChecklistRun).
- Free→Paid conversion: users with payment `status=ok` / active users in period.
- Payment success rate: ok / (ok + failed) over 7 days.

## Current Measurement Coverage (Current Code)
- AI latency: persisted in `chats` with `token_in`, `token_out`, `latency_ms`, `response_id` when user context is present (AIController). Status: PARTIAL.
- CTR: `push_logs` has `sent_at`/`delivered_at` (PushSchedulerJob); `/api/simulate/click` updates `clicked_cta_at` (local env only). Status: PARTIAL (measurable if delivery recorded).
- Saved ratio: `SavedAdsController` persists saves and emits `SaveDeal`. Status: READY for capture.
- Activation D1: `EventBus::track` currently emits `PriceCheck`, `SaveDeal`, `UpgradeSuccess`; others pending. Status: PARTIAL.
- Free→Paid + Payment success: `PaymentsController@verify` idempotently activates subscription and emits `UpgradeSuccess`. Status: READY.

## Event Coverage vs KPIs
Expected event types (per docs) vs code:
- Start: MISSING
- SelectCity: MISSING
- ViewDeal: MISSING
- SaveDeal: PRESENT (SavedAdsController)
- CallFromCard: MISSING
- PriceCheck: PRESENT (AIController)
- ChecklistRun: MISSING
- PushOpen: MISSING
- UpgradeClick: MISSING
- UpgradeSuccess: PRESENT (Payments verify)
- CancelStart: MISSING
- CancelRescueSuccess: MISSING
- ReferralJoin: MISSING

## Sample Queries

- p80 AI latency (if chats persisted):
```sql
SELECT PERCENTILE_CONT(0.8) WITHIN GROUP (ORDER BY latency_ms)
FROM chats
WHERE module = 'valuation' AND created_at >= NOW() - INTERVAL 1 DAY;
```

- CTR (by campaign, last 7 days):
```sql
SELECT campaign_id,
       COUNT(delivered_at) AS delivered,
       COUNT(clicked_cta_at) AS clicks,
       ROUND(COUNT(clicked_cta_at) / NULLIF(COUNT(delivered_at),0) * 100, 2) AS ctr_pct
FROM push_logs
WHERE sent_at >= NOW() - INTERVAL 7 DAY
GROUP BY campaign_id
ORDER BY campaign_id;
```

- Saved ≥10% (week-1):
```sql
WITH delivered AS (
  SELECT COUNT(*) AS delivered
  FROM push_logs
  WHERE delivered_at BETWEEN :w1_start AND :w1_end
), saved AS (
  SELECT COUNT(*) AS saved
  FROM saved_ads
  WHERE created_at BETWEEN :w1_start AND :w1_end
)
SELECT saved.saved, delivered.delivered,
       ROUND(saved.saved / NULLIF(delivered.delivered,0) * 100, 2) AS saved_pct
FROM saved, delivered;
```

- Activation D1 (users with ≥3 events in 24h of first event):
```sql
WITH first_event AS (
  SELECT user_id, MIN(created_at) AS t0
  FROM events GROUP BY user_id
), window_events AS (
  SELECT e.user_id, e.type, e.created_at
  FROM events e
  JOIN first_event f ON f.user_id = e.user_id
  WHERE e.created_at BETWEEN f.t0 AND f.t0 + INTERVAL 1 DAY
)
SELECT user_id
FROM (
  SELECT user_id, COUNT(DISTINCT type) AS actions
  FROM window_events
  GROUP BY user_id
) t
WHERE actions >= 3;
```

- Free→Paid conversion (last 30 days):
```sql
SELECT COUNT(*) AS paid
FROM payments
WHERE status = 'ok' AND updated_at >= NOW() - INTERVAL 30 DAY;
```

- Payment success rate (7 days):
```sql
SELECT SUM(CASE WHEN status='ok' THEN 1 ELSE 0 END) AS ok,
       SUM(CASE WHEN status='failed' THEN 1 ELSE 0 END) AS failed,
       ROUND(SUM(CASE WHEN status='ok' THEN 1 ELSE 0 END) / NULLIF(COUNT(*),0) * 100, 2) AS success_pct
FROM payments
WHERE updated_at >= NOW() - INTERVAL 7 DAY;
```

## Gaps and Instrumentation Plan
- Emit `Start`, `SelectCity`, `ViewDeal`, `CallFromCard`, `ChecklistRun`, `PushOpen`, `UpgradeClick`, `CancelStart`, `CancelRescueSuccess`, `ReferralJoin` at appropriate interaction points.
- Consider a dedicated `PushOpen` endpoint for open tracking separate from CTA click (if needed).
