* Update claude.md to push more tests. * Archiving old plans. * fix: run DB migrations programmatically on server startup Replace unreliable drizzle-kit CLI migration with drizzle-orm's built-in migrator running in the server process before accepting connections. This ensures migrations are always applied on deploy and fails fast if they error. - Add runMigrations() to server.ts using drizzle-orm/postgres-js/migrator - Skip migrations in development (handled manually via db:migrate) - Add DATABASE_URL guard with a clear error message - Remove start:production script (now identical to start) - Update Dockerfile CMD to use npm run start Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
3.3 KiB
3.3 KiB
Phase 3: Socket.IO Implementation - Summary
Key Decision: Modify server.js (Option A)
After researching React Router v7 + Socket.IO integration patterns, the recommended approach is:
Why This Approach?
- Industry Standard: Socket.IO requires
http.createServer(app)- this is the documented pattern - Single Port: HTTP and WebSocket traffic on same port (simpler deployment)
- No CORS Issues: Everything runs on same origin
- Works with SSR: Compatible with React Router v7's server-side rendering
- Simpler Deployment: One process, one port, one service
What Changes?
Minimal changes to server.js:
// Before:
app.listen(PORT, () => {...});
// After:
import { createServer } from "http";
const httpServer = createServer(app);
const { initializeSocketIO } = await import("./server/socket.js");
initializeSocketIO(httpServer);
httpServer.listen(PORT, () => {...});
That's it! Just 4 lines changed in server.js.
Alternative Considered: Separate Socket Server (Option B)
Why we rejected this:
- Requires managing two processes
- CORS configuration complexity
- Different ports (3000 for HTTP, 3001 for WebSocket)
- More complex deployment (two services)
- Not the standard pattern
When to use Option B:
- If you absolutely cannot modify server.js
- If you need to scale WebSocket separately from HTTP
- If you're using a microservices architecture
Implementation Steps
Step 1: Create Socket Module
- File:
server/socket.js(not .ts to avoid bundling) - Exports:
initializeSocketIO()andgetSocketIO() - Stores instance globally for route handlers
Step 2: Modify server.js
- Import
http.createServer - Create HTTP server from Express app
- Initialize Socket.IO with HTTP server
- Call
httpServer.listen()instead ofapp.listen()
Step 3: Client Hook
- Create
app/hooks/useDraftSocket.ts - Handles connection/disconnection
- Auto-joins draft room on connect
- Provides
on/offhelpers for events
Step 4: Route Handlers
- Import
getSocketIO()in API routes - Emit events after database writes
- Example: After creating pick, emit
pick-madeto room
Event Architecture
Write Operations → HTTP POST
- Making picks
- Queue management
- Commissioner actions
- Reason: Reliability, error handling, validation
Read Operations → Socket.IO Broadcast
- Pick made notifications
- Timer updates
- Draft status changes
- Reason: Real-time updates to all clients
Testing Checklist
- Server starts with "Socket.IO initialized"
- Browser console shows "Connected to Socket.IO"
- Server logs show "Client connected: [id]"
- Multiple clients can join same draft room
- Picks broadcast to all clients in room
- Disconnection handled gracefully
Production Notes
- Socket.IO auto-upgrades from polling → WebSocket
- Load balancer needs sticky sessions for WebSocket
- Monitor connection counts
- Consider Redis adapter for horizontal scaling (future)
Files Created/Modified
New Files:
server/socket.js- Socket.IO initializationserver/types.d.ts- TypeScript globalsapp/hooks/useDraftSocket.ts- Client hook
Modified Files:
server.js- 4 lines changed (http.createServer)tsconfig.node.json- Add server directory
Total LOC: ~150 lines of new code