Archery Tournament Platform
A shared archery scoring database with a service from each team member, run as five containers from one Docker Compose file.
Overview
Final project for COS20031 Database Design, done in a team of four. The team shares one archery database, and each member built their own functionality on top of it. Mine is the photo-scoring service: I wrote it on my own with FastAPI and gave the frontend developer the endpoints with their request and response formats. A teammate built the React pages that call it. I also put the services together in this repository with Docker Compose.
At a glance
- Course
- COS20031 Database Design
- Frontend
- React 19, Vite, Tailwind CSS
- Backend API
- Node.js, Express 5, MySQL
- Photo scoring
- Python, FastAPI, Roboflow
- Database
- MySQL 8.0, 14 tables
- Run it
- Docker Compose
From photo to confirmed score
- Photo of the target
- FastAPI detection service
- Roboflow model
- Scores for the end
- Arrow staging (pending)
- Recorder confirms
What it shows
- One file runs everything. docker-compose.yml defines five services. The React, backend and detection images are built straight from their own GitHub repositories, so the system is assembled from separate repos.
- Database created on first start. The mysql service mounts mysql/init into /docker-entrypoint-initdb.d, so schema.sql runs once and a named volume keeps the data afterwards.
- Verification before scores count. Every end first lands in an arrowStaging table as pending. A recorder reviews and confirms it before it becomes a final round score.
- Layered detection service. The FastAPI service is split into routes, controllers, services and repositories, with an async MySQL pool shared by the repositories.
- Built for slow installs. The detection Dockerfile installs core and heavy Python packages in separate layers and raises the pip timeout and retries, so rebuilds stay cached and reliable.
What I built
- The Docker Compose setup that runs MySQL, phpMyAdmin, the React app, the backend API and the detection service together.
- The whole photo-scoring service, on my own: a FastAPI app with a route that takes a target photo and returns the arrow scores, and a route that stores an end in the staging table.
- The API contract for the frontend: the endpoints with their request and response formats, which my teammate used to build the photo-entry page.
- The MySQL init folder, so the database and its tables are created automatically on the first start.
- The Dockerfile for the React app (a Node build served by nginx) and the Dockerfile for the detection service.
How it works
- Docker Compose starts MySQL first and loads schema.sql. phpMyAdmin is included for inspecting the data.
- The archer logs in to the React app (port 3000), which talks to the Express backend (port 4000) for competitions, eligibility, rankings and score entry.
- For photo entry, the app uploads the picture to the detection service (port 8000). It sends the image to a Roboflow-hosted model, keeps confident arrow detections and pads or trims them to the number of arrows in an end for that range.
- The scores go to the staging table as pending. A recorder reviews the end, edits it if needed and confirms it, and the rankings are built from the confirmed scores.
Run it
Start every service
docker compose up --buildWhere things run
React app http://localhost:3000
Backend API http://localhost:4000
Detection service http://localhost:8000
phpMyAdmin http://localhost:8080
MySQL localhost:3306