A comprehensive player availability tracking system for table tennis teams in the Edinburgh and Lothians Table Tennis League (ELTTL). This tool helps team captains manage player availability and finalize team selections for upcoming fixtures.
- Team Import: Import team data directly from ELTTL URLs
- Availability Management: Track which players are available for each fixture
- Final Selection: Select exactly 3 players for each match
- Player Statistics: View comprehensive stats including games played, scheduled, and selection rates
- Real-time Updates: Instant updates across all components with optimistic UI
- Responsive Design: Works seamlessly on mobile, tablet, and desktop
- Dark Mode Support: Full support for light and dark themes
- Past vs Future Fixtures: Separate handling with edit mode for historical data
- Validation: Built-in validation to ensure proper team selection
- Loading States: Skeleton loaders and progress indicators
- Error Handling: Graceful error messages with retry options
- Frontend: SvelteKit with TypeScript (client-side rendering)
- Backend: Cloudflare Workers with Hono
- Database: Cloudflare D1 (SQLite)
- Styling: TailwindCSS
- Testing: Vitest (unit), Playwright (E2E)
- Decoupled Design: Frontend and backend are fully independent
- Client-Side Rendering: All data fetching happens in the browser
- API-First: RESTful API with JSON responses
- Deployment: Frontend on Cloudflare Pages, Backend on Cloudflare Workers
-- Teams: Stores imported team information
teams (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
elttl_url TEXT UNIQUE,
created_at INTEGER,
updated_at INTEGER
)
-- Fixtures: Match schedule for each team
fixtures (
id TEXT PRIMARY KEY,
team_id TEXT,
match_date TEXT,
day_time TEXT,
home_team TEXT,
away_team TEXT,
venue TEXT,
is_past INTEGER,
created_at INTEGER
)
-- Players: Team roster
players (
id TEXT PRIMARY KEY,
team_id TEXT,
name TEXT,
created_at INTEGER
)
-- Availability: Player availability for each fixture
availability (
id TEXT PRIMARY KEY,
fixture_id TEXT,
player_id TEXT,
is_available INTEGER,
updated_at INTEGER,
UNIQUE(fixture_id, player_id)
)
-- Final Selections: The 3 players selected for each match
final_selections (
id TEXT PRIMARY KEY,
fixture_id TEXT,
player_id TEXT,
selected_at INTEGER,
UNIQUE(fixture_id, player_id)
)See API Documentation for detailed endpoint specifications.
Quick Reference:
POST /api/availability/import- Import team from ELTTLGET /api/availability/:teamId- Get all team dataPATCH /api/availability/:teamId/fixture/:fixtureId/player/:playerId- Update availabilityPOST /api/availability/:teamId/fixture/:fixtureId/selection- Set final selectionGET /api/availability/:teamId/summary- Get player statistics
- Node.js 18+ and npm
- Cloudflare account (for deployment)
- Wrangler CLI (
npm install -g wrangler)
- Clone the repository
git clone <repository-url>
cd tt- Install dependencies
# Frontend
cd frontend
npm install
# Worker
cd ../worker
npm install- Set up the database
cd worker
# Create local D1 database
wrangler d1 create availability-tracker-dev
# Run migrations
wrangler d1 execute availability-tracker-dev --local --file=schema.sql
# Optional: Seed with test data
wrangler d1 execute availability-tracker-dev --local --file=seed.sql- Start development servers
Terminal 1 - Worker:
cd worker
npm run devTerminal 2 - Frontend:
cd frontend
cp .env.example .env # First time only
npm run devThe app will be available at http://localhost:5173
Note: The frontend makes API calls to http://localhost:8787/api by default. Update .env file if your worker runs on a different port.
Worker Tests (Unit & Integration):
cd worker
npm test # Run all tests
npm run test:coverage # With coverage reportFrontend Tests (E2E):
cd frontend
npm run test:e2e # Run Playwright tests
npm run test:e2e:ui # Run with UI mode- Navigate to the Availability Tracker page
- Click "Import New Team"
- Enter your ELTTL team URL (format:
https://elttl.interactive.co.uk/teams/view/{id}) - Click "Import Team"
- Your team data, fixtures, and players will be automatically imported
- For each fixture, check the boxes next to available players
- Availability is automatically saved as you check/uncheck
- Past fixtures are read-only by default (toggle edit mode if needed)
- Once you have at least 3 players available, click "Select 3 Players"
- Choose exactly 3 players from the available list
- Click "Save Selection" to confirm
- The selection is highlighted with a trophy icon
- Player cards show total games played and scheduled
- Selection rate percentage indicates how often each player is chosen
- Stats update automatically when selections are made
- Availability: Players must be marked available before selection
- Selection Limit: Exactly 3 players must be selected per match
- Insufficient Players: Warning shown if fewer than 3 players are available
- Past Fixtures: Read-only unless edit mode is enabled
- Health Check: 1 minute cache
- Team Data: 30 seconds with 60-second stale-while-revalidate
- Player Summary: 1 minute with 2-minute stale-while-revalidate
- Indexed foreign keys for fast joins
- Composite index on availability (fixture_id, player_id)
- Batch queries using Promise.all for parallel data fetching
- Code splitting by route
- Optimistic UI updates for instant feedback
- Skeleton loaders during data fetching
- Lazy loading of components
- Gzip/Brotli compression enabled on all API responses
- Reduces payload size by ~70%
All API operations are logged with:
- Timestamp (ISO 8601)
- Log level (info, warn, error)
- Operation details (teamId, fixtureId, etc.)
- Performance metrics (duration)
- Error messages and stack traces
Example log entry:
{
"timestamp": "2025-12-30T10:15:30.123Z",
"level": "info",
"message": "Team import successful",
"teamId": "abc-123",
"elttlUrl": "https://elttl.interactive.co.uk/teams/view/123",
"playerCount": 12,
"fixtureCount": 8,
"durationMs": 2341
}- Import success/failure rates
- API response times
- Database query performance
- Error rates and types
- Cache hit rates
- Create production D1 database
wrangler d1 create tabletennis-availability-
Update wrangler.toml with production database ID
-
Run migrations on production
wrangler d1 execute tabletennis-availability --file=schema.sql- Deploy Worker
cd worker
npm run deploy- Deploy Frontend to Cloudflare Pages
cd frontend
npm run build
# Connect repository to Cloudflare Pages dashboard- Environment Variables
Set
VITE_API_URLin frontend to point to production Worker URL
Follow the same steps as production but use separate databases and worker names for staging.
Import Fails
- Verify the ELTTL URL format is correct
- Check if the team page is publicly accessible
- Ensure the HTML structure hasn't changed
Availability Not Saving
- Check browser console for errors
- Verify the Worker is running
- Check database connection in Wrangler logs
Selection Validation Errors
- Ensure exactly 3 players are selected
- Verify all selected players are marked as available
- Check if the fixture is in the past (read-only)
Performance Issues
- Clear browser cache
- Check Cloudflare Workers analytics for rate limiting
- Verify database indexes are present
- TypeScript for type safety
- Functional components in Svelte
- Comprehensive error handling
- Unit tests for business logic
- E2E tests for user workflows
- All new features must have tests
- Maintain >80% code coverage
- E2E tests for critical user paths
- Integration tests for database operations
- Authentication with team passwords
- Email notifications for selections
- PDF/Excel export of availability data
- Historical data analysis and trends
- Player notes and comments
- Real-time updates via WebSockets
- Mobile PWA with push notifications
- WhatsApp/SMS integration
- Multi-season support
- Redis cache layer for high-traffic teams
- GraphQL API for more efficient queries
- Optimistic locking for concurrent updates
- CDN for static assets
See LICENSE file for details.
For issues, questions, or feature requests, please open an issue on GitHub.
Version: 1.0.0
Last Updated: December 2025
Maintainers: Table Tennis Team