How is the Dattavani backend built?

Answer

The backend is one FastAPI service, core-service, in front of Supabase Postgres. Most rules for access, XP and completion run as Postgres RPCs that core-service calls. AI, video, voice, billing, push and email are outside providers.

  1. core-service registers 28 routers in one app. The ai-service/ folder is a stub that returns fake text and is not deployed.12
  2. Access, XP and completion live in SQL functions such as check_content_access_rpc and update_daily_stats_rpc.34
  3. Kids call with a 12-hour HS256 kid JWT, and core-service then runs their queries as the parent.56
  4. Production is a manual deploy to DigitalOcean droplets in blr1 and nyc1 behind one global load balancer.78

Applies todattavani-backend at 2574334 (branch dev-dattajayanthi)code read on 30 Oct 2026, nothing runpayments are in the separate payments setseverities are our judgment

1

What are the parts and how do they connect?

Dattavani backend at a glance
Diagram structure
  • Mobile app app
  • Admin console admin
  • Load balancer + Caddy edge
  • core-service core
  • Supabase Postgres db
  • Cloudflare R2 r2
  • CHRAG RAG chrag
  • LiveAvatar + Swamiji live
  • Stripe + RevenueCat bill
  • FCM + SMTP notify
  • Host cron + pg_cron cron
  • app → edge · HTTPS
  • edge → core · proxy
  • core → db · RPC + SQL
  • core → chrag · /query
  • core → live · sessions
  • core → r2 · media
  • core → notify · push, email
  • bill → core · webhooks
  • cron → core · jobs
  • admin → db · service role
  • admin → r2 · uploads
  1. Mobile app

    Parents sign in with a Supabase OTP; kids then call with a kid JWT. Media plays from the R2 CDN and LiveKit directly.

  2. Load balancer + Caddy

    A global load balancer feeds regional droplets. Caddy on each droplet hides /docs in production.

  3. core-service

    FastAPI holds the HTTP shape, auth and orchestration. It keeps small caches in each process.

  4. Supabase Postgres

    Holds all state, plus the RPCs that decide access and write XP, rings and streaks.

  5. CHRAG RAG

    Answers Ask Tataji questions. A circuit breaker returns 503 when it is slow or failing.

  6. LiveAvatar + Swamiji

    Live video and voice. core-service only creates, records and bills the sessions.

  7. Stripe + RevenueCat

    Billing events arrive as signed webhooks; see the payments set.

  8. Host cron + pg_cron

    Host cron runs python -m app.jobs.run_*; pg_cron runs two SQL clean-up jobs.

  9. Admin console

    Edits content straight in Supabase with the service-role key, and uploads media to R2.

2

Which page answers which question?

PageQuestion it answersDiagram
01-system-overview.htmlWhat runs where, and who calls whom?Architecture
02-core-service-map.htmlWhere does each area live inside core-service?Tree
03-request-pipeline.htmlWhat happens to one request, from middleware to response?Sequence
04-auth-and-identity.htmlHow do parent sign-in, the PIN and kid sessions work?Sequence
05-ask-tataji.htmlHow is a chat question checked, answered and billed?Sequence
06-live-voice-and-avatar.htmlHow do live video and Swamiji voice sessions start, stop and bill?Sequence
07-learning-content.htmlHow does a kid browse, read, take a quiz and complete content?Sequence
08-gamification.htmlWhich events earn XP, coins, rings, streaks, badges and rank?Dataflow
09-access-and-limits.htmlWhich gates decide whether a kid may use a feature now?Workflow
10-notifications-and-email.htmlHow is a push, inbox or email message made and sent?Dataflow
11-background-jobs.htmlWhich scheduled jobs exist, and what do they touch?Workflow
12-data-model-family-progress.htmlWhich tables hold parents, kids, progress and rewards?ERD
13-data-model-content-ai.htmlWhich tables hold content, chat, live sessions and config?ERD
14-admin-console.htmlHow does the admin console reach data and media?Architecture
15-deployment.htmlHow do staging and production get built and run?Architecture
../payments/index.htmlHow do Stripe and RevenueCat payments work?Separate set

All pages sit in this folder. Each diagram node links to its pinned source lines at commit 2574334.

3

Which rules does every change need to respect?

RuleWhere it livesWhy it matters
Change the schema only with a new migrationsupabase/migrations/Nobody edits the database or an applied migration by hand.9
Access is decided in SQL, in a fixed ordercheck_content_access_rpcConsent, then membership, then the kid's minutes, then the trial cap.3
One function writes XP, coins, rings and streakupdate_daily_stats_rpcA second writer gets out of step with the leaderboard.4
Two error shapes existmain.py path listChat, avatar and Swamiji routes always return {success, message, data, code}; others may return {detail}.10
Caches live in each worker processcachetools TTL cachesA cache clear reaches one worker only; content can be up to 5 minutes stale.11
Two schedulers run jobshost crontab and pg_cronA new job needs its schedule added in docs/CRON_JOBS_SETUP.md and on the host.12
4

What risks did the analysis find?

RiskWhereEffectSeverity
Admin bundle ships the Supabase service-role key and R2 secretsadmin/lib/supabase.ts, admin/lib/r2.tsAnyone who loads the hosted admin can read and write every table and the R2 bucket.1314P0
PIN verify has no attempt limitrouters/user_management.pyA 4-digit parent PIN has 10,000 values to try.15P1
A video session the app never stops is never billedservices/avatar_session.pyThe next start closes it with a plain stop, not stop-and-bill.16P1
Credit deduction reads, then writesservices/tataji_app_config.pyTwo paid turns at once can under-charge.17P1
Badge XP and coins bypass the daily-stats RPCservices/badge_service.pyUpdates can be lost, and badge XP never counts on the leaderboard.18P1
Python and SQL disagree on a RevenueCat trialservices/trial_service.pyA RevenueCat trial skips the trial cap on v1 routes only.19P1
Registry keeps only 3 imagesdeploy-production.ymlRetagging an image older than the last 3 fails, so rollback needs a rebuild.20P1
Admin calls a story cache route that does not existadmin/services/contentService.tsStory edits wait out the cache.21P2
CHRAG concurrency cap is never appliedlifespan.pyThe semaphore is created but unused, so CHRAG calls are uncapped.22P2
Device-token insert omits NOT NULL columnsrouters/notifications.pyA parent without a session gets a 500.23P2

Each page's cards list more findings with file and line. The admin allowlist screen still queries a dropped table. PIN reset-token reuse is tracked in per-process memory.

5

Where should a new engineer start?

Opening diagram…