Simple view

Classroom Check

The website and members' system of a student organization: photo room checks, announcements and fee records behind role-based logins.

Type
Web app
Role
Design and build, solo
Status
Live, in use

Built with Next.js, TypeScript, Supabase, PostgreSQL, Tailwind CSS, Apps Script

Classroom Check screenshot

Context

Classroom Check is the website and members' system of SINCOTECS, a student organization in Davao City. It was my idea: I proposed it, designed and built it on my own, and the organization adopted it as its official site. I built it between September and November 2026, and it is in regular use.

The problem

Several class groups share the same rooms through the day. When a room is left in a mess, someone has to know which group left it. Classroom Check has each group's representative, called a mayor, photograph the room on arrival and before leaving, and officers review the photos.

What it does

  • Public site. About, membership, announcements and contact pages.
  • Mayors. A guided room check on the phone, with photo slots, an arrival checklist and a countdown to check-out. An unsent check is kept on the phone and sends by itself when the connection returns.
  • Officers. A review queue with flag reasons, a room board that re-reads the day's checks every two minutes, insights charts, and a Manage tab for people, the timetable, rooms and class groups.
  • Treasurer. Payments, balances, late penalties, a cash book and reports with CSV export, behind a separate passcode.

Key decisions

  • The database decides, not the phone. The app talks to Supabase straight from the browser, so every rule lives in PostgreSQL: row-level security policies for each role, and triggers that set the time, the class group and the check-out themselves and refuse changes to a reviewed check.
  • Clashes cannot be saved. Exclusion constraints on the timetable stop a room or a class group from being booked twice at the same time.
  • Missed checks are worked out when the page is read, never stored. There is no scheduled job, and a late check-out corrects the record the moment it arrives.
  • Fee records live in a Google Sheet by request, not in the database. A Google Apps Script web app sits in front of the sheet as its API, with signed 12-hour sessions, hashed passcodes and a lockout after ten wrong tries.

The hard part

The app has no server of its own, so a signed-in mayor could send by hand anything the page sends. Every rule moved into the database, and the change was tested with twelve attack and normal-use cases (another group's room, someone else's photo, a forged time or status, a second check-out) inside a transaction that was rolled back, before it went live.

Result

  • Live, and in regular use by the organization.
  • Logins with two roles, each sent to its own dashboard, plus the passcode-protected treasurer area.
  • Fourteen SQL files in the repository record every database change in the order it was applied.
  • 34 automated tests cover the treasurer backend and its balance rules. The type check and lint pass with no errors.

Known limits

Accounts are created by hand: there is no sign-up or password reset on the site. The officer pages refresh on a timer, not the instant a check arrives, and reminders only arrive while the app is open.

Members log-in