Skip to main content

Materials

Materials are files attached to a lesson — documents, slides, images, code files, and notes. After upload, each material goes through a background RAG (Retrieval-Augmented Generation) pipeline that extracts text, chunks it, and builds an embedding index so the AI assistant can cite it during chat.


Material Entity

{
"id": "mat_789",
"title": "Lecture Slides Week 1",
"label": "SLIDE",
"visibility_state": "DRAFT",
"processing_status": "READY",
"processing_stage": "READY",
"processing_progress_percent": 100,
"summary_text": "Introduction to sorting algorithms including bubble sort and merge sort.",
"original_file_name": "week1-slides.pdf",
"mime_type": "application/pdf",
"file_size_bytes": 2048576
}

Processing Status Values

The processing_status field gives a coarse view of where the material stands:

StatusDescription
PENDINGFile accepted; pipeline not yet started.
PROCESSINGPipeline is actively running.
READYPipeline completed successfully; material is searchable.
FAILEDPipeline encountered an unrecoverable error.

Processing Stage Values

The processing_stage field provides fine-grained pipeline progress:

StageDescription
QUEUEDWaiting for a pipeline worker to pick up the job.
EXTRACTINGExtracting raw text from the file.
CHUNKINGSplitting text into retrieval chunks.
EMBEDDINGGenerating vector embeddings for each chunk.
FINALIZINGWriting results to the knowledge store.
READYAll stages complete.
FAILEDA stage failed; check server logs.

Label Values

LabelDescription
DOCUMENTGeneral document (PDF, DOCX, etc.).
SLIDEPresentation slides.
IMAGEImage file (PNG, JPG, etc.).
CODESource code file.
NOTESFreeform notes (plain text, Markdown).

Endpoints

GET /api/v1/lessons/{lessonId}/materials

List all materials for a lesson.

Authentication: Required — approved class member or global ADMIN.

Visibility:

  • Students see only materials with visibility_state: "PUBLISHED".
  • Teachers/Admins see all materials regardless of state.

Response: List of material objects ordered by upload time.


POST /api/v1/lessons/{lessonId}/materials

Upload a new material file to a lesson.

Authentication: Required — class TEACHER or global ADMIN.

Content-Type: multipart/form-data

Form fields:

FieldRequiredDescription
fileYesThe file to upload. Maximum size: 30 MB.
titleNoDisplay title. Defaults to the original filename (without extension).
labelNoOne of DOCUMENT, SLIDE, IMAGE, CODE, NOTES. Defaults to DOCUMENT.

Response: Created material object with processing_status: "PENDING" and 201 Created. Background processing begins immediately after upload.


GET /api/v1/materials/{id}

Retrieve a single material including current processing status and stage.

Authentication: Required — approved class member (published only) or class TEACHER/global ADMIN.


PATCH /api/v1/materials/{id}

Update material metadata (title and/or label). Does not re-trigger processing.

Authentication: Required — class TEACHER or global ADMIN.

Request:

{
"title": "Week 1 Lecture Slides (Updated)",
"label": "SLIDE"
}

POST /api/v1/materials/{id}/publish

Publish a material, making it visible to students.

Authentication: Required — class TEACHER or global ADMIN.

Precondition: processing_status must be READY. Returns PRECONDITION_FAILED otherwise.

Request body: Empty.


POST /api/v1/materials/{id}/unpublish

Revert a published material to draft, hiding it from students.

Authentication: Required — class TEACHER or global ADMIN.

Request body: Empty.


DELETE /api/v1/materials/{id}

Soft-delete a material. The material is removed from the lesson view and excluded from RAG retrieval. The original file and embeddings are retained server-side.

Authentication: Required — class TEACHER or global ADMIN.

Response: 204 No Content.


GET /api/v1/materials/{id}/download

Download the original uploaded file.

Authentication: Required — approved class member (published materials only) or class TEACHER/global ADMIN.

Response: The raw file with appropriate Content-Type and Content-Disposition: attachment headers. The response is a direct file stream, not a JSON envelope.