10 KiB
10 KiB
Growth Analyst Capability Spec
- Status: Approved — implementation authorized 2026-08-21
- Capability: Read-only AI-assisted growth analytics
- Public contract:
docs/openapi.yaml - UI contract: frontend
docs/GROWTH-ANALYST-UX-SPEC.md
Objective
Give an authenticated merchant a trustworthy 90-day Persian growth outlook: historical event wins, upcoming similar occasions, likely low-performance windows, privacy-safe peer context, and compact campaign briefs. PostgreSQL and deterministic Go calculations own every financial or performance number; AvalAI may only prioritize approved evidence, allocate relative planning attention, and produce qualitative copy.
Deterministic analytics contract
- Aggregate session count and paid Rial amount by Tehran-local day for the authenticated merchant and optional owned terminal.
PaidandVerifiedare successful; money remains integer Rial at session grain. - Forecast begins the day after the latest complete imported dataset date and covers 90 days. Count and amount are modeled independently from weekday-aware rolling baselines, bounded trend adjustment, catalogued event uplift, and empirical residual P10/P50/P90 values.
- Rolling-origin backtests classify output as
HIGH,MEDIUM, orLOW. Limited-history and poorly validated forecasts remain visible asLOWwith wider uncertainty; only a scope with no historical observations returnsINSUFFICIENT_DATA. - Historical event effect compares matching weekdays from the preceding eight non-event weeks. At least four observations and 100 baseline sessions are required. A material win/decline is at least 20%.
- Upcoming evidence first matches the most recent completed catalog occurrence with the exact same
occasion_keyandevent_variant. A demand/campaign window must never use an operational/closure window as its own prior experience, even when both relate to the same holiday. Similar-family or tag matches are not presented as exact prior experience. - Exact historical evidence is usable only when the existing event-effect completeness, observation, and baseline-volume thresholds pass. When it is absent or suppressed, reasoning falls back to current onboarding context: business category, business description/niches, and sales channels matched against reviewed catalog categories, channels, themes, and tags.
- Upcoming similarity beyond the exact-evidence decision may use catalog tag similarity of at least 0.60. Return at most five opportunities and three risks. A risk requires a forecast at least 20% below a baseline with at least 100 sessions.
- Merchant scope may include peer context only under the existing threshold of 10 other same-category merchants and 1,000 combined peer sessions, with one equally weighted value per merchant. Terminal scope always suppresses peers.
- The versioned catalog stores Persian title, Gregorian date range, explicit year-free
occasion_key,event_variant, reviewed Jalali occurrence year, tags, source, supported merchant categories, and official/commercial classification. Coverage declarations must contain at least one dated event for every declared Jalali year. Repeated occurrences use the same canonical key, and one canonical key/variant may occur at most once per Jalali year. Campaign and operational windows for one holiday share the key and differ by variant. - Product-defined analytical windows must cite their reviewed internal window policy and describe the derivation; an external source that establishes only the occasion must not be presented as evidence for a custom date range. A catalog cannot be approved or activated while its source checksum is a review placeholder.
Ranked event-priority contract
- Return exactly three recommendations when at least three reviewed candidates exist. Each has rank order,
priorityPercent, and stancePROMOTE,PREPARE, orCAUTION. priorityPercentis a positive integer share of the merchant's suggested planning attention. It is not a forecast, probability, predicted uplift, expected sales share, or guarantee. The three shares descend with rank and sum to exactly 100.- Eligible exact historical evidence takes precedence over profile reasoning. Its deterministic prior window, observation count, paid-session uplift BPS, paid-amount uplift BPS, and material direction are displayed separately from AI prose.
- A negative historical result may still receive high planning priority because it warrants preparation or caution. Rank therefore measures attention, while stance communicates whether the recommended response is promotion, preparation, or caution.
- Without eligible exact history, show a visible
BUSINESS_PROFILEbasis and an insufficient-history explanation. Do not imply that profile relevance is the merchant's prior performance.
AI boundary
- AvalAI is backend-only and receives five sanitized, chronologically upcoming events from the active reviewed calendar, minimized deterministic evidence summaries, and non-identifying merchant category/niche/channel context. It never receives raw transactions, payer keys, credentials, merchant ids, SQL, or peer rows.
- The consumer-owned
GrowthAnalyticsToolsboundary exposes onlyget_growth_context,get_event_evidence,get_peer_context, andget_campaign_playbook. Scope is injected from the authenticated job, not accepted from model arguments. - Use
POST /v1/responses,store:false, strict function schemas, strict structured output,parallel_tool_calls:false, no more than four tool calls and two model turns, 1,600 output tokens, a 30-second deadline, and one transient retry. - Treat model output as untrusted. Accept only known evidence ids, the bounded stance enum, integer planning-priority fields, and qualitative Persian reasons. Reject unsafe language, unknown references, refusal/incomplete output, schema drift, evidence-basis mismatch, or numeric performance claims in prose.
- The model selects exactly three distinct candidate evidence ids and returns one short qualitative Persian relevance reason, stance, and positive integer
priorityPercentper event. The collection is valid only when shares descend with rank and sum to 100. The structured percentage field is planning preference, not a model-authored financial metric. - Invalid output or provider failure produces
PARTIALusing deterministic ranking: eligible historical evidence first, then reviewed catalog importance/relevance/confidence and profile matches. Largest-remainder normalization yields positive integer shares totaling 100; equal scores resolve to34/33/33. Deterministic evidence supplies stance and reason fallback, and verified historical metrics remain unchanged.
Persistence, caching, jobs, and limits
- PostgreSQL is authoritative for reports, revisions, deterministic evidence, validated AI copy, usage metadata, and idempotency. Redis is disposable hot cache, lock, rate-counter, and budget state.
- A fingerprint includes merchant/terminal scope, import watermark, forecast date/horizon, catalog, analytics, prompt/schema, and model versions. A matching successful report is reused without an AI call.
- Keep the current matching report indefinitely and superseded/manual-refresh revisions for 90 days. Concurrent identical requests collapse to one job.
- States are
QUEUED,ANALYZING,GENERATING,READY,PARTIAL, andFAILED. Preserve the previous successful report during refresh/failure. - Defaults: create 10/user/minute; five uncached scopes/merchant/Tehran day; four concurrent generations globally; explicit production daily request/token budgets; one active generation per fingerprint. Manual retries remain available for a scope until it has a persisted
READYAI summary; after that, one manual refresh per terminal scope is available per Tehran day. The all-terminals selection is a separate scope. - Budget exhaustion returns deterministic
PARTIALoutput. Only an unavailable manual refresh returns429withnextRefreshAt/Retry-After. - Structured logs include safe report/version/status/cache/usage/latency fields without prompts, transaction values, usernames, or sensitive identifiers.
Public API
POST /api/v1/analytics/growth-reportsaccepts optionalterminalIdandrefresh, requires CSRF plusIdempotency-Key, and returns an existing or queued report resource.GET /api/v1/analytics/growth-reports/latest?terminalId=...returns the latest authorized scope report.GET /api/v1/analytics/growth-reports/{reportId}returns an owned report; absent and cross-tenant ids are indistinguishable.GET /api/v1/analytics/growth-reports/{reportId}/eventsis authenticated SSE with stable ids, heartbeat, replay/snapshot recovery, and terminal status.- Responses include the five deterministic calendar candidates, exactly three validated AI-ranked event recommendations (or deterministic fallback), their evidence basis and planning-priority shares, cache metadata, and next refresh time.
Boundaries and acceptance
- Always derive merchant identity from the server session, validate terminal ownership, use parameterized SQL/context deadlines, keep numbers deterministic, and preserve useful prior output on failure.
- Never add chat, memory, notifications, automated campaigns/actions, runtime web search, raw-data tools, or model-authored numerical predictions.
- Tests cover exact occasion/variant matching, historical thresholds and profile fallback, event/baseline/forecast/backtest/risk/peer logic, fingerprints, Tehran refresh boundaries, authorization, persistence, locks/deduplication, budgets, AI percentage sum/order/uniqueness validation, evidence-basis rejection, deterministic fallback, SSE, and sensitive-field absence.
- Feature is disabled by default behind
AI_GROWTH_ENABLED. Production enablement requires explicit AvalAI key/model/request budget/token budget configuration.
Sources
- AvalAI Responses: https://docs.avalai.ir/en/api-reference/responses
- AvalAI function calling: https://docs.avalai.ir/en/guides/function-calling?api-mode=responses
- AvalAI structured outputs: https://docs.avalai.ir/en/guides/structured-outputs?api-mode=responses
- University of Tehran Iranian calendar: https://calendar.ut.ac.ir/