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

68 lines
2.8 KiB
Markdown

# FRAME Entries Backend
## Purpose
`frame_entries` stores weekly F.R.A.M.E. focus entries per organization. The backend is the
source of truth for persisted FRAME data; the frontend never substitutes static samples for it.
## Slice Files (by layer)
- Route: `src/routes/frame_entries.ts` (thin wiring; `GET /`, `POST /`, `PUT /:id`).
- Controller: `src/api/controllers/frame_entries.controller.ts` (custom — not the CRUD factory).
- Service (BLL): `src/services/frame_entries.ts`.
- Repository (DAL): queries run through `db.frame_entries` inside the service (no separate
`db/api/frame_entries.ts`).
- Model: `src/db/models/frame_entries.ts`.
- Shared used: `db/with-transaction.ts` (`withTransaction`), `services/shared/access.ts`
(`getOrganizationIdOrGlobal`, `hasRoleAccess`), `shared/constants/pagination.ts` (`resolvePagination`),
`shared/constants/frame.ts` (`FRAME_EDITOR_ROLE_NAMES`), `shared/errors/*`
(`ForbiddenError`, `ValidationError`).
## API
All routes require JWT authentication.
- `GET /api/frame_entries` -> `200` `{ rows, count }` for the current user's organization
(paginated via `resolvePagination`).
- `POST /api/frame_entries` -> `201` the created entry DTO.
- `PUT /api/frame_entries/:id` -> `200` the updated entry DTO (scoped to the org).
Request body for create/update is wrapped as `{ data: <FrameEntryInput> }`.
## Access Rules
- Read: any authenticated user in the organization, or any user with `globalAccess` (sees all
organizations).
- Edit (create/update): restricted to roles in `FRAME_EDITOR_ROLE_NAMES` (director/superintendent
capabilities) — `Super Administrator`, `Administrator`, `Platform Owner`, `Tenant Director`,
`Campus Manager`. Enforced by `assertCanEdit` via `hasRoleAccess`; a non-editor gets
`ForbiddenError`. Frontend may hide editing controls, but the backend check is authoritative.
## Tenant Scope
- Organization is resolved via `getOrganizationIdOrGlobal`: users with `globalAccess` bypass the
org filter and see/create entries across all organizations; regular users are bound to their
organization.
- `campusId` is optional; when omitted it defaults to the current staff profile's campus
(`currentUser.staff_user[0].campusId`) when available, else `null`.
## Data Contract
Required request fields (`REQUIRED_FIELDS`): `week_of`, `posted_date`, `formal`, `recognition`,
`application`, `management`, `emotional`, `author`. Optional: `campusId`. Missing/invalid input
raises `ValidationError`.
## Behavior / Notes
- Create/update run inside `withTransaction`.
- List is paginated with the shared defaults (`resolvePagination`).
## Tests
None yet (no `frame_entries` unit/e2e test in `src/`).
## Related
- Frontend: `frontend/docs/frame-integration.md`.
- Related slices: `user-progress.md` (dashboard zone check-ins), `staff` (campus resolution).