Quiz Management & Question Bank
Source: Dev.to
Data Model
- One Quiz has many Questions
- One Question has many Options
- One Option can be marked as the correct answer
These nested relations appear simple during initial data creation but become significantly more complex when entering the editing process.
Complex Data Editing
A typical editing workflow might look like this:
- A teacher opens the quiz editor.
- Changes the quiz title.
- Deletes question #2.
- Edits the text of question #5.
- Adds a new question at the end.
All changes are sent to the backend with a single Save click. The backend must decide how to apply these modifications.
Approaches
| Approach | Pros | Cons |
|---|---|---|
| Partial Update (Diffing) | Updates only changed parts. | Complex, hard to maintain, prone to bugs in nested relations. |
| Full Replacement | Simple implementation. | Risk of losing data references. |
Modified Full Replacement (Academic Suite)
Academic Suite uses a modified full replacement wrapped in a database transaction to balance simplicity, data consistency, and safety. The entire update process is performed atomically; if any step fails, all changes are rolled back.
UpdateQuiz Implementation (handlers/quiz.go)
// Go (gorm)
err := database.DB.Transaction(func(tx *gorm.DB) error {
// 1. Update main quiz data (title, duration, etc.)
if err := tx.Save(&quiz).Error; err != nil {
return err
}
// 2. Delete all old questions
if err := tx.Delete(&models.Question{}, "quiz_id = ?", id).Error; err != nil {
return err
}
// 3. Re‑insert questions from request
for _, q := range req.Questions {
q.QuizID = id
if err := tx.Create(&q).Error; err != nil {
return err
}
}
return nil
})
Consequences
- Question IDs change on every edit.
- If
answersorattemptstables referencequestion_id, student grade data can be corrupted.
Production Safeguards
- Quizzes that are Active or have Attempts should be locked (frozen).
- Alternatively, use soft delete or versioning for questions to preserve exam history.
Excel Question Import
Typing dozens of questions via a web form is inefficient, so Academic Suite provides an import feature from Excel (.xlsx) files.
- Library used:
github.com/xuri/excelize/v2
Data Validation Challenges
Excel files are free‑form:
- Columns can be empty.
- Formatting can be inconsistent.
- Correct answers may be in the wrong position.
The backend validates each row individually:
// Go
for i, row := range rows {
if len(row) < 7 {
errors = append(errors, fmt.Sprintf(
"Row %d: Incomplete columns",
i+1,
))
continue
}
// Further parsing and validation...
}
Benefits
- Valid rows are still saved.
- Problematic rows are reported specifically to the user, improving the experience without sacrificing data consistency.
Efficient Data Retrieval
To display a quiz with all its questions and answer options, Academic Suite uses GORM’s eager loading, preventing the N+1 query problem.
// Go (gorm) – eager loading
database.DB.
Preload("Questions").
Preload("Questions.Options").
First(&quiz, "id = ?", id)
With eager loading, performance remains stable even for quizzes with a large number of questions.
Summary
In this chapter we built the foundation of a stable and scalable Question Bank and Quiz Management system. Key points covered:
- Challenges of nested updates.
- Transaction strategies to maintain data consistency.
- Risks of editing active quizzes and mitigation techniques.
- User‑friendly Excel import with row‑level validation.
- Eager loading techniques for optimal performance.
Next up: Chapter 5 will dive into the Exam Engine, covering timer settings, exam status, and precise grading mechanisms.