Skip to content

Course and tutor application workflow

Verified against the workspace on 14 September 2026. Local implementation and database read checks are available; a complete authenticated browser acceptance run is still required.

Who does what?

flowchart TD
  A[Organiser creates course] --> B[Set minimum mark and tutors needed]
  B --> C[Add tutorial and lab sessions]
  C --> D[Open applications]
  D --> E[Student or tutor sets free time and weekly hours]
  E --> F[Submit course mark for verification]
  F --> G[Apply with hours and motivation]
  G --> H[Organiser verifies mark against school records]
  H --> I{Mark, availability, clashes and hours pass?}
  I -->|No| J[Show issues; correct information or reject with reason]
  I -->|Yes| K[Organiser approves with reason]
  K --> L[Create active allocation; student becomes tutor]
  L --> M[Tutor works and logs hours]
  M --> N[Submit timesheet for organiser approval]

Organiser walkthrough

  1. Sign in with a database-backed ORGANISER account. Open Courses → New course. Enter code, name, year, semester, number of tutors and minimum mark. New courses start with applications closed.
  2. Open the course and Add its sessions: day, start/end time, venue and type. Session creation reports API errors in the modal.
  3. Choose Open applications. Applicants can now apply from the same course page.
  4. Review each applicant's motivation, requested hours, submitted mark and mark status. Verify mark means you checked the mark against an authoritative school record; the app does not fetch academic transcripts automatically. Reject an incorrect mark with a reason.
  5. Read the eligibility warnings and remaining weekly hours. Approval is unavailable while marks are unverified or any qualification warning remains, while applications are closed, or while sessions are missing. The API rechecks all constraints and staffing capacity at approval time.
  6. Enter a review reason and approve or reject. Approval creates/reactivates an allocation, promotes a student to tutor and records the decision in the audit log. Refresh the allocation board to see the assignment.
  7. Use Close applications when recruitment ends. Remove course → Confirm removal removes only unused courses and their sessions. The API refuses deletion when marks, applications, allocations, payroll/work records, budget or allocation drafts would lose history.

Applicant walkthrough

  1. Sign in as a student or tutor. Go to Profile, set maximum weekly hours and enter the times you are free. These are not busy periods. Save the profile and availability.
  2. Browse Courses. Each card shows its minimum mark and whether applications are open.
  3. Open the course. Submit your mark; the server currently rejects a mark below the course threshold. Submitted marks are PENDING until organiser review. Resubmission requires verification again.
  4. Enter requested weekly hours (1–40) and a motivation, then choose Apply to tutor. Applying does not allocate you immediately.
  5. The course page displays your application status, qualification issues and organiser decision. You may withdraw a pending application. Reapplying after rejection/withdrawal is not yet supported.
  6. After approval, reload the app so its database role refreshes. Your tutor dashboard is the starting point for assignments, timesheets and excusals.

Overflow volunteering remains a separate Volunteers workflow for unclaimed/overflow work. It is not a regular course application.

Allocation board

Existing tutors can also be assigned from Allocation Board using drag-and-drop or the assignment form. Marks, availability, conflicts and hours are checked before saving. A validation network failure must not be shown as a successful check.

Current manual policy: a missing mark or excess weekly hours is an advisory warning; a below-threshold/unverified mark or timetable conflict is an error. Any warning requires an override reason. Errors produce PENDING allocations, whereas advisory-only overrides can create ACTIVE allocations. Application approval is deliberately stricter and permits no warnings. Confirm this override policy with the stakeholder before release.

API contract

Prefix /api/v1; authenticated bearer token required. Responses normally use {success:true,data:...}. Request-schema failures use 400, authentication 401, forbidden 403, missing resource 404, conflicting state/capacity 409 and eligibility failures 422. Removal returns 204.

Action Endpoint Role/body
Create course POST /courses Organiser; code, name, year, semester, requiredTutors, minMarkRequired; applicationsOpen defaults false
Open/close recruitment PATCH /courses/:id Organiser; {applicationsOpen:true/false}
Remove unused course DELETE /courses/:id Organiser; protected historical records cause 409
Add session POST /courses/:id/sessions Organiser; dayOfWeek, startTime, endTime, venue, sessionType
Submit own mark POST /tutors/me/marks Student/tutor; {courseId,mark}
Verify/reject mark PATCH /tutors/marks/:markId Organiser; {status:"VERIFIED"} or {status:"REJECTED",rejectionReason}
Apply POST /courses/:id/applications Student/tutor; {hoursPerWeek:2,motivation:"I enjoy helping students"}
List applications GET /courses/:id/applications Organiser sees all applicants for this course; others see their own
Review PATCH /courses/:id/applications/:applicationId Organiser; {status:"APPROVED" or "REJECTED",reason:"..."}
Withdraw POST /courses/:id/applications/:applicationId/withdraw Owner of a pending application

Database and connection findings

React uses Axios → Express /api/v1 → Prisma → Supabase PostgreSQL. Auth0 supplies authentication; the database supplies the authoritative role. Local Vite proxies /api/v1 to http://localhost:3000. Production needs VITE_API_URL pointing to the actual API, matching Auth0 audience/domain, permitted callback/web origins and the frontend origin in API FRONTEND_URL.

CourseApplication: UUID application ID; required user/course relations; unique user/course pair; required integer hours and motivation; pending/approved/rejected/withdrawn status; optional review reason, reviewer ID and timestamp; created/updated timestamps; unique user/course index. User deletion cascades applications; the local schema restricts course deletion. Approval runs in a serializable transaction and records an audit entry. The reviewer is an optional user relation with ON DELETE SET NULL.

The live database already uses ApplicationStatus, a required motivation, and nullable reviewReason. Prisma now maps its CourseApplicationStatus enum to ApplicationStatus and API reason to reviewReason. This fixes the observed P2022 missing-column failure without rewriting live data. Read-only generated-client course/application queries now pass.

Recovery update: the original application migration has now been recovered with an exact database checksum match. All seven migrations are applied and the Prisma schema diff is empty. The conflicting replacement is archived outside migrations. See connection recovery for provenance, public URL findings and deployment steps.

Use node prisma/check-connection.js in toodle-api for a read-only check. It reports schema/history and no credentials or personal records. A successful read is not proof of writes, authenticated browser behavior or deployment readiness.

For local use: generate Prisma Client (npm.cmd run build) and run npm.cmd run dev in the API; run npm.cmd run dev in the frontend. The Windows .cmd form avoids PowerShell's npm.ps1 execution-policy restriction. Do not put secrets in documentation or prompts.

Acceptance script

Use approved test accounts and a disposable course. Record actual results rather than marking these passed in advance.

  1. Organiser creates course (minimum 60%, one tutor), adds Monday 10:00–12:00 session, opens applications.
  2. Student enters Monday 09:00–13:00 free time and 6h weekly capacity; submits 75% mark and applies for 2h with motivation.
  3. Before verification, organiser sees a blocked approval. Verify against the supplied test school record, give reason and approve.
  4. Reload student's app; confirm tutor role, active board assignment and 4h remaining.
  5. Repeat with low/unverified mark, absent availability, overlapping assignment and insufficient hours; verify each issue is visible and blocks application approval.
  6. Try competing approvals for the last place using two organiser sessions; verify one succeeds and the other refreshes after a conflict.
  7. Reject and withdraw pending applications; verify reasons and ownership restrictions.
  8. Close recruitment; application POST must fail. Remove a separate unused course; removing the used course must fail without data loss.
  9. Follow the existing timesheet and excusal/volunteer flows with these accounts; capture any failures in the team's tracker.