Inspiration

Schools run on tools they don't control. Staff coordinate over personal WhatsApp groups and personal Gmail accounts — mixing work with private life, leaking student data, and letting anyone who finds the link into a "staff" group. There's no verification, no 2FA, and no audit trail. We built the School Staff Platform so a school can own a sealed, internal communication network: accounts start locked (pending), only an admin can verify a member. It's the staff intranet schools never had time to build.

What it does

A full-stack internal staff platform: (1) internal email — inbox / sent / threaded compose-reply, self-contained; (2) messaging — 1:1 and group threads with unread counts, edit/delete, and auto-created group chats; (3) groups — create/join/leave with owner/admin management; (4) a documents drive — public & private, base64 upload, safe inline rendering; (5) a posts feed with likes and Reddit-style nested comments, plus events (chat + members + attached docs) and Substack-style blogs any user can publish; (6) a user directory with profiles and avatars; and (7) a full admin console — verify pending members, change roles, lock/unlock the portal, a live activity log, and broadcast announcements.Security is built in- rate-limited login, and session-fixation-safe cookies.

How we built it

Node.js + Express backend (express-session, helmet, zod, bcrypt). A single provider-agnostic async DB interface (db.get / db.all / db.run / db.insert / db.transaction) lets the same SQL run on local SQLite (better-sqlite3) and production Supabase Postgres (pg) — routes use the Postgres $1,$2 dialect and the SQLite adapter rewrites placeholders, so there are zero dialect forks in route code. The frontend is a React 18 + Vite SPA. It deploys to Vercel as a serverless function (serverless-http wraps the Express app; api/index.js is the entry) with the SPA served statically and /api/* rewritten to the function; Supabase holds Postgres plus the session store.

Challenges we ran into

  • One SQL, two engines: keeping transactions safe while rewriting $N → ? between SQLite and Postgres.
  • Vercel's serverless body cap (~4.5 MB): base64 uploads inflate ~37%, so the real max file is 3 MB — we encoded that as a single source of truth (config.maxUploadMb / maxUploadBytes / vercelBodyCapMb) driving the scoped body parsers.
  • SPA + API on one serverless deploy: getting the index.html fallback and /api rewrite right so the root URL doesn't 404.
  • Verify-only onboarding on a fresh Postgres DB: signup only creates pending accounts and seed.js is SQLite-only, so the first admin is promoted via BOOTSTRAP_ADMIN_EMAIL.

Accomplishments that we're proud of

  • A genuinely sealed system: pending-by-default, constant-time backup-code comparison, SVG upload rejection + nosniff.
  • One codebase, two databases, no dialect forks in route code.
  • A production-secret guard that refuses to boot with dev secrets or a missing DATABASE_URL.

What we learned

Object storage for production-scale files (past the 3 MB cap); SSO/SAML for district-wide rollout; per-department spaces and richer audit exports; and a one-click deploy template (env + Supabase migration wired).

What's next for Complete School Staff Platform

Object storage for production-scale files (past the 3 MB cap); SSO/SAML for district-wide rollout; per-department spaces and richer audit exports; and a one-click deploy template (env + Supabase migration wired).

Credentials for admin

email- [email protected] password- asdasdasd (the password does not apply to the gmail or any accounts.) When running locally, credentials are given in the repo's readme.

Discord Username

VolarQuill

Built With

Share this project:

Updates

Submission history