Document purpose
This document is the authoritative technical reference for the Hellcats MVP system
(frontend + Firebase). It is designed to remain useful long-term, including for maintainers
who were not involved in the original implementation.
This is intentionally verbose. The focus is clarity, deterministic behavior, and maintainability,
not minimal text length.
1. Scope and non-goals
The MVP system is a lightweight, cost-free application that tracks participants, event placements,
and computes an MVP candidate using transparent rules. It is built for small groups where:
- operational simplicity is preferred over enterprise-grade identity management
- a single shared “truth” for all users is required
- real-time synchronization is beneficial
- hosting costs should be essentially zero
Explicit non-goals (things intentionally not implemented):
- No individual user accounts, profiles, or permissions per person.
- No complex multi-document relational schema. The state is intentionally centralized.
- No backend services (server) or API layer attaching business logic. Firestore is persistence + sync.
- No conflict-free merging of simultaneous admin operations (last-write-wins is acceptable).
These choices reduce complexity and keep the system easy to operate.
2. Overall architecture
The system uses a static frontend hosted on GitHub Pages and a shared cloud state stored in Firestore.
All clients subscribe to the same Firestore document and render the same state.
High-level data flow
Browser (HTML/CSS/JS)
- renders UI
- authenticates anonymously
- checks password gate (admin-only for this wiki page)
- subscribes to Firestore state via real-time listener
- writes updates back to Firestore
Firestore (Cloud)
- stores shared application state in state/main
- stores password/admin hashes in config/security
- stores undo snapshot in state/undo
The architecture is intentionally “backendless”. Firestore provides managed storage + real-time updates.
GitHub Pages provides globally available static hosting.
3. Static hosting model (GitHub Pages)
GitHub Pages serves static files only. There is no server-side computation. This provides:
- zero hosting cost
- simple deployment (push to main branch)
- stable HTTPS via GitHub-managed certificates
Important implication: Because the site is static, all runtime logic must run in the browser.
For Firebase usage without a bundler, the application imports Firebase SDK modules from the official CDN.
4. Firebase services used
The MVP system uses a minimal set of Firebase services:
- Firebase Authentication (Anonymous) — provides
request.auth != null for security rules
- Cloud Firestore — shared state storage + real-time synchronization
Other services (Hosting, Functions, Storage, etc.) are not required for this system
and remain disabled unless needed later.
5. Authentication strategy
The system uses Firebase anonymous authentication. This creates an authenticated session without user accounts.
The goal is not identity management; it is to ensure Firestore requests have request.auth != null,
enabling simple security rules.
Why not user accounts?
User accounts add friction (registration, password resets, permissions) and increase maintenance burden.
For a small group application, anonymous auth + a password gate is sufficient.
6. Password gate design
The password gate is a UI overlay that blocks access until a correct password is provided.
The password is never stored in the source code. Validation is done by hashing the input (SHA-256)
and comparing to the stored hash in Firestore.
Stored values
config/security
passwordHash: string // sha256(password) - used by the MVP app / normal wiki pages
adminHash: string // sha256(adminPassword) - used for admin-only access
This page is admin-only: it validates against adminHash (not passwordHash).
Why a hash and not plaintext?
Storing plaintext passwords is a security anti-pattern. Hashing prevents accidental disclosure
and avoids storing secrets in clear text. SHA-256 is sufficient for this small-group threat model.
If stronger protection is desired later, a salted hash scheme can be introduced.
7. Firestore data model
The application state is stored as a single document to simplify reasoning and synchronization:
Primary state document
state/main
persons: Person[]
events: Event[]
mvpCooldown: number
Person structure
Person
id: string
name: string
title: boolean
blocked: boolean
mvpCount: number
cooldownLeft: number
placements: Placement[]
Placement
event: number
place: number
Why single-document state?
A single document avoids partial updates and complicated joins. It also makes backup/export trivial:
the entire system can be restored by replacing one document.
This scales well for small datasets (dozens of persons, hundreds of events).
If you ever approach Firestore document size limits, you would split the model into collections,
but that is out of scope for now.
8. Real-time synchronization
The frontend subscribes to the state document using Firestore’s real-time listener (onSnapshot).
Whenever the document changes, all clients receive the update and re-render the UI.
Expected behavior
- When one user adds a person, everyone sees it immediately.
- When one user saves an event, all participants see updated placements.
- When admin performs import/reset/undo, state changes atomically for all users.
9. Write strategy and consistency
Writes update the top-level fields of state/main. This is simple and deterministic,
but simultaneous conflicting edits can cause last-write-wins behavior.
Consistency notes
- Firestore provides atomic document writes.
- Last-write-wins can happen if two users edit at the same time.
- The system intentionally does not attempt to merge edits.
10. Admin mode
Admin mode is session-local. Unlocking admin enables destructive operations: import, reset, undo.
This separation reduces accidental data loss.
Admin unlock design
Admin unlock validates the admin password by comparing SHA-256(input) to config/security.adminHash.
If successful, an admin flag is stored in sessionStorage.
Admin mode is not persisted in Firestore and is not shared across users.
11. Export / Import
Export produces a JSON file containing the entire current application state.
Import replaces the entire state with a JSON payload.
Import is destructive (overwrite). Therefore it is restricted to admin mode and paired with an automatic undo snapshot.
12. Undo mechanism
Undo is implemented as snapshot restore. Before import or reset, the system stores the current state as a snapshot
in state/undo. Undo writes the snapshot back to state/main.
Key properties
- Deterministic: restores exactly the previous state.
- Safe: restricted to admin mode.
- Simple: no diff/merge logic.
13. Firestore security rules
Rules must allow anonymous-auth users to access state, and allow reading config/security for hashing checks.
Example rule set (minimal)
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /state/{doc} {
allow read, write: if request.auth != null;
}
match /config/{doc} {
allow read: if true;
}
}
}
14. Deployment and DNS
This wiki is hosted on GitHub Pages and mapped to wiki.zabini.org using a DNS CNAME record.
Enforce HTTPS in GitHub Pages settings.
Common DNS configuration
CNAME
Name: wiki
Target: fp1892.github.io
15. Debugging checklist
- Plain HTML only: CSS path broken. Verify
/assets/wiki.css returns 200.
- No background image: verify
/documentations-background-image.jpg exists and returns 200.
- Login never unlocks: ensure
config/security.adminHash exists and matches SHA-256(admin password).
- Firestore permission errors: confirm Firestore rules and anonymous auth are enabled.
16. Maintenance & extension guidelines
When extending the system, preserve transparency, determinism, and low operational overhead.
- Prefer explicit data fields over hidden derived state.
- Document every rule affecting scoring/eligibility.
- Keep destructive operations behind admin mode.
- Export before major structural changes.