4.7 KiB
Staff Backend
Purpose
staff is the per-organization employee profile roster, linking an optional user account and
campus to each staff member. It is a generic-CRUD slice assembled from the shared factories;
the backend is the source of truth for staff records.
Slice Files (by layer)
- Route:
src/routes/staff.ts—createCrudRouter(controller, { permission: 'staff' }). - Controller:
src/api/controllers/staff.controller.ts—createCrudController(service, { csvFields }). - Service (BLL):
src/services/staff.ts—createCrudService(DbApi, { notFoundCode: 'staffNotFound' }). - Repository (DAL):
src/db/api/staff.ts(StaffDBApi) — entity-specificcreate/bulkImport/update/findBy/findAll;remove/deleteByIds/findAllAutocompletedelegate todb/api/shared/repository.ts. - Model:
src/db/models/staff.ts. - Shared used: CRUD factories (
services/shared/crud-service.ts,api/controllers/shared/crud-controller.ts,api/http/crud-router.ts), repository helpers (db/api/shared/repository.ts),shared/constants/pagination.ts(resolvePagination),shared/constants/database.ts(BULK_IMPORT_TIMESTAMP_STEP_MS),db/utils.ts(Utils),db/api/file.ts(FileDBApi.replaceRelationFilesfor thephotorelation).
API
The standard generic-CRUD surface (all under /api/staff, JWT + ${METHOD}_STAFF permission,
all 200) — see backend-architecture.md for the shared contract:
POST /— body{ data }, returnstrue.POST /bulk-import— multipart CSV file, returnstrue.PUT /:id— body{ data, id }(the service reads the id from the body, not the path param), returnstrue.DELETE /:id— returnstrue.POST /deleteByIds— body{ data: string[] }, returnstrue.GET /— query filters, returns{ rows, count };?filetype=csvstreams a CSV ofcsvFields.GET /count— returns{ rows: [], count }.GET /autocomplete—?query&limit&offset, returns[{ id, label }]wherelabelisemployee_number.GET /:id— returns the record with eager associations (see Data Contract).
csvFields: id, employee_number, job_title, hire_date.
Access Rules
- JWT required; the whole router is guarded by
checkCrudPermissions('staff'), derivingREAD_STAFF/CREATE_STAFF/UPDATE_STAFF/DELETE_STAFFper HTTP method. - Access is granted by role permission or per-user
custom_permissions(seepermissions.md).
Tenant Scope
findAllscopeswhere.organizationIdtocurrentUser.organizationId; aglobalAccessrole clears the org filter (sees all tenants).createassigns the organization fromcurrentUser.organizationId;updateonly reassigns organization forglobalAccessusers (otherwise it stays the caller's org), and only whendata.organizationis provided.
Data Contract
Model columns (paranoid, soft-delete via deletedAt):
id(UUID PK),employee_number,job_title(TEXT, nullable).staff_type— ENUMteacher|admin|support.status— ENUMactive|on_leave|inactive.hire_date— DATE.importHash(unique),campusId,organizationId,userId,createdById,updatedById, timestamps.
Associations: belongsTo organization, campus, user (a users record), createdBy/updatedBy
(users); hasMany classes_homeroom_teacher (classes via homeroom_teacherId),
class_subjects_teacher (class_subjects via teacherId), attendance_sessions_taken_by
(attendance_sessions via taken_byId), payments_received_by (payments via received_byId);
hasMany file as photo (scoped relation). findBy/GET /:id eager-load all of these in a
single Promise.all.
List filters (StaffFilter): id, employee_number, job_title, hire_dateRange,
staff_type, status, campus (id or name, |-separated), user (id or firstName,
|-separated), organization (id list, |-separated), createdAtRange, plus field/sort
ordering and limit/page pagination.
Behavior / Notes
create/bulkImport/updatemanage thephotofile relation viaFileDBApi.replaceRelationFiles.bulkImportoffsetscreatedAtper row byBULK_IMPORT_TIMESTAMP_STEP_MSto preserve order.- List pagination uses the shared
resolvePaginationdefaults (page size 10, capped at 100). - Note:
StaffFilteraccepts anactiveflag andfindAllfilters on anactivecolumn, but the model has noactivecolumn; this filter is currently inert (kept for source accuracy).
Tests
None yet.
Related
- Generic-CRUD contract:
backend-architecture.md; related slices:organizations,campuses,classes,class_subjects,attendance_sessions,payments,file.md,permissions.md.