Skip to Content
Living documentation — last reviewed 2026-05-28
FeaturesTrialsTrials — QA Plan

Trials — QA Plan

Pre-requisites

  • Org with a non-UTC timezone; owner, admin, coach A, coach B, a Sales rep (coach with an own grant), a Sales manager, members.
  • A published session S coached by A, starting in ~50 minutes, capacity 3, waitlist on; a second published session S2 tomorrow.
  • A lead with a phone number assigned to the rep.
  • A Trial workout plan “Trial class” (created as Trial workout in the plan editor), and member M1 holding it; member M2 on a regular plan; member M3 with no plan.
  • A published health_declaration compliance form (and an org without one for the null case).
  • The mobile app signed in as coach A, notifications allowed.

Golden paths

G1 — Rep books a trial into a class

StepActionExpected
1Sales → lead → Log result → Trial scheduled.Session picker lists published future sessions for 14 days with time, class, coach and spots left; full ones disabled; “Other (no class)” keeps the date-time input.
2Pick S, save.Appointment starts_at = S start, type = class name, class_session_id = S. Lead sheet shows class, time, coach.
3Open S on the web schedule.bookingCount/capacityRemaining include the trial; roster lists the lead in “Trials · N” with a Trial badge and the intake note (also as coach A); no source, no lead source anywhere.

G2 — Coach sees and checks in the trialist

StepActionExpected
1Coach A opens the mobile home.”Trials today” card lists S with the lead (Trial badge, no source). Coach B does not see S; the owner sees it without “mine”.
2Wait for the brief job (S starts within 60 min).One push “1 trial at HH:MM · ” naming the lead (no source); tapping it opens S. Next tick: no second push.
3Open S → Roster → Check in on the trial.Entry shows attended (checked in); seat still taken; lead activity “checked in” by coach A.
4Rep opens the lead.”Checked in HH:MM by A”; outcome editor preselects attended.
5Rep confirms attended.Outcome attended; seat still held (no waitlist promotion); entry stays on the roster.

G3 — Plan and staff trials

StepActionExpected
1M1 books S with the trial plan.Roster: M1 in “Trials · N” with a Trial badge (no plan name, no source); no Mark/Unmark action.
2M2 books S.Not a trial; “Mark as trial” offered (canMarkTrial).
3Coach A marks M2 as trial.M2 moves into the trials block (no “Marked by”); “Unmark” offered (canUnmarkTrial); trialCount +1; the brief and the Trials today card include M2.
4Unmark M2.Back to “Everyone else”.
4bMark M2, M2 cancels and books S again.A plain booking: not a trial, “Mark as trial” offered, revocable by the entitlement sweep.
4cA cancelled or no-show booking.Neither Mark nor Unmark offered; the route answers 409 trial_not_markable.
4dM2 opens their bookings in the app / web, and the booking response when booking.No trialMarkedByUserId / trialAppointmentId keys.
5Plain drop-in (not flagged) booking.Not a trial.

G3b — Trial workout plan

StepActionExpected
1Plans → New plan.Type picker: Subscription, Class Pack, Drop-in, then Trial workout nested under Drop-in (“A single trial class for newcomers”). No “Trial plan” switch anywhere.
2Pick Trial workout.Name pre-filled “Trial workout” (kept if already typed); price shows “Set 0 for a free trial”; Use within (days/weeks), Show in shop, One per person (on), payment link. No interval, credits, presale/intro, purchase cap, plan group, booking limits, overlap.
3Price 0, Use within 2 weeks, save.Plan saved drop_in + isTrial, trialOncePerPerson: true, expiresInDays: 14. List type cell and plan header: “Trial workout”.
4Edit it.Kind shown locked as Trial workout; One per person and Use within loaded.
5M3 buys it in the shop.Active at once; usable for 14 days (expired after).
6M3 buys any trial plan again (shop, join link with that plan, minisite CTA).Shop: “A trial was already used here…” toast. Join: “You’ve already had a trial” with Browse plans; no failed-checkout task for the gym.
7Guardian buys the trial for a child twice.Second purchase refused with the same message (add-child step / shop).
8Owner sells M3 another trial at the desk / enrolls M3.Allowed.
9Turn One per person off; M3 buys again.Allowed. Plain drop-ins and other plans are never affected.
10M4 starts a paid checkout of trial A, leaves it unpaid, then buys trial B.Refused trial_already_used. Resuming the trial A checkout works.
11Un-flag a trial plan someone bought (or abandoned a checkout of).400 trial_plan_in_use; plan stays a trial. Un-flag an unsold one with a Use within window: 400 saying to clear expiresInDays; with it cleared: saved, One per person reset.

G4 — Lead converts before class

StepActionExpected
1S full (capacity reached with the lead’s trial), a member waitlisted. Convert the lead (Sales convert, Sales link, CRM convert, CRM link, or a self-signup with the lead’s email).Appointment converted (lead sheet: “Converted — booked as member”); the new member has a confirmed booking in S with trial_appointment_id; waitlisted member still waitlisted; seat counts unchanged.
2Open the roster.One entry for the person (kind booking), a Trial badge (no source), lead note kept; no lead-trial row; no Mark/Unmark.
3Member has exactly one plan that can pay.Booking carries that plan, credit spent once. With no plan: booking without a plan.
4End the member’s plan (cancel / plan change).The converted booking is not revoked by the entitlement sweep.
5Member already booked in S before converting.Their booking kept and linked; the trial’s seat goes to the waitlist.
6Lead checked in before converting.Trial ends attended, no booking created.
7Class already started, not checked in.Every path (Sales and CRM convert/link, self-signup): trial cancelled and superseded; no booking created.

G5 — Notes carry over

StepActionExpected
1Coach adds an important note on the trial from the roster.Note on the lead; visible in the Sales lead sheet.
2Convert the lead into a member.Member detail lists the note (no copy made); roster shows it as important on their booking.
3Coach B (not author) opens it.No edit/delete (canEdit = false); owner can edit/delete.

G6 — Book an existing member as a trial

StepActionExpected
1Members → M2 → Overview.Trial classes card: “No upcoming trial classes” and Book trial class.
2Book trial class → pick S2 (picker lists the next 14 days with time, class, coach, spots left; full classes selectable) → Book trial.Toast “Trial class booked”; the card lists S2 (class, date/time, coach, Booked) with Unmark. Booking row: trial_marked_by_user_id and booked_by_user_id = the caller, subscription_id = M2’s plan; a credit plan loses one credit like a normal booking; M2 gets the usual confirmation. Roster of S2: M2 in the trials block, “Marked by …“.
3Give M2 a second plan that can pay, book another class.The dialog asks which plan pays (server’s candidate list, first preselected); resubmitting books on the chosen plan.
4Book M2 into a full class with a waitlist.Toast “Added to the waitlist as a trial”; card shows Waitlisted; booking marked.
5Book M2 into a class M2 already booked.No second booking; the existing one is marked (no-op if already a trial).
6Unmark from the card.Booking unmarked; it leaves the card and the roster trials block.
7M1 (trial plan) and a member converted from a lead with a class trial.Their trials are listed without Unmark.
8Refusals: M3 (no plan, org requires one), a plan out of credits, a class whose registration closed.The booking copy naming the member (e.g. “M3 needs an active plan…”); nothing booked.
9Sales → a converted lead’s sheet.Trial classes · card for the member (book + list). An open lead shows no such card and keeps the Sales trial flow; Sales “Trial scheduled” on the converted lead is still refused.
10As a member, call GET/POST …/members/:membershipId/trial-bookings.403.

Trial seats

#CaseExpected
1Session with all seats takenPicker shows 0, disabled; API 409 trial_session_full
2Draft / deleted / started / other-org session400 trial_session_unavailable
3Member books the last seat at the same moment as the trial claimExactly one wins; the other gets full / waitlisted
4Reschedule the trial within the same full sessionAllowed (own seat not counted)
5Reschedule to S2S seat freed and waitlist filled; S2 seat taken
6Rep records no-show / cancelledSeat freed, waitlist filled
7Result Not relevantTrial cancelled, seat freed
8Archive the lead (single and bulk)Trial cancelled and superseded, seat freed, waitlist filled
9Convert / link the lead with a pending trial in a future classSeat moves into the member booking (G4); no waitlist promotion
10Move S’s start timeAppointment starts_at, lead trial_date and the open trial follow-up task (start + 1h) move
11Trial with “Other (no class)“No seat held anywhere
12Coach check-inSeat stays held
13Coach checks the lead in, then the rep converts / marks Not relevant / archives, or reschedulesThe checked-in trial ends attended, not superseded: still on S’s roster, seat still held, no promotion on S
14Cancel S (or delete it, bulk-delete its week with booked classes, overwrite it with a template apply, or Arbox stops reporting an Arbox-owned S) with a pending trial not checked inTrial cancelled and superseded; lead activity sales_trial session_cancelled; the rep’s open trial task cancelled; no waitlist promotion
14bS holds only the lead’s trial; bulk delete without “include booked”, or a template apply with overwriteS is treated as booked: kept (overwrite reports it blocked), trial still pending
15Same, with the trial checked inTrial ends attended; activity written; trial task left open

Marking

#CaseExpected
1Mark a booking twice by two staffFirst marker kept
2Mark / unmark a plan trial or a converted-trial booking, or a cancelled / no-show booking409 trial_not_markable
3Booking of another session404
4Member calls the route403

Check-in

#CaseExpected
1Check in twiceSecond is 409 trial_not_pending
2Check in after the rep recorded an outcome409 trial_not_pending
3Undo while pendingColumns cleared, version bumped, activity check_in_undone
4Appointment of another session / org404
5Session ended with no outcomeTrial stays pending (no auto no-show); appears as outcome work in Sales

Health declaration

#CaseExpected
1Member signed the current declarationsigned
2Member did not signnot_signed
3Org with no health_declaration formnull for all
4Lead trial entrynull

Coach brief

#CaseExpected
1Session in 90 minNo push yet
2Session with no trial (members only)No push, no marker; a trial added later is briefed before start
3Session moved after its briefBriefed again for the new time
4notifyUser throws while enqueuingMarker cleared; retried next tick
4bEnqueue succeeds but Expo rejects the deliveryNot retried; marker stays
5Coach turned trials push offNo push
6Session without a coach / inactive coachNo push
7Push for an org that is not active in the appApp switches org, then opens the session

Trials report, history, Action Center

#CaseExpected
1A lead trial checked in, then the lead converts and starts a regular plan 30 days after the classOne trial, source lead: attended, checked in, converted; median 30 days
2Same, plan starts on day 31Attended, not converted; listed under “Attended, not converted”
3A lead converted before the classCounted once, as the member booking (source lead)
4A lead trial past its time with no check-in and no Sales outcomeawaiting_outcome
5Staff-marked booking set no-show; trial-plan booking in the futureno_show (source staff); upcoming (source plan)
6By coach / by repCoach = the class’s coach; rep = the lead’s owner or the staff member who marked it, both as membership ids; trial plans have no rep
7Member page and the lead’s Sales sheet for a converted leadBoth list the same trials, newest first, with status, check-in, converted plan and days; no source
8Someone attended in the last 14 days with no regular planAction Center row trials.attended_not_converted for owner/admin, linking to the Trials report; gone once they convert
9Sales cohort report”Trial attended” counts checked-in trials and converted trials whose booking was attended

Telemetry

#CaseExpected
1Schedule, reschedule, release, check in, mark, convertMatching TrialEvents, organization group set, no name / phone / note text
2subscription.started delivered twice for a converting planTwo captures with the same uuid; PostHog keeps one trial_converted
3Refused trial seat / purchase / un-flag / markOne trial_refused info log with its reason
4A brief runOne trial_brief_run log with due, briefed, skipped, failed, durationMs

Permissions

ActionOwner / AdminCoachCoach with a Sales grantMember
Roster / trials today / mark trial / trial check-in / trial note✓✓ (trials today: own sessions)✓403
Member notes read/add✓✓✓403
Edit/delete someone else’s member note✓403403—
Lead notes, trial-sessions picker✓403Leads in grant scope403
Edit/delete someone else’s lead note✓ (implicit manager)403Manager bit only—
Create/edit a Trial workout plan✓ (plan editors)———
Buy a once-per-person trial a second time✓ (desk sale / enrollment allowed)——409 trial_already_used
Trials report✓403403403
Member trial history✓✓✓403
Lead trial history✓403Leads in grant scope403

Mobile specifics

  • Card and roster hidden for members and while acting for a child.
  • Notification settings hide trials for non-staff.
  • Mark, check-in and notes with no connection fail; never queued.
  • Roster data is not in the persisted query snapshot after an app restart offline.