|
| 1 | +# Survey Branching Implementation Status |
| 2 | + |
| 3 | +## Completed Features ✅ |
| 4 | + |
| 5 | +### Database Layer |
| 6 | +- ✅ Added `QuestionGroup` model with properties: |
| 7 | + - Id, SurveyId, GroupNumber, GroupName, NextGroupId, SubmitAfterGroup |
| 8 | +- ✅ Added `GroupId` property to `Question` model (default 0) |
| 9 | +- ✅ Added `BranchToGroupId` property to `ChoiceOption` model for branching logic |
| 10 | +- ✅ Created and applied migration `20251013180811_AddSurveyBranching` |
| 11 | + |
| 12 | +### ViewModels |
| 13 | +- ✅ Created `QuestionGroupViewModel` in Common project |
| 14 | +- ✅ Updated `ChoiceOptionViewModel` with `BranchToGroupId` |
| 15 | +- ✅ Updated `QuestionViewModel` with `GroupId` |
| 16 | +- ✅ Updated `SurveyViewModel` with `QuestionGroups` list |
| 17 | +- ✅ Updated AutoMapper configuration for all new mappings |
| 18 | + |
| 19 | +### API Layer |
| 20 | +- ✅ Created `QuestionGroupController` with full CRUD operations: |
| 21 | + - GET api/QuestionGroup/Survey/{surveyId} - Get groups for a survey |
| 22 | + - GET api/QuestionGroup/{id} - Get specific group |
| 23 | + - POST api/QuestionGroup - Create new group |
| 24 | + - PUT api/QuestionGroup - Update existing group |
| 25 | + - DELETE api/QuestionGroup/{id} - Delete group (moves questions to group 0) |
| 26 | +- ✅ Added UpdateGroup endpoint to `QuestionController` |
| 27 | +- ✅ Updated `SurveyController` to include QuestionGroups when fetching surveys |
| 28 | +- ✅ Added `QuestionGroup` constant to `ApiEndpoints` |
| 29 | + |
| 30 | +### UI - Survey Creation/Management |
| 31 | +- ✅ Created `BranchingSurveyEdit.razor` page with comprehensive UI: |
| 32 | + - Collapsible accordion panels for each question group |
| 33 | + - Add/delete question groups |
| 34 | + - Assign custom names to groups |
| 35 | + - Move questions between groups |
| 36 | + - Configure branching for Multiple Choice, Select All That Apply, and True/False questions |
| 37 | + - Set group completion behavior (Submit or Branch to another group) |
| 38 | + - Visual indicators showing group names or numbers |
| 39 | +- ✅ Added "Configure Branching" button to main EditSurvey page |
| 40 | +- ✅ Full drag-and-drop support maintained for question ordering |
| 41 | +- ✅ Validation to ensure deleted groups move questions back to group 0 |
| 42 | + |
| 43 | +## Remaining Work 🚧 |
| 44 | + |
| 45 | +### UI - Survey Taking Experience |
| 46 | +The following enhancements are needed in `Survey.razor` and `Survey.razor.cs`: |
| 47 | + |
| 48 | +#### 1. One-Question-at-a-Time Display |
| 49 | +When a survey has multiple groups (more than just group 0), the interface should: |
| 50 | +- Display only the current question instead of all questions |
| 51 | +- Show Previous/Next buttons for navigation |
| 52 | +- Show Submit button only at the end of the survey |
| 53 | +- Disable Next button until current question is answered |
| 54 | + |
| 55 | +#### 2. Progress Indicator |
| 56 | +- Add a progress bar or counter showing "Question X of Y" |
| 57 | +- Update dynamically as user progresses through branching paths |
| 58 | +- Account for conditional questions that may or may not be shown |
| 59 | + |
| 60 | +#### 3. Branching Logic Implementation |
| 61 | +In `Survey.razor.cs`, implement: |
| 62 | + |
| 63 | +```csharp |
| 64 | +// Track which questions have been shown in current session |
| 65 | +private List<int> _shownQuestions = new(); |
| 66 | +private int _currentQuestionIndex = 0; |
| 67 | + |
| 68 | +// Determine next question based on answer and branching rules |
| 69 | +private int? GetNextQuestion(QuestionViewModel currentQuestion, AnswerViewModel answer) |
| 70 | +{ |
| 71 | + // For Multiple Choice - check if selected option has branching |
| 72 | + if (answer is MultipleChoiceAnswerViewModel mcAnswer) |
| 73 | + { |
| 74 | + var option = GetSelectedOption(currentQuestion, mcAnswer.SelectedOptionId); |
| 75 | + if (option?.BranchToGroupId != null) |
| 76 | + { |
| 77 | + return GetFirstQuestionInGroup(option.BranchToGroupId.Value); |
| 78 | + } |
| 79 | + } |
| 80 | + |
| 81 | + // For Select All That Apply - determine branching based on checked options |
| 82 | + // (Implementation note: may need to decide on priority if multiple options selected) |
| 83 | + |
| 84 | + // For True/False - check branching configuration |
| 85 | + // (Note: Need to extend ChoiceOption or add separate table for True/False branching) |
| 86 | + |
| 87 | + // Check if current group is complete |
| 88 | + var currentGroup = GetQuestionGroup(currentQuestion.GroupId); |
| 89 | + if (IsGroupComplete(currentGroup)) |
| 90 | + { |
| 91 | + if (currentGroup.SubmitAfterGroup) |
| 92 | + { |
| 93 | + return null; // End survey |
| 94 | + } |
| 95 | + else if (currentGroup.NextGroupId.HasValue) |
| 96 | + { |
| 97 | + return GetFirstQuestionInGroup(GetGroupNumber(currentGroup.NextGroupId.Value)); |
| 98 | + } |
| 99 | + } |
| 100 | + |
| 101 | + // Default: return next question in sequence |
| 102 | + return GetNextQuestionInSequence(currentQuestion); |
| 103 | +} |
| 104 | +``` |
| 105 | + |
| 106 | +#### 4. Captcha Handling |
| 107 | +- Ensure captcha is shown at the START of survey (already implemented) |
| 108 | +- Do not show captcha again during branching navigation |
| 109 | + |
| 110 | +#### 5. Answer Persistence |
| 111 | +- Save answers immediately when user moves to next question |
| 112 | +- Handle case where user goes back and changes an answer |
| 113 | +- Recalculate branching path if answers change |
| 114 | + |
| 115 | +### Data Model Considerations |
| 116 | + |
| 117 | +#### True/False Branching |
| 118 | +Currently, True/False questions don't have "options" like Multiple Choice. Consider: |
| 119 | +- **Option A**: Extend True/False to have two implicit ChoiceOptions (True, False) |
| 120 | +- **Option B**: Add separate branching fields to TrueFalseQuestion model |
| 121 | +- **Current Implementation**: Uses Dictionary in UI (TrueBranch/FalseBranch) but not persisted |
| 122 | + |
| 123 | +**Recommendation**: Add BranchToGroupIdOnTrue and BranchToGroupIdOnFalse to TrueFalseQuestion model. |
| 124 | + |
| 125 | +### Testing Requirements |
| 126 | + |
| 127 | +1. **Single Group Survey** - Ensure existing surveys (all in group 0) continue to work exactly as before |
| 128 | +2. **Linear Branching** - Group 0 → Group 1 → Group 2 → Submit |
| 129 | +3. **Conditional Branching** - Multiple choice option determines which group to show next |
| 130 | +4. **Skip Groups** - Group 0 → Group 3 (skip 1 and 2 based on answer) |
| 131 | +5. **Return to Earlier Group** - Group 0 → Group 1 → back to Group 0 questions |
| 132 | +6. **Dead End Detection** - Validate that all branches eventually lead to submission |
| 133 | +7. **Select All That Apply** - Handle branching when multiple options selected |
| 134 | + |
| 135 | +### Documentation Updates |
| 136 | + |
| 137 | +- Update CreatingSurveys.razor docs page with branching instructions |
| 138 | +- Add screenshots of branching UI |
| 139 | +- Create user guide for setting up conditional logic |
| 140 | +- Document best practices for survey flow design |
| 141 | + |
| 142 | +## Known Limitations |
| 143 | + |
| 144 | +1. **Select All That Apply Branching**: When multiple options are selected, need to decide on branch priority |
| 145 | + - Possible solutions: Take first selected option's branch, OR show union of all branched groups |
| 146 | + |
| 147 | +2. **True/False Branching Persistence**: Currently only configured in UI, needs backend persistence |
| 148 | + |
| 149 | +3. **Circular References**: No validation yet to prevent Group A → Group B → Group A loops |
| 150 | + |
| 151 | +4. **Group Deletion**: When deleting a group that is referenced as NextGroupId by another group, |
| 152 | + need to update those references |
| 153 | + |
| 154 | +## Architecture Decisions |
| 155 | + |
| 156 | +### Why Separate Branching Page? |
| 157 | +- EditSurvey.razor was already feeling crowded (per requirements) |
| 158 | +- Branching is advanced functionality - not needed for simple surveys |
| 159 | +- Separates concerns: question content vs. flow logic |
| 160 | +- Easier to navigate and understand for users |
| 161 | + |
| 162 | +### Why Group Numbers vs. IDs? |
| 163 | +- GroupNumber (0, 1, 2...) is more user-friendly than database IDs |
| 164 | +- Allows easy reference in UI ("Go to Group 2") |
| 165 | +- Group 0 is special "default" group that always exists |
| 166 | +- Actual database uses Ids for relationships, GroupNumber for display |
| 167 | + |
| 168 | +### Why Not Question-Level Next? |
| 169 | +- Group-based branching is clearer for users to understand and configure |
| 170 | +- Reduces complexity of the branching UI |
| 171 | +- Still allows fine-grained control by putting each question in its own group if needed |
| 172 | +- More maintainable codebase |
| 173 | + |
| 174 | +## Next Steps |
| 175 | + |
| 176 | +Priority order for remaining implementation: |
| 177 | + |
| 178 | +1. **High Priority**: Implement one-question-at-a-time display when groups exist |
| 179 | +2. **High Priority**: Implement basic branching logic in Survey.razor.cs |
| 180 | +3. **Medium Priority**: Add progress indicator |
| 181 | +4. **Medium Priority**: Handle True/False branching persistence |
| 182 | +5. **Low Priority**: Add circular reference validation |
| 183 | +6. **Low Priority**: Update documentation |
| 184 | + |
| 185 | +## Migration Path for Existing Surveys |
| 186 | + |
| 187 | +All existing surveys will automatically have their questions in Group 0 (default value). |
| 188 | +They will continue to display all questions on one page unless groups are explicitly added. |
| 189 | +This ensures backward compatibility. |
0 commit comments