Allow instructors to group questions inside a single exercise into named sections, so one assignment, quiz, or exam can be structured into logical parts (e.g., "Section A: Multiple Choice", "Section B: Written Responses") with per-section instructions, navigation, and review.
## Terminology
- **Exercise question section**: A grouping inside one exercise. This PRD is about this concept.
- **Course section**: The existing course content grouping that contains lessons and exercises. This PRD does not change course sections.
- The existing `exercise.sectionId` field points to a **course section**. New question-level grouping must use `question.exerciseSectionId` / DB `question.exercise_section_id` so the two concepts are not overloaded.
Today, every exercise is a flat list of questions. Instructors cannot:
1.**Organize questions by topic or format** — a 30-question exam has no visual grouping, making it harder for students to navigate and for teachers to author.
2.**Provide per-section instructions** — if Section A requires different rules than Section B, the instructor must embed instructions into individual question prompts.
3.**Control post-section flow** — there is no way to submit answers after a subset of questions or to route students to a specific next section.
4.**Grade or review by section** — submissions are a single flat list, so teachers cannot quickly assess performance on distinct parts of an exercise.
| `exercise` table | Has `title`, `description`, and `section_id` for the parent course section; questions link via `question.exercise_id` | No internal question-section concept |
| `question` table | Has `exercise_id`, `order`, `title`, `points`, `question_type_id` | No `exercise_section_id` or section ordering |
| Exercise store | `questionnaire.questions` is a flat `Question[]` | No section grouping or section metadata |
| Edit mode UI | Renders all questions in a single vertical list | No section headers, section CRUD, or drag-between-sections |
| Take mode (view-mode) | Shows one question at a time via `currentQuestionIndex` on flat array | No section-at-a-time mode, no section overview screen |
| Question navigation | `QuestionNavigation` component has `onPrevious`/`onNext` with `isLast` flag | No section awareness |
| Preview mode | Renders all questions via `QuestionList` | No section grouping |
| Submissions/Grading UI | `individual.svelte` and `summary.svelte` iterate flat question list | No section-level subtotals |
| Exercise templates | `exercise_template.questionnaire` is `{ questions: [...] }` JSON | No sections in template schema |
| Clone service | `cloneExercises` copies exercises → questions → options | No section cloning |
| Progress bar | Computes `currentQuestionIndex / questions.length` | No section-aware progress |
1. An exercise is either **flat questions** (no sections) or **sections with questions** — not a mix of both. If an exercise has sections, every question must belong to a section.
3. Section scoring is the **sum of question points** within that section — no separate section-level weight multiplier.
4. Student display mode is **configurable per exercise**: either "one question at a time" (current behavior, but section-aware) or "one section at a time" (all questions in the current section shown together).
5. Students see a **section overview screen** before beginning each section (section title + description + question count + total points).
6. Students navigate sections **linearly by default**, but the post-section behavior can route them elsewhere.
7. Post-section behavior options: **"Continue to next section"** (default), **"Go to section [X]"** (select from list), **"Submit exercise"**.
8. Progress bar tracks **questions completed** (not sections). The question navigation sidebar shows questions **grouped by section** (e.g., "Section 1: Q1, Q2, Q3 | Section 2: Q1, Q2").
9. Grading UI shows submissions **grouped by section** with per-section subtotals and an overall total.
10. Existing exercises without sections continue to work exactly as they do today. Sections are **fully optional**.
11. Exercise templates support sections. Exercise cloning preserves sections.
12. Instructors can **drag questions between sections**, **reorder sections**, and **select which section** when adding a new question.
- Instructor can choose a section **color theme** from a fixed set of swatches. The selected theme appears as a dot in the section header and is persisted with the section.
- Instructor can configure the **after-section behavior** via a compact settings row near the section card when routing is in scope:
- "Go to section [X]" (dropdown listing all other sections by title)
- "Submit exercise"
- The last section's default after-section behavior is "Submit exercise".
#### FR-1.3: Delete Section
- Instructor can delete a section.
- When a section is deleted, the instructor is prompted: "Move questions to [other section] or delete them?"
- If the exercise has only one section and it's deleted, the exercise becomes sectionless and all questions remain as a flat list.
#### FR-1.4: Reorder Sections
- Instructor can reorder sections via drag-and-drop or an order modal (consistent with the existing question reorder pattern).
- When sections are reordered, the `order` field on each section is updated accordingly.
#### FR-1.5: Move Questions Between Sections
- Instructor can drag a question from one section to another.
- Instructor can move a question via a context menu: "Move to Section → [list of sections]".
- When adding a new question, the instructor selects which section it belongs to (defaults to the currently focused or last section).
### FR-2: Student Experience (Take Mode)
#### FR-2.1: Section Overview Screen
- Before the first question of each section, the student sees a section overview:
- Section title
- Section description (if any)
- Number of questions in this section
- Total points available in this section
- "Begin Section" button
- This mirrors the existing exercise start screen pattern but at the section level.
#### FR-2.2: Question Display Mode (Configurable)
The exercise has a setting `sectionDisplayMode` with two options:
- **`one_question`** (default): Questions are shown one at a time. The student navigates with Previous/Next buttons. A section header/indicator is visible showing which section the student is in (e.g., "Section 1 of 3 — Multiple Choice"). When the last question of a section is completed, the post-section behavior fires.
- **`all_questions`**: All questions in the current section are displayed together in a scrollable list. The student answers all questions and clicks a "Complete Section" button. Post-section behavior then fires.
#### FR-2.3: Post-Section Behavior
After completing a section:
- **"Continue to next section"**: Show the next section's overview screen.
- **"Go to section [X]"**: Show section X's overview screen.
- **"Submit exercise"**: Submit all answers collected so far and show the completion/grading screen.
If the student finishes the last section and its after-behavior is "Continue to next section" (or not explicitly set), the exercise auto-submits.
#### FR-2.4: Section-Aware Navigation
- The question navigation UI groups questions by section:
```
Section 1: Multiple Choice
Q1 Q2 Q3 Q4
Section 2: Written Responses
Q1 Q2
```
- Answered questions are visually distinguished (filled dot, checkmark, etc.).
- The current section and question are highlighted.
- Students can only navigate within the current section (no jumping between sections) unless the exercise allows free navigation (future enhancement, not v1).
#### FR-2.5: Progress Tracking
- The progress bar reflects **total questions answered / total questions** across all sections.
- A secondary indicator shows the current section (e.g., "Section 2 of 3").
#### FR-2.6: Autosave
- Existing autosave behavior extends to section-aware exercises.
- The autosaved state includes which section the student is currently in and which question within that section.
- On resume, the student returns to their last position (correct section and question).
### FR-3: Preview Mode (Instructor)
- Preview mode shows questions grouped under section headers.
- Each section header displays the section title and description.
- Questions are numbered within their section (Section 1: Q1, Q2; Section 2: Q1, Q2).
### FR-4: Grading & Submissions
#### FR-4.1: Section-Grouped Grading View
- In the individual student submission view (`individual.svelte`), questions are grouped under section headers.
- Each section shows a subtotal: "Section 1: 15/20 points".
- An overall total is shown at the top/bottom: "Total: 35/50 points".
#### FR-4.2: Summary Analytics
- In the summary view (`summary.svelte`), chart data is grouped by section.
- Each section has its own aggregate view before the overall aggregate.
### FR-5: Exercise Templates
- Exercise templates (`exercise_template` table) support sections in the `questionnaire` JSONB field.
- `exercise_section_id` is **nullable**. When `NULL`, the question belongs to a sectionless exercise (backward compatible).
- When a question is part of a sectioned exercise, `exercise_section_id` is required (enforced at the application level, not DB constraint, to keep migration safe).
questions: Array<{ /* questions without sections (backward compat) */ }>;
}
```
- If the exercise has sections, `sections` is populated and `questions` only contains ungrouped questions (should be empty for a properly formed sectioned exercise).
- If the exercise has no sections, `sections` is an empty array and `questions` contains all questions (current behavior preserved).
#### 4.2: Exercise Update — Accept Sections
The `PUT /course/:courseId/exercise/:exerciseId` endpoint accepts an optional `sections` array:
4. Validate that all `go_to_section` references point to valid section IDs within the same exercise.
5. Validate that if sections exist, every non-deleted question has a section assignment.
#### 4.3: Exercise Submission — Section-Aware
No changes to the submission API shape. Students still submit a flat array of `{ questionId, optionId?, answer? }`. The server groups answers by section for grading display, not at submission time.
- Shows a small muted required-question count on the left. Until optional questions ship, this count equals the active question count.
- Shows small up/down arrow icon buttons on the right for moving the section within the exercise.
If post-section routing remains in v1, render the "After section N" control as a compact settings row above the footer or in section settings. Do not overload the footer, which is reserved for required count and section reorder controls.
If section descriptions remain in v1, expose description editing in an expandable section settings area rather than in the compact header.
Questions can be dragged between sections, with context-menu movement as a fallback.
#### 8.2: New Dashboard Component — `SectionEditor`
A dropdown component that renders the "After section N" routing control. It should be visually adjacent to the section editor, but not inside the section editor footer.
- Exercise cloning without sections works as before.
- Exercise templates without sections work as before.
---
## Build and Verification Commands
```bash
pnpm --filter @cio/db build
pnpm --filter @cio/utils build
pnpm --filter @cio/question-types build
pnpm --filter @cio/ui build
pnpm --filter @cio/api build
pnpm --filter @cio/dashboard build
```
---
## Success Metrics (90 Days Post-Launch)
1. 30% of newly created exercises with 10+ questions use at least one section.
2. Students report improved navigation experience in sectioned exercises (qualitative feedback).
3. Grading time for sectioned exercises is comparable to flat exercises (no regression).
4. Zero backward-compatibility incidents for existing exercises.
---
## Risks and Mitigations
| Risk | Mitigation |
| --- | --- |
| Section-aware state machine in take mode adds complexity and potential navigation bugs | Comprehensive state machine tests; keep flat-exercise code path untouched |
| After-behavior "go to section" can create loops (A→B→A) | Validate at save time: warn if cycles detected, but allow (instructor may want loops intentionally for review) |
| Drag-and-drop between sections may be unreliable on mobile | Provide "Move to section" context menu as a fallback; drag-drop is enhancement only |
| Large exercises with many sections may slow down the editor | Lazy-render collapsed sections; only expand the active section |