40227-vm/backend/docs/walkthrough-checkins.md
2026-06-10 18:27:19 +02:00

5.5 KiB

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 Administrator, Administrator, Platform Owner, Tenant Director, Campus Manager) 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 Administrator, Administrator, Platform Owner, Tenant Director) or globalAccess see all org records; other managers (e.g. Campus Manager) 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/).

  • 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.