diff --git a/.gitignore b/.gitignore index 9625039..1a9cb2b 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,6 @@ node_modules/ !.env.example !*.env.example .codex -AGENTS.md \ No newline at end of file +AGENTS.md + +education-support-management/ \ No newline at end of file diff --git a/backend/docs/staff-attendance.md b/backend/docs/staff-attendance.md index 75e04ca..3f495b6 100644 --- a/backend/docs/staff-attendance.md +++ b/backend/docs/staff-attendance.md @@ -108,8 +108,10 @@ Associations (`belongsTo`): `organization`, `campus`, `user`, `createdBy`, `upda ## Tests - `src/services/staff_attendance.test.ts` verifies school report scope includes both school-owned - users and campuses under the school, and that school-scope office attendance upserts are scoped to - school office users. + users and campuses under the school, summary completion counts for fill-only users, school-scope + office attendance upserts, and campus/class staff upserts that store the resolved campus. +- `src/db/seeders/user-roles.test.ts` verifies the seeded attendance filler/report-reader roles, + including notification eligibility through `FILL_ATTENDANCE` or `READ_STAFF_ATTENDANCE_REPORTS`. ## Related diff --git a/backend/docs/users.md b/backend/docs/users.md index f7775f3..0fbc902 100644 --- a/backend/docs/users.md +++ b/backend/docs/users.md @@ -62,15 +62,19 @@ record when `req.params.id`/`req.body.id` equals their own id. otherwise `ValidationError('errors.forbidden.message')`. - `create` rejects a duplicate email (`iam.errors.userAlreadyExists`) and a missing email (`iam.errors.emailRequired`). -- Teacher users can be seeded with `CREATE_USERS` / `UPDATE_USERS` so they can manage student and - guardian accounts from `/my-class`. Service-level role policy limits that access to the `student` - and `guardian` target roles. Class-scope guards require student targets and requested `classId` - values to match the teacher's own `classId`; guardian updates require an existing - `guardian_students` link to a student in the teacher's class. Class-scoped user management cannot - add custom permissions or permission exclusions. +- Teacher users are seeded with `CREATE_USERS` / `UPDATE_USERS` and + `CREATE_GUARDIAN_STUDENTS` so they can manage student and guardian accounts from `/my-class`. + Service-level role policy limits that access to the `student` and `guardian` target roles. + Class-scope guards treat a student as in the teacher's class when either `users.classId` matches + or an active `class_enrollments` row links the student to that class. Requested student `classId` + values must stay unset or match the teacher's own class. Guardian updates require an existing + `guardian_students` link to a student in the teacher's class, using the same direct-class or + enrollment-backed membership rule. Class-scoped user management cannot add custom permissions or + permission exclusions. - Guardian-student links are handled by `guardian_students`. Teachers also receive `CREATE_GUARDIAN_STUDENTS`; the link service verifies class-scoped actors only link `guardian` - users to `student` users in their own class. + users to `student` users in their own class, including students whose class membership is stored + only in `class_enrollments`. ## Tenant Scope @@ -96,9 +100,11 @@ hook trims `email`/`firstName`/`lastName`; for non-local OAuth providers `before `emailVerified = true` and generates a random bcrypt password when none is supplied. Associations: `belongsToMany permissions` as `custom_permissions` (and `custom_permissions_filter` -for list filtering) through `usersCustom_permissionsPermissions`; `hasMany messages` as `messages_sent_by`; `belongsTo roles` as `app_role`; `belongsTo -organizations` as `organizations`; `hasMany file` as `avatar`; `belongsTo users` as -`createdBy`/`updatedBy`. +for list filtering) through `usersCustom_permissionsPermissions`; `hasMany messages` as +`messages_sent_by`; `belongsTo roles` as `app_role`; `belongsTo organizations` as +`organizations`; `belongsTo classes` as `class`; `hasMany class_enrollments` as +`class_enrollments_student` for enrollment-backed student class display and scope checks; +`hasMany file` as `avatar`; `belongsTo users` as `createdBy`/`updatedBy`. On `create`/`bulkImport` the repository sets `emailVerified` to `true` on single create and to `false` (unless supplied) on bulk import. A user created without an explicit `app_role` has no role and falls back to the `guest` role @@ -136,7 +142,14 @@ List filters (`findAll`): `id`, `firstName`, `lastName`, `phoneNumber`, `email`, ## Tests -None yet (no `users` unit/e2e test under `src/`). +- `src/services/users.test.ts` covers teacher create/update access for student and guardian + accounts, including enrollment-backed students that do not have a direct `users.classId`. +- `src/services/guardian_students.test.ts` covers class-scoped guardian-student linking for + enrollment-backed students and rejects links outside the teacher's class. +- `src/services/shared/role-policy.test.ts` covers the role-management matrix, including teacher + limits to student and guardian accounts. +- `src/db/seeders/user-roles.test.ts` covers the seeded teacher roster-management permission + grants. ## Related diff --git a/backend/src/db/migrations/20260623091000-backfill-all-teacher-student-user-management.ts b/backend/src/db/migrations/20260623091000-backfill-all-teacher-student-user-management.ts index 6110508..8115c02 100644 --- a/backend/src/db/migrations/20260623091000-backfill-all-teacher-student-user-management.ts +++ b/backend/src/db/migrations/20260623091000-backfill-all-teacher-student-user-management.ts @@ -1 +1,11 @@ -export { default } from './20260623090000-grant-teacher-student-user-management'; +import type { QueryInterface } from 'sequelize'; + +export default { + up: async (_queryInterface: QueryInterface) => { + // Kept as a timestamp marker for deployments that saw the intermediate + // backfill name. The canonical idempotent grant is 20260623090000. + }, + down: async (_queryInterface: QueryInterface) => { + // No-op by design; teacher roster permissions are baseline role grants. + }, +}; diff --git a/backend/src/db/migrations/20260623092000-backfill-teacher-guardian-link-permission.ts b/backend/src/db/migrations/20260623092000-backfill-teacher-guardian-link-permission.ts index 6110508..ef13355 100644 --- a/backend/src/db/migrations/20260623092000-backfill-teacher-guardian-link-permission.ts +++ b/backend/src/db/migrations/20260623092000-backfill-teacher-guardian-link-permission.ts @@ -1 +1,11 @@ -export { default } from './20260623090000-grant-teacher-student-user-management'; +import type { QueryInterface } from 'sequelize'; + +export default { + up: async (_queryInterface: QueryInterface) => { + // Kept as a timestamp marker for deployments that saw the intermediate + // guardian-link backfill name. The canonical idempotent grant is 20260623090000. + }, + down: async (_queryInterface: QueryInterface) => { + // No-op by design; teacher guardian-link permission is a baseline role grant. + }, +}; diff --git a/frontend/docs/campus-attendance-integration.md b/frontend/docs/campus-attendance-integration.md index aceb514..28c2ed9 100644 --- a/frontend/docs/campus-attendance-integration.md +++ b/frontend/docs/campus-attendance-integration.md @@ -88,6 +88,7 @@ API/data access layer: ## Verification - `frontend/src/business/campus-attendance/selectors.test.ts` covers attendance calculations, scope titles, staff daily summaries, and staff-only summary selectors. -- `frontend/src/business/campus-attendance/printReport.test.ts` covers printable report generation with separate student, staff, and combined attendance totals. +- `frontend/src/business/campus-attendance/printReport.test.ts` covers printable staff-attendance + report generation and no-data labels. - `frontend/src/business/campus-attendance/printReport.test.ts` covers blocked-popup handling for attendance report printing. - `frontend/src/business/campus-attendance/mappers.test.ts` covers API DTO mapping. diff --git a/frontend/docs/my-class-integration.md b/frontend/docs/my-class-integration.md index 05d1c0b..1c0d35f 100644 --- a/frontend/docs/my-class-integration.md +++ b/frontend/docs/my-class-integration.md @@ -20,6 +20,8 @@ linked guardian accounts for each student. - The page requires the signed-in user to have a `classId`; otherwise it shows the existing unassigned-class message. - The Students section lists class-scoped student users from `GET /api/users?classId=`. + Backend listing includes both direct `users.classId` matches and students linked through + `class_enrollments`, which is how the seeded class roster is represented. - The add/edit form is collapsible. It is fixed to the current class, the seeded `student` role id, and the seeded `guardian` role id. It does not show arbitrary role, tenant, or custom-permission controls. @@ -36,14 +38,16 @@ linked guardian accounts for each student. - The UI enables create/edit controls only when the current user has `CREATE_USERS` or `UPDATE_USERS`, a current `classId`, and the `student` / `guardian` role ids have loaded. - Backend user service guards remain authoritative: class-scoped users can only manage student - accounts in their own class and guardian accounts linked to students in their own class. The - guardian-student link service also verifies that class-scoped links connect a `guardian` user to - a `student` user in the teacher's own class. Class-scoped user management cannot add custom - permissions or permission exclusions. + accounts in their own class and guardian accounts linked to students in their own class. Direct + `users.classId` and `class_enrollments` membership both count as own-class membership, so seeded + enrollment-backed students can be edited from `/my-class`. The guardian-student link service also + verifies that class-scoped links connect a `guardian` user to a `student` user in the teacher's + own class. Class-scoped user management cannot add custom permissions or permission exclusions. ## Tests - `frontend/src/business/my-class/selectors.test.ts` covers payload normalization and permission / class / role gating. - Backend coverage lives in `backend/src/services/users.test.ts`, + `backend/src/services/guardian_students.test.ts`, `backend/src/services/shared/role-policy.test.ts`, and `backend/src/db/seeders/user-roles.test.ts`. diff --git a/frontend/docs/test-coverage.md b/frontend/docs/test-coverage.md index 6a2d951..0a7dfcc 100644 --- a/frontend/docs/test-coverage.md +++ b/frontend/docs/test-coverage.md @@ -35,6 +35,7 @@ Current coverage includes architecture guardrails, API/data-access behavior, and - `frontend/src/business/esa-funding/selectors.test.ts` - `frontend/src/business/frame/mappers.test.ts` - `frontend/src/business/frame/selectors.test.ts` +- `frontend/src/business/my-class/selectors.test.ts` - `frontend/src/business/audio-files/selectors.test.ts` - `frontend/src/business/audio-files/generate.test.ts` - `frontend/src/business/zone-checkin/selectors.test.ts` @@ -67,6 +68,7 @@ Current coverage includes architecture guardrails, API/data-access behavior, and - `frontend/src/shared/api/contentCatalog.test.ts` - `frontend/src/shared/api/frame.test.ts` - `frontend/src/shared/api/httpClient.test.ts` +- `frontend/src/shared/api/guardianStudents.test.ts` - `frontend/src/shared/api/personality.test.ts` - `frontend/src/shared/api/safetyQuizResults.test.ts` - `frontend/src/shared/api/staffAttendance.test.ts` @@ -81,7 +83,7 @@ Current coverage includes architecture guardrails, API/data-access behavior, and - `frontend/src/hooks/usePermissions.test.tsx` - `frontend/src/components/sign-in-modal/SignInForm.test.tsx` -These tests verify import-boundary enforcement, centralized network access through `shared/api/httpClient`, alias-only source imports, required API contract-test coverage, HTTP client request normalization, cookie-backed auth refresh behavior, JSON body serialization, empty response handling, backend error propagation, API wrapper endpoint/query/body contracts, shared list/query/error helpers, route config, module route metadata, module access correction, sidebar navigation selectors, mobile sidebar overlay visibility, auth display/profile mapping, signup validation, campus mapping, dashboard and director dashboard selectors, classroom support selectors including search over titles/descriptions and favorites-only filtering, timer formatting/progress/threshold parsing, DTO mapping, FRAME edit access, campus attendance mapping, calculations, and printable report output, staff attendance mapping and rollups, walkthrough create DTO mapping, walkthrough filtering, walkthrough check-in stats/history mapping, walkthrough scoring, generated summaries, repeated low-rating flags, communication role visibility, community catalog filtering and stats, ESA funding selectors, policy mapping/filtering/validation, safety-protocol mapping and authoring (steps/considerations) validation, audio-library management gating and the local recipe-generation stub, daily Zone check-in eligibility/nudge/completion API, QBS/EI/personality completion reminders, header search over accessible modules + their content, outside-click dismissal, the shared American (Sunday-start) week canonicalization, F.R.A.M.E. week/label mapping, safety quiz compliance mapping and editable payload validation, unified profile quiz result rows including Daily Zone Check-In, sign language selectors, top bar display selectors, user progress normalization including Classroom Support favorite list/upsert API contracts, vocational zip/category/search/stat calculations, zones selectors, personality DTO mapping, personality distribution grouping, EI thresholds, personality quiz progress, and MBTI-derived communication guidance. +These tests verify import-boundary enforcement, centralized network access through `shared/api/httpClient`, alias-only source imports, required API contract-test coverage, HTTP client request normalization, cookie-backed auth refresh behavior, JSON body serialization, empty response handling, backend error propagation, API wrapper endpoint/query/body contracts, guardian-student API contracts, shared list/query/error helpers, route config, module route metadata, module access correction, sidebar navigation selectors, mobile sidebar overlay visibility, auth display/profile mapping, signup validation, campus mapping, dashboard and director dashboard selectors, classroom support selectors including search over titles/descriptions and favorites-only filtering, timer formatting/progress/threshold parsing, DTO mapping, FRAME edit access, My Class student/guardian payload normalization and permission gating, campus attendance mapping, calculations, and printable staff report output, staff attendance mapping and rollups, walkthrough create DTO mapping, walkthrough filtering, walkthrough check-in stats/history mapping, walkthrough scoring, generated summaries, repeated low-rating flags, communication role visibility, community catalog filtering and stats, ESA funding selectors, policy mapping/filtering/validation, safety-protocol mapping and authoring (steps/considerations) validation, audio-library management gating and the local recipe-generation stub, daily Zone check-in eligibility/nudge/completion API, QBS/EI/personality completion reminders, header search over accessible modules + their content, outside-click dismissal, the shared American (Sunday-start) week canonicalization, F.R.A.M.E. week/label mapping, safety quiz compliance mapping and editable payload validation, unified profile quiz result rows including Daily Zone Check-In, sign language selectors, top bar display selectors, user progress normalization including Classroom Support favorite list/upsert API contracts, vocational zip/category/search/stat calculations, zones selectors, personality DTO mapping, personality distribution grouping, EI thresholds, personality quiz progress, and MBTI-derived communication guidance. The component and hook tests verify SignInForm rendering, loading states, user interactions, form submission, password visibility toggling, auth session initialization, sign-in/sign-out flows, AuthExpiredError handling, modal workflow state management, and permissions hook behavior including has(), hasAny(), hasAll() methods with globalAccess support and explicit personal-workflow exclusions.