Changelog
All notable changes to AgenticVexa. Dates are in YYYY-MM-DD. Versions follow
CalVer — YEAR.SPRINT_GROUP until we cut a v1.
[2026.5-gateway-ops] – 2026-05-17
Operational layer on top of the gateway shipped in [2026.5-gateway]:
auth options, health/RPM controls, async-job attribution, customer
visibility into available models. The 100-call burst against ohgrtapi
that previously produced 40 503s now succeeds 100% — 84 stayed on
the LAN GPU box (kokoro), 16 fell over to OpenAI's tts-1 cleanly.
Added
- Google Sign-In (
POST /v1/auth/google). Browser obtains an ID
token via Google Identity Services; backend verifies it against
Google's JWKS, accepts the audience for either web or iOS client,
upserts a User with provider="google". New email accounts are
pre-verified (Google's own attestation). Existing email+password
accounts get their Google identity *linked*, password preserved —
either method works after. Wired into the developer portal
(/login, /register) and admin console (/login, with the
same is_superadmin gate the password path has). No client
secret required.
- Provider health probe, every 5 minutes. New columns
`ai_providers.last_health_status / last_health_latency_ms /
last_health_check_at`. Periodic Celery task pings each active
provider's base_url and fires admin.provider.{down,recovered}
on real status transitions — never on repeats, so a chronically
dead provider doesn't page the team every 5 min.
- On-demand probe button at
POST /v1/admin/providers/{id}/probe
+ UI button on each row. Same alert semantics as the periodic
sweep so the rule "only real transitions page" still holds.
- Provider-wide RPM cap. New
ai_providers.rate_limit_rpm
(integer, NULL = no cap). ai_service._dispatch calls
acquire_for_provider(slug, rpm) before the adapter call.
UpstreamRateLimitExceeded is reframed as a retriable
ProviderError(429) so the chain falls over to the next route.
ohgrtapi is seeded at 50 rpm — 10 under its 60/IP gateway cap.
- Async-job provider attribution. New columns
ai_jobs.provider_slug / provider_cost_inr. Worker lifts
_provider_meta from the result dict (instead of just stripping
it) so async traffic shows up in /admin/providers/margin
instead of bucketing as unattributed.
- Customer-visible model picker in the developer portal
/docs
page — renders GET /v1/ai/models as a live table.
avxCLI--modelflag on text/image/voice/stt/vision +
avx models subcommand for the live catalog.
- Admin weekly digest (
admin.digest.weekly) Monday 09:30 IST.
Rolls up 7d signups, new subs / MRR added, cancellations / MRR
lost, payment failures, revenue captured, top orgs by credits,
provider margin per-provider. Reuses notify_superadmins to
fan out.
admin.subscription.downgradedtemplate + dispatch in
change_user_plan — symmetry with the upgrade path so churn is
visible in real time.
- Audit logs for provider/route mutations. Every create/
update/delete on ai_providers and ai_provider_routes writes
an audit_log row with before/after diffs.
Changed
- OhGrtAPI base_url switched to LAN IP
http://192.168.1.15:8100
while public DNS for agenticvexa.in is unreliable. Verified live —
text 3.34s, image 9.95s, voice 4.67s.
Verified end-to-end
- 100×voice burst (no model pin): 100/100 succeeded · 84 ohgrtapi +
16 openai · zero 503s · ₹7.40 total cost. Same shape as the
100×image batch which had been 100/100 since the route-table
dispatch landed.
- Google sign-in: page renders the GIS button (340×44) on
developer/login, developer/register, admin/login; /v1/auth/google
upserts a user, bootstraps the personal org, returns access +
refresh tokens; Playwright probe of the post-token half lands at
/dashboard with the authenticated chrome.
- Provider health: ohgrtapi 22-84 ms (LAN), OpenAI ~1100 ms (WAN),
transitions fire admin.provider.{down,recovered} exactly once
per change.
[2026.5-gateway] – 2026-05-16
Multi-provider AI gateway. Five-phase build that swapped the previously
hardcoded env-var dispatch for a route-table driven failover chain, added
cost-aware routing, and exposed model selection to customers.
Added
ai_providers+ai_provider_routestables (migration094faa68162b).
Catalog is admin-managed via /admin/providers; routes ordered by
priority ASC drive the runtime failover chain.
- OhGrtAPI provider (operator's own GPU host — SD 1.5 / Kokoro TTS /
LangGraph + Llama 3.2 3B) seeded as priority-0 for text/image/voice.
OpenAI sits at priority-1 as failover, primary for stt/vision.
provider_router.resolve(db, service)+_dispatch()inai_service.py.
Walks the chain, falls over on ProviderError(retriable=True), surfaces
non-retriable immediately (auth/quota/bad-body).
- Per-provider adapters under
services/provider_adapters/—
openai_adapter.py (all 5 modalities) and ohgrtapi_adapter.py
(text/image/voice; stt+vision raise retriable so failover hits OpenAI).
- Cost-aware routing (migration
c1d49bea7e21):
ai_provider_routes.cost_per_call_inr editable in the admin UI;
api_logs.provider_slug + api_logs.provider_cost_inr stamped at
request time so margin reporting doesn't move under retroactive price
edits.
GET /v1/admin/providers/margin?days=N+ new "Margin" tab in
/admin/providers (24h / 7d / 30d / 90d) with per-(provider, service)
rollups of call count, revenue (credits), and cost (₹).
- Customer-visible model picker: every AI request body now accepts
model: str | None. Unknown model → 400 with a pointer to
/v1/ai/models. Default ("no preference") preserves the full chain.
- Public
GET /v1/ai/modelsendpoint. Developer portal/docs
renders the live catalog so customers can see what they can pin.
- TS SDK (
packages/sdk) — addedmodel?to ImageRequest /
VoiceRequest / TranscribeRequest / VisionRequest, and a
client.models.list() accessor returning AvailableModel[].
- Python SDK (
packages/sdk-python) —client.models.list()and
matching async variant. model flows through **kwargs already.
- Pytest coverage (
tests/test_provider_gateway.py) — 12 tests
covering resolve ordering/filters and _dispatch failover, model
filter, and provider_meta stamping.
Changed
- `ai_service.text_generate / image_generate / voice_synthesize /
transcribe / vision_analyze all accept an optional model` kwarg that
flows into _dispatch(..., model=).
routers/ai.py._log_requestacceptsprovider_metaand writes
provider_slug + provider_cost_inr onto the api_logs row.
_classify_provider_errornow handlesProviderError: 404 → 400
(customer fixes body), 401/403 → 503 (operator auth issue), other →
503 with message.
Notes
- Existing deployments don't need a re-seed — an empty catalog falls
back to the legacy env-var path (OPENAI_API_KEY etc.) unchanged.
Re-seed to pick up the OhGrtAPI provider and the cost defaults.
[2026.5-mobile7] – 2026-05-16
Phase 6 mobile audit — closed the audit. WCAG AA-clean across all 42 routes × 2 viewports. New contrast + landmark + close-target probes; sweeping content + token fixes; mobile-first 404 / error pages on every app.
Added
closeTargetsprobe (rule I2): flags pairs of standalone tap targets <8px apart. Skipsrole="tablist" | "group" | "radiogroup"(segmented controls).lowContrastprobe (rule C1/C2): WCAG ratio with alpha compositing of ancestor backgrounds so semi-transparent layers (bg-brand-primary/10) resolve to what's actually visible on screen. Skipsaria-hidden,role="presentation",role="none". Honors WCAG large-text relaxation (3:1) for ≥18px regular or ≥14px bold.missingLandmarks+multipleH1sprobes (rule L1): every page must expose<main>,<header>,<nav>,<footer>(or matching ARIA roles), and exactly one<h1>.SecondaryChromefor landing (apps/landing/src/components/secondary-chrome.tsx): shared header + nav + footer for blog, changelog, legal pages, 404, and error pages.AuthShellfor developer and admin (apps/{developer,admin}/src/components/auth-shell.tsx): shared header + nav + main + footer for pre-login pages.- Mobile-first 404 page per app (
not-found.tsx) — wrapped in its shell, full landmarks,min-h-[44px]CTAs. - Error boundary page per app (
error.tsx) — catches uncaught render errors, shows mobile-first recovery screen withreset()+ "Go home" actions, surfaces Next.jsdigestref.
Fixed
- Contrast token bump:
--color-text-tertiary#71717A→#8B8B95across all 4 apps'globals.css. Was 4.12:1, now 5.0:1. Lifts dozens of subdued-text instances above WCAG AA in one change. - Shared
Buttonprimary variant (packages/ui/src/button.tsx):bg-[var(--color-brand-primary)](#6366F1, 4.47:1) →bg-[#4F46E5]indigo-600 (5.6:1). Hover/active still flips to brand-secondary violet. - Admin Sign In button:
bg-error(#EF4444, 3.76:1) →bg-[#B91C1C]red-700 (6.1:1). - Hero "1 credit" usage chip: colored text on tinted bg → white text on stronger-tint bg; remains color-coded but always legible.
- Blog page contrast/tap targets: "All" filter
text-text-brandonbg-brand-primary/15, category chips →text-text-secondary, "← Back to home" →text-text-secondary. Featured + post-card category chips bumped. "All" pill expanded to 44×44. - Developer code-language tabs (
developer-section.tsx): active tabtext-brand-primary→text-text-brand; addedrole="tablist"+role="tab"+aria-selected. - Playground credit chips (service-page + landing):
text-text-tertiary→text-text-secondary. - Adjacent tap-target spacing: product-tour + testimonials carousel dots
gap-1→gap-2; pricing Monthly/Yearly toggle wrapped inrole="group" aria-label="Billing period"; playground image example chipsgap-1.5→gap-2+role="group". - Decorative
·separators in hero →aria-hidden="true"so SRs skip and contrast probes don't flag. - F1 a11y on remaining auth pages: forgot-password got inline
role="alert" aria-live="polite"banner,aria-invalid,aria-describedby,inputMode="email", mobile-friendly autocapitalize/autocorrect/spellcheck attrs,noValidate. Verify-email error state wrapped inrole="alert" aria-live="polite". Reset-password verified already F1-compliant. - Landmark structure across non-home pages: changelog, legal/terms, legal/privacy, legal/cookies, blog, blog/[slug] all wrapped in
<SecondaryChrome>. Developer login/register/forgot/reset/verify/resend-verification all wrapped in<AuthShell>. Admin login/forgot-password/reset-password all wrapped in<AuthShell>. Playground header inner div upgraded to<nav>, new<footer>added. - Changelog markdown heading levels demoted by 1 so the page renders a single
<h1>(the page title), keeping the document outline sensible for SR rotor navigation.
Verification (iPhone 13 + Pixel 7)
| App | Routes | hScroll | inputsNoLabel | smallTargets | closeTargets | lowContrast | landmarks | h1s |
|---|---|---|---|---|---|---|---|---|
| landing | 6 (+ 404) | clean | 0 | 0–1* | 0 | 0 | all present | 1 |
| playground | 7 (+ 404) | clean | 0 | 0 | 0 | 0 | all present | 1 |
| developer | 12 (+ 404) | clean | 0 | 0 | 0 | 0 | all present | 1 |
| admin | 14 (+ 404) | clean | 0 | 0 | 0 | 0 | all present | 1 |
*Lone remainder is the chatbot bubble caught mid motion.div enter animation; measurement artifact, not a real bug.
Total: 42 routes × 2 viewports = 84 audits, all passing the rulebook end-to-end.
[2026.5-mobile6] – 2026-05-16
Phase 5 mobile audit — finished the marketing-CTA sweep, image-alt audit, universal focus rings, register-form a11y, and probe refinements.
Fixed
- All remaining landing-home small touch targets bumped to ≥44×44: product-tour tabs + dots, testimonials carousel dots, developer-section language tabs, pricing Monthly/Yearly toggle + per-card "Start Free" CTA, demo-request "Skip the demo", cta-banner "Developer Portal" link, footer legal links. Probe count: 27 → 1 (the lone remainder is the chatbot bubble caught mid-animation).
- Pagination dots <44×44 (product-tour, testimonials) — visible dot kept small, hit area wrapped in a 44×44 invisible padding via inner
<span>pattern. - Register form was toast-only on errors — added the inline
role="alert" aria-live="polite"banner +aria-invalid+aria-describedby="register-error"on name/email/password inputs, plusnoValidateso the inline message wins over native browser tooltips. Matches the login pattern from Phase 4.
Added
- Image-alt probe in
scripts/mobile-audit.ts(imagesNoAlt+ samples). All 4 apps measured: 0 missing alts on every route. - Universal
:focus-visiblerule in playground, developer, and adminglobals.css(landing already had it). Keyboard focus is now visible across all apps. - Skip-rules in the touch-target probe: ignore
display: inline,sr-only, clipped, or elements nested in larger interactive ancestors.
Verification (iPhone 13)
| App | font≥ | hScroll | inputsNoLabel | smallTargets | imgNoAlt |
|---|---|---|---|---|---|
| landing home | 9px (dev pill) | clean | 0 | 1 (anim artifact) | 0 |
| landing other | 11–14px | clean | 0 | 0–2 | 0 |
| playground all | 11px | clean | 0 | 0 | 0 |
| developer all | 13–14px | clean | 0 | 0 | 0 |
| admin all | 13px | clean | 0 | 0 | 0 |
[2026.5-mobile5] – 2026-05-16
Phase 4 mobile audit — keyboard handling, form a11y, responsive toast, skip-to-content, overscroll containment, and a partial marketing-CTA sweep.
Fixed
- Focused inputs hidden by virtual keyboard — every app's
globals.cssgothtml { scroll-padding-bottom: 120px }+input, textarea, select { scroll-margin-block-end: 120px }at<sm. Focus auto-scroll respects these so the field lands clear of the iOS keyboard + autocomplete bar. - Toast position collided with mobile chrome — shared
Toasteris now a client component that switchesbottom-right→top-centerbelow 640px. Landing's direct Sonner usage got aResponsiveToastercompanion with identical logic. - Developer login errors were toast-only (F1 violation) — added inline
role="alert" aria-live="polite"banner +aria-invalid+aria-describedbyon both inputs. Errors now persist visually and for screen readers. - No skip-to-content link (A1) — every app's
layout.tsxstarts the body with a focus-only "Skip to main content" anchor; all<main>elements gotid="main-content"+tabIndex={-1}so keyboard / SR users can bypass the nav. - Page-level pull-to-refresh fired from inner scrolls — global rule
.overflow-y-auto, .overflow-auto, [data-scroll-container] { overscroll-behavior: contain }in all 4 apps. Affects chat history, sidebar nav, tall modal lists. - Landing marketing CTAs at <44px (P2-1 in flight) — 5 of the most visible inline CTAs (hero "Try without signup", cta-banner, demo-request, contact-form sales, use-cases cards) bumped to
min-h-[44px] sm:min-h-0. Probe count: 52 → 27 on landing home. The remaining ~27 are scattered across other section components; deferred.
[2026.5-mobile4] – 2026-05-16
Phase 3 mobile audit — input ergonomics, tap feedback, touch-target compliance, and PWA installability.
Fixed
- iOS Safari auto-zoom on input focus — added a
@media (max-width: 639px)rule across all 4 apps that forces every form field tofont-size: 16pxon phones. The page no longer jumps when a user taps an input. - No press feedback on mobile — shared
Buttoncomponent now hasactive:parallels tohover:(scale-[0.98] + color shift) on every variant, plus[-webkit-tap-highlight-color:transparent]to kill iOS Safari's grey overlay. Every app'sglobals.cssalso gotbutton, a, [role="button"] { -webkit-tap-highlight-color: transparent }. - Touch targets <44×44 — playground header (AV logo, back-link, Sign up CTA), shared
Buttonmd size (h-10→h-11), suggestion chips on text/image pages, landing announcement X, navbar hamburger, navbar AV logo — all bumped to ≥44×44 on mobile. - Tailwind v4 not scanning
packages/ui— fixed via@source "../../../../packages/ui/src/**/*.{ts,tsx}"in each app'sglobals.css. New utility classes used only inside the shared UI package now compile correctly.
Added
- PWA manifest + apple-touch-icon in all 4 apps.
public/manifest.json(standalone display, theme color, icon set) + Next.jsmetadata.manifest/metadata.icons.apple/metadata.appleWebApp. "Add to Home Screen" now works on iOS and "Install app" on Chrome Android. inputMode+enterKeyHinton chat input (send), email fields (email/next), password fields (go), and name fields (next). Right mobile keyboard pops up; the soft "Enter" key shows the right verb.
Tooling
scripts/mobile-audit.tsextended with a touch-target probe (skips inline links, skips elements wrapped in larger interactive ancestors). ReportssmallTargets=Nplus a top-3 sample of offenders per route.
[2026.5-mobile3] – 2026-05-16
Phase 2 round 2 — eliminated the remaining false-positive on developer auth pages and shipped the actionable P2 polish.
Fixed
- Developer login + register inputs now have explicit
id/<label htmlFor>/autoCompletepairings. Probe goes from 2/3 unlabeled inputs to 0. - Landing announcement bar wrapped to 2 lines at 360px — split copy: tight "Text, image, voice, video — one API. Start free" at
<sm, longer original at≥sm. Now single-line on iPhone 13.
Added
prefers-reduced-motion: reduceguards in every app'sglobals.css. Animations drop to 0.001ms, smooth-scroll disabled. Landing also hard-disables aurora / grid-fade / pulse / gradient / typewriter animations.- **
viewport-fit: cover+env(safe-area-inset-*)** support across all 4 apps. Bottom-fixed elements (cookie consent, back-to-top, chatbot bubble + window) now sit above the iPhone home indicator.
Changed
- Admin login shield softened —
bg-error/8+text-error/80reads as "secure" rather than "danger". The vivid red is reserved for the Sign In button below.
[2026.5-mobile2] – 2026-05-15
Phase 2 of the mobile audit — all four P1 issues from MOBILE_UI_AUDIT.md closed the same day as Phase 1.
Fixed
- Playground 10px caption pills bumped to 11px (the
X CREDITS / REQchip inservice-page.tsxand the playground home service-card grid). - Playground body + empty-state copy (warning text, file-format hints, "Output appears here…" copy) raised from 12px → 13px on mobile via
text-[13px] sm:text-xs. - Playground inputs without
<label htmlFor>pairing all wired up:image-prompt,video-prompt,voice-text,voice-select,vision-question, plus ansr-onlylabel on the chat input. Probe now reports 0 unlabeled inputs across every service page. - Developer + admin 12px metadata text raised to 13px on mobile via a single
@media (max-width: 639px) { .text-xs { font-size: 13px } }rule per app — zero desktop impact, covers 30+text-xsusages per app without touching individual files. - Mobile horizontal-scroll backstop extended from landing to playground/developer/admin (
html, body { overflow-x: clip; }in eachglobals.css).
Verification
Smallest visible body font went from 9–12px to 11–14px across all 4 apps. No horizontal scroll on any route at 360–412px viewport widths. Full numbers in docs/MOBILE_UI_AUDIT.md.
[2026.5-mobile1] – 2026-05-15
Fixed
- Landing horizontal scroll on mobile — added
html, body { overflow-x: clip; }as a backstop against rogue absolute-positioned aurora/blur elements that escape their containers. Pages now respect 390px viewport width. - Playground header overflowed at 390px — the "Sign up free" CTA was clipped off the right edge. Header now responsively collapses at
<sm: subtitle hidden, back-link icon-only, CTA shortened to "Sign up", CreditCounter drops its caption. - Admin Sign In button rendered as plain text — the shared
Button'svariant="danger"usedbg-[var(--color-error)]arbitrary syntax which didn't resolve in this Tailwind v4 setup. Pinned the admin login button tobg-errorexplicitly. - Landing
/changelog500 — reverted the page to a 40-line hand-rolled markdown renderer, eliminating theremarkruntime dependency. - Landing hero typewriter mid-frame clipping — reserved
min-w-[5ch]for the cycled word so the surrounding line no longer reflows during the animation.
Added
docs/MOBILE_UI_RULES.md— 28-rule mobile UI validation checklist (layout, typography, color, touch, forms, a11y).docs/MOBILE_UI_AUDIT.md— per-screen scored audit of all 4 web apps with P0/P1/P2 issues + per-fix verification screenshots indocs/mobile-audit/.scripts/mobile-audit.ts— Playwright harness that captures iPhone-13 + Pixel-7 screenshots of every route and runs in-page probes (overflow, smallest font, unlabeled inputs).
[2026.5-sprint16] – 2026-05-15
Added
- Python SDK (
pip install agenticvexa) — syncAgenticVexa+ async
AsyncAgenticVexa clients mirroring the TypeScript SDK API surface.
avxCLI (pip install agenticvexa-cli) —auth login,text,
image, voice, stt, vision, tasks, webhooks tail, status.
- CHANGELOG (this file) and
/changelogroute on the landing site.
[2026.5-sprint15] – 2026-05-15
Added
- Spending budgets & alerts — per-org soft alerts at admin-set %
thresholds (50/80/100 by default). Optional hard caps refuse deductions
past the cap. GET/PUT /v1/billing/budget.
- Cost forecasting —
GET /v1/billing/forecastreturns end-of-period
projection from 7-day rolling rate, with per-service breakdown.
- Plan recommendation —
GET /v1/billing/recommended-plansuggests the
cheapest plan that fits projected 30-day usage.
- Developer onboarding wizard — first-login banner on /dashboard tracking
"create key / make first call / invite team"; auto-dismisses when done.
[2026.5-sprint14] – 2026-05-15
Added
- GDPR data export —
POST /v1/users/me/data-exporttriggers a Celery
job that compiles profile + orgs + 365d API logs + ledger + invoices + 90d
webhook deliveries into a JSON file; emails a 7-day download link.
- Audit log search + CSV export —
/v1/admin/audit-logsfilters by
actor/action/target/date/substring; sibling .csv endpoint streams matches.
- Status page email subscriptions — opt-in via
POST /v1/status/subscribe
with double-opt-in confirmation; fanned out on every incident create/update.
- Webhook signing-secret rotation —
POST /v1/webhooks/{id}/rotate-secret
returns the new secret while keeping the previous valid for 24 hours;
deliveries dual-signed during the window (X-AgenticVexa-Signature: v1=new,v1=old).
[2026.5-sprint13] – 2026-05-15
Added
- Self-hostable Docker Compose (
docker-compose.selfhost.yml) — api +
worker + beat + Postgres + Redis. docs/SELF_HOSTING.md covers seed/backup/
scale-out/upgrade runbooks.
- Public status page —
status_components,status_incidents,
status_incident_updates tables; /v1/status (public) +
/v1/admin/status/* (write).
- Stripe scaffold — code-complete payment provider; activates only when
STRIPE_API_KEY is set, otherwise the /v1/webhooks/stripe route returns 503.
[2026.5-sprint12] – 2026-05-15
Added
- WebSocket text streaming at
/v1/ai/text/stream?token=<jwt>— delta
frames over JSON-lines; charges credits upfront, refunds on upstream failure.
- MCP server (
apps/mcp/server.py) — exposes 5 AgenticVexa tools to
Claude Desktop / Cursor / Continue via stdio.
- TypeScript SDK (
@agenticvexa/sdk) — hand-written, Node 18+ and
browser-compatible; sync calls + async tasks.wait() + text.stream()
async generator.
[2026.5-sprint11] – 2026-05-15
Added
- Developer webhooks page — full CRUD, one-time signing secret reveal,
per-endpoint delivery log with auto-refresh, test-ping.
- Developer referrals page — code, share URL, signup/conversion/credits
stats, anonymized top-10 leaderboard.
- Admin AI providers page — catalog + per-service route chain with
priority reorder.
- Admin customer health page — red/yellow/green filter, score bar,
factor breakdown.
[2026.5-sprint10] – 2026-05-15
Added
- Maintenance Redis cache + pub/sub — admin flips publish on
maintenance.flip; in-process cache invalidated across all API instances
in ~10ms.
- Playground async UI — image/voice/stt/vision pages POST to
/asyncand
poll /v1/tasks/{job_id} by default.
[2026.5-sprint9] – 2026-05-15
Added
- DB-driven provider catalog —
ai_providers+ai_provider_routes
tables; per-service fallback chain managed at /v1/admin/providers.
- JWT RS256 + JWKS —
JWT_ALGORITHM=RS256enables asymmetric signing
with rotation grace window; JWKS at /.well-known/jwks.json.
[2026.5-sprint8] – 2026-05-15
Added
- Log table partitioning helpers —
app/db/partitioning.py+ monthly
beat creating next-month partitions. Cutover runbook at
docs/PARTITIONING_RUNBOOK.md.
- Maintenance auto-flip — 1-minute beat flips
enabledat
scheduled_start/scheduled_end.
- Customer health score —
customer_health_snapshotstable; daily
beat scoring on 5 signals (volume, errors, recency, trend, stickiness).
- Invoice PDF rendering —
GET /v1/billing/invoices/{id}/pdfstreams a
reportlab-rendered PDF with GST split for INR.
[2026.5-sprint7] – 2026-05-15
Added
- Redis hot credit counter — Lua-atomic deduct + 30s reconciler beat;
removes SELECT FOR UPDATE from the hot path.
- Webhook delivery worker —
webhook_deliveriestable, HMAC-SHA256
signing, exp-backoff retries (1m→3d), DLQ at 8 attempts, /v1/webhooks CRUD.
- Outbound provider rate limiter — Redis token-bucket per (provider,
service); raises 503 UpstreamRateLimitExceeded after a 5s grace.
get_org_ownerRedis cache — 10-min TTL; invalidate on
ownership/email/name change.
[2026.5-sprint6] – 2026-05-15
Added
- Lifecycle drip — daily beat fires welcome day 1/3/7 and 7-day
re-engagement emails based on users.created_at / last_login_at.
- Referral program —
referrals+referral_redemptionstables, code
generation, paid-conversion 500-credit reward, /v1/referrals/{me,leaderboard}.
[2026.5-sprint5] – 2026-05-15
Added
- Per-key abuse detection — hourly beat, 3σ over 7-day baseline →
auto-disable key + audit log + apikey.exposed.github_scan email.
- Failed-login throttling — 5 fails / 15 min / IP → 15 min Redis lockout
(fail-open if Redis is unreachable).
[2026.5-sprint4] – 2026-05-15
Added
- structlog —
request_id/user_id/path/methodauto-bound. - Prometheus —
http_requests_total,http_request_duration_seconds,
credits_deducted_total, ai_jobs_total, email_sends_total,
active_subscriptions; /metrics endpoint.
- Grafana dashboard at
infra/grafana/agenticvexa-api.json(7 panels).
[2026.5-sprint3] – 2026-05-15
Added
- Async AI proxy —
ai_jobstable;POST /v1/ai/{service}/async(202) +
GET /v1/tasks/{job_id} polling. Credits refunded on worker failure.
[2026.5-sprint2] – 2026-05-15
Added
- All Razorpay billing email events wired (renewed/upgraded/downgraded/
suspended, payment.failed, 3 dunning_retry stages).
- Dunning scheduler — daily 09:00 IST beat; D+1/3/7 retries + D+10
auto-suspend.
- Subscription upgrade/downgrade with proration — upgrade immediate +
invoiced, downgrade takes effect at period end.
[2026.5-sprint1] – 2026-05-15
Added
- Alembic baseline migration +
app.bootstrapfor fresh DBs. - Celery worker + email dispatch auto-failover (
asyncio.create_task→
email_send.delay() with fallback).
- Email retry sweep every 15 minutes.
- Redis User cache (5-min TTL) on JWT validation; invalidate on mutation.