Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/vruizz22/innova-backend-serverless/llms.txt

Use this file to discover all available pages before exploring further.

The Guides pipeline lets teachers upload a worksheet PDF and have the system automatically extract its questions, generate a step-by-step solution key for each one, and grade student photo submissions — all without leaving the Innova dashboard. Teachers retain full editorial control at every stage: extracted questions can be edited and re-classified, solution keys can be regenerated or hand-edited, and individual student responses can have their error tag overridden. The result is a zero-marking workflow that still produces structured, per-question error analytics.

Pipeline Stages

1

Create guide

The teacher calls POST /guides with a title and courseId. The server verifies course ownership via CourseTeacher, creates a Guide record with status: UPLOADED, and returns a presigned S3 PUT URL for the PDF together with the new guideId.
2

Upload PDF

The teacher’s client PUTs the PDF file directly to S3 using the presigned URL. The file lands in the innova-backend-serverless-{stage}-guides bucket at key guides/uploads/{uuid}.pdf. No server bandwidth is consumed.
3

Ingest

The teacher calls POST /guides/:id/ingest. The server transitions the guide to EXTRACTING and publishes a GuideIngestMessage to the SQS_GUIDE_INGEST_URL queue. The innova-ai-engine worker picks up the message, runs OCR + LLM extraction on the PDF, and creates GuideQuestion records — one per detected question — each with a statementLatex, sequence, and AI-classified subdomain.
4

Review & approve

The guide transitions to REVIEW. The teacher inspects each extracted question in the UI, edits any statementLatex, and confirms the subdomain classification with PATCH /guides/:id/questions/:qid. Confirming a subdomain sets topicSource: TEACHER and topicConfidence: 1.0, anchoring the question to the taxonomy for error analysis.
5

Solution generation

On demand (or automatically after all questions are approved), the server enqueues a SolutionGenMessage to SQS_SOLUTION_GEN_URL. The AI engine generates a canonical solution for each approved question: a JSON object with final_answer, points, ordered steps (each with a LaTeX expression and an optional checkpoint flag), and optional alt_paths. The guide moves to GENERATING_SOLUTIONS and then back to REVIEW (status SOLUTION_READY at the question level).
6

Publish

The teacher calls POST /guides/:id/publish. The server verifies all questions are APPROVED or EXCLUDED, then runs a database transaction that:
  1. Creates an Assignment of kind: GUIDE with one AssignmentTarget per enrolled student.
  2. Materializes an Exercise row for each APPROVED question that has a confirmed topic.
  3. Flips the guide to PUBLISHED and records publishedAt.
The guide is now visible to enrolled students.
7

Student submission

Students call POST /student/guides/:id/questions/:qid/submissions to get one or more presigned PUT URLs for their handwritten photo(s). They PUT the JPEG/PNG directly to the innova-submissions-{stage} S3 bucket.
8

Photo upload & grading

The student calls POST /student/submissions/:id/complete. The server enqueues a grading message to SQS_SUBMISSION_GRADE_URL. The AI engine transcribes the handwriting, aligns it against the canonical solution checkpoints, determines correctness, and creates an Attempt record with a errorTag assigned via the rule engine (or LLM fallback). The GuideSubmission status transitions to GRADED.
9

Results

The teacher views GET /guides/:id/results, which returns a student × question matrix — every cell shows the latest submission’s correctness, score, error tag, and attempt number. Common error tags are aggregated per question to highlight class-wide patterns.

Guide State Machine

The guide lifecycle is enforced by assertTransition in guide-state-machine.ts. Invalid transitions throw InvalidGuideTransitionError.
// guide-state-machine.ts — TRANSITIONS registry
const TRANSITIONS: Record<GuideStatusValue, readonly GuideStatusValue[]> = {
  UPLOADED:              ['EXTRACTING', 'ARCHIVED'],
  EXTRACTING:            ['GENERATING_SOLUTIONS', 'EXTRACTION_FAILED', 'ARCHIVED'],
  EXTRACTION_FAILED:     ['EXTRACTING', 'ARCHIVED'],
  GENERATING_SOLUTIONS:  ['REVIEW', 'GENERATION_FAILED', 'ARCHIVED'],
  GENERATION_FAILED:     ['EXTRACTING', 'GENERATING_SOLUTIONS', 'ARCHIVED'],
  REVIEW:                ['PUBLISHED', 'GENERATING_SOLUTIONS', 'ARCHIVED'],
  PUBLISHED:             ['ARCHIVED'],
  ARCHIVED:              [],
};
The valid happy path is:
UPLOADED → EXTRACTING → GENERATING_SOLUTIONS → REVIEW → PUBLISHED → ARCHIVED
Both EXTRACTION_FAILED and GENERATION_FAILED are retryable: calling POST /guides/:id/ingest from either state re-queues the work. A guide can be ARCHIVED from any non-terminal state.
Nothing is visible to students before PUBLISHED. The GET /student/guides endpoint filters by status, so teachers can safely iterate on extraction and solution quality without students seeing partial work.

Scan-Page Mode

For handwritten worksheets where all questions are on one page, students can upload a single full-page photo instead of individual question photos:
  1. GET /student/guides/:id/scan-page-url — returns a presigned PUT URL targeting the submissions bucket.
  2. Student PUTs the page image.
  3. POST /student/guides/:id/scan-page — the server enqueues a scan-split job. The AI engine splits the page into per-question regions, creates one GuideSubmission per question, and grades each independently.
This mode is especially useful for younger students who submit physical worksheets digitized by a classroom camera or scanner.

S3 Storage Layout

Two buckets, each with its own lifecycle policy:
Bucket patternContentsLifecycle
innova-backend-serverless-{stage}-guidesSource PDFs (guides/uploads/*.pdf)1-year expiry
innova-submissions-{stage}Student handwriting photos30-day expiry
The bucket names are injected via S3_GUIDES_BUCKET and S3_SUBMISSIONS_BUCKET environment variables. The GuidesService raises a BadRequestException at startup if either variable is absent, ensuring misconfiguration is caught before any request is served.
Presigned URL TTLs are configurable via environment variables. The defaults are:
  • GUIDES_PRESIGNED_PUT_TTL600 seconds (10 min) for PDF uploads
  • GUIDES_PRESIGNED_GET_TTL300 seconds (5 min) for teacher preview URLs
  • SUBMISSIONS_PRESIGNED_GET_TTL300 seconds (5 min) for student photo preview in the results drawer
Increase GUIDES_PRESIGNED_PUT_TTL for slow network environments (e.g., rural schools with limited bandwidth).

Build docs developers (and LLMs) love