I am:
Connecting...
🔔 Changes saved by another team member are available.

What is UAT and why does it matter?

UAT (User Acceptance Testing) is the final check before the system goes live. It means real staff and learners use the actual platform — not a demo — and confirm that every feature works the way it should. If something is wrong, we catch it here, not after launch.

This document is the single reference point for the entire 5-day testing session. It tells everyone who tests what, what to look for, how to log problems, and when we need to be done. Non-technical stakeholders can read the Test Scripts and Feature Matrix tabs without needing any system knowledge. Technical staff will find the setup requirements in the Technical Setup tab.

The 10 areas being tested

1 · Programme setup
2 · Registration & apply
3 · Documents
4 · Review & score
5 · Shortlist & award
6 · Waitlist
7 · Contract & sign
8 · Deadline reminders
9 · POPIA data rights
10 · Audit trail

Sign-off criteria

The system may go live when all three conditions are met:

1. Zero blocker bugs outstanding. A blocker is any defect that causes wrong data to be saved, a notification not to fire, a document to be lost, or a security gap. Blockers must be fixed and re-tested before go-live.
2. All testers have completed their Feature Matrix. Every role's checklist must be 100% completed, or explicitly marked "N/A" with a reason logged in the bug log.
3. Written sign-off from JTG staff. Tshidi or Gomolemo confirms in writing (email is sufficient) that they have reviewed the bug log triage and are satisfied the system is ready.

What happens after UAT

The bug log is triaged into three buckets: blockers, functional gaps, and polish. Blockers get fixed immediately. Functional gaps are negotiated against the go-live timeline. Polish items are deferred to a post-launch iteration. The system does not need to be perfect to go live — it needs to be trustworthy.

Team assignments

Six people cover four system roles. Only Tshidi's admin account is pre-seeded by the developer. Everyone else self-registers on Day 1 morning, verifies their email, and then Tshidi assigns their system role from the Admin → Users panel before testing begins.

Bursary programme staff

TK
Tshidi
super_admin & verification_officer · pre-seeded
GM
Gomolemo
programme_admin · self-registers Day 1

Interns

VA
Vanessa
learner (eligible) · self-registers Day 1
RO
Rorisang
learner (ineligible) + bug log owner · self-registers Day 1
TS
Tshidiso
reviewer + sponsor · self-registers Day 1
BO
Bonolo
verification_officer + admin support · self-registers Day 1

Registration and role assignment flow

On Day 1 morning, everyone except Tshidi follows the same three steps:

Step 1 — Self-register. Go to the UAT URL, click Register, fill in name, email address, and a password, and submit. Use your real email address so you can receive the verification link and all notification emails during testing.
Step 2 — Verify your email. Check your inbox for the verification email. Click the link. Your account becomes active.
Step 3 — Wait for role assignment. After all five people have registered, Tshidi logs into the Admin panel → Users and assigns each person their system role. Once assigned, log out and log back in — you will now land on the correct portal (learner / reviewer / sponsor / admin).
Tshidi runs role assignment for all five team members before any other testing begins. This is the first thing on Day 1 afternoon and takes approximately 10 minutes.

Why two learners?

The waitlist promotion flow requires one learner to accept an award offer and another to be waiting on the waitlist. Without two separate learner accounts this cannot be tested. Vanessa accepts; Rorisang is on the waitlist and gets promoted. To separately test the decline path, Vanessa will also decline a second award offer — this is what triggers Rorisang's waitlist promotion rather than running an artisan command manually.

Rorisang's institution profile will be set by Gomolemo before the testing session starts — her institution or year of study will fall just outside the eligibility criteria for the UAT programme. This confirms the system correctly blocks ineligible applicants.

Account details

Person Role assigned by admin How account is created Email used
Tshidisuper_adminPre-seeded by developertshidi@uat.jtg (or real email)
Gomolemoprogramme_adminSelf-registers on Day 1Real email address
VanessalearnerSelf-registers on Day 1Real email address
RorisanglearnerSelf-registers on Day 1Real email address
Tshidisoreviewer sponsorSelf-registers on Day 1Real email address
Bonoloverif. officer admin supportSelf-registers on Day 1Real email address
Because real email addresses are used, all notification emails will land in real inboxes — not just Mailtrap. Confirm with the developer that Mailtrap is only used for the queue/delivery testing steps, and that the UAT mail config sends real emails for the self-registration flow.

Bug log owner

Rorisang is assigned as bug log owner for the session. She is responsible for ensuring every issue — including ones flagged verbally by other testers — is logged in this document before end of each testing day. Her own testing workload is lighter than Vanessa's, which creates the capacity for this role. She does not need to fix anything, only record it clearly and completely.

Scripts are written in plain language. Each step tells the tester exactly what to do and what they should see if the system is working correctly. If what they see differs from the expected result, that is a bug — log it in the Bug Log tab with the step reference number.

ALL
Pre-session — Self-registration & email verification
Gomolemo, Vanessa, Rorisang, Tshidiso, and Bonolo — Day 1 morning. Tshidi skips this (her account is pre-seeded).
Complete all steps below before Tshidi assigns your role. You will not have full portal access until role assignment is done.

Step R1 — Self-register your account

  1. 1
    Go to the UAT URL (shared by Tshidi). Click "Register" or "Create account".
    ✓ Registration form loads with fields for name, email address, and password.
  2. 2
    Enter your real full name, your real email address, and a password. Submit the form.
    ✓ You see a message like "Please check your email to verify your account." You are NOT taken to any portal yet.
    ⚠ If you land immediately on a dashboard with no email verification step, log this as a Blocker: "Email verification not triggered on registration."

Step R2 — Verify your email address

  1. 1
    Open your inbox. Look for a "Verify your email" or "Confirm your account" message from the system.
    ✓ Email arrives within 2 minutes containing a verification link.
    ⚠ If no email after 5 minutes, check spam. If still missing, log as Blocker: "Verification email not delivered."
  2. 2
    Click the verification link in the email.
    ✓ Browser confirms "Email verified." Account is now active, but you have no role yet.
  3. 3
    Log in with your email and password.
    ✓ You can log in. You see a limited or blank dashboard. No full portal features yet — this is expected until Tshidi assigns your role.

Step R3 — Confirm role access after assignment

Wait for Tshidi to confirm in the group chat that all roles have been assigned, then continue.
  1. 1
    Log out, then log back in (or refresh).
    ✓ You land on the correct portal: learner (Vanessa, Rorisang), reviewer (Tshidiso), sponsor (Bonolo), admin (Gomolemo).
    ⚠ Still seeing the default page? Your role has not been assigned yet. Message Tshidi before logging this as a bug.
  2. 2
    Manually type a URL for a portal that is not yours (e.g. type /admin/dashboard while you are a learner).
    ✓ Access denied — redirected to your own portal or shown a 403 error.
    ⚠ If you can access another role's portal, log immediately as a Blocker: "Role access control not enforced."
TK/GM
Tshidi & Gomolemo — Admin portal
Tshidi oversees Steps 0 and 8 (super_admin — oversight & sign-off). Gomolemo runs Steps 1–7 (programme_admin). Bonolo runs Step 2 as verification_officer in a separate incognito tab and provides technical support to Gomolemo throughout.

Step 1 — Programme, form, rubric, and rule setup (Gomolemo)

  1. 1
    Log in as Gomolemo. Go to Admin → Programmes → Create new programme. Enter name "JTG UAT Bursary 2025", set the deadline 3 days from today, fund amount R15,000. Under eligibility, set institution to match Vanessa's pre-seeded institution only.
    ✓ Programme saves and appears in the programme list.
  2. 2
    Click "Form Builder" on the new programme. Add 3 fields: a text field ("Motivation letter"), a file upload ("Supporting document"), and a dropdown ("Year of study"). Save, then click "Publish Form".
    ✓ Fields save correctly in preview. Status changes to "Published".
  3. 3
    Navigate to Rubrics. Add 3 criteria: "Academic merit" (weight 40%), "Financial need" (weight 35%), "Motivation" (weight 25%). Confirm weights total 100%.
    ✓ Three criteria saved. Weight total shows 100%.
  4. 6
    Navigate to Auto-assignment rules. Add a rule to assign Tshidiso as reviewer when an application is moved to "approved_for_review". Save and confirm it is active.
    ✓ Rule appears in the list and is toggled on.
  5. 7
    Go to Admin → Contract Templates → Create. Build a template with merge fields for learner name, award amount, and programme name. Save and preview it.
    ✓ Template saved. Preview shows merge fields as readable placeholders, not raw code.

Step 1b — Universal programme setup (Gomolemo)

  1. 1
    Create a second programme: "JTG UAT Open Bursary 2025". Set this one to universal mode — no eligibility restrictions. Publish its form.
    ✓ Programme saves in universal mode. Both Vanessa and Rorisang can see it in their listings (Rorisang cannot see the restricted programme but should see this one).
  2. 2
    Confirm Rorisang can see the universal programme in her listing even though she is excluded from the restricted one.
    ✓ Rorisang sees "JTG UAT Open Bursary 2025" in her programme list. She does not see "JTG UAT Bursary 2025". This confirms restricted and universal modes filter correctly.

Step 2 — Document verification (Bonolo in incognito as verification_officer)

Wait until Vanessa has uploaded her documents (Vanessa Script Step 3) before starting this step.
  1. 1
    Open a new incognito window. Log in as Tshidi's verification_officer account. Go to the verification dashboard.
    ✓ Applications with pending documents are listed.
  2. 2
    Open Vanessa's application. Verify both her ID document and transcript by clicking "Verify" on each.
    ✓ Both documents show as "Verified". Application status automatically moves to "under_review".
  3. 3
    Test the rejection path: find Rorisang's ID document and reject it with a reason (e.g. "File is unreadable").
    ✓ Rejection reason is saved and visible. Rorisang's application remains in pending document state.

Step 3 — Move to review and confirm auto-assignment (Gomolemo)

Run this after Bonolo has verified Vanessa's documents (Step 2 above).
  1. 1
    Go to Admin → Applications. Find Vanessa's application. Change its status to "approved_for_review".
    ✓ Status updates. Tshidiso appears as the assigned reviewer (auto-assignment rule fired).
  2. 2
    Check Mailtrap (or Tshidiso's in-app notifications) for a reviewer assignment email.
    ✓ ReviewerAssigned email visible in Mailtrap addressed to Tshidiso.
  3. 3
    After Tshidiso declares a conflict (his Step 3), go to Admin → COI. Find the flagged declaration and reassign to a backup reviewer.
    ✓ Reassignment recorded. Original reviewer is marked as recused on that application.

Step 3b — Manual reviewer assignment test (Gomolemo)

  1. 1
    Create a second test application (or use an existing one that has no auto-rule match). Go to Admin → Applications and manually assign a reviewer using the direct assign control — without relying on the auto-assignment rule.
    ✓ Reviewer is assigned manually. The assignment is visible on the application detail. A reviewer alert notification fires to the assigned reviewer.

Step 4 — Shortlisting and awards (Gomolemo)

Run after Tshidiso has submitted and locked his scores.
  1. 1
    Go to Admin → Shortlist for the UAT programme. Confirm applications are ranked by weighted score and Vanessa's application appears with a score.
    ✓ Ranked list displayed with weighted scores visible per application.
  2. 3
    Select both Vanessa and Rorisang's test applications. Click "Bulk Shortlist".
    ✓ Both move to "shortlisted". Two StatusChanged emails appear in Mailtrap — one per learner. This was a previously fixed bug — confirm both emails arrive.
  3. 4
    Create an award for Vanessa. Set offer amount to R15,000 and expiry date 5 days from today. Generate the offer letter.
    ✓ Offer letter PDF generated and stored. AwardOffered email fires to Vanessa.
  4. 5
    Add Rorisang to the waitlist (Admin → Waitlist). Confirm she is at position 1.
    ✓ Rorisang shows as waitlisted at position 1.

Step 5 — Waitlist promotion (Gomolemo)

Trigger this either by having Vanessa decline a second award offer, or by running: php artisan awards:process-expired to expire it manually.
  1. 1
    Check the waitlist panel. Confirm Rorisang has been automatically promoted.
    ✓ Rorisang's status changes. WaitlistPromoted email visible in Mailtrap. Waitlist panel shows her as promoted.

Step 6 — Deadline reminders (Gomolemo, with developer)

  1. 1
    Ask the developer to set the programme deadline to tomorrow. Run: php artisan reminders:deadline --dry-run
    ✓ Output lists the correct applications without sending any emails.
  2. 2
    Run the same command without --dry-run. Then run it again.
    ✓ Emails appear in Mailtrap on first run. Second run sends no duplicates (idempotency confirmed).

Step 7 — POPIA data subject requests (Gomolemo)

Wait until Vanessa and Rorisang have each submitted their DSR from their own portals.
  1. 1
    Go to Admin → Data Subject Requests. Find Vanessa's access request. Acknowledge it.
    ✓ Status moves to "acknowledged". Vanessa receives a status update notification.
  2. 2
    Download the data export for Vanessa's request. Open the JSON file and confirm it contains her real data.
    ✓ JSON file downloads. Contains Vanessa's name, institution, and application data.
  3. 3
    Find Rorisang's erasure request. Execute the erasure. Only on the UAT database.
    ✓ Rorisang's account is anonymised. Erasure report PDF written to storage. Her name no longer visible anywhere in the system.

Step 7b — Retention policy framework (Gomolemo)

  1. 1
    Go to Admin → POPIA / Data Settings. Confirm there is a retention policy configuration area — this is where the system defines how long different data types are retained before automatic deletion or anonymisation.
    ✓ Retention policy settings are visible. You can see or configure retention periods for application data, personal profiles, and financial records.
  2. 2
    Check whether the policy settings show the current configured retention period and any upcoming scheduled deletions.
    ✓ Retention settings display correctly without errors. Changes to the configuration save successfully.

Step 8 — Audit log and user management (Tshidi — super_admin)

  1. 1
    Go to Admin → Audit Logs. Filter by today's date. Spot-check: find the bulk shortlist entry, the erasure executed entry, and a reviewer assignment entry.
    ✓ All three entries present with correct user names and timestamps.
  2. 2
    Go to Admin → Contracts. Search for Vanessa's contract by her name.
    ✓ Contract appears in search results. The signed version is downloadable. Version history is visible (showing at minimum the generated version and the signed version with timestamp).
  3. 3
    Go to Admin → Contracts. Search for Vanessa by name.
    ✓ Her signed contract appears in results. Version history shows generated → signed with timestamps. Contract is downloadable.
  • X
    Go to Admin → Users. Toggle a user account inactive, then reactivate it. Run a password reset.
    ✓ Toggle works. Password reset email appears in Mailtrap.
  • Each tester ticks off features as they confirm them working during the session. The progress summary updates automatically. If a feature could not be tested, mark it "N/A" and log the reason in the Bug Log.

    FeatureTested byResult
    Create a new programme with deadline and eligibility rulesGomolemo
    Form builder — add, edit, and publish form fieldsGomolemo
    Form preview renders correctly before publishingGomolemo
    Scoring rubric saved with weighted criteria summing to 100%Gomolemo
    Auto-assignment rule fires reviewer on status changeGomolemo
    Document verification — verify a documentTshidi
    Document verification — reject a document with reasonTshidi
    Application moves to under_review automatically after all docs verifiedTshidi
    Bulk shortlist fires StatusChanged email to each learner (both emails arrive)Gomolemo
    Award created with offer letter generated as downloadable PDFGomolemo
    AwardOffered email fires to learnerGomolemo
    Waitlist panel — add learner and confirm position 1Gomolemo
    Waitlist auto-promotion triggers and WaitlistPromoted email firesGomolemo
    COI conflict: admin successfully reassigns recused reviewerGomolemo
    Contract template saved with merge fields, preview worksGomolemo
    Deadline reminder sends correct emails, no duplicates on re-runGomolemo
    DSR access request acknowledged, data export JSON downloaded with real dataGomolemo
    DSR erasure: account anonymised, erasure report written to storageGomolemo
    Audit log shows all UAT actions with correct user and timestampTshidi
    User management: toggle active/inactive and password reset workTshidi
    Self-registration creates account without immediate portal accessTshidi
    Email verification link sent on registration; activates account when clickedTshidi
    Role assignment via Admin → Users grants correct portal access per roleTshidi
    Conditional logic on form field: dependent field shows/hides based on selectionGomolemo
    Document checklist per programme — required document types configured and enforced on uploadGomolemo
    Manual reviewer assignment (no auto-rule) works and fires reviewer alertGomolemo
    Notifications configurable per programme — event-level toggles save correctlyGomolemo
    Bulk status movement: multiple applications transitioned in one actionGomolemo
    POPIA retention policy framework visible and configurable in admin settingsGomolemo
    Contract repository searchable by applicant nameTshidi
    Contract version history shows generated → signed with timestampsTshidi
    Universal programme mode: visible to all learners regardless of eligibility filterGomolemo

    Owned by Rorisang. Every issue found must be logged here before end of each testing day. The log will be triaged on Day 4 into blockers (fix before go-live), functional gaps (negotiate), and polish (defer).

    Total bugs
    0
    Blockers
    0
    Functional gaps
    0
    Polish
    0
    # Day Tester Portal Step ref What happened Expected behaviour Severity Screenshot
    1

    Severity definitions

    🔴 Blocker Wrong data saved; data loss; notification not firing; security issue (e.g. learner sees another learner's data); document upload fails silently; erasure does not anonymise; contract not generated on acceptance. Must be fixed before go-live.
    🟡 Functional gap Feature works but behaves differently than staff expected. Usually a workflow or UX issue rather than a code error. Examples: a filter behaves unexpectedly, a confirmation step is missing, a label is confusing. Negotiate against the timeline.
    ⚪ Polish Cosmetic: spelling errors, font sizes, colour mismatches, spacing, wording that does not cause incorrect behaviour. Defer to a post-launch iteration — this list will never end otherwise.

    The session runs over 5 business days. Day 1 is admin-only setup. Learner and reviewer testing runs in parallel on Days 2 and 3. Day 4 is for completing any outstanding items and the group triage meeting. Day 5 is blocker re-testing and written sign-off.

    Sessions are 1–3 hours each — not full days. Confirm exact times with Tshidi or Gomolemo based on everyone's availability before the week begins.

    Day 1
    Environment setup, self-registration, role assignment & programme configuration
    Monday
    Morning
    Developer confirms: migrations clean, storage linked, Mailtrap connected, seeders run, all accounts created and distributed.
    Developer only — completed before 9am
    Morning (~45 min)
    Gomolemo, Vanessa, Rorisang, Tshidiso, and Bonolo self-register at the UAT URL, verify their email addresses, and confirm accounts are active. Pre-session Steps R1–R3.
    All testers except Tshidi
    Late morning (~30 min)
    Tshidi runs Admin Step 0: assigns roles to all five registered accounts. Each person logs out and back in and confirms correct portal access in the group chat.
    Tshidi (others on standby)
    Afternoon (~2.5h)
    Gomolemo runs Admin Script Steps 1 (programme, form builder, rubric, auto-assignment, contract template). Tshidi verifies super_admin access and audit log.
    Tshidi + Gomolemo (afternoon only, after role assignment)
    End-of-day checkpoint: All six people have working portal access. Both programmes (restricted and universal) are configured and confirmed. Do not proceed to Day 2 until all team members confirm access in the group chat.
    Day 2
    Registration, application, document verification, and reviewer assignment
    Tuesday
    Morning (~1.5h)
    Vanessa and Rorisang run their registration and application scripts. Rorisang tests the eligibility block. Vanessa submits and uploads documents.
    Vanessa + Rorisang
    Midday
    Tshidi (incognito as verification_officer) verifies Vanessa's documents and rejects one of Rorisang's. Gomolemo moves application to approved_for_review and confirms auto-assignment fires.
    Tshidi + Gomolemo
    Afternoon (~1h)
    Tshidiso logs in and runs the reviewer script: COI clean path, scoring, locked scores, conflict path, committee recommendation.
    Tshidiso
    Rorisang logs all Day 2 bugs before 5pm.
    Day 3
    Shortlisting, awards, waitlist, contract signing, and sponsor portal
    Wednesday
    Morning (~1.5h)
    Gomolemo runs shortlisting, bulk shortlist, creates award for Vanessa, places Rorisang on waitlist. Confirms both StatusChanged emails and AwardOffered email in Mailtrap.
    Gomolemo
    Midday (~1h)
    Vanessa accepts award, downloads and checks offer letter PDF, signs contract, downloads signed contract.
    Vanessa
    Afternoon (~1h)
    Gomolemo triggers waitlist promotion (or runs expiry command). Rorisang confirms WaitlistPromoted email. Tshidiso runs sponsor portal steps (S1–S3). Bonolo runs admin tech support check (V2).
    Gomolemo + Rorisang + Tshidiso + Bonolo
    If blockers are already piling up, flag this to Tshidi today — Wednesday is the last realistic point to add a buffer day before the Friday sign-off deadline.
    Day 4
    POPIA requests, deadline reminders, audit log, and bug triage
    Thursday
    Morning (~1h)
    Vanessa and Rorisang submit DSR requests. Gomolemo acknowledges and processes them. Rorisang's erasure executed on UAT database. Deadline reminder command tested with developer.
    Gomolemo + Vanessa + Rorisang + Developer
    Midday (~30 min)
    Tshidi reviews the full audit log and confirms all UAT actions appear with correct users and timestamps. Runs user management tests.
    Tshidi
    Afternoon (~1.5h)
    Bug triage meeting. Tshidi, Gomolemo, and developer review every logged item together. Each item confirmed as Blocker, Functional Gap, or Polish. Blockers assigned to developer for Day 5 fix.
    Tshidi + Gomolemo + Developer
    All Feature Matrix checklists must be fully completed by end of Day 4. Outstanding unchecked items must be discussed in the triage meeting.
    Day 5
    Blocker re-testing and formal sign-off
    Friday
    Morning
    Developer deploys fixes for all Day 4 blockers. Gomolemo and/or Tshidi re-run only the affected steps to confirm fixes — no need to re-run the entire script.
    Developer + Gomolemo + Tshidi
    Afternoon
    Formal sign-off. Tshidi or Gomolemo reviews the final bug log (blockers resolved, gaps documented, polish deferred) and sends written sign-off. System is cleared for go-live.
    Tshidi or Gomolemo
    If the Day 4 triage surfaces more than 3 blockers, alert the developer on Wednesday afternoon so a timeline adjustment can be made before it becomes a last-minute crisis.

    This section is for the developer or system administrator setting up the UAT environment. Non-technical stakeholders do not need to read this — but it is included so that all prerequisites are visible to everyone and no setup step can be quietly skipped.

    Prerequisites — all must be green before Day 1 afternoon

    PrerequisiteHow to verify
    All 6 new migrations run clean against a fresh database in the correct orderphp artisan migrate --fresh
    Scheduler cron is active on the UAT server* * * * * php artisan schedule:run
    Mail is routed to Mailtrap — not real addressesSend a test email and confirm it appears in Mailtrap
    Storage symlink createdphp artisan storage:link
    File permissions on storage/app/public allow web writesUpload a test PDF and confirm URL is accessible in browser
    Database seeded with realistic test data (learner profiles, sponsor link, contract template)php artisan db:seed
    Queue driver decision made and confirmed working: either QUEUE_CONNECTION=sync in .env, or queue:work running persistentlySubmit test application and confirm email arrives immediately in Mailtrap
    UAT environment is NOT the production databaseConfirm DB_DATABASE in .env points to the UAT schema
    All 6 tester accounts pre-created with correct roles assignedLog in as each account and confirm correct portal redirect
    Rorisang's learner profile institution set outside eligibility criteria for the UAT programmeLog in as Rorisang and confirm the programme is not visible or apply is blocked
    Tshidi can see all self-registered accounts in Admin → Users and assign roles after Day 1 morning registrationTshidi confirms all five names appear in users list after they register
    Bonolo has a verification_officer account or the developer has confirmed how she accesses the verification dashboard (separate account or role assignment)Bonolo logs in with verification credentials in incognito and lands on verification dashboard before Day 2
    Tshidiso's account supports both reviewer and sponsor roles, or a second sponsor account is set up for himTshidiso confirms he can access both portals before Day 2 testing begins

    Commands reference

    Command When to run during UAT
    php artisan migrate --fresh --seedBefore Day 1. Resets the UAT database to a clean seeded state.
    php artisan storage:linkOnce, before Day 1. Required for document and offer letter file serving.
    php artisan queue:workRun persistently if using database queue driver. Alternatively set QUEUE_CONNECTION=sync.
    php artisan awards:process-expiredDay 3 — manually expires a pending award to trigger waitlist promotion.
    php artisan reminders:deadline --dry-runDay 4 — preview which applications would receive reminders without sending.
    php artisan reminders:deadlineDay 4 — send actual reminders. Run twice to confirm no duplicate sends.

    Known behaviours that are not bugs

    Email delivery timing. If QUEUE_CONNECTION=sync, emails arrive in Mailtrap instantly. If using the database queue driver without queue:work running, emails queue but are not delivered. Decide before Day 1 and brief testers so they know what to expect.
    Eligibility filter hides programmes entirely. Ineligible learners (Rorisang) will not see the restricted programme in the listing at all — the system does not show it with a "you are ineligible" message, it simply does not appear. This is by design. Brief Rorisang before the session so she knows what to expect and does not incorrectly log an absence as a bug.
    Session timeout on long forms. Learners who fill in a long application and step away may return to a logged-out session. The system will prompt them to log in again. The draft should be preserved. This is expected behaviour — testers will likely report it anyway, so flag it in the known-issues briefing before the session starts.
    POPIA erasure is irreversible. DataAnonymisation::anonymise() soft-deletes the user account and permanently wipes all PII fields. There is no undo. Only execute the erasure step on the UAT database. Confirm DB_DATABASE in .env is not pointing at production before Rorisang's erasure step on Day 4.