Skip to content

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:
    1. Ownership: A tutor can only request excusal for an allocation belonging to their own user account (403 Forbidden).
    2. Active State: Excusals can only be submitted against ACTIVE allocations (422 Unprocessable Entity).
    3. Future Dates: Session dates must strictly occur in the future (422 Unprocessable Entity).
    4. Duplicate Guard: Rejects duplicate requests for the same allocation and session date (409 Conflict).
    5. Auto-Chaining: When an organiser approves an excusal, the service runs inside prisma.$transaction. It updates the excusal to APPROVED and automatically inserts an OverflowPost for the course with description: "Cover needed: <Course> on <Date> (excusal approved for <Name>)", setting hours needed to the allocation's weekly hours.

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:
    1. Role Visibility: Non-organisers only see OPEN posts; organisers see all posts.
    2. Double-Claim Prevention: Enforced at the application level and backed by the composite unique index @@unique([overflowPostId, userId]) in PostgreSQL (409 Conflict).
    3. 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 with 422 Unprocessable Entity.
    4. Atomic Approval & Allocation Promotion: When an organiser approves a claim, a serializable transaction atomically marks the claim APPROVED, the post CLAIMED, and creates an active Allocation for the volunteer with reason: "Volunteer cover for overflow".
    5. Deletion Safety: Prevents deleting an overflow post that already contains approved claims (422 Unprocessable Entity).

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 notifications table, 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-reports to route diagnostic feedback directly to toodle.issues@gmail.com.
    • Security: escapeHtml() sanitizes all user input against HTML/script injection.

D. Route Validator Wiring & Fixes (B12)

  • Files: src/routes/tutor.routes.js, src/routes/course.routes.js.
  • Wired validate(upsertMarkSchema) to POST /tutors/:id/marks and POST /tutors/me/marks.
  • Wired validate(setAvailabilitySchema) to PUT /tutors/:id/availability.
  • Wired validate(createSessionSchema) to POST /courses/:id/sessions.
  • Added requireSelfOrRole('ORGANISER') ownership guard to PUT /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

  1. Mocked Email Delivery: The automated test suite mocks the @getbrevo/brevo SDK 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.
  2. Concurrency Validation: Concurrency guards (updateMany with status: '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).
  3. 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.