dubs-server 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (304) hide show
  1. package/.claude/settings.local.json +280 -0
  2. package/CLAUDE.md +46 -0
  3. package/CONNECT4_PRODUCTION_DEPLOY.md +155 -0
  4. package/CURRENT_SESSION.md +171 -0
  5. package/CURRENT_SESSION_DRAW.md +516 -0
  6. package/MARCH_MADNESS_SURVIVOR.md +254 -0
  7. package/PANDA.md +166 -0
  8. package/Procfile +4 -0
  9. package/README.md +476 -0
  10. package/controllers/livescoresController.js +376 -0
  11. package/controllers/pickemController.js +554 -0
  12. package/controllers/survivorAdminController.js +887 -0
  13. package/controllers/survivorController.js +623 -0
  14. package/cron/oracleMonitor.js +77 -0
  15. package/cron/pickemOracleMonitor.js +73 -0
  16. package/data/jackpot-history.json +952 -0
  17. package/data/ncaaTeams.js +406 -0
  18. package/documentation/API_SECURITY_GUIDE.md +327 -0
  19. package/documentation/ARCADE_API.md +593 -0
  20. package/documentation/ARCADE_IMPLEMENTATION_SUMMARY.md +399 -0
  21. package/documentation/ARCADE_QUICKSTART.md +242 -0
  22. package/documentation/AUTOMATIC_MODE_ORACLE.md +321 -0
  23. package/documentation/BUG_FIX_COHORT_DATE_DISPLAY.md +171 -0
  24. package/documentation/CLAIM_MIGRATION_INSTRUCTIONS.md +52 -0
  25. package/documentation/CLAIM_STATUS_FIX.md +67 -0
  26. package/documentation/CLI_TOOL_GUIDE.md +372 -0
  27. package/documentation/COHORT_RETENTION_ANALYSIS.md +295 -0
  28. package/documentation/COHORT_RETENTION_IMPLEMENTATION_COMPLETE.md +461 -0
  29. package/documentation/COHORT_RETENTION_SUMMARY.md +204 -0
  30. package/documentation/COMPLETE_PROJECT_SUMMARY.md +490 -0
  31. package/documentation/DATABASE_QUERIES.md +269 -0
  32. package/documentation/DATABASE_RETENTION_POLICY.md +390 -0
  33. package/documentation/DATABASE_SETUP_GUIDE.md +361 -0
  34. package/documentation/DATABASE_SETUP_SUMMARY.md +247 -0
  35. package/documentation/DEMO_API_CURL_COMMANDS.md +656 -0
  36. package/documentation/DEPLOYMENT_SUMMARY.txt +100 -0
  37. package/documentation/DUPLICATE_NOTIFICATIONS_FIXED.md +201 -0
  38. package/documentation/EXCHANGE_RATES_INTEGRATION.md +371 -0
  39. package/documentation/FINAL_API_PROTECTION_TABLE.md +175 -0
  40. package/documentation/GAME_START_NOTIFICATIONS_DEPLOYMENT.md +256 -0
  41. package/documentation/GAME_START_NOTIFICATIONS_INTEGRATION.md +275 -0
  42. package/documentation/HEROKU_DEPLOYMENT.md +134 -0
  43. package/documentation/HEROKU_SCHEDULER_SETUP.md +271 -0
  44. package/documentation/JACKPOT_API.md +521 -0
  45. package/documentation/JACKPOT_DEPLOYMENT_GUIDE.md +362 -0
  46. package/documentation/JWT_IMPLEMENTATION_SUMMARY.md +373 -0
  47. package/documentation/JWT_QUICK_SETUP.md +268 -0
  48. package/documentation/JWT_TESTING_GUIDE.md +404 -0
  49. package/documentation/KEEPER_RECOVERY_GUIDE.md +381 -0
  50. package/documentation/KEEPER_SETUP.md +206 -0
  51. package/documentation/KEEPER_STATE_MACHINE.md +423 -0
  52. package/documentation/LATEST_PRODUCTION_SETUP.md +387 -0
  53. package/documentation/LOCAL_VOTING_TEST.md +279 -0
  54. package/documentation/ORACLE_FIXES_SUMMARY.md +188 -0
  55. package/documentation/ORACLE_POSTGRESQL_UPDATE.md +202 -0
  56. package/documentation/PAYMENT_DEPLOYMENT.md +209 -0
  57. package/documentation/PNL_TRACKING_SETUP.md +189 -0
  58. package/documentation/PREVENTING_LOCKUP_ERRORS.md +472 -0
  59. package/documentation/PRODUCTION_READY_SUMMARY.md +227 -0
  60. package/documentation/PUBLIC_VS_PRIVATE_ENDPOINTS.md +278 -0
  61. package/documentation/QUICK_AUTH_SETUP.md +99 -0
  62. package/documentation/QUICK_DEPLOY.md +224 -0
  63. package/documentation/QUICK_FIX.md +114 -0
  64. package/documentation/QUICK_START.md +152 -0
  65. package/documentation/REFEREE_MODE_GUIDE.md +392 -0
  66. package/documentation/RETENTION_CORE_ACTION_UPDATE.md +313 -0
  67. package/documentation/RETENTION_UPDATE_SUMMARY.md +108 -0
  68. package/documentation/RUN_MIGRATION_NOW.md +39 -0
  69. package/documentation/SCRIPTS_UPDATE_SUMMARY.md +251 -0
  70. package/documentation/SETUP_GUIDE.md +184 -0
  71. package/documentation/STATE_MACHINE_IMPLEMENTATION.md +250 -0
  72. package/documentation/TELEGRAM_NOTIFICATIONS_DIAGNOSIS.md +361 -0
  73. package/documentation/UNIFIED_ARCHITECTURE.md +231 -0
  74. package/documentation/VOTING_DEPLOYMENT_SUMMARY.md +392 -0
  75. package/documentation/WEBSOCKET_ARCHITECTURE.md +881 -0
  76. package/documentation/WHAT_WE_BUILT_TODAY.md +369 -0
  77. package/documentation/latest/LATEST_PRODUCTION_SETUP.md +865 -0
  78. package/ecosystem.config.js +65 -0
  79. package/env.template +125 -0
  80. package/middleware/apiKeyAuth.js +136 -0
  81. package/middleware/authenticate.js +214 -0
  82. package/middleware/developerUserAuth.js +76 -0
  83. package/middleware/socketAuth.js +69 -0
  84. package/package.json +49 -0
  85. package/postman/Dubs-API-v1-With-Voting.postman_collection.json +555 -0
  86. package/postman/Dubs-API-v1.postman_collection.json +205 -0
  87. package/postman/Dubs_Developer_API.postman_collection.json +662 -0
  88. package/postman/QUICKSTART.md +118 -0
  89. package/postman/QUICK_REFERENCE.md +246 -0
  90. package/postman/README.md +71 -0
  91. package/postman/VOTING_API_GUIDE.md +426 -0
  92. package/refactor/Animations.md +148 -0
  93. package/refactor/Chat.md +252 -0
  94. package/routes/actionsRoutes.js +699 -0
  95. package/routes/adminRoutes.js +370 -0
  96. package/routes/analyticsRoutes.js +1262 -0
  97. package/routes/arcadeRoutes.js +557 -0
  98. package/routes/authRoutes.js +2310 -0
  99. package/routes/avatarRoutes.js +85 -0
  100. package/routes/botRoutes.js +211 -0
  101. package/routes/chatRoutes.js +377 -0
  102. package/routes/cryptoPriceRoutes.js +105 -0
  103. package/routes/developerRoutes.js +4201 -0
  104. package/routes/deviceRoutes.js +214 -0
  105. package/routes/dmRoutes.js +167 -0
  106. package/routes/esportsRoutes.js +806 -0
  107. package/routes/exchangeRateRoutes.js +233 -0
  108. package/routes/gamesRoutes.js +3028 -0
  109. package/routes/jackpotRoutes.js +754 -0
  110. package/routes/keeperMonitoringRoutes.js +156 -0
  111. package/routes/keeperWebhookRoutes.js +466 -0
  112. package/routes/livescoresRoutes.js +31 -0
  113. package/routes/pickemAdminRoutes.js +199 -0
  114. package/routes/pickemRoutes.js +231 -0
  115. package/routes/playerStatsRoutes.js +147 -0
  116. package/routes/portfolioRoutes.js +217 -0
  117. package/routes/promoRoutes.js +418 -0
  118. package/routes/referralEarningsRoutes.js +392 -0
  119. package/routes/socialRoutes.js +459 -0
  120. package/routes/sportsRoutes.js +1271 -0
  121. package/routes/survivorAdminRoutes.js +345 -0
  122. package/routes/survivorRoutes.js +756 -0
  123. package/routes/uploadRoutes.js +256 -0
  124. package/routes/userProfileRoutes.js +244 -0
  125. package/routes/whatsNewRoutes.js +331 -0
  126. package/scripts/.claude/settings.local.json +15 -0
  127. package/scripts/README.md +170 -0
  128. package/scripts/RESTART_EVERYTHING.sh +104 -0
  129. package/scripts/add-claim-columns.sql +48 -0
  130. package/scripts/add-crypto-prices-cache.sql +27 -0
  131. package/scripts/add-exchange-rates-cache.sql +40 -0
  132. package/scripts/add-game-invite-column.sql +23 -0
  133. package/scripts/add-game-invite-notification.sql +33 -0
  134. package/scripts/add-game-invite-telegram-pref.sql +16 -0
  135. package/scripts/add-game-joined-notification.sql +16 -0
  136. package/scripts/add-game-joined-pref.js +40 -0
  137. package/scripts/add-game-joined-preference.sql +6 -0
  138. package/scripts/add-game-start-notifications.sql +41 -0
  139. package/scripts/add-notification-flags-to-games.sql +55 -0
  140. package/scripts/add-pending-game-dismissals.sql +19 -0
  141. package/scripts/add-preferred-currency.sql +34 -0
  142. package/scripts/add-winner-columns.js +61 -0
  143. package/scripts/add_mention_system.sql +53 -0
  144. package/scripts/add_payment_system.sql +96 -0
  145. package/scripts/add_sports_event_id_column.sql +22 -0
  146. package/scripts/analyze-cohort-data-heroku.js +276 -0
  147. package/scripts/analyze-cohort-data.js +295 -0
  148. package/scripts/analyze-prod-cohorts.sh +10 -0
  149. package/scripts/backfill-matchup-images.js +245 -0
  150. package/scripts/backfill-missing-signatures.js +175 -0
  151. package/scripts/backfill-referral-earnings.js +202 -0
  152. package/scripts/check-chat-schema.js +130 -0
  153. package/scripts/check-db.sh +14 -0
  154. package/scripts/check_oracle_in_game.js +54 -0
  155. package/scripts/cleanup-database.js +193 -0
  156. package/scripts/clear-notification-cache.js +85 -0
  157. package/scripts/convert-mnemonic.js +50 -0
  158. package/scripts/create-users-table.sql +44 -0
  159. package/scripts/debug-cohort-counts.js +248 -0
  160. package/scripts/debug-winner-calc.js +84 -0
  161. package/scripts/deploy-payment-system.sh +118 -0
  162. package/scripts/deploy-to-heroku.sh +63 -0
  163. package/scripts/diagnose-locked-round.js +143 -0
  164. package/scripts/dubs-cli.js +720 -0
  165. package/scripts/dump-account.js +65 -0
  166. package/scripts/find-vrf-offset.js +48 -0
  167. package/scripts/fix-chat-notifications-constraint.sql +122 -0
  168. package/scripts/fix-claim-columns.js +124 -0
  169. package/scripts/fix-constraint-now.js +44 -0
  170. package/scripts/fix-lock-timestamps.js +96 -0
  171. package/scripts/fix-locked-round.sh +126 -0
  172. package/scripts/fix-missing-badges.sql +91 -0
  173. package/scripts/fix-payment-notifications.sql +41 -0
  174. package/scripts/force-new-round.js +55 -0
  175. package/scripts/force-resolve-and-claim.js +278 -0
  176. package/scripts/important/README.md +115 -0
  177. package/scripts/important/authority-force-lock.js +197 -0
  178. package/scripts/important/authority-resolve-game.js +267 -0
  179. package/scripts/important/check-game-status.js +373 -0
  180. package/scripts/important/list-pending-games-by-version.js +270 -0
  181. package/scripts/important/reconcile-v1-v2-payouts.js +270 -0
  182. package/scripts/initialize-jackpot.js +111 -0
  183. package/scripts/jackpot/.claude/settings.local.json +10 -0
  184. package/scripts/jackpot/force-reset.js +84 -0
  185. package/scripts/jackpot/initialize-mainnet.js +100 -0
  186. package/scripts/jackpot/keeper.js +742 -0
  187. package/scripts/jackpot/status.js +107 -0
  188. package/scripts/jackpot/update-round-duration.js +143 -0
  189. package/scripts/keeper-bot.js +112 -0
  190. package/scripts/list-pending-games.js +131 -0
  191. package/scripts/migrate-chat-v2.js +127 -0
  192. package/scripts/migrate-chat-winners.js +84 -0
  193. package/scripts/migrate-chat.sh +17 -0
  194. package/scripts/migrate-game-invite.js +83 -0
  195. package/scripts/migrate-heroku-game-notifications.sh +159 -0
  196. package/scripts/migrations/001_analytics_tables.sql +422 -0
  197. package/scripts/migrations/002_add_matchup_image_url.sql +14 -0
  198. package/scripts/migrations/003_referral_earnings.sql +208 -0
  199. package/scripts/migrations/004_add_whats_new_notification_type.sql +62 -0
  200. package/scripts/migrations/005_add_connect4_your_turn_notification.sql +61 -0
  201. package/scripts/migrations/005_push_notifications.sql +55 -0
  202. package/scripts/migrations/006_add_draw_team_players.sql +28 -0
  203. package/scripts/migrations/006_add_game_cancelled_notification.sql +62 -0
  204. package/scripts/migrations/007_add_gif_url.sql +8 -0
  205. package/scripts/migrations/008_add_connect4_columns.sql +139 -0
  206. package/scripts/migrations/008_add_pool_tracking.sql +22 -0
  207. package/scripts/migrations/009_create_survivor_pool_tables.sql +174 -0
  208. package/scripts/migrations/010_add_survivor_pool_outcome.sql +28 -0
  209. package/scripts/migrations/011_create_developer_tables.sql +67 -0
  210. package/scripts/migrations/011_fix_keeper_tables.sql +85 -0
  211. package/scripts/migrations/012_create_developer_webhooks.sql +31 -0
  212. package/scripts/migrations/013_add_network_mode.sql +18 -0
  213. package/scripts/migrations/014_create_developer_app_users.sql +19 -0
  214. package/scripts/migrations/015_add_ui_config.sql +4 -0
  215. package/scripts/migrations/016_add_resolution_secret.sql +4 -0
  216. package/scripts/migrations/017_add_external_game_id.sql +3 -0
  217. package/scripts/migrations/018_create_pickem_tables.sql +115 -0
  218. package/scripts/migrations/019_expo_push_tokens.sql +19 -0
  219. package/scripts/migrations/create_whats_new_tables.sql +88 -0
  220. package/scripts/migrations/drop_live_games_tables.sql +34 -0
  221. package/scripts/open-jackpot-round.js +85 -0
  222. package/scripts/purge-all-data.sh +329 -0
  223. package/scripts/purge-all-data.sql +142 -0
  224. package/scripts/purge-heroku-data.sh +149 -0
  225. package/scripts/purge-heroku-data.sql +62 -0
  226. package/scripts/rebuild-heroku-database.sh +113 -0
  227. package/scripts/recover-funds.js +357 -0
  228. package/scripts/regenerate-epl-images.js +278 -0
  229. package/scripts/resize-s3-matchup-images.js +374 -0
  230. package/scripts/resolve-direct.js +88 -0
  231. package/scripts/resolve-mock-game.js +124 -0
  232. package/scripts/resolve-pickem-game.js +55 -0
  233. package/scripts/resolve-round-manual.js +83 -0
  234. package/scripts/resolve-stuck-game.js +382 -0
  235. package/scripts/resolve-stuck-round.js +42 -0
  236. package/scripts/run-connect4-migration.sh +16 -0
  237. package/scripts/run-mention-migration.sh +32 -0
  238. package/scripts/run-payment-migration.sh +51 -0
  239. package/scripts/run-preferred-currency-migration.sh +31 -0
  240. package/scripts/run-referral-earnings-migration.sh +32 -0
  241. package/scripts/run-survivor-outcome-migration.sh +16 -0
  242. package/scripts/seed-test-users.js +346 -0
  243. package/scripts/setup-auth-tables.js +78 -0
  244. package/scripts/setup-complete-database.sql +992 -0
  245. package/scripts/setup-database-fresh.sh +359 -0
  246. package/scripts/setup-heroku-keeper.sh +48 -0
  247. package/scripts/setup-keeper-database.js +83 -0
  248. package/scripts/setup-keeper-state-db.sql +110 -0
  249. package/scripts/setup-oracle.sh +39 -0
  250. package/scripts/setup-pnl-tracking.js +111 -0
  251. package/scripts/start-devnet.sh +14 -0
  252. package/scripts/test-arcade-devnet.sh +160 -0
  253. package/scripts/test-arcade-match.sh +109 -0
  254. package/scripts/test-automatic-mode.sh +239 -0
  255. package/scripts/test-connect4-cancel-claim.js +370 -0
  256. package/scripts/test-connect4-e2e.js +369 -0
  257. package/scripts/test-connect4-resolve.js +369 -0
  258. package/scripts/test-game-state-endpoint.js +136 -0
  259. package/scripts/test-invite-notification.js +86 -0
  260. package/scripts/test-jackpot-api.sh +71 -0
  261. package/scripts/test-poll-confirmation.js +267 -0
  262. package/scripts/test-resolve-game.js +271 -0
  263. package/scripts/test-resolve-signature.js +223 -0
  264. package/scripts/test-signature-preservation.js +124 -0
  265. package/scripts/test-state-machine.js +291 -0
  266. package/scripts/test-webhook-receiver.js +60 -0
  267. package/scripts/update-notification-constraint.js +52 -0
  268. package/scripts/verify-account-layout.js +145 -0
  269. package/scripts/verify-winner-algorithm.js +278 -0
  270. package/server.js +5259 -0
  271. package/services/arcadeMatchService.js +763 -0
  272. package/services/automaticGameOracle.js +1596 -0
  273. package/services/chatService.js +1612 -0
  274. package/services/connect4GameService.js +1049 -0
  275. package/services/connect4NotificationService.js +374 -0
  276. package/services/cryptoPriceService.js +223 -0
  277. package/services/customGameResolver.js +260 -0
  278. package/services/db.js +79 -0
  279. package/services/directMessageService.js +389 -0
  280. package/services/discordNotifications.js +160 -0
  281. package/services/exchangeRateService.js +289 -0
  282. package/services/expoPushService.js +314 -0
  283. package/services/gamesCacheService.js +539 -0
  284. package/services/jackpotHistory.js +331 -0
  285. package/services/jackpotService.js +856 -0
  286. package/services/keeperStateService.js +355 -0
  287. package/services/matchupImageService.js +591 -0
  288. package/services/notificationCacheService.js +407 -0
  289. package/services/pickemOracle.js +440 -0
  290. package/services/playerStatsService.js +389 -0
  291. package/services/portfolioService.js +555 -0
  292. package/services/promoService.js +757 -0
  293. package/services/promoTreasuryService.js +239 -0
  294. package/services/pushNotifications.js +353 -0
  295. package/services/redisService.js +422 -0
  296. package/services/referralEarningsService.js +728 -0
  297. package/services/s3Service.js +396 -0
  298. package/services/socialService.js +1202 -0
  299. package/services/survivorOracle.js +469 -0
  300. package/services/survivorSimulator.js +475 -0
  301. package/services/telegramNotifications.js +461 -0
  302. package/services/userProfileStatsService.js +1185 -0
  303. package/services/whatsNewService.js +388 -0
  304. package/utils/urlHelper.js +95 -0
@@ -0,0 +1,252 @@
1
+ # Chat System Refactor
2
+
3
+ ## Overview
4
+ This document tracks the optimization work for the Dubs chat system across frontend and backend.
5
+
6
+ **Date**: 2025-02-01
7
+ **Status**: Complete - Ready for Production
8
+
9
+ ---
10
+
11
+ ## Architecture
12
+
13
+ ### Frontend (`dubs-jackpot-spa`)
14
+
15
+ | Component | Location | Purpose |
16
+ |-----------|----------|---------|
17
+ | `ChatWidget.tsx` | `app/v2/components/chat/` | Main orchestrator |
18
+ | `MessageList.tsx` | same | Scrollable container with pagination |
19
+ | `MessageRow.tsx` | same | Individual message with GIF onLoad |
20
+ | `ChatInput.tsx` | same | Input + GIF picker |
21
+ | `ChatContext.tsx` | `app/v2/contexts/` | State management + deduplication |
22
+ | `chatSocket.ts` | `app/v2/services/` | Socket.io singleton |
23
+
24
+ ### Backend (`dubs-server`)
25
+
26
+ | File | Purpose |
27
+ |------|---------|
28
+ | `server.js:4005-4758` | Socket.io `/chat` namespace handlers |
29
+ | `services/chatService.js` | Database operations with cursor pagination |
30
+ | `routes/chatRoutes.js` | HTTP endpoints with pagination support |
31
+ | `services/notificationCacheService.js` | Redis caching layer |
32
+
33
+ ### Data Flow (Updated)
34
+
35
+ ```
36
+ ┌──────────────────────────────────────────────────────────────────┐
37
+ │ FRONTEND │
38
+ ├──────────────────────────────────────────────────────────────────┤
39
+ │ ChatWidget │
40
+ │ ├── ChatContext (state: messages[], pagination, dedup) │
41
+ │ │ ├── chatSocket.ts (singleton Socket.io client) │
42
+ │ │ └── useToast (rate limit errors) │
43
+ │ ├── MessageList │
44
+ │ │ ├── "Load older messages" button (if hasMore) │
45
+ │ │ ├── Smart scroll (new msgs only, not load more) │
46
+ │ │ └── MessageRow × N │
47
+ │ │ └── <img onLoad={handleImageLoad}> (GIF scroll) │
48
+ │ └── ChatInput → sendMessage() │
49
+ └───────────────────────────┬──────────────────────────────────────┘
50
+ │ Socket.io /chat namespace
51
+
52
+ ┌──────────────────────────────────────────────────────────────────┐
53
+ │ BACKEND │
54
+ ├──────────────────────────────────────────────────────────────────┤
55
+ │ server.js │
56
+ │ └── chatNamespace.on('send_message') │
57
+ │ ├── Rate limit check (5/min) → "Woah, slow down 🤣" │
58
+ │ ├── chatService.addMessage() → PostgreSQL │
59
+ │ └── chatNamespace.emit('new_message') → ALL clients │
60
+ │ │
61
+ │ GET /chat/messages?limit=20&before={id} │
62
+ │ └── chatService.getRecentMessages(limit, userId, before) │
63
+ │ └── SELECT ... WHERE id < {before} LIMIT {limit+1} │
64
+ │ └── Returns { messages, hasMore, oldestId } │
65
+ └──────────────────────────────────────────────────────────────────┘
66
+ ```
67
+
68
+ ---
69
+
70
+ ## Issues Fixed
71
+
72
+ ### Issue #1: Scroll-to-Bottom with GIFs ✅
73
+
74
+ **Problem**: GIFs load asynchronously, scroll happens before GIF height is known.
75
+
76
+ **Solution**:
77
+ - Added `onImageLoad` prop to MessageRow
78
+ - GIF `<img>` has `onLoad={onImageLoad}` handler
79
+ - MessageList checks if user is within 150px of bottom
80
+ - If near bottom, scrolls after GIF loads
81
+
82
+ ---
83
+
84
+ ### Issue #2: Double/Triple Posting ✅
85
+
86
+ **Problem**: Users see duplicate messages (2-3x of same message).
87
+
88
+ **Solution**: Added deduplication in ChatContext:
89
+ ```javascript
90
+ setMessages((prev) => {
91
+ if (prev.some(m => m.id === message.id)) {
92
+ console.log('[Chat] Duplicate message ignored:', message.id);
93
+ return prev;
94
+ }
95
+ return [...prev, message];
96
+ });
97
+ ```
98
+
99
+ ---
100
+
101
+ ### Issue #3: Loading Too Many Messages ✅
102
+
103
+ **Problem**: Always loaded 100 messages with no pagination.
104
+
105
+ **Solution**:
106
+ - Reduced initial load to 20 messages
107
+ - Added cursor-based pagination (`before` param)
108
+ - "Load older messages" button at top of chat
109
+ - Smart scroll: only scrolls to bottom for new messages, not when loading older
110
+
111
+ ---
112
+
113
+ ### Issue #4: Rate Limit Error Not Shown ✅
114
+
115
+ **Problem**: Users spam chat, get socket error but no UI feedback.
116
+
117
+ **Solution**:
118
+ - Added `useToast` hook to ChatContext
119
+ - Listen for `chat:error` window events
120
+ - Shows friendly toast: "Woah, slow down there 🤣"
121
+
122
+ ---
123
+
124
+ ## Files Modified
125
+
126
+ | File | Repo | Changes |
127
+ |------|------|---------|
128
+ | `routes/chatRoutes.js` | dubs-server | `before` cursor, `hasMore`/`oldestId` response |
129
+ | `services/chatService.js` | dubs-server | Cursor pagination in `getRecentMessages()` |
130
+ | `server.js` | dubs-server | Friendly rate limit message |
131
+ | `app/v2/contexts/ChatContext.tsx` | dubs-jackpot-spa | Pagination, deduplication, rate limit toast |
132
+ | `app/v2/components/chat/MessageList.tsx` | dubs-jackpot-spa | Load more button, smart scroll, GIF handler |
133
+ | `app/v2/components/chat/MessageRow.tsx` | dubs-jackpot-spa | `onImageLoad` prop for GIFs |
134
+ | `app/v2/components/chat/ChatWidget.tsx` | dubs-jackpot-spa | Pagination props, auto-refresh on panel open |
135
+
136
+ ---
137
+
138
+ ## Deployment
139
+
140
+ ### Order: Backend First, Then Frontend
141
+
142
+ **Why**: Backend changes are backwards compatible. Old frontend works with new backend.
143
+
144
+ ### Backend Deploy
145
+ ```bash
146
+ cd ~/Developer/iheartsolana/solana-programs/dubs-server
147
+ git add routes/chatRoutes.js services/chatService.js server.js refactor/
148
+ git commit -m "Chat optimization: pagination, rate limit UX"
149
+ git push
150
+ # Deploy to production
151
+ ```
152
+
153
+ ### Verify Backend
154
+ ```bash
155
+ curl https://api.dubs.gg/chat/messages?limit=5
156
+ # Should return: { hasMore: true, oldestId: X, messages: [...] }
157
+ ```
158
+
159
+ ### Frontend Deploy
160
+ ```bash
161
+ cd ~/Developer/iheartsolana/dubs-jackpot-spa
162
+ git add app/v2/contexts/ChatContext.tsx app/v2/components/chat/
163
+ git commit -m "Chat optimization: pagination, deduplication, GIF scroll, rate limit toast"
164
+ git push
165
+ # Deploy frontend
166
+ ```
167
+
168
+ ---
169
+
170
+ ## Backwards Compatibility
171
+
172
+ **Backend**:
173
+ - `before` parameter is optional - old clients work without it
174
+ - New response fields (`hasMore`, `oldestId`) are additive
175
+ - Old clients ignore new fields
176
+
177
+ **Frontend**:
178
+ - Has fallbacks: `data.hasMore ?? false`
179
+ - Old v1 `DegenChat.tsx` still works (uses `limit=50`)
180
+ - New v2 uses `limit=20` with pagination
181
+
182
+ ---
183
+
184
+ ## Rollback Plan
185
+
186
+ | Scenario | Action |
187
+ |----------|--------|
188
+ | Frontend issues | Revert frontend commit - old frontend works with new backend |
189
+ | Backend issues | Revert backend commit - new frontend has fallbacks |
190
+ | Both | Revert both - system returns to previous state |
191
+
192
+ ---
193
+
194
+ ## Future Improvements
195
+
196
+ - [ ] Virtual scrolling for very long chat histories
197
+ - [ ] Preload GIF dimensions from GIPHY API metadata
198
+ - [ ] Message search/filter
199
+ - [ ] Lazy load game invite cards for old messages
200
+
201
+ ---
202
+
203
+ ## Additional Optimizations
204
+
205
+ ### React.memo for MessageRow ✅
206
+
207
+ **Added memoization to prevent unnecessary re-renders:**
208
+
209
+ **MessageRow** (`MessageRow.tsx`):
210
+ ```javascript
211
+ export const MessageRow = memo(MessageRowComponent, (prevProps, nextProps) => {
212
+ return (
213
+ prevProps.message.id === nextProps.message.id &&
214
+ prevProps.message.edited === nextProps.message.edited &&
215
+ prevProps.message.reactions === nextProps.message.reactions &&
216
+ prevProps.isHighlighted === nextProps.isHighlighted
217
+ );
218
+ });
219
+ ```
220
+
221
+ **Note:** GameInviteCard is NOT memoized because it uses `useChat()` context internally for real-time game state updates. Memoizing components that depend heavily on context can cause stale data issues.
222
+
223
+ **Impact:** With 20 messages, new message arrival goes from 20 component re-renders → 1 re-render.
224
+
225
+ ---
226
+
227
+ ### Auto-Refresh on Panel Open ✅
228
+
229
+ **Problem**: Users had to manually pull-to-refresh or reconnect to see new messages when reopening chat.
230
+
231
+ **Solution**: ChatWidget now watches `leadingPanel.isOpen` from ThreePanelLayout:
232
+
233
+ ```javascript
234
+ // ChatWidget.tsx
235
+ const { leadingPanel } = useLayout();
236
+ const wasOpenRef = useRef(leadingPanel.isOpen);
237
+
238
+ useEffect(() => {
239
+ // Only refresh when panel transitions from closed to open
240
+ if (leadingPanel.isOpen && !wasOpenRef.current) {
241
+ console.log('[Chat] Panel opened - refreshing messages');
242
+ refreshMessages();
243
+ }
244
+ wasOpenRef.current = leadingPanel.isOpen;
245
+ }, [leadingPanel.isOpen, refreshMessages]);
246
+ ```
247
+
248
+ **Behavior**:
249
+ - When user taps chat FAB button to open chat panel
250
+ - Chat automatically fetches fresh messages from API
251
+ - Old messages are replaced with new ones
252
+ - No manual refresh needed