diff --git a/docs/superpowers/plans/2026-07-31-class-task-allocation-names.md b/docs/superpowers/plans/2026-07-31-class-task-allocation-names.md new file mode 100644 index 0000000..a5962cb --- /dev/null +++ b/docs/superpowers/plans/2026-07-31-class-task-allocation-names.md @@ -0,0 +1,90 @@ +# Class Task Allocation Names Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Make the teacher task-allocation table display each selected teaching class's edited training-task names while keeping publication selection keyed by `taskKey`. + +**Architecture:** The task-allocation view will load task rows through the existing class-scoped training-task API after a teaching class is selected. The API already applies the class override over the school default. Only the table's data source changes; publication state and save payloads continue to use `taskKey`. + +**Tech Stack:** Vue 3 Composition API, Vite, Node.js static contract tests using `assert`. + +## Global Constraints + +- Only task names are synchronized; selection range, selection state, sort order, and saved publication keys must remain unchanged. +- Use the selected teaching class only; never substitute data from another class after a request failure. +- Continue saving publication entries as `taskKey` values in `module`. + +--- + +## File Structure + +- Modify `src/views/teacherEnd/task/index.vue`: load the table's task rows from the selected teaching class and retain its current key-based publication behavior. +- Modify `tests/task-publication.static.test.cjs`: assert the class-scoped API is imported and is used during selected-class loading. + +### Task 1: Load task names by teaching class + +**Files:** +- Modify: `tests/task-publication.static.test.cjs` +- Modify: `src/views/teacherEnd/task/index.vue:35-121` + +**Interfaces:** +- Consumes: `listClassTrainingTasks(teachingClassId, { enabledOnly: false })` from `src/api/trainingTask.js`, returning `{ data: TrainingTask[] }` with `taskKey` and class-resolved `taskName`. +- Consumes: `indexApi.getTaskPublication({ classId })`, returning `{ data: { configured: boolean, taskKeys: string[] } }`. +- Produces: `tasks.value`, whose task rows contain the selected class's `taskName`; `selectedTaskKeys.value`, whose entries remain `taskKey` strings. + +- [ ] **Step 1: Write the failing contract test** + +Add these assertions to `tests/task-publication.static.test.cjs` immediately after the existing `listTrainingTasks` assertion: + +```js +assert(taskPage.includes("listClassTrainingTasks"), "task allocation must load training tasks for the selected teaching class"); +assert(taskPage.includes("await listClassTrainingTasks(classId.value, { enabledOnly: false })"), "class task loading must request disabled and enabled tasks"); +``` + +- [ ] **Step 2: Run the contract test and verify it fails** + +Run: `node tests/task-publication.static.test.cjs` + +Expected: `AssertionError` stating that task allocation must load training tasks for the selected teaching class. + +- [ ] **Step 3: Implement class-scoped task loading** + +In `src/views/teacherEnd/task/index.vue`: + +1. Replace the `listTrainingTasks` import with `listClassTrainingTasks`. +2. Replace the parameterless default-task loader with: + +```js +async function loadTasks() { + if (!classId.value) { + tasks.value = []; + return; + } + const res = await listClassTrainingTasks(classId.value, { enabledOnly: false }); + tasks.value = res.data || []; +} +``` + +3. At the start of `loadPublication`, after the empty-class guard, call `await loadTasks()` before reading publication state so table rows are refreshed for every class switch. +4. In `onMounted`, load classes first, then call `loadPublication`; remove the parallel default-task request because the selected class loader supplies the task rows. + +Do not change `applySelection`, `handleSelectionChange`, or `savePublication`; they must continue to operate on `task.taskKey`. + +- [ ] **Step 4: Run the contract test and verify it passes** + +Run: `node tests/task-publication.static.test.cjs` + +Expected: `task publication front-end contract passed`. + +- [ ] **Step 5: Build the frontend** + +Run: `npm run build:prod` + +Expected: Vite completes successfully and emits the production bundle without Vue compilation errors. + +- [ ] **Step 6: Commit the implementation** + +```bash +git add tests/task-publication.static.test.cjs src/views/teacherEnd/task/index.vue +git commit -m "feat: show class task names in allocation" +```