Skip to main content

Web app

An alumni archive only the team can write to.

Public to read, roster only to publish. The NJIT fencing team's memories live here, not in some Facebook group.

By Daniel Jeun


Most college alumni platforms have the same problem. They open everything, which kills the signal, or they lock everything, which kills the contributions. About a fifth of alumni ever engage with the school that asks them to.

The NJIT Highlanders fencing team wanted a third option. Anyone can read the memories. Only people the roster recognizes can post them.

How the gate works

Auth runs through Supabase magic links, with an extra step. Before the link gets sent, an RPC checks the email against the roster table. If the email is on the roster, the link goes out. If it isn’t, the user sees a request access form, which lands in an access_requests queue that the admins triage at /admin/requests.

The roster check has to fail closed, and it has to fail silently. The system never tells an off roster visitor whether their email is or isn’t on the list. That’s the kind of detail that sounds paranoid until you remember a roster is a list of real people.

The feed

The home feed is keyset paginated through a single RPC that folds in like counts, comment counts, and whether the current viewer has already reacted. One query, not three. Pinned memories sit on top, capped at three, enforced both by row level security and by a database trigger so the cap can’t be bypassed by writing directly to the column.

Comments and reactions ride one Supabase realtime channel per memory. Reactions used to be a five emoji set. The team voted with their thumbs and we cut it down to a single heart, which required a destructive migration on data that had already been written.

Mobile LCP budget is under 2.5 seconds. JavaScript transfer budget is under 180 KB gzipped. Sprint 0 through 5 are mostly landed. Sprint 6 is the polish pass: Playwright smoke tests, a Lighthouse CI gate, an axe scan.

Next.js 16 React 19 Supabase Tailwind v4 Tiptap

← Back to all projects