Installation and local development#
This page gets CrabbyTab running on your own machine. To put it online for a real tournament, continue with Deploying to Vercel and Firebase.
Requirements#
- Node.js 22 (
package.jsonpins"node": "22.x"). - npm.
package-lock.jsonis the authoritative lockfile. The repository also contains abun.lock; leave it alone unless you are deliberately changing package-manager conventions. - A Firebase project with Authentication (email/password) and Cloud Firestore. Tournament data lives in your browser, but creating a tournament (including a demo tournament or a DebateXML import) needs a signed-in global administrator, and that needs Firebase Authentication plus server credentials. Without Firebase the hub shows Firebase is not configured.
- Optional: an SMTP server to try the email tools, staff invitations and registration emails.
Install and run#
git clone https://github.com/The-Studio-of-Sadiq/crabbytab.git
cd crabbytab
npm ci
cp .env.example .env.local
npm run dev
Open http://localhost:3000. The dev server always uses port 3000.
Environment variables#
Copy .env.example to .env.local and fill it in. Never commit .env.local.
| Variable | Where it is used | Purpose |
|---|---|---|
NEXT_PUBLIC_APP_URL |
Server (page metadata) | Canonical base URL of the site. If empty it falls back to https://$VERCEL_URL on Vercel, otherwise http://localhost:3000. |
NEXT_PUBLIC_FIREBASE_API_KEY, _APP_ID, _AUTH_DOMAIN, _MEASUREMENT_ID, _MESSAGING_SENDER_ID, _PROJECT_ID, _STORAGE_BUCKET |
Browser | The Firebase web-app config from Project settings → Your apps. These are public identifiers, not secrets. |
FIREBASE_SERVICE_ACCOUNT_JSON |
Server only | The full JSON of a Firebase service-account key, on one line. Escaped \n in the private key are converted back to newlines. If empty, the server falls back to Application Default Credentials. |
FIREBASE_ADMIN_UIDS |
Server only | Firebase Authentication UIDs of global administrators, separated by commas or whitespace. See Staff and roles. |
SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS, SMTP_FROM, SMTP_SECURE |
Server only | Outgoing mail. SMTP_HOST, SMTP_USER, SMTP_PASS and SMTP_FROM are required for email; SMTP_PORT defaults to 587. SMTP_SECURE is true or false (TLS from the start of the connection); if empty, it is on only for port 465. |
EMAIL_WEBHOOK_SECRET |
Server only, optional | Shared secret for the signed delivery-status webhook (POST /api/email/webhook). Without it the endpoint answers 404. |
SMS_WEBHOOK_URL, SMS_WEBHOOK_SECRET |
Server only, optional | A generic HTTPS SMS relay you control; each SMS is POSTed and signed with the secret. No SMS provider is built in. |
Details for the email and SMS variables: docs/email-notifications.md.
Never put the service account, SMTP password or webhook secrets in a
NEXT_PUBLIC_variable — those are compiled into the browser bundle.
Make yourself a global administrator#
CrabbyTab has no public account sign-up. (The /register/{slug} pages are tournament registration forms for teams and adjudicators, not account creation.) Accounts are created in Firebase Authentication by hand, or by accepting a staff invitation from a tournament administrator.
- In the Firebase console, enable Authentication → Sign-in method → Email/Password and add a user.
- Copy that user's UID into
FIREBASE_ADMIN_UIDSin.env.local. - Provide server credentials (
FIREBASE_SERVICE_ACCOUNT_JSON). On every sign-in the server adds or removes theglobalAdmincustom claim to match the list. - Deploy the repository's
firestore.rulesto your project (see Deploying). - Restart
npm run dev, sign in at/loginand open/tournaments. You should now see Create a new tournament, Or import a DebateXML archive and Or load a demo tournament for a rehearsal.
Trying it out without real data#
- Demo tournament:
/tournaments→ Or load a demo tournament for a rehearsal creates a seeded BP (24 teams) or WSDC (16 teams) practice tournament on this device. Its URL starts withdemo-. See the First tournament walkthrough. - Sample CSVs: the
testdata/folder contains small files (institutions, teams, adjudicators, venues, motions) for the import pages. See CSV formats.
Useful scripts#
| Command | What it does |
|---|---|
npm run dev |
Development server on port 3000 |
npm run build |
Production build (also type-checks application code) |
npm run start |
Serve the production build on port 3000 |
npm run test |
Run the Vitest suite once (no Firebase credentials needed) |
npm run lint |
next lint |
npx tsc --noEmit |
Full type check including tests |
CI (.github/workflows/ci.yml) runs npm ci, npm run lint, npx tsc --noEmit, npm run test and npm run build in that order. Run the same before opening a pull request.
Details#
- The 1000-team scale benchmark runs inside
npm run testwith 2 rounds per format (about 20 s). SetCRABBYTAB_SCALE=fullto play every round, orCRABBYTAB_SCALE=offto skip it. Seedocs/storage-and-scale.md. tools/tabbycat-diffcompares CrabbyTab's draws, standings, breaks and allocations against recorded Tabbycat v2.12.1 output; its report runs innpm run testwithout Docker or Python. Regenerating Tabbycat's golden output needs Docker (or Python 3.11 and PostgreSQL); see its README.tools/i18nholds the translation tooling; seedocs/internationalization.md.site/build.mjsrenders these wiki pages into the static GitHub Pages site and checks every internal link and anchor (--strictfails on a broken link).markedis not a project dependency; the script header explains how to point it at a separate install.- The repository has no Firestore emulator setup, so
firestore.rulesare not executed in CI. Check rule changes in the Firebase console's Rules Playground before deploying them.
Next steps#
- Deploying to Vercel and Firebase
- First tournament walkthrough
- Architecture if you want to change the code