How-to
Analytics events
Instrumenting the FSM without coupling it to a vendor.
src/infrastructure/Analytics.ts is a small interface:
interface Analytics {
track(event: string, payload?: Record<string, unknown>): void;
}
Swap ConsoleAnalytics for your vendor (Segment, Amplitude, GA4) in
composition.ts. Emit events from phase handlers — they're the
natural event boundaries.
Where to emit
// SpinPhase.enter
ctx.analytics.track('spin_requested', { bet: ctx.stores.balance.bet });
// WinShowPhase.enter
if (winlines.length > 0) {
ctx.analytics.track('win_shown', {
totalWin,
lineCount: winlines.length,
});
} Where NOT to emit
- Not from presenters. They fire on MobX reactions — too many duplicates.
- Not from the view. Too deep in the tree — hard to trace causality.
- Not from stores. Stores should be pure data, no side effects.
What to track
- Round lifecycle: spin requested, response received, wins shown, round complete.
- User intent: bet changed, speed changed, skip pressed.
- Errors: network timeouts, malformed responses, unexpected state transitions.
What NOT to track (client-side)
- Win amounts per se — the server has the authoritative data.
- Paytable-derived metrics — you don't have the paytable.
- RTP — server-side certification.
The client emits user behavior events; the server emits money/outcome events.