* 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>
11 KiB
Draft Room Redesign Plan
Status: ✅ Complete - All Features Implemented & Tested Created: 2025-10-24 Last Updated: 2025-10-24
Overview
Redesigning the draft room to use a full-screen layout with a collapsible left sidebar and tabbed main content area.
Requirements
Layout Changes
1. Full-Screen Layout (No Page Scroll)
- Page fills entire viewport (100vh)
- Individual sections scroll internally
- Fixed header at top
- Content area uses remaining height
2. Collapsible Left Sidebar
- Default State: Expanded
- Width:
- Expanded: 350px
- Collapsed: 50px
- Contents (Accordion-style sections):
- My Queue (top section) - Collapsible
- Eligibility status banner
- Queue list (ordered, scrollable)
- Autodraft settings
- Clear queue button
- Available Participants (bottom section) - Collapsible
- Search bar
- Sport filter dropdown
- Show/hide drafted toggle
- Participants table (scrollable)
- Action buttons (Pick/Add to Queue)
- My Queue (top section) - Collapsible
- Section Behavior:
- Both sections can be expanded or collapsed independently
- When both expanded: 50/50 vertical split
- When one collapsed: Expanded section takes 100% of space
- At least one section must remain expanded
- Responsive:
- Desktop (≥1024px): Fixed sidebar on left
- Mobile (<1024px): Full-screen modal
3. Tabbed Main Content Area
Three tabs with toggle functionality:
Tab 1: Draft Board (Default)
- Current draft grid display
- Team headers with timers and autodraft status
- Snake draft grid (scrollable)
- Context menu for commissioners
- Reuse existing DraftGrid component or inline implementation
Tab 2: Recent Picks
- List of recent picks (latest 10-20)
- Same format as current Recent Picks section
- Scrollable list
- Shows: Pick number, team, participant, sport
Tab 3: Teams Drafted (NEW)
- Grid layout:
- Rows: Sports (from season sports)
- Columns: Teams (in draft order)
- Cells: Participants drafted by that team in that sport
- Highlighting: Visual indicator when team has multiple participants in same sport
- Flex Display: Show "X of Y flexes used" somewhere with team data
- Scrollable: Both horizontal and vertical as needed
Design Decisions
Teams Drafted Grid:
- ✅ Cell content: Show participant names (e.g., "Patrick Mahomes, Travis Kelce")
- ✅ Cell interactivity: No clickability needed (existing commissioner context menu on draft board remains)
- ✅ Empty cells: Leave empty (just border, no text)
- ✅ Flex display: In team column header, below team name (similar to timer positioning)
Tab UI: 5. ✅ Tab style: ShadCN Tabs component 6. ✅ Recent Picks data: Same 10 most recent picks as current implementation
Sidebar: 7. ✅ Section sizing: Accordion-style - both sections collapsible independently
- Both expanded: 50/50 split
- One collapsed: Expanded section takes 100%
- At least one must remain expanded
Current Implementation Analysis
File Structure
Main Route: /app/routes/leagues/$leagueId.draft.$seasonId.tsx
- All draft room logic currently in this single file
- ~1,300 lines of code
- Inline rendering of Queue and Available Participants (not extracted components)
Related Components:
/app/components/DraftGrid.tsx- Reusable draft grid (not currently used in draft room)/app/components/AutodraftSettings.tsx- Autodraft toggle and settings
Current Layout:
Header (full width, fixed)
├─ Title and metadata
├─ Control buttons (start/pause/resume)
└─ Connection status
Draft Grid (full width, scrollable)
├─ Team headers
└─ Pick grid
3-Column Grid (lg:grid-cols-3)
├─ My Queue (conditional if user has team)
│ ├─ Eligibility status
│ ├─ Queue list (max-h-96)
│ ├─ Autodraft settings
│ └─ Clear button
├─ Recent Picks
│ └─ Last 10 picks (max-h-96)
└─ Available Participants
├─ Search and filters
└─ Participants table (max-h-[500px])
State Management
Component state (useState):
picks- All draft pickscurrentPick- Current pick numbersearchQuery- Participant search termhideDrafted- Toggle drafted visibilitysportFilter- Active sport filterqueue- User's queue itemsteamTimers- Timer for each teamautodraftStatus- Autodraft state per teamconnectedTeams- Set of connected team IDsforcePickDialogOpen- Commissioner dialog state
Real-time updates via Socket.IO:
pick-madetimer-updatedraft-paused/draft-resumeddraft-completedautodraft-updatedteam-connected/team-disconnectedparticipant-removed-from-queues
Data Flow
- Loader provides initial data
- Socket.IO provides real-time updates
- Form actions handle queue management and draft actions
- Draft eligibility calculated client-side via
calculateDraftEligibility()
Proposed Architecture
New Component Structure
leagues/$leagueId.draft.$seasonId.tsx (Main Route)
├─ Full-screen flex container (100vh)
├─ Header (fixed, flex: 0 0 auto)
├─ Content Area (flex: 1 1 auto, flex row)
│ ├─ DraftSidebar (NEW component)
│ │ ├─ Collapse toggle button
│ │ ├─ QueueSection (scrollable)
│ │ └─ AvailableParticipantsSection (scrollable)
│ └─ MainContent (flex: 1 1 auto)
│ ├─ TabSelector (Draft Board | Recent Picks | Teams Drafted)
│ └─ TabContent (scrollable)
│ ├─ DraftBoardTab (uses DraftGrid component)
│ ├─ RecentPicksTab
│ └─ TeamsDraftedTab (NEW)
Files to Create
-
/app/components/DraftSidebar.tsx(NEW)- Collapsible sidebar container
- Props: collapsed state, queue data, participants data, handlers
- Two internal sections with separate scrolling
-
/app/components/draft/QueueSection.tsx(NEW, optional)- Extracted queue rendering logic
- Props: queue, eligibility, autodraft settings, handlers
-
/app/components/draft/AvailableParticipantsSection.tsx(NEW, optional)- Extracted participants table logic
- Props: participants, filters, handlers
-
/app/components/draft/TeamsDraftedGrid.tsx(NEW)- Grid showing teams × sports with drafted participants
- Props: teams, sports, picks, flex usage
- Highlighting logic for multiple drafts per sport
-
/app/components/draft/DraftTabs.tsx(NEW, optional)- Tab selector and content container
- Props: active tab, tab change handler, children
Files to Modify
-
/app/routes/leagues/$leagueId.draft.$seasonId.tsx- Add full-screen layout container
- Add sidebar collapsed state
- Add active tab state
- Import and render DraftSidebar
- Render tabbed main content
- Remove 3-column grid layout
- Remove Recent Picks section (moved to tab)
-
/app/components/DraftGrid.tsx- Ensure it works in flex container
- May need height/overflow adjustments
State Additions
Add to main route component:
const [sidebarCollapsed, setSidebarCollapsed] = useState(() => {
// Check localStorage for user preference
const stored = localStorage.getItem('draftSidebarCollapsed');
return stored ? JSON.parse(stored) : false; // Default: expanded
});
const [activeTab, setActiveTab] = useState<'board' | 'picks' | 'teams'>('board');
CSS/Styling Strategy
Layout CSS
/* Main container */
.draft-room-container {
height: 100vh;
display: flex;
flex-direction: column;
overflow: hidden;
}
/* Header */
.draft-room-header {
flex: 0 0 auto;
}
/* Content area */
.draft-room-content {
flex: 1 1 auto;
display: flex;
overflow: hidden;
}
/* Sidebar */
.draft-sidebar {
flex: 0 0 auto;
width: 350px; /* Expanded */
transition: width 0.3s ease, transform 0.3s ease;
overflow-y: auto;
display: flex;
flex-direction: column;
}
.draft-sidebar.collapsed {
width: 50px;
}
/* Sidebar sections */
.sidebar-section {
flex: 0 0 auto; /* Queue: take what you need */
overflow-y: auto;
}
.sidebar-section.grow {
flex: 1 1 auto; /* Available Participants: take remaining */
}
/* Main content */
.draft-main-content {
flex: 1 1 auto;
overflow-y: auto;
display: flex;
flex-direction: column;
}
/* Tab content */
.draft-tab-content {
flex: 1 1 auto;
overflow-y: auto;
}
Responsive Breakpoints
/* Mobile (<1024px) */
@media (max-width: 1023px) {
.draft-sidebar {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
z-index: 50;
transform: translateX(-100%);
}
.draft-sidebar.open {
transform: translateX(0);
}
}
Teams Drafted Grid Styling
.teams-grid {
display: grid;
grid-template-columns: 150px repeat(auto-fit, minmax(120px, 1fr));
overflow: auto;
}
.teams-grid-cell {
border: 1px solid var(--border);
padding: 0.5rem;
min-height: 60px;
}
.teams-grid-cell.multiple-picks {
background-color: var(--accent);
font-weight: 600;
}
Implementation Steps
Phase 1: Setup and Layout Structure
- Create plans directory and documentation
- Add sidebar collapsed state with localStorage persistence
- Add active tab state
- Create full-screen layout container in main route
- Update header to work with new layout
- Test basic layout structure
Phase 2: Sidebar Component
- Create DraftSidebar.tsx component shell
- Add collapse/expand toggle button
- Move Queue section rendering to sidebar
- Move Available Participants section to sidebar
- Add internal scrolling for both sections
- Test sidebar functionality and transitions
- Add mobile modal behavior
Phase 3: Tab System
- Create tab selector UI (choose style based on user feedback)
- Add Draft Board tab (use existing grid)
- Add Recent Picks tab (move existing section)
- Create TeamsDraftedGrid component
- Implement Teams Drafted grid logic
- Add flex usage display
- Add highlighting for multiple picks
- Test tab switching and content rendering
Phase 4: Refinement
- Adjust spacing and padding throughout
- Test all Socket.IO real-time updates
- Test all form actions (queue management, making picks)
- Test responsive behavior (desktop, tablet, mobile)
- Add keyboard shortcuts (optional)
- Performance testing with large datasets
- Accessibility audit (ARIA labels, focus management)
Phase 5: Polish
- Animation tuning
- Dark mode verification
- Cross-browser testing
- User acceptance testing
Notes
- Preserve all existing Socket.IO functionality
- Maintain commissioner-specific features (force pick, context menus)
- Keep eligibility calculation logic unchanged
- Ensure autodraft integration remains functional
- Test with various screen sizes and data volumes
Success Criteria
- Draft room fills viewport (no page scroll)
- Sidebar collapses/expands smoothly
- All three tabs render correctly
- Teams Drafted grid shows accurate data
- Queue and Available Participants work as before
- All real-time updates continue to work
- Mobile experience is usable
- No regressions in existing functionality
- Performance is acceptable (no lag during picks/updates)