BS ECE · Carnegie Mellon · May 2028

zhaojinchu@cmu.edu github.com/zhaojinchu linkedin.com/in/zhaojinc


AN-006 · Software · Finished
Started Jul 2026

海那边: a bilingual tutoring portal


1.0Abstract

A Next.js portal I built and deployed for a Chinese-language tutor and the parents of her students, live at hainabian.org. Parents can see how many lessons they have left, get bank-transfer invoices by email and book through a Google appointment schedule, in English or Chinese. Lesson credits are kept in an immutable ledger with database-level guards.

At a glance

Parameter Value
Status Finished. Live at hainabian.org
When and where 2026, for a Chinese-language tutor and the parents of her students
My part Built and deployed it
Built with Next.js and TypeScript; PostgreSQL with Drizzle; Better Auth; Docker Compose behind a Cloudflare Tunnel
Code github.com/zhaojinchu/HaiNaBian
Live hainabian.org
Lesson credits One immutable ledger entry per lesson; voids add a restoring entry; database-level guards reject edits, deletions and negative balances
Money AED stored as integer fils; invoices generated, saved and emailed for bank transfer; payment status set by hand
Booking A Google Appointment Schedule embedded read-only, so Google owns availability and conflicts
The hainabian.org home page in English: the 海那边 wordmark, the headline “Chinese can thrive, wherever home is”, and buttons to contact the teacher and view lesson options
hainabian.org, the English home page, September 2026.

The problem

A tutor and the parents of her students need three answers: how many lessons are left, who has paid, and when the next slot is. The portal gives each approved parent one page with those answers and gives the teacher one admin page to manage all of it. It intentionally does not integrate a bank or the Google Calendar API.

Design decisions

  • Credits are a ledger, not a counter. Recording a lesson consumes one immutable entry per learner; voiding it adds a restoring entry. Migrations add database-level guards so a balance can never go negative and a ledger row can never be edited or deleted, even by a bug.
  • Payment and usage are independent. A package can be used before it is paid for; the teacher marks payment when the transfer lands. That matches how the business actually runs.
  • Google owns booking. The public appointment schedule is embedded; nothing is copied into Postgres, so there is no second source of truth to drift.
  • Boring, safe production. A separate Compose stack with strict environment validation, health checks that know about the database, and a Cloudflare Tunnel instead of open ports.

← All projects