Files
openccb/TEST_TEMPLATES_IMPLEMENTATION.md
T

8.3 KiB

Test Templates System - Implementation Summary

Overview

This document describes the implementation of a comprehensive Test Template System for OpenCCB, allowing instructors to create and reuse test/quiz templates based on:

  1. Course Level: beginner, beginner_1, beginner_2, intermediate, advanced, etc.
  2. Course Type: intensive or regular
  3. Assessment Type: CA, MWT, MOT, FOT, FWT

Database Changes

New Enums

-- Course levels
CREATE TYPE course_level AS ENUM (
    'beginner', 'beginner_1', 'beginner_2',
    'intermediate', 'intermediate_1', 'intermediate_2',
    'advanced', 'advanced_1', 'advanced_2'
);

-- Course types
CREATE TYPE course_type AS ENUM ('intensive', 'regular');

-- Test types (assessment types)
CREATE TYPE test_type AS ENUM ('CA', 'MWT', 'MOT', 'FOT', 'FWT');

New Tables

test_templates

Main table for storing test templates with metadata:

  • id: UUID primary key
  • organization_id: Multi-tenancy support
  • name, description: Template identification
  • level, course_type, test_type: Classification enums
  • duration_minutes, passing_score, total_points: Configuration
  • instructions: General test instructions
  • template_data: JSONB with complete test structure
  • tags: Text array for categorization
  • usage_count: Tracks template popularity
  • is_active: Soft delete support

test_template_sections

Optional sections within a test (e.g., "Reading", "Grammar", "Listening"):

  • template_id: Foreign key to test_templates
  • section_order: Ordering within template
  • points, instructions: Section-specific config
  • section_data: JSONB for advanced configuration

test_template_questions

Individual questions for each template:

  • template_id, section_id: Foreign keys
  • question_order: Ordering
  • question_type: "multiple-choice", "true-false", "short-answer", "essay", "matching", "ordering"
  • question_text, options, correct_answer, explanation: Question content
  • points, metadata: Scoring and additional data

Database Functions

  • get_test_templates_by_filters(): Filter templates by level, type, test type, and search
  • increment_template_usage(): Track template usage statistics

Course Model Updates

Added optional fields to courses table:

  • level: Course level enum
  • course_type: Course type enum

Backend Implementation

Models (shared/common/src/models.rs)

New Rust structs:

  • CourseLevel, CourseType, TestType: Enum types
  • TestTemplate, TestTemplateSection, TestTemplateQuestion: Main models
  • CreateTestTemplatePayload, UpdateTestTemplatePayload: Request/Response DTOs
  • TestTemplateWithQuestions: Composite response type

API Handlers (services/cms-service/src/handlers_test_templates.rs)

RESTful endpoints:

Method Endpoint Description
GET /test-templates List templates with filters
POST /test-templates Create new template
GET /test-templates/{id} Get template with questions
PUT /test-templates/{id} Update template
DELETE /test-templates/{id} Delete template
POST /test-templates/{id}/questions Add question
DELETE /test-templates/{id}/questions/{qid} Delete question
POST /test-templates/{id}/sections Add section
DELETE /test-templates/{id}/sections/{sid} Delete section
POST /test-templates/{id}/apply Apply template to lesson

Routes (services/cms-service/src/main.rs)

All routes are protected and require organization context.

Frontend Implementation

TypeScript Types (web/studio/src/lib/api.ts)

type CourseLevel = 'beginner' | 'beginner_1' | ... | 'advanced_2';
type CourseType = 'intensive' | 'regular';
type TestType = 'CA' | 'MWT' | 'MOT' | 'FOT' | 'FWT';
type QuestionType = 'multiple-choice' | 'true-false' | ...;

interface TestTemplate { ... }
interface TestTemplateSection { ... }
interface TestTemplateQuestion { ... }
interface CreateTestTemplatePayload { ... }

API Functions (cmsApi object)

  • listTestTemplates(filters)
  • getTestTemplate(templateId)
  • createTestTemplate(payload)
  • updateTestTemplate(templateId, payload)
  • deleteTestTemplate(templateId)
  • createTemplateQuestion(templateId, payload)
  • deleteTemplateQuestion(templateId, questionId)
  • createTemplateSection(templateId, payload)
  • deleteTemplateSection(templateId, sectionId)
  • applyTemplateToLesson(templateId, lessonId, gradingCategoryId)

UI Components

TestTemplateManager (web/studio/src/components/TestTemplates/TestTemplateManager.tsx)

Main management interface with:

  • Grid view of templates
  • Search functionality
  • Advanced filters (level, course type, test type)
  • Template cards showing:
    • Name, description
    • Level, type badges with color coding
    • Duration, passing score, total points
    • Tags
    • Usage statistics
    • Action buttons (view, edit, delete, apply)

TestTemplateForm (web/studio/src/components/TestTemplates/TestTemplateForm.tsx)

Modal form for creating/editing templates with:

  • Basic info (name, description)
  • Classification (level, course type, test type)
  • Configuration (duration, passing score, total points)
  • Instructions
  • Tag management

Page (web/studio/src/app/test-templates/page.tsx)

Dedicated page at /test-templates route.

Usage Examples

Creating a Template via API

curl -X POST http://localhost:3001/test-templates \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "X-Organization-Id: YOUR_ORG_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Final Exam - Beginner 1",
    "description": "Comprehensive final exam for beginner level",
    "level": "beginner_1",
    "course_type": "regular",
    "test_type": "FWT",
    "duration_minutes": 90,
    "passing_score": 70,
    "total_points": 100,
    "instructions": "Answer all questions. You have 90 minutes.",
    "tags": ["final", "beginner", "written"]
  }'

Filtering Templates

# Get all FOT templates for beginner intensive courses
curl "http://localhost:3001/test-templates?level=beginner_1&course_type=intensive&test_type=FOT" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"

Applying Template to a Lesson

curl -X POST http://localhost:3001/test-templates/TEMPLATE_ID/apply \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "X-Organization-Id: YOUR_ORG_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "lesson_id": "LESSON_ID",
    "grading_category_id": "CATEGORY_ID"
  }'

Migration

Run the migration to set up the database schema:

cd services/cms-service
sqlx migrate run --source migrations

The migration file is: 20260316000000_test_templates.sql

Future Enhancements

  1. Template Cloning: Allow duplicating existing templates
  2. Question Bank: Centralized repository of questions that can be mixed and matched
  3. Template Sharing: Share templates across organizations
  4. Analytics: Track template effectiveness and student performance
  5. AI Generation: Auto-generate templates based on course content
  6. Version Control: Track template revisions
  7. Bulk Operations: Apply templates to multiple lessons at once
  8. Preview Mode: Preview template before applying

File Structure

openccb/
├── shared/common/src/models.rs          # Rust models
├── services/cms-service/
│   ├── migrations/20260316000000_test_templates.sql
│   ├── src/handlers_test_templates.rs   # API handlers
│   └── src/main.rs                       # Routes
└── web/studio/
    ├── src/lib/api.ts                    # TypeScript types & API functions
    ├── src/components/TestTemplates/
    │   ├── TestTemplateManager.tsx
    │   ├── TestTemplateForm.tsx
    │   └── index.ts
    └── src/app/test-templates/
        └── page.tsx

Testing

Backend Tests

cargo test -p common
cargo test -p cms-service

Frontend Type Check

cd web/studio
npm run type-check

Notes

  • All templates are organization-scoped for multi-tenancy
  • Soft delete via is_active flag preserves historical data
  • Usage count helps identify popular templates
  • JSONB fields provide flexibility for evolving question types
  • The system integrates with existing grading categories via tipo_nota catalog