40227-vm/backend/docs/policy-documents.md
2026-06-12 06:55:35 +02:00

5.9 KiB

Policy Documents & Acknowledgments

Workstream 11 — persistence of staff acknowledgment of policy/safety documents.

Purpose

Campus staff must acknowledge two categories of documents — Safety Protocols (official/government) and Handbook & Policies (internal). director and office_manager author the documents; all four campus staff roles (director, office_manager, teacher, support_staff) acknowledge them. Acknowledgment is per document version: editing a document bumps its version, which requires re-acknowledgment.

Frontend wiring

The two existing pages consume this single store (the old generated documents entity it replaced has been removed):

  • Handbook & Policies (business/policies) lists policy_documents of category = handbook_policy, mapping the handbook's sub-category to/from tag (toPolicyViewModel / toPolicyDocumentMutationDto). Management is gated to owner/superintendent/director/office_manager (canManagePolicies, mirroring the backend grant). Acknowledgment is persisted via policy_acknowledgments (usePolicyAcknowledgments / useAcknowledgePolicy), replacing the former local-state set.
  • Safety Protocols (business/safety-protocols) consumes category = safety_protocol, rendering author-filled steps + autism considerations with a static per-tag card icon (fire/shield/heart). It shares the persistent acknowledgment hooks. Both pages are seeded from 20260611050000-policy-documents-seed.ts (safety protocols reuse the former content-catalog safetyProtocols payload; a few handbook policies seed the handbook page). The Safety Protocols page also has a manager-gated structured-authoring flow (mirrors the F.R.A.M.E. module: header New Protocol button → create form, per-card Edit/Delete) with dynamic steps + autismConsiderations rows that add/remove independently, so each protocol carries its own count (useSafetyProtocolsModule + SafetyProtocolForm / SafetyDynamicListEditor; gated by canManageSafetyProtocols, which reuses the policy grant). Title/body/steps/considerations changes bump version and require re-acknowledgment.

Entities

  • policy_documents (generic-CRUD entity): title, body, category (safety_protocol | handbook_policy — selects the page), tag (nullable finer sub-category; the Handbook page maps its Operations/Behavior/Safety/Communication/Legal categorisation onto it, and the Safety page uses it to pick the static card icon), author (display name of the creating user, set server-side at creation and not changed on update), steps + autism_considerations (JSONB string arrays — author-filled structured content for safety protocols; null for handbook policies), version (bumped when title/body/steps/autism_considerations change), active, tenant organizationId + nullable campusId. This is the single unified store for both the Safety Protocols and Handbook & Policies pages (filter by ?category= and optionally ?tag=). The category list + icons are static frontend config; each document's category assignment (tag) is DB data. author is derived from the current user's name — ${name_prefix} firstName lastName (the honorific title from users.name_prefix, e.g. "Dr. Sarah Williams"), else email.
  • policy_acknowledgments (per-user): one row per (userId, policyDocumentId, version), with acknowledgedAt. Unique index on those three columns; acknowledging is idempotent for a given version.

Routes

  • GET/POST /api/policy_documents, PUT/DELETE /api/policy_documents/:id, plus the standard generic-CRUD extras — guarded by checkCrudPermissions('policy_documents') (${METHOD}_POLICY_DOCUMENTS).
  • GET /api/policy_acknowledgments (the caller's own acknowledgments) and POST /api/policy_acknowledgments ({ data: { policyDocumentId } } → acknowledges the document's current version) — both guarded by checkPermissions('ACK_POLICY').

Authorization

  • READ_POLICY_DOCUMENTS — granted to the four campus roles (director via full access; office_manager/teacher/support via the read-only entity grant). student/guardian get no policy-document access.
  • CREATE/UPDATE/DELETE_POLICY_DOCUMENTSdirector (full access) and office_manager (explicit grant in the role seeder). teacher/support_staff are read-only.
  • ACK_POLICY — the four campus roles (a product-feature action permission; extendable per user via custom_permissions).

Tenant/campus scoping is applied in the data layer (tenantWhere / findOwnedByPk); acknowledgment reads are additionally restricted to the caller's own userId. A manager-facing acknowledgment-status report (audience TBD) is a deferred refinement.

Tests

  • Unit (backend/src/shared/constants/policy-documents.test.ts + users.test.ts, npm test): the pure domain rules — isPolicyDocumentCategory validation, the nextPolicyDocumentVersion re-acknowledgment bump, and formatPersonName (author rendering).
  • Frontend unit (vitest): business/policies/mappers.test.ts (handbook; tag↔category, author), business/safety-protocols/mappers.test.ts (steps + autism considerations) and business/safety-protocols/selectors.test.ts (management grant + draft validation for the authoring form).
  • Seeded e2e (frontend/tests/e2e/policy-acknowledgments.seeded.e2e.ts, npm run test:e2e:content): document create/persist, manage-vs-read RBAC (director/office_manager manage; teacher reads but cannot create), idempotent per-version acknowledgment, version-bump re-acknowledgment, and external-role lockout.

Open / deferred

  • Acknowledgment-status reporting for managers (who-acknowledged-what) — pending the report-audience decision.
  • The acknowledgment + document-management UI is design-gated (see docs/backlog.md).