Core Features¶
This page is the short inventory of Toodle's implemented core features. Detailed walkthroughs live in Role Workflows, and endpoint-level details live in the API Reference.
Feature Inventory¶
| Feature | Purpose |
|---|---|
| Authentication and role access | Signs users in with Auth0, then uses the database role to control access for ADMIN, LECTURER, TUTOR, and STUDENT users. |
| Realistic staff role split | Separates system administration from course coordination so admins manage platform-wide access while lecturers manage the courses they coordinate. |
| Profile, onboarding, and availability | Collects eligibility details such as year of study, weekly hours, course marks, and free-time availability before students can apply or volunteer. |
| Course and session management | Lets admins and lecturers create or manage courses, set tutor requirements, add tutorial or lab sessions, and open or close applications. |
| Tutor mark management | Stores course marks, supports staff verification or rejection, and allows bulk CSV mark imports for class lists. |
| Course applications | Lets students apply for tutoring opportunities, submit motivation and requested hours, and receive staff approval or rejection. |
| Allocation board | Gives staff one place to assign tutors to courses while seeing staffing, pending allocations, locks, and validation results. |
| Allocation validation | Checks minimum mark, availability, timetable clashes, duplicate allocation risk, and weekly-hour limits before assignments are saved. |
| Timesheets | Lets tutors log work, submit timesheets, and receive staff approval, dispute feedback, or rejection. |
| Excusals | Lets tutors request leave from scheduled sessions, with staff review and notifications when the request is resolved. |
| Overflow volunteering | Creates cover opportunities for approved excusals or extra staffing needs, then lets eligible users claim them. |
| Session swaps | Trades dated sessions with suitability previews, tutor consent, staff approval, audit history and controlled reversal. |
| Calendar and iCal feed | Shows a user's scheduled sessions on a week, month, or list calendar, marks approved excusals as cancelled occurrences, and offers a per-user subscribable .ics feed for Google, Outlook, and Apple Calendar. |
| Notifications and email | Sends in-app notifications and Brevo transactional emails for important workflow events. |
| Reports and exports | Summarises active staffing, allocated hours, tutor workload, and CSV exports for staff review. |
| Problem reports | Lets authenticated users report bugs or app issues from inside Toodle. |
| Admin user management | Lets admins search users and update roles with safeguards against locking out the last admin. |
| Responsive and accessible UI | Provides role-specific dashboards, mobile-friendly navigation, accessible modals, and visible error states. |
| My Courses | Gives tutors and lecturers a tab listing only the courses they tutor or coordinate, alongside the full course list. |
| Due dates and automated reminders | Gives timesheets a monthly due date (the 27th) and reminds tutors and reviewers about overdue or held-up work, without duplicate reminders. |
Sprint 4 Updates¶
Sprint 4 extended several features in the inventory above. This section records what changed and why the team decided on each change.
Session-bound excusals (B11)¶
What changed: a tutor now requests an excusal for one occurrence of a scheduled session. The form asks for the course, then the session (e.g. Lab · Tuesday 14:00–15:30 · MSL 004), then one of that session's upcoming dates, and shows how long the tutor will miss. The excusal stores the session, the date and the duration. The cover post created on approval is for the same session, date and duration, and the Volunteers page shows "Covers Lab · Tuesday 14:00–15:30 · MSL 004 · Tue, 6 Oct 2026" with a "1h 30m · one session" badge. The tutor's reason and the reviewer's note are kept separately. An approved excusal cancels only its own session in the calendar and .ics feed.
Why: excusals used to be a free date and time. A tutor could pick a day their session does not run, the system could not tell which session or how many hours were missed, the cover post used weekly hours rather than the missed session, and the calendar cancelled every session of the course on that weekday. Declining also overwrote the tutor's reason. Offering only real upcoming dates makes an invalid choice impossible in the form, and the API rejects it anyway.
Limitations the team accepted: excusals created before this change have no session and keep working on date only; partial-hour sessions round up in hoursNeeded; an approved cover claim still creates a weekly allocation (there is no dated-coverage allocation model yet); and locked allocations cannot be excused because the form reuses the swap-options list, which excludes them.
Courses and My Courses¶
What changed: tutors and lecturers have a Courses tab (every course) and a My Courses tab. A tutor's My Courses lists courses with an active or pending allocation and shows Tutoring · 4h/week or Allocation pending. A lecturer's lists the courses they coordinate. A tutor with no allocations sees a link to browse all courses.
Why: the single Courses page showed every course to everyone, including courses the user does not tutor or lecture, and the tutor's "My Courses" link actually opened the full list. The full catalogue was kept because people still need to browse and apply. Pending allocations are included so tutors can see where they stand. Admins did not get the tab because it was not requested; the API already supports it if wanted later.
Editing course sessions¶
What changed: admins and the course's coordinators can edit a session's day, times, venue and type, and remove sessions, from the course page. Editing reports how many tutor allocations were moved back to pending; removing asks for confirmation and warns that the session's excusal requests are deleted with it.
Why: a lab was created on the wrong day and could not be corrected from the app, because only Add existed in the UI. The pending-tutors notice and the removal warning were added so that correcting the timetable does not silently affect tutors or excusal history.
Notifications and delivery reliability (B03)¶
What changed:
- Every change to a tutor's allocation notifies them exactly once: assigned, hours or status changed (listing what changed), removed, reactivated, or moved to pending by a timetable change.
- Saving an allocation without a real change, or removing an already-removed one, no longer sends a notice.
- Notification links open a page the recipient can access.
- Each notification records whether its email was sent, failed, or not attempted because email is not configured, and the bell shows this.
- Problem reports only report success when the email was accepted.
Why: tutors were linked to the staff-only allocation board; failed emails looked identical to delivered ones; problem reports claimed success even when lost; duplicate or empty "updated" notices were sent; and tutors demoted by a timetable change were never told. The team decided that the in-app notification is always kept and written first, and that the email's real outcome is recorded rather than assumed. Failed emails are not retried yet; retrying is a possible follow-up, using emailStatus = FAILED as the work list.
Due dates and automated reminders (B08)¶
Agreed deadlines. The team agreed which workflows have deadlines and the timesheet policy at the start of the item:
-
Timesheets run in monthly cycles that close on the 27th. A weekly timesheet belongs to the first 27th on or after the Sunday its week ends, so tutoring after the 27th is counted in the next month. Submission and review are both due by the end of the 27th (SAST).
Week Due Mon 21 Sep – Sun 27 Sep 2026 27 Sep Mon 12 Oct – Sun 18 Oct 2026 27 Oct Mon 26 Oct – Sun 1 Nov 2026 27 Nov
| Workflow | Held up when | Reminder goes to | When |
|---|---|---|---|
| Timesheet submission | DRAFT or DISPUTED sheet in the cycle, or an active allocation with no timesheet logged in the cycle | the tutor (one grouped message per cycle) | due soon from the 20th; overdue after the 27th |
| Timesheet review | SUBMITTED sheet in the cycle | admins + the course's coordinators (grouped) | due soon from the 24th; overdue after the 27th |
| Excusal review | pending excusal whose session starts within 48 hours | admins + the course's coordinators | within 48 h; again once the session starts |
| Overflow claim | pending for 3 days | admins + the post's course coordinators | once |
| Session swap | recipient has not answered in 3 days | the recipient tutor | once |
| Session swap | both tutors agreed, undecided for 3 days | admins + coordinators of both courses | once |
| Course application | pending for 7 days | admins + the course's coordinators | once |
The Timesheets page shows each sheet's due date and a Due soon or Overdue badge.
How it runs. An in-process job in the API runs one minute after start-up and then hourly. Every reminder has a fixed key stored under a unique database index, so a re-run, a restart or two overlapping runs cannot send it twice. If saving a reminder fails it is retried on the next run, with no email sent in between. If its email fails, the in-app reminder is kept and the failure recorded, and it is not resent.
Why: timesheets had no deadline and stalled reviews were invisible until someone noticed. Specific choices:
- The 27th cycle gets a month's work submitted and reviewed by month-end and gives later work a clear home in the next cycle.
- Submission reminders start a week before the 27th so reviewers have time to finish by the deadline.
- Grouped reminders (one message per cycle and stage) avoid flooding people who have several outstanding weeks.
- Overdue sheets older than 90 days are not chased, so the first run after deployment cannot send reminders about old history.
- In-process timer. The team chose it over an external cron service because it keeps everything inside the API, with no extra infrastructure or credentials. The accepted trade-off: on Render's free plan the instance sleeps when idle, so reminders pause and catch up on the next wake.