Use this file to discover all available pages before exploring further.
Innova uses a dual-database architecture: Supabase Postgres (relational, via Prisma) for structured application data — identities, curriculum, attempts, mastery, guides — and MongoDB Atlas for high-volume, schema-flexible telemetry and AI job audit records. A third storage tier, AWS S3, holds binary assets: teacher worksheet PDFs, student photo submissions, and OCR upload staging. Each tier is chosen for its strengths; no data is duplicated across them except the attempt_id foreign key that links a Postgres Attempt row to its MongoDB AttemptEvent document.
The central work record. Created on every POST /attempts call. Starts with status: PENDING and is updated asynchronously by the LLM classifier or OCR reprocess worker. classifierSource tracks which pipeline produced the final error tag.
Stores the live BKT (Bayesian Knowledge Tracing) state per student-topic pair. pKnown is the probability that the student has mastered the skill. trend7d is a 7-day rolling delta written by the nightly calibration job in innova-ai-engine.
Represents a teacher-uploaded worksheet PDF. Moves through a GuideStatus state machine from UPLOADED → EXTRACTING → REVIEW → PUBLISHED. Linked to an Assignment (kind=GUIDE) once published so students can be assigned the worksheet.
Raw keystroke and interaction events for every attempt. Used for learning analytics, replay, and debugging. Archived to S3 after processing (archived_to_s3_at).
Full audit trail of every Claude classification call: request tokens, cache usage, per-attempt classifications with evidence and confidence, estimated cost, and latency. Used for cost accounting, debugging classification quality, and prompt optimization.
Per-image OCR job record. Tracks the primary provider (Gemini) and optional fallback (Anthropic), bounding-box step positions, overall confidence, and cost. The s3_purge_at field mirrors the bucket’s 30-day lifecycle rule for COPPA-compliant data deletion tracking.
The OCRResult.steps array contains RecognizedStep objects with rawText, type, bounding-box position (x, y, w, h), and a confidence score between 0 and 1.
Stores teacher worksheet PDFs and the AI-generated LaTeX keys extracted from them.
Prefix
Contents
Lifecycle
guides/uploads/
Raw teacher-uploaded PDFs
Deleted after 365 days
guides/{id}/figures/
Question figure crops (from extraction)
Inherits bucket default
guides/{id}/latex/
Generated .tex solution keys (ADR-117)
Inherits bucket default
CORS is configured for PUT and GET from any origin (*) to support presigned upload URLs from the browser. Presigned PUT TTL defaults to 600 seconds (GUIDES_PRESIGNED_PUT_TTL); presigned GET TTL defaults to 300 seconds (GUIDES_PRESIGNED_GET_TTL).
Stores student handwritten photo submissions uploaded from mobile apps.
Prefix
Contents
Lifecycle
(root)
Student photos (UUID-named, no PII in key)
Deleted after 30 days
The 30-day lifecycle rule is a COPPA compliance requirement — student minors’ images must not be retained longer than necessary. The OCRJob.s3_purge_at field tracks the expected deletion date independently for auditing.
Migration files live in prisma/migrations/. Each migration is a timestamped directory containing a migration.sql file generated by Prisma Migrate.
# Create a new migration during developmentpnpm prisma migrate dev --name <descriptive-name># Apply pending migrations in CI / productionpnpm prisma migrate deploy# Open Prisma Studio (GUI) against the local databasepnpm prisma studio
The seed script (prisma/seed.ts) creates a demo school, courses, students, and exercises. pnpm seed:full runs the seed and also imports the innova-ai-engine error taxonomy into the error_tags table. The auth seed (pnpm seed:auth) is guarded by ALLOW_SEED=1 and creates demo Supabase Auth users idempotently via the Admin REST API.
Connection pooling in serverless mode: Prisma is configured with @prisma/adapter-pg and the pg driver. In production, DATABASE_URL must point to the Supabase transaction pooler on port :6543 with ?pgbouncer=true&connection_limit=1 appended. This prevents each Lambda container from holding an open idle connection — without it, a burst of concurrent invocations will exhaust Supabase’s connection limit. The PrismaService implements a serverless-safe singleton so that warm Lambda containers reuse an existing PrismaClient instance rather than constructing a new one on every invocation.