Dev 3 deliverables and verification record¶
Verified locally on 15 September 2026 across the toodle-api, Toodle, and toodle-docs repositories.
1. Role & Scope Overview¶
During Sprint 2, Dev 3 owned backend API development, external service integration, route boundary validation, test suite implementation, and technical documentation.
| Backlog ID | Deliverable | Scope / Implementation | Status |
|---|---|---|---|
| B7 | Excusal API | Route, controller, service, Zod validator for tutor session excusals; auto-generation of overflow posts upon approval | ✅ Implemented & Tested |
| B10 | Overflow / Volunteer API | Route, controller, service, Zod validator for overflow posts and volunteer claims; hours budget checks and allocation creation | ✅ Implemented & Tested |
| B11 | External API Integration (Brevo) | Brevo SDK integration, 9 transactional notification triggers, dual-channel delivery, fire-and-forget error resilience, and in-app problem reports | ✅ Implemented & Tested |
| B12 | Sprint 1 Validator Bug Fixes | Wired previously disconnected Zod schemas for tutor marks, availability, and course sessions; wired ownership middleware | ✅ Implemented & Tested |
| T4 | Excusal & Overflow Service Tests | Comprehensive unit test suites testing business logic, validation boundaries, concurrency guards, and role permissions | ✅ 37 Tests Passing |
| D2 | Third-Party Code Documentation | Complete inventory and architectural motivation for all 31 third-party libraries across backend, frontend, and docs | ✅ Documented in third-party.md |
| D4 | API Reference Update | Full update of reference.md covering all Sprint 2 routes, schemas, status codes, and the Brevo integration contract |
✅ Documented in reference.md |
2. Implemented Workflows & Architectural Decisions¶
A. Excusal Workflow (B7)¶
- Files:
src/routes/excusal.routes.js,src/controllers/excusal.controller.js,src/services/excusal.service.js,src/validators/excusal.validator.js. - Core Rules:
- Ownership: A tutor can only request excusal for an allocation belonging to their own user account (
403 Forbidden). - Active State: Excusals can only be submitted against
ACTIVEallocations (422 Unprocessable Entity). - Future Dates: Session dates must strictly occur in the future (
422 Unprocessable Entity). - Duplicate Guard: Rejects duplicate requests for the same allocation and session date (
409 Conflict). - Auto-Chaining: When an organiser approves an excusal, the service runs inside
prisma.$transaction. It updates the excusal toAPPROVEDand automatically inserts anOverflowPostfor the course with description:"Cover needed: <Course> on <Date> (excusal approved for <Name>)", setting hours needed to the allocation's weekly hours.
- Ownership: A tutor can only request excusal for an allocation belonging to their own user account (
B. Overflow Volunteering Workflow (B10)¶
- Files:
src/routes/overflow.routes.js,src/controllers/overflow.controller.js,src/services/overflow.service.js,src/validators/overflow.validator.js. - Core Rules:
- Role Visibility: Non-organisers only see
OPENposts; organisers see all posts. - Double-Claim Prevention: Enforced at the application level and backed by the composite unique index
@@unique([overflowPostId, userId])in PostgreSQL (409 Conflict). - Workload Budget Validation: Reuses the core allocation hours budget calculation. Computes remaining hours:
$$\text{remainingHours} = \text{user.maxHoursPerWeek} - \sum \text{activeAllocationHours}$$
If
post.hoursNeeded > remainingHours, the claim is rejected with422 Unprocessable Entity. - Atomic Approval & Allocation Promotion: When an organiser approves a claim, a serializable transaction atomically marks the claim
APPROVED, the postCLAIMED, and creates an activeAllocationfor the volunteer withreason: "Volunteer cover for overflow". - Deletion Safety: Prevents deleting an overflow post that already contains approved claims (
422 Unprocessable Entity).
- Role Visibility: Non-organisers only see
C. Brevo External API Integration (B11)¶
- Files:
src/config/brevo.js,src/services/email.service.js,src/routes/report.routes.js. - Architecture:
- Dual-channel delivery: creates a persistent database record in
notificationstable, then dispatches email via Brevo REST API. - Fire-and-forget: email delivery is executed asynchronously without blocking HTTP response times.
- Graceful degradation: Brevo outages or network drops are caught and logged; they never abort database transactions or throw errors to users.
- In-app problem reporting: exposes
POST /api/v1/problem-reportsto route diagnostic feedback directly totoodle.issues@gmail.com. - Security:
escapeHtml()sanitizes all user input against HTML/script injection.
- Dual-channel delivery: creates a persistent database record in
D. Route Validator Wiring & Fixes (B12)¶
- Files:
src/routes/tutor.routes.js,src/routes/course.routes.js. - Wired
validate(upsertMarkSchema)toPOST /tutors/:id/marksandPOST /tutors/me/marks. - Wired
validate(setAvailabilitySchema)toPUT /tutors/:id/availability. - Wired
validate(createSessionSchema)toPOST /courses/:id/sessions. - Added
requireSelfOrRole('ORGANISER')ownership guard toPUT /tutors/:id/availability.
3. Automated Test Evidence¶
Automated testing was executed via Vitest across all unit and integration suites:
npm.cmd test
# Output:
# Test Files: 31 passed | 2 skipped (33 total)
# Tests: 382 passed | 11 skipped (393 total)
Dedicated Unit Test Suites¶
| Test File | Tests | Focus / Scenarios Tested |
|---|---|---|
tests/unit/services/excusal.service.test.js |
10 | Excusal creation for active allocation; rejection of non-owned allocations (403); rejection of inactive allocations (422); rejection of past session dates (422); duplicate rejection (409); atomic approval with overflow post creation; decline with feedback reason; role-based query filtering. |
tests/unit/services/overflow.service.test.js |
12 | Overflow post creation; missing course validation (404); claiming open posts; non-open post rejection (422); double-claim rejection (409); weekly hours budget validation; claim approval with post transition to CLAIMED and automatic allocation creation; post deletion checks. |
tests/unit/services/email.service.test.js |
15 | Allocation notifications; timesheet submitted and reviewed notifications; excusal resolution notifications; overflow broadcast to students; swap approval notifications; course application submitted and reviewed notifications; problem report emails to issues inbox; HTML entity escaping; fire-and-forget resilience against database and Brevo API errors. |
Code Quality & Linting¶
npm.cmd run lint
# Output: 0 errors, 0 warnings across all src/ files.
4. Verification Limits & Live Acceptance¶
- Mocked Email Delivery: The automated test suite mocks the
@getbrevo/brevoSDK to prevent consuming daily email limits during continuous integration and to ensure tests can run offline. Real email delivery has been verified locally using a test Brevo API key. - Concurrency Validation: Concurrency guards (
updateManywithstatus: 'PENDING') were tested via mock transitions. True multi-threaded PostgreSQL race conditions require running the isolated PostgreSQL container test suite (tests/integration/*.postgres.test.js). - Acceptance Verification: Follow the step-by-step role scenario documented in Excusal & Overflow Workflow to verify the end-to-end browser journey from tutor excusal request to student volunteer allocation.