Overview
KnowledgeCheckr uses Zod for runtime type validation and TypeScript type inference. All schemas are defined in /src/schemas/ and provide robust validation for API requests and database operations.
KnowledgeCheck Schema
The main schema for creating and managing knowledge checks.
Source: src/schemas/KnowledgeCheck.ts
TypeScript Type
type KnowledgeCheck = {
id: string // UUID
name: string // Knowledge check name
description: string | null // Optional description
difficulty?: number // 1-10 scale
questions: Question[] // Array of questions
questionCategories?: CategorySchema[] // Question categories
share_key: string | null // Share token
openDate: Date // When check becomes available
closeDate: Date | null // Optional end date
createdAt?: Date
updatedAt?: Date
owner_id: string // User ID (max 36 chars)
collaborators: string[] // Array of user IDs
settings: KnowledgeCheckSettings // Check settings
}
Field Specifications
id
string
default:"auto-generated UUID"
Unique identifier for the knowledge check. Automatically generated if not provided.
name
string
default:"'Knowledge Check'"
The name under which the created check is associated with.
description
string | null
default:"auto-generated lorem"
Describe the concept of your knowledge check using a few words.
difficulty
number
default:"random 1-10"
Defines the skill level needed for this check. Must be between 1 and 10.
Array of questions. All question IDs must be unique.
questionCategories
CategorySchema[]
default:"[{id: UUID, name: 'general', ...}]"
Categories for organizing questions. Questions must reference existing categories.
openDate
Date | string
default:"new Date()"
The day on which users can start to use the check.
closeDate
Date | string | null
default:"null"
The last day on which the check can be used by others. Cannot be before openDate.
User ID of the check owner. Maximum 36 characters.
Array of user IDs who can collaborate on this check.
settings
KnowledgeCheckSettings
required
Configuration settings for practice and examination modes.
Validation Rules
- Question IDs must be unique
- All questions must reference a defined category
- closeDate cannot be before openDate
- owner_id must be a valid user ID (max 36 characters)
Usage Example
import { safeParseKnowledgeCheck, instantiateKnowledgeCheck } from '@/schemas/KnowledgeCheck'
// Validate existing data
const { success, error, data } = safeParseKnowledgeCheck(checkData)
if (!success) {
console.error('Validation failed:', error)
} else {
// data is fully typed and validated
console.log(data.name)
}
// Create new instance with defaults
const newCheck = instantiateKnowledgeCheck({
owner_id: 'user-123',
questions: [/* ... */],
settings: {/* ... */}
})
Question Schema
Schemas for different question types.
Source: src/schemas/QuestionSchema.ts
Base Question
All question types share these base fields:
UUID identifier for the question.
Points awarded for correct answer. Must be positive.
category
string
default:"'general'"
Category name this question belongs to.
The question text. Must be at least 3 words long.
accessibility
'all' | 'practice-only' | 'exam-only'
default:"'all'"
Specifies in which environments the question should be displayed.
Question Types
Single Choice
Questions with exactly one correct answer.
type SingleChoice = {
type: 'single-choice'
answers: Array<{
id: string // UUID
answer: string // Answer text
correct: boolean // Exactly one must be true
}>
} & BaseQuestion
Validation:
- Must have at least one answer
- Exactly one answer must be marked as correct
- All answer IDs and text must be unique
Example:
import { instantiateSingleChoice } from '@/schemas/QuestionSchema'
const question = instantiateSingleChoice({
id: '123e4567-e89b-12d3-a456-426614174000',
points: 10,
question: 'What is the capital of France?',
type: 'single-choice',
answers: [
{ id: 'ans-1', answer: 'London', correct: false },
{ id: 'ans-2', answer: 'Paris', correct: true },
{ id: 'ans-3', answer: 'Berlin', correct: false }
]
})
Multiple Choice
Questions with one or more correct answers.
type MultipleChoice = {
type: 'multiple-choice'
answers: Array<{
id: string // UUID
answer: string // Answer text
correct: boolean // At least one must be true
}>
} & BaseQuestion
Validation:
- Must have at least one answer
- At least one answer must be marked as correct
- All answer IDs and text must be unique
Drag and Drop
Questions where users order items in a specific sequence.
type DragDropQuestion = {
type: 'drag-drop'
answers: Array<{
id: string // UUID
answer: string // Answer text
position: number // 0-based position in sequence
}>
} & BaseQuestion
Validation:
- Positions must start from 0
- Positions must form a continuous range [0, n-1]
- No duplicate positions allowed
- All answer IDs and text must be unique
Example:
const dragDropQuestion = {
id: '123e4567-e89b-12d3-a456-426614174001',
type: 'drag-drop',
points: 15,
question: 'Order these events chronologically',
answers: [
{ id: 'ans-1', answer: 'World War I', position: 0 },
{ id: 'ans-2', answer: 'World War II', position: 1 },
{ id: 'ans-3', answer: 'Cold War', position: 2 }
]
}
Open Question
Free-form text questions.
type OpenQuestion = {
type: 'open-question'
expectation?: string // Optional expected answer
} & BaseQuestion
Category Schema
Organize questions into categories with prerequisite support.
Source: src/schemas/CategorySchema.ts
type CategorySchema = {
id: string // UUID (auto-generated)
name: string // Category name
prequisiteCategoryId: string | null // Optional prerequisite
skipOnMissingPrequisite: boolean // Skip if prerequisite not met
}
id
string
default:"auto-generated UUID"
Unique identifier for the category.
prequisiteCategoryId
string | null
default:"null"
ID of a prerequisite category. Must not be empty string if set.
Whether to skip questions in this category if prerequisite is not met.
KnowledgeCheck Settings Schema
Configuration for practice and examination modes.
Source: src/schemas/KnowledgeCheckSettingsSchema.ts
type KnowledgeCheckSettings = {
id: string
practice: {
enablePracticing: boolean // Enable practice mode
allowedPracticeCount: number | null // null = unlimited
}
examination: {
enableExaminations: boolean // Enable exam mode
startDate: Date // When exams can start
endDate: Date | null // When exams end (null = no limit)
questionOrder: 'create-order' | 'random'
answerOrder: 'create-order' | 'random'
allowAnonymous: boolean // Allow anonymous users
allowFreeNavigation: boolean // Allow question navigation
examTimeFrameSeconds: number // 60-18001 seconds (1min-5hrs)
examinationAttemptCount: number // Min 1 attempt
}
shareAccessibility: boolean // Publicly discoverable
}
Practice Settings
practice.enablePracticing
Defines whether users are able to practice with this check or not.
practice.allowedPracticeCount
number | null
default:"null"
The amount of practice attempts users have. When set to null, users have unlimited attempts. Minimum 1 if set.
Examination Settings
examination.enableExaminations
Defines whether users are able to start an examination attempt for this check.
examination.startDate
Date | string
default:"new Date()"
The start-date on which users can start examinations.
examination.endDate
Date | string | null
default:"1 year from now"
The end-date after which users can no longer start examinations. Set to null for no end constraint.
examination.questionOrder
'create-order' | 'random'
default:"'random'"
Defines how questions are ordered during exams.
examination.answerOrder
'create-order' | 'random'
default:"'random'"
Defines how answers are ordered during exams.
examination.allowAnonymous
Specifies whether anonymous users can interact with this check.
examination.allowFreeNavigation
Specifies whether users can switch between questions freely.
examination.examTimeFrameSeconds
The max duration users have to finish their examination attempt. Must be between 60 and 18001 seconds (1 minute to 5 hours).
examination.examinationAttemptCount
The amount of examination attempts users have. Minimum 1.
Examination Schema
Tracks examination attempts and results.
Source: src/schemas/ExaminationSchema.ts
type ExaminationSchema = {
knowledgeCheck: KnowledgeCheck // The check being examined
startedAt: Date // When exam started
finishedAt: Date | null // When exam completed
score: number // Current score
results: QuestionInput[] // User's answers
}
The knowledge check being examined (with schema effects stripped).
Timestamp when the examination started.
finishedAt
Date | null
default:"null"
Timestamp when the examination was completed. Null if still in progress.
Current score for the examination.
results
QuestionInput[]
default:"[]"
Array of user’s answers to questions.
Custom Zod Types
Source: src/schemas/CustomZodTypes.ts
StringDate
Accepts either a Date object or ISO date string and transforms it to a Date.
const StringDate = z
.union([z.date(), z.string()])
.transform((date) => (typeof date === 'string' ? new Date(date) : date))
.refine((check) => !isNaN(check.getTime()), 'Invalid date value provided')
Usage:
// Both are valid
StringDate.parse(new Date())
StringDate.parse('2024-03-01T12:00:00Z')
Schema Utilities
All schemas export three utility functions:
// Validate and throw on error
const data = validateKnowledgeCheck(input)
// Safe parsing with error handling
const { success, error, data } = safeParseKnowledgeCheck(input)
// Create instance with defaults
const instance = instantiateKnowledgeCheck(partialInput)
Source: src/schemas/utils/schemaUtilities.ts