/** * Exam-marker types — mirror the FastAPI /api/exam contract (see api routers/exam/schemas.py). * Supabase is source of truth for this operational data; the graph (cc.public.exams) joins by * the shared UUIDs (template/question/region ids, exam_code). */ export type ExamTemplateStatus = 'draft' | 'ready' | 'archived'; export interface ExamTemplate { id: string; title: string; subject: string | null; exam_id: string | null; exam_code: string | null; source_file_id: string | null; page_count: number | null; institute_id: string; teacher_id: string; status: ExamTemplateStatus; created_at: string; updated_at: string; } export interface CreateTemplatePayload { title: string; subject?: string; exam_id?: string; exam_code?: string; source_file_id?: string; page_count?: number; institute_id?: string; } export type MarkSchemeType = 'points' | 'levels' | 'parts' | 'checklist' | 'free'; export interface MarkSchemePoint { mark: number; text: string; } export interface MarkSchemeLevel { level: string; min: number; max: number; descriptor: string; } export interface MarkSchemePart { label: string; marks: number; guidance: string; } export interface MarkSchemeChecklistItem { text: string; marks: number; } export interface MarkScheme { type?: MarkSchemeType; points?: MarkSchemePoint[]; levels?: MarkSchemeLevel[]; parts?: MarkSchemePart[]; checklist?: MarkSchemeChecklistItem[]; text?: string; notes?: string; [key: string]: unknown; } export interface UpdateTemplateMetaPayload { title?: string; subject?: string | null; page_count?: number | null; status?: ExamTemplateStatus; } /** Canvas children (used from S4-9 onward; defined here so the seam is complete). */ export interface ExamQuestion { id: string; template_id: string; parent_id: string | null; label: string; order: number; max_marks: number; answer_type: string | null; mcq_options: unknown | null; mark_scheme: MarkScheme; is_container: boolean; spec_ref: string | null; bounds?: Record | null; page?: number | null; } export type ExamResponseAreaKind = | 'response' | 'context' | 'question_number' | 'mark_area' | 'reference' | 'furniture'; export interface ExamResponseArea { id: string; question_id: string; template_id: string; page: number; bounds: Record; kind: ExamResponseAreaKind; response_form: string | null; context_type?: string | null; source: 'manual' | 'ai'; confirmed: boolean; confidence: number | null; } export interface ExamBoundary { id: string; template_id: string; question_id: string | null; label: string | null; page_index: number; y: number; bounds: Record | null; source: 'manual' | 'ai'; confirmed: boolean; } export interface ExamTemplateDetail extends ExamTemplate { questions: ExamQuestion[]; response_areas: ExamResponseArea[]; boundaries: ExamBoundary[]; } export interface TemplateReplacePayload { meta?: { title?: string; subject?: string; page_count?: number; status?: ExamTemplateStatus; }; questions: Array<{ id?: string; parent_id?: string | null; label: string; order?: number; max_marks?: number; answer_type?: 'written' | 'mcq' | 'short' | 'diagram' | null; mcq_options?: unknown | null; mark_scheme?: Record; is_container?: boolean; spec_ref?: string | null; bounds?: Record | null; page?: number | null; }>; response_areas: Array<{ id?: string; question_id: string; page: number; bounds: Record; kind: ExamResponseArea['kind']; response_form?: string | null; context_type?: string | null; source?: 'manual' | 'ai'; confirmed?: boolean; confidence?: number | null; }>; boundaries: Array<{ id?: string; question_id?: string | null; label?: string | null; page_index: number; y: number; bounds?: Record | null; source?: 'manual' | 'ai'; confirmed?: boolean; }>; } export interface PatchQuestionPayload { label?: string; order?: number; max_marks?: number; answer_type?: 'written' | 'mcq' | 'short' | 'diagram' | null; mcq_options?: unknown; mark_scheme?: MarkScheme; is_container?: boolean; spec_ref?: string | null; } export interface SpecPoint { uid?: string; uuid_string?: string; ref: string; description: string; spec_code: string; exam_board_code?: string; } export interface Neo4jSyncResult { status: string; projection?: Record; } export interface MarkingBatch { id: string; template_id: string; class_id: string | null; institute_id: string; teacher_id: string; title: string | null; status: 'open' | 'closed' | 'archived' | string; created_at: string; updated_at?: string; submission_count?: number; } export interface StudentSubmission { id: string; batch_id: string; student_id: string | null; student_name: string | null; status: 'absent' | 'unmatched' | 'matched' | 'marking' | 'complete' | string; storage_path?: string | null; mark_entry_count?: number; } export interface BatchQueueResponse { batch: MarkingBatch; submissions: StudentSubmission[]; progress: { total: number; absent: number; complete: number; in_progress: number; }; } export interface ExamResultRow { submission_id: string; student_id: string | null; student_name: string | null; status: string | null; marks: Record; total: number | null; } export interface BatchResultsResponse { batch: MarkingBatch; questions: Array>; results: ExamResultRow[]; } export interface CreateBatchPayload { template_id: string; class_id?: string; title?: string; } export interface MarkUpsertPayload { submission_id: string; question_id: string; awarded_marks: number; mark_scheme_detail?: Record; annotation_shape_ids?: unknown; comment?: string; confirmed?: boolean; }