Skip to main content

Consultation Session Completion Lifecycle

Purpose

This document describes what happens in the backend when consultation sessions move to terminal states (done or missed), including payments, wallet availability, review gating, and testing behavior from faker.

Core Entities

  • consultation_sessions (ConsultationSessions): runtime session state (scheduled, ongoing, done, missed, etc.)
  • ledger (Ledger): provider credits per consultation session, initially PENDING
  • wallet (Wallet): derived balances from ledger + withdrawals
  • withdrawal (Withdrawal): payout pipeline constrained by wallet.availableBalance

Lifecycle Sequence

sequenceDiagram
participant F as Faker
participant SS as SessionsScheduler
participant S as ConsultationSessions
participant E as EventEmitter
participant L as LedgerService
participant Q as BullMQ(FUND_RELEASE)
participant FR as FundReleaseProcessor
participant W as WalletService
participant WD as WithdrawalAdminService

F->>S: adjustSessionTime(sessionId, hoursFromNow, triggerCompletionCheck)
alt session is expired (endTime <= now - 15m)
F->>SS: handleSessionCompletion()
end

SS->>S: find pending sessions and detect expired
alt bothPartiesJoined = true
SS->>S: status = done, save
SS->>E: emit consultation.session.updated
SS->>E: emit consultation.completed
SS->>L: findBySessionId(sessionId)
SS->>L: scheduleRelease(ledgerId, holdDelay)
L->>Q: enqueue release-funds job
else bothPartiesJoined = false
SS->>S: status = missed, save
SS->>E: emit consultation.session.updated
SS->>E: emit consultation.session.missed
SS->>SS: send SESSION_MISSED notifications
end

Q->>FR: process release-funds job
FR->>L: releaseEntry(ledgerId)
FR->>W: reconcileWallet(providerId)

WD->>W: getBalance(providerId, includePending=true)
W-->>WD: availableBalance (released credits only)

Runtime Side Effects Tied to Completion

  1. Session finalization:
  • server/src/consultation/sessions.scheduler.ts
  • Expired + both joined => done
  • Expired + not both joined => missed
  1. Emitted events:
  • consultation.session.updated on both done and missed
  • consultation.completed on done
  • consultation.session.missed on missed
  1. Payment release:
  • done sessions schedule delayed fund release with PAYMENT_HOLD_DAYS
  • missed sessions do not auto-release
  1. Wallet availability:
  • Only RELEASED ledger credits contribute to availableBalance
  • Withdrawals are validated against availableBalance
  1. Review/completion gating:
  • Consultation completion logic requires terminal sessions and at least one done
  • This impacts ability to submit reviews through enrollment completion checks
  1. Metrics:
  • Student/analytics “finished consultation” counts use done sessions
  • Calendar excludes terminal statuses by default (done, missed, cancelled, pending_payment)

Faker Testing Behavior

When calling:

  • POST /faker/session/:sessionId/time

with payload:

{
"hoursFromNow": -1,
"triggerCompletionCheck": false
}

behavior is:

  • Session time is shifted.
  • If shifted end time is already expired (<= now - 15 minutes) and triggerCompletionCheck is true, faker immediately runs the same scheduler completion pass (handleSessionCompletion), so downstream effects start without waiting for cron.
  • Default is false, so completion is not auto-triggered unless explicitly requested.

Notes for Deterministic Tests

  1. Use hoursFromNow negative enough so endTime <= now - 15m.
  2. Ensure bothPartiesJoined=true before forcing completion if you expect done and release scheduling.
  3. Use admin POST /sessions/:id/release-funds for missed-session dispute resolution path.