Files
dotcom-arcade/docs/11-diagrams/play-tracking-flow.mmd
T

205 lines
7.9 KiB
Plaintext

%% Play Session Tracking Flow
%% Complete lifecycle of play session tracking from start to end
---
title: Play Session Lifecycle
---
sequenceDiagram
participant User
participant GamePlayer
participant usePlayTracking
participant API
participant Backend
participant PlayTrackingService
participant UserDB
participant FlashpointDB
User->>GamePlayer: Game loaded and playing
GamePlayer->>usePlayTracking: useEffect on mount
usePlayTracking->>usePlayTracking: Generate sessionId<br/>crypto.randomUUID()
usePlayTracking->>API: playTrackingApi.startSession()
Note over usePlayTracking,API: {<br/> gameId,<br/> gameTitle,<br/> sessionId<br/>}
API->>Backend: POST /api/play-tracking/start
Backend->>PlayTrackingService: startSession(userId, gameId, sessionId)
PlayTrackingService->>UserDB: BEGIN TRANSACTION
PlayTrackingService->>UserDB: INSERT INTO user_game_plays
Note over UserDB: (user_id, game_id, game_title,<br/>started_at, session_id)
PlayTrackingService->>UserDB: INSERT OR IGNORE INTO user_game_stats
Note over UserDB: (user_id, game_id, game_title,<br/>first_played_at)
PlayTrackingService->>UserDB: INSERT OR IGNORE INTO user_stats
Note over UserDB: (user_id, first_play_at)
PlayTrackingService->>UserDB: COMMIT
UserDB-->>PlayTrackingService: Session created
PlayTrackingService->>FlashpointDB: UPDATE game<br/>SET playCounter = playCounter + 1,<br/>lastPlayed = NOW()<br/>WHERE id = ?
PlayTrackingService-->>Backend: Session started
Backend-->>API: {success: true, sessionId}
API-->>usePlayTracking: Session active
Note over User,GamePlayer: User plays game...
alt User closes game normally
User->>GamePlayer: Navigate away or close
GamePlayer->>usePlayTracking: useEffect cleanup
usePlayTracking->>API: playTrackingApi.endSession(sessionId)
API->>Backend: POST /api/play-tracking/end
Backend->>PlayTrackingService: endSession(sessionId, duration)
PlayTrackingService->>UserDB: BEGIN TRANSACTION
PlayTrackingService->>UserDB: UPDATE user_game_plays<br/>SET ended_at = NOW(),<br/>duration_seconds = ?<br/>WHERE session_id = ?
PlayTrackingService->>UserDB: SELECT * FROM user_game_plays<br/>WHERE session_id = ?
UserDB-->>PlayTrackingService: Session data
PlayTrackingService->>UserDB: UPDATE user_game_stats<br/>SET total_plays = total_plays + 1,<br/>total_playtime_seconds = total_playtime_seconds + ?,<br/>last_played_at = NOW()<br/>WHERE user_id = ? AND game_id = ?
PlayTrackingService->>UserDB: UPDATE user_stats<br/>SET total_sessions = total_sessions + 1,<br/>total_playtime_seconds = total_playtime_seconds + ?,<br/>last_play_at = NOW()<br/>WHERE user_id = ?
PlayTrackingService->>FlashpointDB: UPDATE game<br/>SET playtime = playtime + ?<br/>WHERE id = ?
PlayTrackingService->>UserDB: COMMIT
PlayTrackingService-->>Backend: Session ended
Backend-->>API: {success: true}
else User abandons session (browser crash, etc.)
Note over User: Session remains active<br/>in database
rect rgb(255, 240, 240)
Note over Backend: Background cleanup job<br/>runs every 6 hours
Backend->>PlayTrackingService: cleanupAbandonedSessions()
PlayTrackingService->>UserDB: SELECT * FROM user_game_plays<br/>WHERE ended_at IS NULL<br/>AND started_at < datetime('now', '-24 hours')
UserDB-->>PlayTrackingService: Abandoned sessions
loop For each abandoned session
PlayTrackingService->>UserDB: UPDATE user_game_plays<br/>SET ended_at = datetime(started_at, '+30 minutes'),<br/>duration_seconds = 1800<br/>WHERE id = ?
PlayTrackingService->>UserDB: UPDATE statistics tables
end
end
end
---
title: Play Statistics Aggregation
---
graph TB
subgraph "Session Data"
Session[user_game_plays<br/>Individual Sessions]
end
subgraph "Aggregated Statistics"
PerGame[user_game_stats<br/>Per-Game Totals]
Overall[user_stats<br/>Overall User Totals]
FlashpointStats[game.playCounter<br/>game.playtime<br/>Global Statistics]
end
subgraph "Reporting"
RecentGames[Recently Played Games]
TopGames[Most Played Games]
UserDashboard[User Dashboard Stats]
GlobalLeaderboard[Global Game Rankings]
end
Session -->|Aggregate by game| PerGame
Session -->|Aggregate by user| Overall
Session -->|Update global| FlashpointStats
PerGame --> TopGames
PerGame --> RecentGames
Overall --> UserDashboard
FlashpointStats --> GlobalLeaderboard
style Session fill:#61dafb,stroke:#333,stroke-width:2px
style PerGame fill:#90ee90,stroke:#333,stroke-width:2px
style Overall fill:#90ee90,stroke:#333,stroke-width:2px
style FlashpointStats fill:#ff9999,stroke:#333,stroke-width:2px
---
title: Cleanup Job Flow
---
sequenceDiagram
participant CronJob
participant PlayTrackingService
participant UserDB
participant Logger
Note over CronJob: Runs every 6 hours
CronJob->>PlayTrackingService: cleanupAbandonedSessions()
PlayTrackingService->>UserDB: SELECT * FROM user_game_plays<br/>WHERE ended_at IS NULL<br/>AND started_at < datetime('now', '-24 hours')
UserDB-->>PlayTrackingService: List of abandoned sessions
alt No abandoned sessions
PlayTrackingService->>Logger: info('No abandoned sessions')
PlayTrackingService-->>CronJob: Complete
else Has abandoned sessions
PlayTrackingService->>Logger: info('Found {count} abandoned sessions')
PlayTrackingService->>UserDB: BEGIN TRANSACTION
loop For each session
Note over PlayTrackingService: Estimate 30 minute playtime
PlayTrackingService->>UserDB: UPDATE user_game_plays<br/>SET ended_at = datetime(started_at, '+30 minutes'),<br/>duration_seconds = 1800,<br/>abandoned = 1<br/>WHERE id = ?
PlayTrackingService->>UserDB: UPDATE user_game_stats<br/>SET total_plays = total_plays + 1,<br/>total_playtime_seconds = total_playtime_seconds + 1800<br/>WHERE user_id = ? AND game_id = ?
PlayTrackingService->>UserDB: UPDATE user_stats<br/>SET total_sessions = total_sessions + 1,<br/>total_playtime_seconds = total_playtime_seconds + 1800<br/>WHERE user_id = ?
end
PlayTrackingService->>UserDB: COMMIT
PlayTrackingService->>Logger: info('Cleaned up {count} sessions')
PlayTrackingService-->>CronJob: Complete
end
---
title: Real-time Statistics Query
---
sequenceDiagram
participant User
participant Component
participant API
participant Backend
participant PlayTrackingService
participant UserDB
User->>Component: View profile/statistics
Component->>API: playTrackingApi.getUserStats()
API->>Backend: GET /api/play-tracking/stats
Backend->>PlayTrackingService: getUserStats(userId)
par Get overall stats
PlayTrackingService->>UserDB: SELECT * FROM user_stats<br/>WHERE user_id = ?
UserDB-->>PlayTrackingService: Overall statistics
and Get game stats
PlayTrackingService->>UserDB: SELECT * FROM user_game_stats<br/>WHERE user_id = ?<br/>ORDER BY total_playtime_seconds DESC<br/>LIMIT 10
UserDB-->>PlayTrackingService: Top 10 games
and Get recent sessions
PlayTrackingService->>UserDB: SELECT * FROM user_game_plays<br/>WHERE user_id = ?<br/>AND ended_at IS NOT NULL<br/>ORDER BY started_at DESC<br/>LIMIT 10
UserDB-->>PlayTrackingService: Recent 10 sessions
end
PlayTrackingService->>PlayTrackingService: Calculate additional metrics
Note over PlayTrackingService: - Average session duration<br/>- Favorite platform<br/>- Play streak<br/>- Achievement progress
PlayTrackingService-->>Backend: Complete statistics
Backend-->>API: Statistics response
API-->>Component: Display stats
Component->>User: Render statistics dashboard