---
name: claude-usage-tracker
description: claudeUsageTracker — cross-tenant AI metering/limits/credit/audit subsystem; Phase 1 built (migration unrun)
metadata: 
  node_type: memory
  type: project
  originSessionId: 6dc05bff-66e9-49a8-b666-d5ffa63b35e2
  modified: 2026-07-25T10:08:39.644Z
---

Building `claudeUsageTracker`: meter + hard-limit + top-up + audit for ALL AI tools in Evolution (triggered 2026-07-25 after customers burned Anthropic credit via the [[evolution_ai_quote_notes]] tool).

**Architecture (decided):** central store in master `evolution` DB via `EVO::` is the single source of truth; clients read their own slice (`WHERE companyid=?`), Evolution staff read all. Chosen over per-tenant-DB logging (avoids dual-write drift). Two tiers: (1) structured meter/audit row per call in `evolution.claude_usage`; (2) verbose our-eyes-only JSON-lines diagnostic at `evolution/logs/claude-usage.log` for token-leak hunting.

**User decisions:** hard-block + top-up prompt on limit; per-tenant pool only (audit still per-user); gateways = eWAY (self-service card) + Invoice method, both crediting the same ledger; credit config managed via `evolution.companies` mapping in the `support_companies` DEPLOYMENT console.

**Choke point:** `library/claudeUsage.php` — `ClaudeUsage::call($payload,$tool,$sourceId)` does preflight(credit hard-cap) → curl → capture `usage` → `price()` → `charge()` → `record()`(central audit) → `verbose()`(log file). Every AI tool must route through this instead of its own curl. Pricing map in `PRICING` const (USD/1M, incl. cache write 1.25x / read 0.10x). `DEFAULT_MONTHLY_ALLOWANCE=10.00` USD (TUNE). As of 2026-07-25 the ONLY authenticated `x-api-key` curl lives here — verified via grep; leftover `API_URL`/`API_VER` consts in the two tool classes are dead.

**Tools wired through the meter (tool keys):** `quoteNotes` ([[evolution_ai_quote_notes]], sourceId=quoteId) and `quoteSearch` (quotereg NL→filters/SQL search, `library/claudeSearch.php::interpret`, Haiku 4.5, no sourceId). Both return `mode/status=="limit"` on hard-cap; their handlers in `quoteditsave.php` set HTTP 402; front-ends (`quotedit`, `quotereg.js`) show a top-up prompt. When adding a NEW AI tool, refactor its curl to `ClaudeUsage::call` and add a `"limit"` branch + 402 in its handler.

**Phase 1 (built, NOT deployed):** `migrations/claude_usage_tracker.sql` (central-only; creates claude_usage + claude_credit, seeds 25 active tenants @ $10/mo hard_cap=1). Refactored `library/claudeQuoteNotes.php::generate()` to call `ClaudeUsage::call` (returns status 'limit' on cap). `quoteditsave.php` aiGenerateQuoteNotes handler sets HTTP 402 on 'limit'. All lint-clean. **Migration NOT run** — dev `claude` user is read-only ([[dev_mysql_access]]); Shane runs it via DeploySql/migrate against master `evolution` only. Nothing meters until then.

**Phase 2 (built, lint-clean):** `library/claudeUsageReport.php` (read helpers); client AI-Usage tab in `mybilling.inc`; cross-tenant console `support_aiusage.inc` (+ menu link in `app/templates/menu.php` DEPLOYMENT block); per-tenant credit editor in `support_companyedit.inc` → `saveClaudeCredit()` in `support_companies.php` (support-gated upsert of claude_credit).

**Phase 3 (built, lint-clean):** Top-up subsystem. Migration `migrations/claude_topup.sql` (central `evolution`; UNRUN). Ledger class `library/claudeTopup.php` — one crediting path `applyCredit()`, idempotent `approve()`(invoice)/`markPaid()`(eWAY). **3a Invoice method:** client requests in mybilling AI tab → `mybilling.php?action=aiTopupRequest` → row status=requested; staff Approve/Reject in `support_aiusage.inc` → `support_companies.php::actionClaudeTopup` credits `topup_balance`. **3b eWAY self-service:** official SDK `eway/eway-rapid-php ^2.0` added to `plugins/composer.json` (installed to gitignored `plugins/vendor`; autoloaded by functions.php; prod must `composer install`). `library/claudeEway.php` uses Responsive Shared Page (lowest PCI, no card data on our servers): `startTopup`→SharedPaymentUrl redirect; return handler `mybilling.php?action=aiTopupReturn` verifies via `queryTransaction` → markPaid. **Currency: ledger is USD; eWAY charges AUD at configured rate `$ewayUsdToAud` (.env, margin baked, default 1.62).** Card UI only shows when `ClaudeEway::configured()`. **eWAY config needed in .env (globals, like $anthropicApiKey): `$ewayApiKey`, `$ewayApiPassword`, `$ewayEndpoint`('sandbox'|'production'), `$ewayUsdToAud`.** Untested against live eWAY (no creds/sandbox yet).

**Open / next:** P4 = release notes + docs ([[feature_release_docs_policy]]) for the whole tracker. User must: run BOTH migrations against master `evolution`; add eWAY .env creds + sandbox-test the card flow; tune allowance + FX rate; rotate the committed API key.

**Security flag (unverified by me):** discovery agent reported a live-looking `sk-ant-api03-…` key committed at `evolution/.env:28` — Shane should rotate + move out of VCS. Don't grep .env to confirm.
