Innova Backend Serverless deploys six Lambda functions via Serverless Framework 3, all targeting theDocumentation 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.
nodejs20.x runtime in us-east-1. One function hosts the entire NestJS REST API; the remaining five are purpose-built event-driven workers that handle async telemetry persistence, LLM classification, OCR transcription, scheduled alert generation, and OCR-to-attempt reprocessing. Every function is bundled by serverless-esbuild and shares the same IAM role with scoped SQS and S3 permissions.
Function Reference
api — NestJS HTTP Handler
Handler
src/lambda.handlerTrigger
API Gateway HTTP —
ANY / and ANY /{proxy+}Timeout
30 seconds
Memory
512 MB
api function is the front door for all HTTP traffic. It bridges API Gateway events to the full NestJS application using @vendia/serverless-express, meaning every controller, guard, interceptor, and pipe defined in AppModule runs inside a single Lambda invocation. The custom domain api.superprofes.app is mapped via serverless-domain-manager with TLS 1.2 and a regional endpoint.
telemetryWorker — Attempt Telemetry Persister
Handler
src/infrastructure/workers/telemetry-persister.handlerTrigger
SQS FIFO —
AttemptStreamQueue (attempt-stream.fifo)Timeout
60 seconds
Memory
256 MB
ReportBatchItemFailures so that a single bad message does not cause the entire batch to be retried.
- Receives ordered, deduplicated messages because the source queue is FIFO with
ContentBasedDeduplication: true. - Writes to the
attempt_eventsMongoDB collection (see Data Model). - Sets
archived_to_s3_atonce records are offloaded to the cold-storage S3 prefix.
llmClassifierWorker — LLM Classification Worker
Handler
src/infrastructure/workers/llm-classifier.handlerTrigger
SQS Standard —
LlmClassifyQueueTimeout
120 seconds
Memory
512 MB
UNCLASSIFIED and writes results back to Postgres via Prisma. A LlmClassifyDLQ receives messages that fail after 3 receive attempts.
maximumBatchingWindow: 60lets Lambda accumulate up to 60 seconds of messages before invoking the function, keeping batches dense for better prompt-cache performance.- Each classification audit is written to
llm_classification_jobsin MongoDB (request tokens, cost, confidence per attempt). - 512 MB memory is required because Claude SDK client initialization and JSON marshalling of large batch responses are memory-intensive.
ocrWorker — Handwritten Math OCR Worker
Handler
src/infrastructure/workers/ocr-worker.handlerTrigger
S3
ObjectCreated:* on innova-backend-serverless-{stage}-ocr-uploadsTimeout
60 seconds
Memory
512 MB
ocr_jobs MongoDB collection and then enqueued on AttemptReprocessQueue.
existing: truetells Serverless Framework not to create the bucket — it is managed separately asOcrUploadsBucketin theresourcesblock.- Each OCR job tracks
primary_provider,used_fallback,cost_estimated_usd, andoverall_confidence. - Photos with
status: low_confidence_revieware flagged for human review rather than auto-discarded.
alertGenerator — Scheduled Teacher Alert Generator
Handler
src/infrastructure/workers/alert-generator.handlerTrigger
EventBridge schedule —
rate(1 hour)Timeout
60 seconds
Memory
256 MB
TeacherAlert records from mastery data. It uses @prisma/adapter-pg directly (no NestJS DI) to keep cold-start latency minimal for a cron function. Alerts are deduplicated per teacher/type/topic/day so the teacher dashboard doesn’t flood.
| Alert Type | Trigger | Severity |
|---|---|---|
AT_RISK_STUDENT | pKnown < 0.4 in ≥ 2 active topics | HIGH |
STUDENT_DROP | No attempts in the last 3 days | MED |
UNIT_OFF_TRACK | Course-wide average pKnown < 0.3 in a unit | HIGH |
attemptReprocessWorker — OCR-to-Attempt Reprocess Worker
Handler
src/infrastructure/workers/attempt-reprocess.handlerTrigger
SQS Standard —
AttemptReprocessQueueTimeout
60 seconds
Memory
256 MB
innova-ai-engine back into a full Attempt record in Postgres. It boots a cached NestJS application context (via NestFactory.createApplicationContext) so the full AttemptReprocessWorker service with its DI dependencies is available across warm invocations. Per-message failures are reported individually via ReportBatchItemFailures, with a DLQ after 5 failed receive attempts.
- Parses
AttemptReprocessMessagefrom each SQS record body. - If
guide_submission_idis present, creates a newAttemptwithinputMode='PHOTO_GUIDE'(ADR-120/121). - Legacy OCR-loop messages carry only
attempt_idand omit guide fields — both shapes are handled.
Cold Start Considerations
NestJS dependency injection initialization adds approximately 200–400 ms to cold starts on top of the standard Lambda container boot time. The following mitigations are in place:Cached application context
attemptReprocessWorker (the heaviest worker) caches NestFactory.createApplicationContext result in a module-level variable. Subsequent warm invocations skip the NestJS boot entirely.serverless-express bridge
The
api function uses @vendia/serverless-express to adapt API Gateway events to the NestJS HTTP adapter. The Express app is initialized once per container lifetime.Prisma serverless adapter
All functions that use Prisma instantiate the client with
@prisma/adapter-pg pointing to Supabase’s transaction pooler (:6543) with ?pgbouncer=true&connection_limit=1 to avoid exhausting connection pool slots across concurrent Lambda containers.Error Handling
All SQS-triggered workers usefunctionResponseType: ReportBatchItemFailures. This means each worker’s handler returns an SQSBatchResponse with a batchItemFailures array — only the failed message IDs are returned to SQS for re-queuing. Successful messages in the same batch are not retried.
| Queue | maxReceiveCount | DLQ Retention |
|---|---|---|
LlmClassifyQueue | 3 | 14 days |
AttemptReprocessQueue | 5 | 14 days |
esbuild decorator bundling: Serverless Framework bundles all functions with
serverless-esbuild. NestJS relies on TypeScript decorator metadata (design:paramtypes) for its dependency injection container, but esbuild strips this metadata by default. A custom plugin — esbuild-decorators.cjs — is wired in via custom.esbuild.plugins to preserve it. Without this plugin, NestJS DI would resolve all constructor parameters as undefined at runtime. The keepNames: true flag is also set to prevent esbuild from mangling class names that NestJS uses for token resolution.