You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
❌ This issue is not open for contribution. Visit Contributing guidelines to learn about the contributing process and how to find suitable issues.
Overview
Move the coach plugin's remaining API code — api.py, class_summary_api.py, unit_report_api.py, unit_lesson_progress_api.py, and serializers.py — into a kolibri/plugins/coach/viewsets/ package, one module per domain, deleting the old modules. This is the cleanup issue for the coach plugin under the File Organization convention in #14036; it covers everything except the classroom notifications domain, which moves with its migration in #14311.
Complexity: Medium Target branch: develop
Context
The coach plugin already deviates from the single-module pattern — its API code spans four modules plus serializers.py:
api.py: LessonReportViewset (serializer in serializers.py), the difficult-questions family (BaseExerciseDifficultQuestionsViewset, ExerciseDifficultQuestionsViewset, QuizDifficultQuestionsViewset, PracticeQuizDifficultQuestionsViewset), and the classroom notifications domain (moving in Migrate ClassroomNotificationsViewset to serializer-derived values pattern #14311)
class_summary_api.py: ClassSummaryViewSet plus its serialization helper functions
unit_report_api.py: UnitReportViewSet plus test-score computation helpers
Apart from ClassroomNotificationsViewset, none of these use the ValuesViewset serialization path, so this is a pure move with no serialization changes. Permission classes, filters, and module-level helpers move with their viewsets. A natural split is lesson_report.py, difficult_questions.py, class_summary.py, unit_report.py, and unit_lesson_progress.py; the final split is decided in the PR.
The Change
Move the remaining coach API code into kolibri/plugins/coach/viewsets/, one module per domain, with LessonReportSerializer inline above LessonReportViewset. Update imports in api_urls.py and anywhere else that references the moved classes, then delete api.py, class_summary_api.py, unit_report_api.py, unit_lesson_progress_api.py, and serializers.py. Land each module's relocation as a pure-move commit, separate from import updates.
Moving code breaks GitHub blame (local git blame -C -C still works), so digest the history the move obscures:
Run blame over the code being moved; flag hunks whose purpose isn't evident from the code or tests (odd guards, magic orderings, special cases).
Chase each flagged hunk to its originating PR/issue; where the rationale is non-obvious and load-bearing, carry it forward as a code comment citing the reference.
Where the rationale turns out to be obsolete, flag the code for removal — but as a pure move, this PR should not remove it; raise it for follow-up instead.
How to Get There
All affected endpoints are routed through the router in kolibri/plugins/coach/api_urls.py (lessonreport, classsummary, the difficult-questions routes, unitreport, etc.) — the single routing module whose imports this move updates.
Out of Scope
Any change to endpoint behavior or response shape — this is a pure move
Migrating any coach viewset to the serializer-derived pattern — none of the moved viewsets use the ValuesViewset serialization path
Removing obsolete code found during blame digestion — flag for follow-up instead
Acceptance Criteria
kolibri/plugins/coach/viewsets/ contains all remaining coach API viewsets, permissions, filters, and helper functions, one module per domain, with LessonReportSerializer inline above LessonReportViewset
api.py, class_summary_api.py, unit_report_api.py, unit_lesson_progress_api.py, and serializers.py are deleted
All references updated (api_urls.py, tests, any cross-module imports)
Each relocation lands as a pure-move commit, separate from import updates
Existing API tests pass unchanged
Comments citing the originating PR/issue added where blame digestion found non-obvious, load-bearing rationale
Testing
pytest kolibri/plugins/coach/test/ must pass unchanged — test_class_summary.py, test_difficult_questions.py, test_lesson_report.py, test_unit_report.py, and test_unit_lesson_progress.py cover all moved endpoints.
AI usage
Drafted with AI assistance (Claude Code) from an interactive design discussion, section by section, with review and final edits by @rtibbles. Module contents, routing, and test coverage were verified against the codebase during drafting.
❌ This issue is not open for contribution. Visit Contributing guidelines to learn about the contributing process and how to find suitable issues.
Overview
Move the coach plugin's remaining API code —
api.py,class_summary_api.py,unit_report_api.py,unit_lesson_progress_api.py, andserializers.py— into akolibri/plugins/coach/viewsets/package, one module per domain, deleting the old modules. This is the cleanup issue for the coach plugin under the File Organization convention in #14036; it covers everything except the classroom notifications domain, which moves with its migration in #14311.Complexity: Medium
Target branch: develop
Context
The coach plugin already deviates from the single-module pattern — its API code spans four modules plus
serializers.py:api.py:LessonReportViewset(serializer inserializers.py), the difficult-questions family (BaseExerciseDifficultQuestionsViewset,ExerciseDifficultQuestionsViewset,QuizDifficultQuestionsViewset,PracticeQuizDifficultQuestionsViewset), and the classroom notifications domain (moving in Migrate ClassroomNotificationsViewset to serializer-derived values pattern #14311)class_summary_api.py:ClassSummaryViewSetplus its serialization helper functionsunit_report_api.py:UnitReportViewSetplus test-score computation helpersunit_lesson_progress_api.py:UnitLessonProgressViewSetApart from
ClassroomNotificationsViewset, none of these use the ValuesViewset serialization path, so this is a pure move with no serialization changes. Permission classes, filters, and module-level helpers move with their viewsets. A natural split islesson_report.py,difficult_questions.py,class_summary.py,unit_report.py, andunit_lesson_progress.py; the final split is decided in the PR.The Change
Move the remaining coach API code into
kolibri/plugins/coach/viewsets/, one module per domain, withLessonReportSerializerinline aboveLessonReportViewset. Update imports inapi_urls.pyand anywhere else that references the moved classes, then deleteapi.py,class_summary_api.py,unit_report_api.py,unit_lesson_progress_api.py, andserializers.py. Land each module's relocation as a pure-move commit, separate from import updates.Moving code breaks GitHub blame (local
git blame -C -Cstill works), so digest the history the move obscures:How to Get There
All affected endpoints are routed through the router in
kolibri/plugins/coach/api_urls.py(lessonreport,classsummary, the difficult-questions routes,unitreport, etc.) — the single routing module whose imports this move updates.Out of Scope
ClassroomNotificationsViewset, its filter and permissions) — moves with its migration in Migrate ClassroomNotificationsViewset to serializer-derived values pattern #14311Acceptance Criteria
kolibri/plugins/coach/viewsets/contains all remaining coach API viewsets, permissions, filters, and helper functions, one module per domain, withLessonReportSerializerinline aboveLessonReportViewsetapi.py,class_summary_api.py,unit_report_api.py,unit_lesson_progress_api.py, andserializers.pyare deletedapi_urls.py, tests, any cross-module imports)Testing
pytest kolibri/plugins/coach/test/must pass unchanged —test_class_summary.py,test_difficult_questions.py,test_lesson_report.py,test_unit_report.py, andtest_unit_lesson_progress.pycover all moved endpoints.AI usage
Drafted with AI assistance (Claude Code) from an interactive design discussion, section by section, with review and final edits by @rtibbles. Module contents, routing, and test coverage were verified against the codebase during drafting.