You are the two people who can change this website. Here is how it is built, how to run it on your own laptop, and how to ship a change without taking it down during a game.
This site is two programs that talk to each other. The part you see in a browser is a Next.js app. The part that stores things and enforces the rules is Convex. Everything else — sign-in, email, hosting — is a service bolted onto those two.
It is a real production system, not a class project. Clubs book the crew through it, families get email from it, and gear worth more than a car is checked in and out through it. That is the fun part and it is also the reason for the rules further down.
src/app/. Every folder in there is a URL. src/app/games/page.tsx is the page at /games. Shared UI lives in src/components/.convex/. The database and all the server code. convex/schema.ts defines every table; each other file holds the queries and mutations for one feature. This is where permission checks live.convex/auth.ts. Sign-in is Google only and locked to @salpointe.org. There are no passwords anywhere in this system, which is deliberate: no passwords means nothing to leak, and when the school disables an account it dies here too.convex/email.ts and convex/lib/emailTemplates.ts. Every automatic email — call sheets, checkout confirmations, the notice parents get — is built there.wrangler.jsonc. Where the Next.js app runs once it's deployed, via the OpenNext adapter.You need Node installed and access to the repo. Two terminals, both left running while you work.
npm install
convex/ and pushes your changes to the dev backend the moment you save.npx convex dev
http://localhost:3000.npm run dev
/sign-in with your school Google account. You'll come in as a student admin, same as on the live site.Dev and live share a backend right now
You almost never write code that fetches data. A page calls useQuery(api.games.listUpcoming) and Convex pushes new results whenever the underlying rows change — so when someone claims a camera slot, every open browser updates itself. No refresh button, no polling loop. If you find yourself writing one, you've misunderstood something.
convex/? npx convex dev pushes it in about a second. A schema mistake fails loudly there — read that terminal.src/? The browser hot-reloads.npx next typegen so the route types know it exists, or TypeScript will insist your own link is invalid.npx convex env set RESEND_API_KEY. If you ever paste a key into a file, tell Mr. Rivers immediately — it has to be rotated, and that is a five-minute fix that becomes a big problem if nobody says anything.reference-data/ is ignored by git because it holds SkillsUSA rankings and résumés with other schools' students' names in them. Those are minors. They do not go on the public internet because it was convenient.public/.requireCapability(ctx, ...) or requireAdmin(ctx). See convex/lib/permissions.ts, which is worth reading in full.convex/lib/gameRules.ts or convex/lib/skills.ts: no React, no database, just functions. That's the pattern here, because logic buried in a component can only be checked by clicking around and hoping.Work on a branch, never straight on main. Before you ask for it to go out, both of these must come back silent:
npx tsc --noEmit -p . npx eslint convex src npm test
npm test runs the checks in tests/. They cover the rules that a type checker can't see — who is allowed to do what, and whether a "verified" skill really means a teacher signed it. If you change either, expect them to fail until you've decided what the new rule is.
Then commit, push the branch, and tell Mr. Rivers what changed and what you checked. Deploying to the live site is one command, and it is his call when to run it:
npm run deploy
Don't deploy during a game
Check in this order — it goes from most to least likely.
curl -s https://salpointe-film-club.jetnoirsystems.workers.dev | head -40
npx wrangler tail
Errors students see are deliberately cleaned up on their way out — see src/lib/convexError.ts. If you add a new failure case, write the message for the student who hits it, not for yourself.
Ask first — every time
convex/lib/permissions.ts — the list of what student admins can do. You are student admins. Widening it is exactly the change you shouldn't be able to make quietly, and by design you also cannot grant roles in the app.convex/lib/emailTemplates.ts that goes to parents. That wording quotes the Parent/Student Handbook on purpose.README.md — the long version of all of this, including how sign-in is locked down and how the b-roll on the landing page is encoded.docs/PRODUCTION-RUNBOOK.md — the plan for moving to film.salpointe.org with its own backend.AGENTS.md and CLAUDE.md — the notes that tell an AI assistant how to work in this repo. Read them before you use one here; they exist because this Next.js version and Convex both changed things that most models still get wrong.Want to see the permission model in action? Your dashboard is shorter than Mr. Rivers'. That's the code in permissions.ts doing its job.