Backend: BTC školovanje detail
Last modified with commit 54c7b1e on
by TjasaSimovic.
Backend task for the BTC školovanje detail page and attendance (GET /btc-trainings/{trainingId}, POST /modules/{moduleNumber}/attendance) – check the response and save semantics against the API spec and DB structure, permissions, implement, and verify against the spec.
Docs: BTC školovanje detail
Spec: GET /btc-trainings/{trainingId} (getBtcTrainingDetail), POST /btc-trainings/{trainingId}/modules/{moduleNumber}/attendance (setBtcTrainingAttendance), BtcTrainingDetail, BtcTrainingModule, BtcTrainingAttendanceRequest in api-docs/openapi.yaml
DB: BtcTrainings, BtcTrainingModules, BtcTrainingCandidates, BtcTrainingAttendance in api/database/create_schema.sql
The detail endpoint is also used by the edit form and the Rezultati feedback forme page.
1. Double check API spec and DB structure
- Header: name, status, brand(s) →
name,status,brandCodes. “UREDI ŠKOLOVANJE” is shown only foractive/upcoming. The frontend decides this fromstatus. - Modules: always 4, ordered by
moduleNumber, withstartDate/endDate(null → “-”). - Attendance table: one entry per candidate per module with
day1/day2. The candidate name and initials come fromcandidates. Check this covers the table. - Save semantics: “Spremi” saves one day of one module. The spec replaces that day:
the listed
presentCandidateIdsare present and every other candidate is not. Check this matches the docs (only one day in edit mode at a time). - Status rule: the docs don’t say whether attendance can be edited on a Prošli školovanje. The spec allows it in any status. Confirm.
- Feedback form: the docs comment asks whether anything about the module feedback form is needed on the detail page. Nothing in the spec. Confirm.
-
hasDataper candidate is used by the edit form (hides “–”). Check it’s true exactly when the candidate has any attendance row. - Roles and permissions: GET →
btc-trainings.access; attendance →btc-trainings.edit. Both Trainer only. - DB:
UQ_BtcTrainingAttendance (ModuleId, CandidateId, Day),Day IN (1, 2). No row = not present.
2. Implementation
- Roles and permissions: GET requires
btc-trainings.access; POST requiresbtc-trainings.edit→ 403. - DB: GET loads the školovanje (not deleted, else 404), its candidates, its 4 modules and all attendance rows in a few queries (no query per module or candidate).
- POST: 404 for an unknown / deleted školovanje;
moduleNumberoutside 1–4 → 400;daynot 1 or 2 → 400; any id inpresentCandidateIdsnot a candidate of this školovanje → 404. OneMERGE, no transaction: target = the day’s rows for this module, source = the present candidates; insert the missing ones, delete the rest. Unique violation (the day saved twice at once) → retry once; FK error 547 (a candidate removed in the meantime) → 404. - POST response: the
BtcTrainingModulewith all candidates’day1/day2.
3. Verify implementation against spec
- Shapes and status codes match
getBtcTrainingDetailandsetBtcTrainingAttendance. - Saving Dan 1 doesn’t change Dan 2 or other modules.
- An empty
presentCandidateIdsclears the day. - A candidate from another školovanje → 404. Evaluator → 403. Deleted školovanje → 404.
- After saving attendance,
hasDataof that candidate istrue.
Done when
The detail page shows the 4 modules with attendance, and a trainer can save attendance for each day.