showwaiyan_

← home · all projects

Archery Tournament Platform

A shared archery scoring database with a service from each team member, run as five containers from one Docker Compose file.

ReactExpressFastAPIMySQLDocker Compose

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

  1. Photo of the target
  2. FastAPI detection service
  3. Roboflow model
  4. Scores for the end
  5. Arrow staging (pending)
  6. 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

  1. Docker Compose starts MySQL first and loads schema.sql. phpMyAdmin is included for inspecting the data.
  2. 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.
  3. 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.
  4. 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 --build
Where things run
React app          http://localhost:3000
Backend API        http://localhost:4000
Detection service  http://localhost:8000
phpMyAdmin         http://localhost:8080
MySQL              localhost:3306