Initial release: Disc Agenda frisbee tournament platform
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:
2026-03-15 14:48:15 +01:00
commit a7244406fd
38 changed files with 5749 additions and 0 deletions

38
frontend/src/api.js Normal file
View File

@@ -0,0 +1,38 @@
const API_BASE = '/api';
async function fetchJSON(path) {
const res = await fetch(`${API_BASE}${path}`);
if (!res.ok) throw new Error(`API error: ${res.status}`);
return res.json();
}
async function postJSON(path, body) {
const res = await fetch(`${API_BASE}${path}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
if (!res.ok) throw new Error(`API error: ${res.status}`);
return res.json();
}
export const getTournaments = () => fetchJSON('/tournaments');
export const getTournament = (id) => fetchJSON(`/tournaments/${id}`);
export const getSchedule = (id) => fetchJSON(`/tournaments/${id}/schedule`);
export const getScore = (tid, gid) => fetchJSON(`/tournaments/${tid}/games/${gid}/score`);
export const updateScore = (tid, gid, u) => postJSON(`/tournaments/${tid}/games/${gid}/score`, u);
export const getAuditLog = (tid, gid) => fetchJSON(`/tournaments/${tid}/games/${gid}/audit`);
export const getQuestionnaire = (id) => fetchJSON(`/tournaments/${id}/questionnaire`);
export const submitQuestionnaire = (id, d) => postJSON(`/tournaments/${id}/questionnaire`, d);
export const getQuestionnaireResults = (id) => fetchJSON(`/tournaments/${id}/questionnaire/results`);
export const getResults = (id) => fetchJSON(`/tournaments/${id}/results`);
export function createGameWebSocket(tourneyId, gameId, userId = 'anon') {
const proto = location.protocol === 'https:' ? 'wss:' : 'ws:';
return new WebSocket(`${proto}//${location.host}/ws/game/${tourneyId}/${gameId}?user_id=${userId}`);
}
export function createTournamentWebSocket(tourneyId) {
const proto = location.protocol === 'https:' ? 'wss:' : 'ws:';
return new WebSocket(`${proto}//${location.host}/ws/tournament/${tourneyId}`);
}