The website is built with TypeScript, Express, EJS templates, Bootstrap, and Supabase-hosted PostgreSQL. PHP pages and PHP database handlers have been replaced by a Node.js application.
- Node.js 20 or later
- A Supabase project with a PostgreSQL database
- Install dependencies with
npm install. - In the Supabase dashboard, open Project Settings → Database, copy the
connection string for your project, and set it as
DATABASE_URLin a local.envfile based on.env.example. Use the URI format and require SSL. Keep the URL private; it contains a database password. - In the Supabase dashboard, open SQL Editor, run
supabase/schema.sql, and check that it completed. - In the SQL Editor, run
supabase/seed.sqlto load the competition, category, class, division, round, distance, and target-face records from the latest SQL export. - (Optional) Run
supabase/sample-archers.sqlto add clearly fictional archer rows for local testing and copy the matching staged memberships intoArcherCategory. These are not real competitor records. - Run
npm run devfor local development, or runnpm run buildfollowed bynpm startfor a production build. - Open
http://localhost:3000.
GET /— select an archer and competition.POST /archer— show the archer's competition and round details.GET /records— point-recording page.GET /recorder— recorder page.GET /api/competitions— competitions as JSON.GET /api/archers— archers as JSON.GET /api/archers/:archerId?competitionId=:competitionId— one archer's competition details as JSON.
The Supabase schema and seed data are based on the latest checked-in MySQL
export. That export does not contain real archer details. Its ArcherCategory
rows are preserved in ArcherCategoryImport rather than inserted into the live
relationship table. For test-only display data, the optional sample archer
script creates fictional rows matching the staged ArcherIDs and copies their
memberships into ArcherCategory. Do not use these fictional rows as
competitor records. When you have the real archer details, import them into
Archer and then copy the matching staged memberships into ArcherCategory.
The app connects server-side using the PostgreSQL connection string; do not put database credentials or a Supabase service-role key in client-side code.