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,345 @@
1
+ /**
2
+ * Survivor Admin Routes
3
+ * Admin API endpoints for March Madness Survivor Pool management
4
+ */
5
+
6
+ const express = require('express');
7
+ const router = express.Router();
8
+ const adminController = require('../controllers/survivorAdminController');
9
+ const survivorController = require('../controllers/survivorController');
10
+
11
+ // Socket.IO for real-time updates
12
+ let io = null;
13
+
14
+ // Inject Socket.IO instance
15
+ router.setSocketIO = (ioInstance) => {
16
+ io = ioInstance;
17
+ console.log('[SurvivorAdmin] Socket.IO injected');
18
+ };
19
+
20
+ // Helper to emit pool update
21
+ const emitPoolUpdate = async (poolId) => {
22
+ if (io) {
23
+ try {
24
+ const updatedPool = await survivorController.getPoolById(poolId);
25
+ if (updatedPool) {
26
+ io.emit('survivor:pool_updated', { poolId, pool: updatedPool });
27
+ }
28
+ } catch (err) {
29
+ console.error('[SurvivorAdmin] Failed to emit pool update:', err.message);
30
+ }
31
+ }
32
+ };
33
+
34
+ /**
35
+ * GET /api/survivor/admin/teams
36
+ * Get all NCAA teams for selection
37
+ */
38
+ router.get('/teams', async (req, res) => {
39
+ try {
40
+ const result = adminController.getAllTeams();
41
+ res.json({ success: true, ...result });
42
+ } catch (error) {
43
+ console.error('[SurvivorAdmin] Error getting teams:', error.message);
44
+ res.status(500).json({ success: false, error: error.message });
45
+ }
46
+ });
47
+
48
+ /**
49
+ * GET /api/survivor/admin/pools/:id/dashboard
50
+ * Get admin dashboard for a pool
51
+ */
52
+ router.get('/pools/:id/dashboard', async (req, res) => {
53
+ try {
54
+ const poolId = parseInt(req.params.id);
55
+ const dashboard = await adminController.getPoolDashboard(poolId);
56
+ res.json({ success: true, ...dashboard });
57
+ } catch (error) {
58
+ console.error('[SurvivorAdmin] Error getting dashboard:', error.message);
59
+ res.status(500).json({ success: false, error: error.message });
60
+ }
61
+ });
62
+
63
+ /**
64
+ * POST /api/survivor/admin/pools/:id/generate-bracket
65
+ * Generate random 68-team bracket (for testing)
66
+ */
67
+ router.post('/pools/:id/generate-bracket', async (req, res) => {
68
+ try {
69
+ const poolId = parseInt(req.params.id);
70
+ const result = await adminController.generateRandomBracket(poolId);
71
+
72
+ // Emit real-time update
73
+ await emitPoolUpdate(poolId);
74
+
75
+ res.json({ success: true, ...result });
76
+ } catch (error) {
77
+ console.error('[SurvivorAdmin] Error generating bracket:', error.message);
78
+ res.status(500).json({ success: false, error: error.message });
79
+ }
80
+ });
81
+
82
+ /**
83
+ * POST /api/survivor/admin/pools/:id/set-bracket
84
+ * Set bracket manually (for real Selection Sunday)
85
+ * Body: { teams: [{ teamId, region, seed }, ...] }
86
+ */
87
+ router.post('/pools/:id/set-bracket', async (req, res) => {
88
+ try {
89
+ const poolId = parseInt(req.params.id);
90
+ const { teams } = req.body;
91
+
92
+ if (!teams || !Array.isArray(teams)) {
93
+ return res.status(400).json({
94
+ success: false,
95
+ error: 'Missing required field: teams (array)'
96
+ });
97
+ }
98
+
99
+ const result = await adminController.setManualBracket(poolId, teams);
100
+ res.json({ success: true, ...result });
101
+ } catch (error) {
102
+ console.error('[SurvivorAdmin] Error setting bracket:', error.message);
103
+ res.status(500).json({ success: false, error: error.message });
104
+ }
105
+ });
106
+
107
+ /**
108
+ * POST /api/survivor/admin/pools/:id/set-deadline
109
+ * Set round deadline
110
+ * Body: { minutes: number }
111
+ */
112
+ router.post('/pools/:id/set-deadline', async (req, res) => {
113
+ try {
114
+ const poolId = parseInt(req.params.id);
115
+ const { minutes } = req.body;
116
+
117
+ if (typeof minutes !== 'number' || minutes < 0) {
118
+ return res.status(400).json({
119
+ success: false,
120
+ error: 'Invalid minutes value'
121
+ });
122
+ }
123
+
124
+ const result = await adminController.setDeadline(poolId, minutes);
125
+ res.json({ success: true, ...result });
126
+ } catch (error) {
127
+ console.error('[SurvivorAdmin] Error setting deadline:', error.message);
128
+ res.status(500).json({ success: false, error: error.message });
129
+ }
130
+ });
131
+
132
+ /**
133
+ * POST /api/survivor/admin/pools/:id/clear-deadline
134
+ * Clear round deadline
135
+ */
136
+ router.post('/pools/:id/clear-deadline', async (req, res) => {
137
+ try {
138
+ const poolId = parseInt(req.params.id);
139
+ const result = await adminController.clearDeadline(poolId);
140
+ res.json({ success: true, ...result });
141
+ } catch (error) {
142
+ console.error('[SurvivorAdmin] Error clearing deadline:', error.message);
143
+ res.status(500).json({ success: false, error: error.message });
144
+ }
145
+ });
146
+
147
+ /**
148
+ * POST /api/survivor/admin/pools/:id/simulate-round
149
+ * Simulate game results for current round
150
+ * Body: { mode: 'chalk' | 'random' | 'chaos' | 'manual', results?: [...] }
151
+ */
152
+ router.post('/pools/:id/simulate-round', async (req, res) => {
153
+ try {
154
+ const poolId = parseInt(req.params.id);
155
+ const { mode = 'random', results } = req.body;
156
+
157
+ const result = await adminController.simulateRound(poolId, mode, results);
158
+
159
+ // Emit real-time update
160
+ await emitPoolUpdate(poolId);
161
+
162
+ res.json({ success: true, ...result });
163
+ } catch (error) {
164
+ console.error('[SurvivorAdmin] Error simulating round:', error.message);
165
+ res.status(500).json({ success: false, error: error.message });
166
+ }
167
+ });
168
+
169
+ /**
170
+ * POST /api/survivor/admin/pools/:id/process-eliminations
171
+ * Process eliminations based on current round results
172
+ */
173
+ router.post('/pools/:id/process-eliminations', async (req, res) => {
174
+ try {
175
+ const poolId = parseInt(req.params.id);
176
+ const result = await adminController.processEliminations(poolId);
177
+
178
+ // Emit real-time update (this is a big change - entries eliminated)
179
+ await emitPoolUpdate(poolId);
180
+ if (io) {
181
+ io.emit('survivor:round_resolved', { poolId, result });
182
+ }
183
+
184
+ res.json({ success: true, ...result });
185
+ } catch (error) {
186
+ console.error('[SurvivorAdmin] Error processing eliminations:', error.message);
187
+ res.status(500).json({ success: false, error: error.message });
188
+ }
189
+ });
190
+
191
+ /**
192
+ * POST /api/survivor/admin/pools/:id/advance-round
193
+ * Advance to next round (creates new matchups from winners)
194
+ */
195
+ router.post('/pools/:id/advance-round', async (req, res) => {
196
+ try {
197
+ const poolId = parseInt(req.params.id);
198
+ const result = await adminController.advanceRound(poolId);
199
+
200
+ // Emit real-time update
201
+ await emitPoolUpdate(poolId);
202
+
203
+ res.json({ success: true, ...result });
204
+ } catch (error) {
205
+ console.error('[SurvivorAdmin] Error advancing round:', error.message);
206
+ res.status(500).json({ success: false, error: error.message });
207
+ }
208
+ });
209
+
210
+ /**
211
+ * POST /api/survivor/admin/pools/:id/reset
212
+ * Reset pool to initial state
213
+ * Body: { deleteEntries: boolean } - if true, also delete all entries
214
+ */
215
+ router.post('/pools/:id/reset', async (req, res) => {
216
+ try {
217
+ const poolId = parseInt(req.params.id);
218
+ const { deleteEntries = false } = req.body;
219
+ const result = await adminController.resetPool(poolId, { deleteEntries });
220
+
221
+ // Emit real-time update
222
+ await emitPoolUpdate(poolId);
223
+
224
+ res.json({ success: true, ...result });
225
+ } catch (error) {
226
+ console.error('[SurvivorAdmin] Error resetting pool:', error.message);
227
+ res.status(500).json({ success: false, error: error.message });
228
+ }
229
+ });
230
+
231
+ /**
232
+ * POST /api/survivor/admin/pools/:id/full-simulation
233
+ * Run a complete round cycle: simulate games → process eliminations → advance round
234
+ * Body: { mode: 'chalk' | 'random' | 'chaos', setDeadlineMinutes?: number }
235
+ */
236
+ router.post('/pools/:id/full-simulation', async (req, res) => {
237
+ try {
238
+ const poolId = parseInt(req.params.id);
239
+ const { mode = 'random', setDeadlineMinutes } = req.body;
240
+
241
+ // 1. Simulate games
242
+ const simResult = await adminController.simulateRound(poolId, mode);
243
+
244
+ // 2. Process eliminations
245
+ const elimResult = await adminController.processEliminations(poolId);
246
+
247
+ // 3. Advance round (skip if all eliminated - tournament over)
248
+ let advResult = null;
249
+ if (!elimResult.allEliminated) {
250
+ advResult = await adminController.advanceRound(poolId);
251
+
252
+ // 4. Optionally set new deadline
253
+ if (setDeadlineMinutes && advResult.newRound <= 7) {
254
+ await adminController.setDeadline(poolId, setDeadlineMinutes);
255
+ }
256
+ }
257
+
258
+ // Emit real-time update
259
+ await emitPoolUpdate(poolId);
260
+ if (io) {
261
+ io.emit('survivor:round_resolved', { poolId, result: elimResult });
262
+ }
263
+
264
+ res.json({
265
+ success: true,
266
+ message: elimResult.allEliminated
267
+ ? 'All players eliminated - House wins!'
268
+ : 'Full round simulation complete',
269
+ simulation: simResult,
270
+ eliminations: elimResult,
271
+ advancement: advResult,
272
+ allEliminated: elimResult.allEliminated || false
273
+ });
274
+ } catch (error) {
275
+ console.error('[SurvivorAdmin] Error in full simulation:', error.message);
276
+ res.status(500).json({ success: false, error: error.message });
277
+ }
278
+ });
279
+
280
+ /**
281
+ * POST /api/survivor/admin/pools/:id/trigger-animation
282
+ * Trigger a survivor animation to all connected users
283
+ * Body: { type: 'eliminated' | 'champion', survivorData?: {...} }
284
+ */
285
+ router.post('/pools/:id/trigger-animation', async (req, res) => {
286
+ try {
287
+ const poolId = parseInt(req.params.id);
288
+ const { type, survivorData = {} } = req.body;
289
+
290
+ if (!type || !['eliminated', 'champion'].includes(type)) {
291
+ return res.status(400).json({
292
+ success: false,
293
+ error: 'Invalid animation type. Use "eliminated" or "champion"'
294
+ });
295
+ }
296
+
297
+ // Get pool info for animation context
298
+ const dashboard = await adminController.getPoolDashboard(poolId);
299
+
300
+ const animationPayload = {
301
+ animationType: type,
302
+ triggeredBy: 'March Madness',
303
+ triggeredAt: new Date().toISOString(),
304
+ survivorData: {
305
+ poolName: dashboard.pool.name,
306
+ roundName: dashboard.pool.roundName,
307
+ eliminatedCount: dashboard.entries.eliminated,
308
+ survivorCount: dashboard.entries.alive,
309
+ prizePool: survivorData.prizePool || `${(dashboard.entries.total * 0.1).toFixed(2)} SOL`,
310
+ ...survivorData
311
+ }
312
+ };
313
+
314
+ // Broadcast to all connected clients
315
+ if (io) {
316
+ // Emit on main namespace for global animations
317
+ io.emit('survivor:animation', animationPayload);
318
+
319
+ // Also emit on chat namespace if available
320
+ const chatNamespace = io.of('/chat');
321
+ if (chatNamespace) {
322
+ chatNamespace.emit('animation_trigger', animationPayload);
323
+ }
324
+
325
+ console.log(`[SurvivorAdmin] 🎬 Triggered ${type} animation for pool ${poolId}`);
326
+
327
+ res.json({
328
+ success: true,
329
+ message: `${type} animation triggered`,
330
+ animation: animationPayload,
331
+ broadcastedTo: 'all connected clients'
332
+ });
333
+ } else {
334
+ res.status(500).json({
335
+ success: false,
336
+ error: 'Socket.IO not available'
337
+ });
338
+ }
339
+ } catch (error) {
340
+ console.error('[SurvivorAdmin] Error triggering animation:', error.message);
341
+ res.status(500).json({ success: false, error: error.message });
342
+ }
343
+ });
344
+
345
+ module.exports = router;