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.

All Innova endpoints are REST + JSON. The API is deployed serverlessly on AWS Lambda and fronted by API Gateway at https://api.superprofes.app. Every request and response body is application/json. The full interactive OpenAPI specification is available at /docs on the running server.

Base URLs

During local development, run pnpm start:dev and open http://localhost:3000/docs for the always-current, interactive OpenAPI contract. The Swagger UI reflects every endpoint, DTO, and response schema automatically.

Response Envelope

Every successful response is wrapped in a standard envelope by the ResponseInterceptor. The data field contains the controller’s return value; timestamp, path, and traceId are top-level envelope fields for observability and debugging. The statusCode field is always 200 for success responses — use the HTTP response status line for non-200 codes.
{
  "statusCode": 200,
  "data": {
    "attemptId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "isCorrect": false,
    "errorTag": "BORROW_OMITTED"
  },
  "timestamp": "2024-01-15T10:30:00.000Z",
  "path": "/attempts",
  "traceId": "abc-123-def-456"
}
The traceId field maps directly to the x-trace-id request header (see Trace IDs). It is null when no trace ID could be resolved — this should not happen in normal operation.

HTTP Status Codes

CodeMeaning
200OK — request succeeded
201Created — resource created successfully
202Accepted — work enqueued asynchronously (e.g. LLM classification, guide ingest)
400Validation error — class-validator rejected one or more fields
401Missing or invalid JWT — attach a valid Supabase token in the Authorization header
403Authenticated but wrong role — your JWT role does not satisfy the required @Roles() guard
404Resource not found
500Internal server error — check logs with the traceId

Error Format

Errors are handled by AllExceptionsFilter, which catches HttpException, DomainException, Prisma known errors, and unhandled exceptions. Every error response shares the same shape:
{
  "statusCode": 400,
  "timestamp": "2024-01-15T10:30:00.000Z",
  "path": "/attempts",
  "traceId": "abc-123-def-456",
  "code": "Bad Request",
  "message": "studentId must be a UUID"
}
FieldTypeDescription
statusCodenumberHTTP status code mirrored in the body
timestampstringISO 8601 UTC timestamp of when the error occurred
pathstringRequest URL (may include query string)
traceIdstring | nullTrace ID for log correlation; matches the x-trace-id response header
codestringMachine-readable error code (e.g. P2002 for Prisma unique constraint, RESOURCE_NOT_FOUND for domain errors)
messagestringHuman-readable description, safe to surface in developer tooling
For 400 validation errors, message contains the concatenated class-validator constraint messages (e.g. "email must be an email", "password must be longer than or equal to 8 characters").

Trace IDs

Every inbound request passes through TraceIdMiddleware, which:
  1. Reads the x-trace-id header from the incoming request.
  2. If present, reuses that value; if absent, generates a new randomUUID().
  3. Attaches the trace ID to the request object (req.traceId) and echoes it back in the x-trace-id response header.
The same trace ID appears in:
  • The traceId field of every success response envelope.
  • The traceId field of every error response.
  • Every structured log line emitted by LoggingInterceptor and AllExceptionsFilter.
# Pass your own trace ID for end-to-end log correlation
curl https://api.superprofes.app/mastery/student-uuid \
  -H 'Authorization: Bearer eyJhbG...' \
  -H 'x-trace-id: my-frontend-request-id-001'
Generate a unique trace ID per user action in your frontend (e.g. crypto.randomUUID()) and pass it on every request. When an error occurs, report the trace ID to the backend team for instant log lookup.

Authentication

All endpoints require a valid Supabase JWT in the Authorization: Bearer <token> header — except:
  • GET / (root healthcheck) — decorated with @Public()
  • All /auth/* endpoints (register, login, refresh, forgot-password, confirm-forgot-password) — decorated with @Public()
The SupabaseAuthGuard checks for the @Public() decorator first; if present, JWT validation is skipped entirely. Otherwise the Supabase JWKS strategy validates the token against https://<project>.supabase.co/auth/v1/.well-known/jwks.json. See the Authentication page for the full token flow, role descriptions, and integration details.

Validation

All request bodies are validated with class-validator and transformed with class-transformer via NestJS’s global ValidationPipe. Key behaviors:
  • Unknown properties are stripped (whitelist mode).
  • Constraint violations throw a 400 Bad Request with message containing per-field error strings.
  • Type coercion is applied (e.g. a numeric string in a numeric field is accepted).
  • Required fields missing entirely produce "<field> should not be empty" or similar messages.
// Example 400 body when email is malformed and password is too short
{
  "statusCode": 400,
  "timestamp": "2024-01-15T10:30:00.000Z",
  "path": "/auth/register",
  "traceId": "abc-123",
  "code": "Bad Request",
  "message": "email must be an email, password must be longer than or equal to 8 characters"
}

Explore the API

Authentication

Register, log in, refresh tokens, and pass JWTs to every request. Role-based access control with Supabase RS256.

Attempts

Submit student work, trigger the rule engine and BKT mastery update, poll async classification status.

Mastery

Retrieve per-student, per-topic BKT mastery state, trend data, and teacher alert summaries.

Guides

Upload teacher worksheets, review extracted questions and LLM-generated solution keys, manage guide submissions.

Build docs developers (and LLMs) love