8.6 KiB
Teacher Student Roster Scope 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 student management list and authorize students strictly by teaching-class ownership for ordinary teachers and by school scope for administrator teachers.
Architecture: UserController will derive the permitted teaching-class set from the authenticated operator record and use it for listing and every roster mutation. The Vue page will show only teaching classes, use each returned row's teachingClassId for unfiltered actions, and render the four actions in a single horizontal line.
Tech Stack: Spring Boot, MyBatis, JUnit 5 + Mockito, Vue 3 Composition API, Element Plus, Node static assertions.
Global Constraints
- Only
TEACHINGclasses are eligible for student management. - Ordinary teachers can access only teaching classes whose
created_byequals their user ID. - Administrator teachers are users with role
3andteacherAdmin=true; they can access everyTEACHINGclass in their own school. - Backend authorization must use the server-resolved operator record; client-supplied class and operator values cannot widen access.
- The operation column must render 编辑、删除、密码初始化、数据初始化 in one non-wrapping horizontal row.
Task 1: Define and test backend teaching-class scope
Files:
- Modify:
link_commerce/src/test/java/com/sztzjy/linkCommerce/controller/stu/UserControllerTeacherAdminTest.java - Modify:
link_commerce/src/main/java/com/sztzjy/linkCommerce/controller/stu/UserController.java
Interfaces:
-
Consumes:
Userinfo.teacherAdmin,SchoolClass.classType,SchoolClass.createdBy,TeachingClassStudentMapper. -
Produces:
resolveManagedRosterStudentIds(Userinfo operator, String teachingClassId)andcanManageTeachingClass(Userinfo operator, SchoolClass teachingClass)for list and mutation authorization. -
Step 1: Write failing controller tests for the manager scope
Add tests that configure one owned teaching class and one other teacher's teaching class in the same school. Assert that an administrator teacher's unfiltered selectStudent query includes the member IDs from both classes, while an ordinary teacher's unfiltered query includes only the owned member ID. Add a test that an administrator teacher can update a student member of the other class and that an ordinary teacher receives BAD_REQUEST for that same class.
assertTrue(hasUserCondition(capturedExample, "user_id in", Arrays.asList("owned-student", "other-student")));
assertEquals(HttpStatus.OK, managerResult.getStatusCode());
assertEquals(HttpStatus.BAD_REQUEST, ordinaryResult.getStatusCode());
- Step 2: Run the targeted test and verify RED
Run: mvn -Dtest=UserControllerTeacherAdminTest test
Expected: the manager-scope assertions fail because the current implementation resolves only created_by = operatorId and isOwnedTeachingClass rejects another teacher's class.
- Step 3: Implement one shared teaching-class scope helper
In UserController, add canManageTeachingClass(Userinfo operator, SchoolClass teachingClass). It must return true only for a TEACHING class in the operator's school when the operator is an administrator teacher or the class creator. Add resolveManagedRosterStudentIds that resolves the selected class when present, or all same-school teaching classes otherwise, then unions active membership student IDs.
Replace resolveOwnedRosterStudentIds use in selectStudent; replace direct isOwnedTeachingClass checks in teacher-roster add/update and single-student data initialization with the shared helper. Update canOperateClass so an administrator teacher may operate same-school TEACHING classes in roster mode. Keep cross-school and ordinary-teacher foreign-class requests rejected.
- Step 4: Run targeted tests and verify GREEN
Run: mvn -Dtest=UserControllerTeacherAdminTest test
Expected: all tests pass, including new ordinary/administrator scope assertions.
- Step 5: Commit the backend scope change
git -C link_commerce add src/main/java/com/sztzjy/linkCommerce/controller/stu/UserController.java src/test/java/com/sztzjy/linkCommerce/controller/stu/UserControllerTeacherAdminTest.java
git -C link_commerce commit -m "feat: scope student roster by teacher authority"
Task 2: Render scoped teaching classes and usable row actions
Files:
- Modify:
e-commerce-internet/src/views/teacherEnd/student/index.vue - Modify:
e-commerce-internet/tests/teacher-owned-student-management.static.test.cjs - Modify:
e-commerce-internet/tests/teacher-student-roster-mode.static.test.cjs
Interfaces:
-
Consumes:
userStore.userInfo.teacherAdmin, teaching-class list from/api/user/seleteSchoolClassListBySchoolId, and row fieldteachingClassId. -
Produces:
teachingClassOptions,resolveRowTeachingClassId(row), and a non-wrapping action group used by all four student actions. -
Step 1: Write failing static tests for the page contract
Extend the Node static tests to assert that the page filters every dropdown option to classType === "TEACHING", branches on userStore.userInfo.teacherAdmin, and passes resolveRowTeachingClassId(row) to delete, password initialization, and data initialization. Assert the operation template always contains all four buttons and CSS has white-space: nowrap for its action group.
assert(page.includes('const isManagerTeacher = computed(() => userStore.userInfo.teacherAdmin === true)'), "管理员教师身份必须显式参与学生范围判断");
assert(page.includes('resolveRowTeachingClassId(row)'), "未选择班级时,行操作必须使用行所属教学班");
assert(page.includes('white-space: nowrap'), "学生操作按钮不得换行");
- Step 2: Run the static tests and verify RED
Run: node tests/teacher-owned-student-management.static.test.cjs; node tests/teacher-student-roster-mode.static.test.cjs
Expected: the new assertions fail because the page currently mixes administrative classes, hides operations when no class is selected, and sends an empty teaching class for unfiltered row actions.
- Step 3: Implement the page scope and action layout
Add isManagerTeacher. Build teachingClassOptions solely from same-school TEACHING classes: for a manager teacher use all of them; otherwise retain only createdBy === currentUserId. Use it for the dropdown in all modes. Keep the default schoolClassId empty so the backend returns the applicable aggregate list.
Replace row-level view-only rendering with an action group containing the four buttons. Add resolveRowTeachingClassId(row) that uses the selected class ID first and otherwise row.teachingClassId; use it for edit, delete, password initialization, and data initialization. When a row has no teaching class ID, show an error and do not call the API. Add scoped CSS for the action group with flex layout, flex-wrap: nowrap, and white-space: nowrap.
- Step 4: Run static tests and production build
Run: node tests/teacher-owned-student-management.static.test.cjs; node tests/teacher-student-roster-mode.static.test.cjs; npm run build:prod
Expected: both static checks pass and Vite emits dist successfully.
- Step 5: Commit the frontend page change
git -C e-commerce-internet add src/views/teacherEnd/student/index.vue tests/teacher-owned-student-management.static.test.cjs tests/teacher-student-roster-mode.static.test.cjs
git -C e-commerce-internet commit -m "feat: scope student management by teacher authority"
Task 3: Full regression verification
Files:
- Verify:
link_commerce/src/test/java/** - Verify:
e-commerce-internet/tests/*.cjs
Interfaces:
-
Consumes: completed backend scope and frontend page changes.
-
Produces: verified local behavior ready for merge and release.
-
Step 1: Run all backend tests
Run: mvn test
Expected: exit code 0 with all JUnit tests passing.
- Step 2: Run relevant frontend regression checks
Run: node tests/teacher-owned-student-management.static.test.cjs; node tests/teacher-student-roster-mode.static.test.cjs; node tests/school-product-config.static.test.cjs
Expected: each command prints its passing confirmation and exits 0.
- Step 3: Inspect the final diffs
Run: git -C link_commerce diff --check HEAD~1..HEAD; git -C e-commerce-internet diff --check HEAD~1..HEAD
Expected: no whitespace errors and no unrelated tracked files.