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
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.
