Initial release: Disc Agenda frisbee tournament platform
Some checks failed
Build and Push / build (push) Failing after 8s
Some checks failed
Build and Push / build (push) Failing after 8s
Full-stack tournament management app with real-time scoring: - Go 1.26 backend with REST API and WebSocket live scoring - React 19 + Vite 8 frontend with mobile-first design - File-based JSON storage with JSONL audit logs - Multi-stage Docker build with Gitea CI/CD pipeline - Post-tournament questionnaire with spirit voting - Technical documentation and project description Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
164
README.md
Normal file
164
README.md
Normal file
@@ -0,0 +1,164 @@
|
||||
# 🥏 Disc Agenda — Frisbee Tournament Platform
|
||||
|
||||
A self-hosted tournament management web app for ultimate frisbee, featuring live multiplayer scoring via WebSockets, a mobile-friendly questionnaire with QR codes, and a clean athletic visual design.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────┐
|
||||
│ Go 1.26 Backend (single binary) │
|
||||
│ ├─ REST API (gorilla/mux) │
|
||||
│ ├─ WebSocket hub (gorilla/websocket) │
|
||||
│ ├─ SPA file server │
|
||||
│ └─ File-based JSON storage │
|
||||
├──────────────────────────────────────────┤
|
||||
│ React 19 + Vite 8 Frontend │
|
||||
│ ├─ react-router-dom v7 (SPA) │
|
||||
│ ├─ qrcode.react (QR generation) │
|
||||
│ └─ Custom CSS (Bebas Neue + Barlow) │
|
||||
├──────────────────────────────────────────┤
|
||||
│ Data: flat JSON files + JSONL audit logs │
|
||||
│ (no database required) │
|
||||
└──────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- **Tournament hub** — home page with location, dates, teams, rules
|
||||
- **Schedule** — round-grouped game schedule with status badges
|
||||
- **Live scoring** — WebSocket-powered multiplayer scoreboard with +/- and SET controls
|
||||
- **Audit log** — every score change persisted as JSONL per game
|
||||
- **Questionnaire** — mobile-friendly survey with QR code, team selectors, spirit voting, custom questions
|
||||
- **Results** — final standings table with spirit award highlight
|
||||
- **Past tournaments** — archive of completed events
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Docker (recommended)
|
||||
|
||||
```bash
|
||||
docker compose up --build
|
||||
# → http://localhost:8080
|
||||
```
|
||||
|
||||
Data persists in a Docker volume. Seed data auto-copies on first run.
|
||||
|
||||
### Local Development
|
||||
|
||||
**Prerequisites:** Go 1.26+, Node 22+
|
||||
|
||||
Terminal 1 — backend:
|
||||
```bash
|
||||
cd backend
|
||||
go mod tidy
|
||||
go run ./cmd/server -data ../data -static ../frontend/dist -port 8080
|
||||
```
|
||||
|
||||
Terminal 2 — frontend (with hot reload + API proxy):
|
||||
```bash
|
||||
cd frontend
|
||||
npm install
|
||||
npm run dev
|
||||
# → http://localhost:5173 (proxies /api and /ws to :8080)
|
||||
```
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
├── backend/
|
||||
│ ├── cmd/server/main.go # Entry point, router, SPA handler
|
||||
│ └── internal/
|
||||
│ ├── handlers/handlers.go # REST + WS HTTP handlers
|
||||
│ ├── models/models.go # Domain types
|
||||
│ ├── storage/storage.go # File-based persistence
|
||||
│ └── websocket/hub.go # Per-game WS hub + broadcast
|
||||
├── frontend/
|
||||
│ ├── src/
|
||||
│ │ ├── api.js # API client + WS factory
|
||||
│ │ ├── App.jsx # Router
|
||||
│ │ ├── main.jsx # Entry
|
||||
│ │ ├── components/ # Header, Footer, Icons
|
||||
│ │ ├── pages/ # All page components
|
||||
│ │ └── styles/global.css # Full stylesheet
|
||||
│ ├── vite.config.js # Dev proxy config
|
||||
│ └── index.html
|
||||
├── data/ # Seed data (JSON files)
|
||||
│ ├── tournaments.json
|
||||
│ └── tournaments/{id}/
|
||||
│ ├── schedule.json
|
||||
│ ├── questionnaire_config.json
|
||||
│ ├── results.json
|
||||
│ └── games/ # Score state + audit logs
|
||||
├── Dockerfile # Multi-stage build
|
||||
├── docker-compose.yml
|
||||
└── Makefile
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| GET | `/api/tournaments` | List all tournaments |
|
||||
| GET | `/api/tournaments/{id}` | Tournament details |
|
||||
| GET | `/api/tournaments/{id}/schedule` | Game schedule |
|
||||
| GET | `/api/tournaments/{id}/games/{gid}/score` | Current score |
|
||||
| POST | `/api/tournaments/{id}/games/{gid}/score` | Update score (REST) |
|
||||
| GET | `/api/tournaments/{id}/games/{gid}/audit` | Audit log |
|
||||
| WS | `/ws/game/{id}/{gid}?user_id=x` | Live score WebSocket |
|
||||
| GET | `/api/tournaments/{id}/questionnaire` | Questionnaire config + teams |
|
||||
| POST | `/api/tournaments/{id}/questionnaire` | Submit response |
|
||||
| GET | `/api/tournaments/{id}/questionnaire/results` | All responses (admin) |
|
||||
| GET | `/api/tournaments/{id}/results` | Final standings |
|
||||
|
||||
### WebSocket Protocol
|
||||
|
||||
Connect: `ws://host/ws/game/{tourneyId}/{gameId}?user_id=alice`
|
||||
|
||||
**Send** (client → server):
|
||||
```json
|
||||
{"action": "increment", "team": "home"}
|
||||
{"action": "decrement", "team": "away"}
|
||||
{"action": "set", "team": "home", "value": 12}
|
||||
```
|
||||
|
||||
**Receive** (server → all clients):
|
||||
```json
|
||||
{
|
||||
"type": "score_update",
|
||||
"state": {"game_id": "g01", "home_score": 8, "away_score": 6, ...},
|
||||
"audit": {"action": "increment", "team": "home", "old_home": 7, ...}
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
All via flags or env vars:
|
||||
|
||||
| Flag | Env | Default | Description |
|
||||
|------|-----|---------|-------------|
|
||||
| `-port` | `PORT` | `8080` | Listen port |
|
||||
| `-data` | `DATA_DIR` | `./data` | Data directory |
|
||||
| `-static` | — | `./static` | Frontend files |
|
||||
|
||||
## Adding Tournament Data
|
||||
|
||||
Edit JSON files directly in `data/`:
|
||||
|
||||
- `tournaments.json` — add/edit tournament objects
|
||||
- `tournaments/{id}/schedule.json` — game schedule
|
||||
- `tournaments/{id}/questionnaire_config.json` — custom survey questions
|
||||
- `tournaments/{id}/results.json` — final standings
|
||||
|
||||
No admin UI yet — data is managed via files. Future: add admin panel.
|
||||
|
||||
## Tech Stack
|
||||
|
||||
- **Backend:** Go 1.26, gorilla/mux 1.8.1, gorilla/websocket 1.5.3, rs/cors
|
||||
- **Frontend:** React 19, Vite 8, react-router-dom 7, qrcode.react
|
||||
- **Storage:** Flat JSON files + JSONL audit logs
|
||||
- **Container:** Alpine 3.21, multi-stage Docker build
|
||||
|
||||
## Documentation
|
||||
|
||||
- **[Technical Documentation](docs/DOCUMENTATION.md)** — detailed API reference, data models, WebSocket protocol, deployment guides, troubleshooting
|
||||
- **[Project Description](docs/PROJECT.md)** — project overview, motivation, features, design philosophy, roadmap
|
||||
Reference in New Issue
Block a user