Skip to Content
Business logicMember lifecycleMember lifecycle rules

Member lifecycle rules

Every member sits in exactly one role_id at a time. Almost every other gate on the platform is downstream of which role_id a member is in plus what flags are set on their record.

role_id reference

role_idNameStatus
1AdministratorIBA staff with back-office access.
2Banned / deletedAccount removed or suspended for cause.
4Pending email verificationRegistration started, email not yet verified.
6FlyerDefault role on entry; the vast majority of members.
7CoachDeprecated. Coach status is now a flag on the member record.
8InstructorAuthorised to approve flyer skills up to their level.
9TrainerAuthorised to certify new instructors.
10ExaminerAuthorised to run formal level assessments.
11AFCPassed the AFC milestone — gateway to the instructor track.

Reserved / unused: 3, 5. Higher values may exist for future classifications; pull from the source of truth before assuming a mapping.

Roles tracked outside role_id

Two roles live as boolean flags on the member record, not as values of role_id:

  • Coach — the legacy role_id = 7 is no longer written. Coach status is a flag, which means a member can be (e.g.) an instructor (role_id = 8) and flagged as a coach simultaneously. Each side carries its own currency clock and its own approval scope.
  • Military — military programme membership is a flag, paired with channel_currency_military for the separate currency cycle. A military flyer is still a regular flyer in role_id terms; the flag activates military-specific rules.

This split — single role_id for the formal progression ladder, flags for parallel programmes — is why a member’s standing depends on both role_id AND the flags on their record.

Transitions

role_id evolves with the member. The valid transitions:

FromToTrigger
(new)4 (pending)Member starts registration.
4 (pending)6 (flyer)Member clicks email verification link.
6 (flyer)11 (AFC)Flyer passes the AFC milestone skill.
11 (AFC)8 (instructor)AFC member passes Instructor Level 1 (initial training + assessment).
8 (instructor)9 (trainer)Instructor completes trainer certification.
9 (trainer)10 (examiner)Trainer completes examiner certification.
any2 (banned/deleted)Administrative action only. Doesn’t drift from inactivity.
1 (admin)(any)Administrative role assignments are out of band — set by IBA staff with appropriate authority.

role_id is independent of currency. An active flyer can be not-current; a not-current member is still in their normal role_id; banned (role_id = 2) wins regardless of currency.

[!NOTE] Whether a demotion path exists (e.g. an instructor stepping back to flyer for a sabbatical) and how it’s triggered isn’t documented here yet. Add when nailed down.

Group 2 in detail (banned / deleted)

role_id = 2 is the IBA’s way of saying “this account is no longer operational” without losing the audit trail.

Effects:

  • Sign-in: blocked.
  • Partner validation: integrated booking systems get a not-found-like response when they look up a Group 2 member.
  • Logbook: no new entries can be made for or by them.
  • Historical records: logbook entries they accumulated AND approvals they granted to other members are preserved for audit. Other members’ records aren’t retroactively invalidated.

Bans are administrative — IBA staff (role_id = 1) move members into Group 2; nothing automated does it.

Group 4 in detail (pending email verification)

A role_id = 4 member has started registration but hasn’t clicked their verification link yet.

Effects:

  • They exist on the platform but aren’t a full member yet.
  • Partner systems treat them as not-found at validation time.
  • They can’t be assigned to a tunnel as a home tunnel, can’t accrue logbook entries, and can’t request skills.
  • They sit at Group 4 until verification completes; after a configured window with no verification, they may be cleaned up by an administrative process.

Parent-skill auto-approval

Skills form a tree: some skills are parents whose completion is defined entirely by their children. When a member is approved for every child skill under a parent, the parent is auto-assigned — there’s no separate request or approval step. (The ladders themselves — levels, prerequisites, who may approve what — are documented in skill levels and approval levels.)

Auto-approval runs synchronously as a side effect of each child approval: when a child skill is approved, the platform checks whether all of that parent’s children are now passed and, if so, writes the parent into the logbook.

Concurrency. The check-then-write is per-member, so two child approvals landing at nearly the same time could both read “not all children passed yet” before either commits — neither then triggers the parent, and the member is left with every child but no parent, with no self-heal. Approvals for a single member are therefore serialised:

  • The synchronous path holds a per-member named lock on a single pooled connection while it assigns the parent, so concurrent child approvals queue instead of racing. This lock is the real serialisation guarantee — see the note below on why the SQL alone isn’t one.
  • The logbook-create routine’s duplicate guard is a single INSERT … WHERE NOT EXISTS rather than a separate check-then-insert, which collapses the read-modify-write window into one statement. It is not a hard atomicity guarantee on its own: a member re-attempts a skill until they pass, so the logbook deliberately keeps every attempt and there is no UNIQUE(author_id, skill) constraint to reject a concurrent second write. The named lock above is what actually serialises the parent write; the single-statement guard narrows the window for the routine’s other callers, which don’t hold that lock.
  • The admin and member UIs submit approvals one at a time rather than firing them in parallel.

Reconciliation safety net. Serialisation closes the race on the live path, but historical data (and any future edge case) can still leave a member with all children and no parent. An hourly reconciliation job re-derives missing parent skills set-based and back-fills them, cascading up the tree, so the system self-heals rather than depending on the synchronous path being perfect. It’s idempotent — a run with nothing to fix assigns nothing — and a non-zero heal count is a signal that the live path is still dropping approvals and worth investigating.

Sub-pages in this module

  • Registration flow — sequence diagram of registration from “Sign Up” click through email verification.
  • Authentication flow — sequence diagram of sign-in and session establishment, including Google OAuth.
Last updated on