4.5 KiB
4.5 KiB
User Progress Backend
Purpose
user_progress stores per-user progress for narrow staff workflows, keyed by a typed
progress_type and an item_id. Current supported types are sign_learned (sign-language items
learned) and zone_checkin (zones-of-regulation check-ins). The backend owns tenant scope, user
ownership, validation, and persistence (one row per user + type + item, upserted).
Slice Files (by layer)
- Route:
src/routes/user_progress.ts(thin wiring;GET /,POST /,DELETE /by-item). - Controller:
src/api/controllers/user_progress.controller.ts(custom — not the CRUD factory). - Service (BLL):
src/services/user_progress.ts. - Repository (DAL): queries run through
db.user_progressinside the service (no separatedb/api/user_progress.ts). - Model:
src/db/models/user_progress.ts. - Shared used:
db/with-transaction.ts(withTransaction);services/shared/access.ts(assertAuthenticatedTenantUser,getCampusId,getOrganizationIdOrGlobal,requireUserId);shared/constants/user-progress.ts(USER_PROGRESS_TYPE_VALUES,UserProgressType);shared/constants/pagination.ts(resolvePagination);shared/errors/validation.ts(ValidationError).
API
All routes require JWT authentication. Base path mounted at /api/user_progress.
GET /api/user_progress->200{ rows, count }. Required queryprogress_type(must be a valid type); optionalitem_id, pluslimit/page(paginated viaresolvePagination). Returns the current user's rows for that type, ordered bycreatedAtdesc.POST /api/user_progress->200. Request body wrapped as{ data: <UserProgressInput> }. Creates or updates one progress item and returns the saved DTO.DELETE /api/user_progress/by-item->200{ deletedCount }. Required queryprogress_typeanditem_id. Deletes the current user's row for that type + item.
Access Rules
- All operations require an authenticated tenant user (
assertAuthenticatedTenantUser). - No additional role gating: every operation is bound to the current user. List, upsert, and delete
are all filtered by
userId(requireUserId), so a user only ever reads, writes, or deletes their own progress. Frontend-provided names or roles are not trusted for ownership.
Tenant Scope
- Organization is resolved via
getOrganizationIdOrGlobal: global access users bypass the org filter; regular users are bound to their organization. All queries are still filtered byuserIdso each user only sees their own progress. userIdis required from the current user (requireUserId).- On upsert,
campusIdis set fromgetCampusId;updatedByIdfrom the current user, andcreatedByIdon create.
Data Contract
- Mutation input (
UserProgressInput):progress_type(must be one ofUSER_PROGRESS_TYPE_VALUES:sign_learned,zone_checkin) anditem_id(non-empty string) are required. Optional:value,score,metadata. Invalid input raisesValidationError. - On save,
valueis persisted only if a string (elsenull),scoreonly if a number (elsenull), andmetadatadefaults tonullwhen absent;item_idis trimmed. - DTO fields:
id,progress_type,item_id,value,score,metadata,organizationId,campusId,userId,createdAt,updatedAt. - Model columns:
progress_type(ENUM overUSER_PROGRESS_TYPE_VALUES, not null),item_id(TEXT, not null),value(TEXT, nullable),score(INTEGER, nullable),metadata(JSONB, nullable),importHash(unique). Tenant/audit columns:organizationId(not null),userId(not null),createdById(not null),campusId(nullable),updatedById(nullable). The model isparanoid(soft delete viadeletedAt) and usesfreezeTableName. - Associations:
belongsToorganizations (organization), campuses (campus), users (user,createdBy,updatedBy).
Behavior / Notes
upsertruns insidewithTransaction: it looks up the existing row byorganizationId+userId+progress_type+item_id, updating it if present, otherwise creating it.listvalidatesprogress_typeand is paginated with shared defaults.removeByItemis a harddestroycall (no transaction wrapper) returning the number of rows deleted.
Tests
None yet (no user_progress unit/e2e test in src/).
Related
- Frontend:
frontend/docs/user-progress-integration.md,frontend/docs/sign-language-integration.md,frontend/docs/zones-of-regulation-integration.md. - Related slices:
safety-quiz-results.md,personality-quiz-results.md,walkthrough-checkins.md.