A golf match-tracking web application built as an example project for a database course at the University of St. Thomas. The primary goal is to evaluate the Firebase ecosystem — with a particular focus on Cloud Firestore — as a backend for a real-time, multi-user application.
| Layer | Technology |
|---|---|
| Frontend | Angular 21, Angular Material |
| Database | Cloud Firestore |
| Auth | Firebase Authentication |
| Backend logic | Firebase Cloud Functions (v2) |
| Local dev | Firebase Emulator Suite |
- Node.js 20+
- npm 11+
- Java 21 (required for the Firebase Emulator)
- Firebase CLI:
npm install -g firebase-tools
-
Install dependencies:
npm install
-
Configure Firebase credentials:
If you are running with the Firebase Emulator, you can skip this step and run the app as-is.
Only configure credentials if you want to run against an online Firebase project. In that case, copy
src/environments/firebase.example.tstosrc/environments/firebase.tsand fill in your Firebase project credentials. (The actualfirebase.tsis not committed to the repository.)cp src/environments/firebase.example.ts src/environments/firebase.ts
-
Start the emulator (imports persisted seed data automatically):
npm run emulator:start
-
Start the Angular dev server connected to the emulator:
npm run start:emulator
-
Open http://localhost:4200.
npm startThe project uses the Firebase Emulator Suite for local development. For complete documentation, see the Firebase Emulator Suite docs.
The following emulators are configured:
| Emulator | Port |
|---|---|
| Authentication | 9099 |
| Firestore | 8080 |
| Cloud Functions | 5001 |
| Emulator UI | 4000 |
npm run emulator:startThis runs firebase emulators:start --import=./emulator-data --export-on-exit=./emulator-data, which:
- Imports the persisted emulator state from
emulator-data/on startup. - Automatically exports the current state back to
emulator-data/when you stop the emulator (Ctrl+C), preserving any changes made during the session.
To populate the emulator with a fresh set of sample users, courses, matches, and scorecards:
# Emulator must already be running
npm run emulator:seedSeed data lives in emulator-seed/seed-data/.
The Firebase Cloud Functions live in the functions/ directory and are written in TypeScript.
Trigger: Firestore onDocumentWritten — fires on any create, update, or delete of a document in the scorecards/{scorecardId} collection.
Purpose: Keeps the scoreboards/{matchId} document in sync with the current state of all scorecards for a match. When a scorecard changes, the function:
- Fetches all scorecards for the affected match.
- Looks up each player's display name (from
publicUsers) and profile photo (from Firebase Auth). - Computes each player's total strokes vs. par and formats the score string (e.g.
+2,-1,E). - Sorts players by score (lowest first) and assigns finishing places.
- Writes the resulting leaderboard to
scoreboards/{matchId}.
This means clients only need a single real-time listener on scoreboards/{matchId} — they never have to aggregate scorecards themselves. For a detailed walkthrough of all Firestore query patterns and the full scoreboard data flow, see docs/dataQueryDetails.md.
# Deploy only Cloud Functions
firebase deploy --only functionsThe predeploy hook (defined in firebase.json) automatically lints and builds the TypeScript source before each deploy.
The entity-relationship diagram for the data models lives in docs/er-diagram.mmd (Mermaid source) and docs/er-diagram.svg (rendered SVG).
Note: This is a rough, auto-generated diagram built by Copilot from the TypeScript
.model.tsfiles using relationship inference (see Regenerating the diagram below). It is not a formal entity-relationship diagram. For detailed diagram types and Mermaid syntax, see the Mermaid documentation.
Source: docs/er-diagram.mmd — see Regenerating the diagram below.
- GitHub / VS Code – The
.mmdfile renders automatically in the Mermaid preview extension and on GitHub (paste the contents into a Markdown fenced code block tagged```mermaid). - SVG – Open
docs/er-diagram.svgdirectly in any browser or image viewer. - Mermaid Live Editor – Paste the contents of
docs/er-diagram.mmdinto mermaid.live.
The diagram is generated from the TypeScript model files in src/app/models/.
Dependencies
| Package | Purpose |
|---|---|
typescript (already a dev dependency) |
Parses *.model.ts files via the compiler API |
@mermaid-js/mermaid-cli (dev dependency) |
Renders the .mmd source to .svg via headless Chromium |
tsx (already a dev dependency) |
Runs the generator script |
Steps
# Install dependencies (only needed once)
npm install
# Regenerate docs/er-diagram.mmd and docs/er-diagram.svg
npm run generate:erThe script (scripts/generate-er-diagram.ts):
- Scans every
*.model.tsfile insrc/app/models/ - Extracts interfaces using the TypeScript compiler API
- Infers relationships from type references and
*Idnaming conventions - Writes
docs/er-diagram.mmd - Calls
mmdc(Mermaid CLI) to renderdocs/er-diagram.svg