99 lines
5.4 KiB
Markdown
99 lines
5.4 KiB
Markdown
# Walk-Through Check-Ins Backend
|
|
|
|
## Purpose
|
|
|
|
`walkthrough_checkins` stores structured classroom-observation ("walk-through") records for
|
|
director-level staff. Each record captures the observed teacher, classroom, observing director,
|
|
date/time, seven rated categories with optional per-category comments, and overall notes. The
|
|
backend owns tenant scope, campus scope, creator ownership, validation, and role-gated access.
|
|
|
|
## Slice Files (by layer)
|
|
|
|
- Route: `src/routes/walkthrough_checkins.ts` (thin wiring; `GET /`, `POST /`, `DELETE /:id`).
|
|
- Controller: `src/api/controllers/walkthrough_checkins.controller.ts` (custom — not the CRUD
|
|
factory; uses `paramStr` for the id param).
|
|
- Service (BLL): `src/services/walkthrough_checkins.ts` (+ `walkthrough_checkins.types.ts` for
|
|
`WalkthroughInput` / `WalkthroughFilter`).
|
|
- Repository (DAL): queries run through `db.walkthrough_checkins` inside the service (no separate
|
|
`db/api/walkthrough_checkins.ts`).
|
|
- Model: `src/db/models/walkthrough_checkins.ts`.
|
|
- Shared used: `services/shared/validate.ts` (`nullableString`); `db/with-transaction.ts`
|
|
(`withTransaction`); `shared/constants/pagination.ts` (`resolvePagination`);
|
|
`shared/constants/walkthrough.ts` (`WALKTHROUGH_MANAGER_ROLE_NAMES`,
|
|
`WALKTHROUGH_TENANT_WIDE_ROLE_NAMES`); `services/shared/access.ts` (`getOrganizationIdOrGlobal`,
|
|
`hasGlobalAccess`, `hasRoleAccess`, `requireUserId`); `shared/errors/*` (`ForbiddenError`,
|
|
`ValidationError`). Note: the service defines a module-local `getCampusId` and `campusScope`
|
|
(staff-profile campus only), not the shared access helpers.
|
|
|
|
## API
|
|
|
|
All routes require JWT authentication. Base path mounted at `/api/walkthrough_checkins`.
|
|
|
|
- `GET /api/walkthrough_checkins` -> `200` `{ rows, count }`. Optional query `teacher_name`, plus
|
|
`limit` / `page` (paginated via `resolvePagination`). Returns check-ins visible to the current
|
|
manager, ordered by `check_in_date` desc then `createdAt` desc.
|
|
- `POST /api/walkthrough_checkins` -> `201`. Request body wrapped as `{ data: <WalkthroughInput> }`.
|
|
Returns the created check-in DTO.
|
|
- `DELETE /api/walkthrough_checkins/:id` -> `200` `{ deletedCount }`. Deletes one check-in visible
|
|
to the current manager.
|
|
|
|
## Access Rules
|
|
|
|
- All operations require a role in `WALKTHROUGH_MANAGER_ROLE_NAMES` (`super_admin`,
|
|
`system_admin`, `owner`, `superintendent`, `director`) or `globalAccess`,
|
|
enforced by `assertCanManage` (which also requires an authenticated user); otherwise
|
|
`ForbiddenError`. Users with `globalAccess` are always allowed.
|
|
- Campus visibility: roles in `WALKTHROUGH_TENANT_WIDE_ROLE_NAMES` (`super_admin`,
|
|
`system_admin`, `owner`, `superintendent`) or `globalAccess` see all org records;
|
|
other managers (e.g. `director`) are restricted to their own staff campus on `list` and
|
|
`delete` via `campusScope`.
|
|
|
|
## Tenant Scope
|
|
|
|
- Organization is resolved via `getOrganizationIdOrGlobal`: global access users bypass the org
|
|
filter and see check-ins across all organizations; regular users are bound to their org.
|
|
- `campusId` is resolved from the module-local `getCampusId` — the current staff profile's campus
|
|
only (`currentUser.staff_user[0].campusId`), else `null`; it never falls back to the user's own
|
|
`campusId`.
|
|
- On create, `createdById` is required from the current user (`requireUserId`); `updatedById` from
|
|
the current user.
|
|
|
|
## Data Contract
|
|
|
|
- Required mutation fields: `teacher_name`, `classroom`, `director_name`, `check_in_date`,
|
|
`check_in_time` (non-empty strings); and the seven rating fields `attitude_rating`,
|
|
`classroom_management_rating`, `cleanliness_rating`, `vibes_rating`, `team_dynamics_rating`,
|
|
`emergency_exit_rating`, `lesson_plan_rating` (finite numbers). Invalid input raises
|
|
`ValidationError`.
|
|
- Optional mutation fields: the matching per-category comments (`attitude_comment`,
|
|
`classroom_management_comment`, `cleanliness_comment`, `vibes_comment`, `team_dynamics_comment`,
|
|
`emergency_exit_comment`, `lesson_plan_comment`) and `overall_notes`. Comments are normalized via
|
|
`nullableString` (trimmed, blank -> `null`).
|
|
- DTO fields: `id`, the five required strings, the seven `*_rating` and matching `*_comment` fields,
|
|
`overall_notes`, `organizationId`, `campusId`, `createdById`, `updatedById`, `createdAt`,
|
|
`updatedAt`.
|
|
- Model columns: the five required strings are TEXT not null except `check_in_date` (DATEONLY) and
|
|
`check_in_time` (TIME); the seven `*_rating` are INTEGER not null; the seven `*_comment` and
|
|
`overall_notes` are TEXT nullable; `importHash` (unique). Tenant/audit columns: `organizationId`
|
|
(not null), `createdById` (not null), `campusId` (nullable), `updatedById` (nullable). The model
|
|
is `paranoid` (soft delete via `deletedAt`) and uses `freezeTableName`.
|
|
- Associations: `belongsTo` organizations (`organization`), campuses (`campus`), users
|
|
(`createdBy`, `updatedBy`). Note: there is no `user` association on this model.
|
|
|
|
## Behavior / Notes
|
|
|
|
- `create` runs inside `withTransaction`; required string fields are trimmed before persistence.
|
|
- `list` is paginated with shared defaults (`resolvePagination`).
|
|
- `remove` is a hard `destroy` scoped by `id` + organization + `campusScope`, returning the number
|
|
of rows deleted (no transaction wrapper).
|
|
|
|
## Tests
|
|
|
|
None yet (no `walkthrough_checkins` unit/e2e test in `src/`).
|
|
|
|
## Related
|
|
|
|
- Frontend: `frontend/docs/walkthrough-integration.md`.
|
|
- Related slices: `frame-entries.md` (similar editor-role-gated, campus-resolved director
|
|
workflow), `safety-quiz-results.md`, `personality-quiz-results.md`.
|