diff --git a/docs/superpowers/specs/2026-07-02-training-task-class-scope-design.md b/docs/superpowers/specs/2026-07-02-training-task-class-scope-design.md new file mode 100644 index 0000000..8d0d352 --- /dev/null +++ b/docs/superpowers/specs/2026-07-02-training-task-class-scope-design.md @@ -0,0 +1,205 @@ +# Training Task Class Scope Design + +## Goal + +Limit teacher-edited training tasks to the students in teaching classes created by that teacher, while allowing platform administrators to maintain a system default version. + +Students should see the training task configuration for their own teaching class. If their teaching class has no custom configuration, they should see the administrator-maintained default task. + +## Current Behavior + +Training task configuration is currently global: + +- The teacher page reads `/api/training-tasks`. +- Student task pages read `/api/training-tasks/key/{taskKey}`. +- The `training_task` table is keyed by `task_key`. +- The student side does not pass or resolve a teaching class when loading the task background, goals, requirements, or material. + +The student menu is currently mostly route-driven in the frontend. Training task records override titles and provide content/materials, but they are not the only source of menu existence. + +## Target Roles + +Administrator: + +- Maintains system default training tasks. +- These defaults are used when a teaching class has no custom task configuration. +- The system should initialize with default task skeletons so the menu/task catalog has stable keys, names, sort order, and enabled state. + +Teacher: + +- Can edit training task configurations only for teaching classes created by that teacher. +- Must choose a teaching class before editing training tasks. +- Saved configurations affect only that teaching class. + +Student: + +- Loads task configuration according to the student's teaching class. +- Cannot choose or spoof another teaching class id through the frontend API. +- Sees class-specific configuration first, then administrator default configuration as fallback. + +## Data Model + +Keep `training_task` as the administrator default task table. + +Add a class-level override table, suggested name: `training_task_class_config`. + +Suggested fields: + +- `id` +- `teaching_class_id` +- `task_key` +- `project_name` +- `task_name` +- `background` +- `objectives` +- `requirements` +- `steps` +- `material_name` +- `material_url` +- `sort` +- `enabled` +- `created_by` +- `create_time` +- `update_time` + +Unique rules: + +- `training_task.task_key` remains unique for default tasks. +- `training_task_class_config` uses unique key `(teaching_class_id, task_key)`. + +Indexes: + +- `(teaching_class_id, task_key)` +- `(teaching_class_id, enabled, sort)` +- `created_by` if teacher-owned filtering needs fast lookup. + +## Default Task Initialization + +The system should initialize built-in task skeletons in `training_task`. + +The skeleton must include: + +- `task_key` +- `project_name` +- `task_name` +- `sort` +- `enabled` + +The content fields can be empty if needed: + +- `background` +- `objectives` +- `requirements` +- `material_name` +- `material_url` + +This ensures administrators and teachers always have a stable task catalog to edit, and students always have a fallback source. + +## Backend API Design + +Administrator APIs: + +- Existing `/api/training-tasks` can remain the default task management API. +- Only administrator-level users should be allowed to create or edit default tasks after this change. +- These APIs operate on `training_task`. + +Teacher APIs: + +- Add class-scoped endpoints, for example: + - `GET /api/training-tasks/classes/{teachingClassId}` + - `GET /api/training-tasks/classes/{teachingClassId}/key/{taskKey}` + - `PUT /api/training-tasks/classes/{teachingClassId}/{taskKey}` +- Backend must verify the teaching class was created by the current teacher. +- Teacher saves write to `training_task_class_config`. +- If a class row does not exist yet, save should create it from the default task plus the submitted changes. + +Student APIs: + +- Keep student-facing loading simple, for example: + - `GET /api/training-tasks/key/{taskKey}` +- Backend resolves the logged-in student and determines the student's teaching class. +- Backend returns class override if present and enabled. +- If no class override exists, backend returns administrator default. +- The frontend should not pass `teachingClassId` for student reads. + +## Student Class Resolution + +The first implementation should assume one effective teaching class for a student. + +Resolution order: + +1. Find the student's teaching class membership. +2. If multiple teaching classes exist, choose the most deterministic current behavior available in existing data. +3. If there is no teaching class membership, fall back to administrator default task. + +If the product later needs multiple active teaching classes per student, add an explicit student-side teaching class switcher instead of guessing. + +## Frontend Changes + +Administrator side: + +- Add a training task management menu. +- Reuse the current task editing UI where practical. +- The page edits default tasks, not class overrides. + +Teacher side: + +- Training task management page starts with a teaching class selector. +- Selector lists only teaching classes created by the logged-in teacher. +- After selecting a class, the page loads class-specific task configuration with default fallback values. +- Save writes only to the selected teaching class. + +Student side: + +- Continue loading each route by `taskKey`. +- Display returned background, goals, requirements, and material. +- No student-side teaching class id should be sent. + +## Fallback Rules + +For a student task page: + +1. Use enabled class-specific task config for the student's teaching class. +2. If missing, use enabled administrator default task. +3. If default is missing, keep the route/menu stable but render empty content or a "not configured" state. + +For teacher edit pages: + +1. Show class override if it exists. +2. Otherwise show administrator default values as editable initial values. +3. Saving creates the class override. + +## Migration + +Existing rows in `training_task` remain administrator default tasks. + +Add the new class override table without deleting or rewriting existing default tasks. + +No class override rows need to be generated immediately. They can be created lazily when a teacher saves a class configuration. + +## Risks And Decisions + +Multiple teaching classes per student: + +- Initial behavior should use one effective class or fallback to default. +- A later switcher can support explicit multi-class selection. + +Permission leakage: + +- Student reads must resolve class server-side. +- Teacher edits must verify class ownership server-side. + +Menu consistency: + +- Current student menus are route-driven. +- Default task skeletons are still required to make task names, enabled state, sort order, and fallback content manageable from the admin side. + +## Acceptance Criteria + +- Administrators can edit default training task configuration from an admin menu. +- Teachers can edit training task configuration only after selecting one of their own teaching classes. +- A teacher cannot edit another teacher's teaching class task configuration. +- Students see their teaching class configuration when it exists. +- Students fall back to administrator default configuration when their class has no configuration. +- Case material follows the same class-specific then default fallback rule. +- The system initializes default task skeletons for all built-in task keys.