← Back to projects

Project Overview · Full-Stack Serverless

KLMathPrep

A full-stack AWS app that autonomously runs my math-tutoring business: scheduling, video lessons, and automated reminders for 20+ students, their parents, and tutors.

The problem

Running a tutoring business by hand doesn't scale.

Tutoring 20+ students, keeping their parents in the loop, and coordinating other tutors is a part-time job on top of actually teaching. Scheduling sessions, sharing video explanations, and remembering to send every confirmation, cancellation, and reminder ate hours I'd rather spend with students.

So I built the operations to run themselves: one app where everyone signs in, and a pipeline that sends the right email at the right time without me touching it.

Architecture

A serverless app with a self-running reminder pipeline.

The browser signs in to Cognito directly, so the server never handles a password, then calls a Next.js server on Amplify for everything else. One service layer reads and writes DynamoDB (app data), S3 (uploads and lesson videos), and SES (email). Outside that request path, EventBridge fires scheduled Lambdas that send reminders and reset weekly availability on their own.

KLMathPrep architecture: the browser signs in to Cognito directly and calls a Next.js server on AWS Amplify; the server reads and writes DynamoDB, S3, and SES; EventBridge triggers scheduled Lambdas that send reminders and update DynamoDB.
Browser signs in to Cognito directly; the Next.js/Amplify server reads and writes DynamoDB, S3, and SES; EventBridge-triggered Lambdas handle reminders and weekly resets.

Key decisions

Why it's built this way.

The server never sees a password

The browser authenticates against Cognito directly through the client SDK; the Next.js server only ever receives a bearer token it verifies per request, so credentials never touch application code.

No double-booking, ever

Booking a session writes a conditional slot-lock item in a single DynamoDB transaction, so two students can't win the same time even under concurrent requests. The race is prevented at the table, not in app logic.

Operations that run themselves

EventBridge-triggered Lambdas send session reminders and reset the tutor's weekly availability automatically, so the business keeps running without me touching it.

Serverless, so one person can run it

DynamoDB, S3, and SES are all managed, with no server to patch. It scales with the roster and costs almost nothing at this size, which matters for a business I run solo.

What shipped

It runs my actual business.

KLMathPrep is in production today. Students book and see their schedule and progress live, parents get confirmations and reminders automatically, and I stopped hand-sending emails. It's live at klmathprep.com.

The KLMathPrep app dashboard
The live KLMathPrep dashboard.

Challenges & what's next

Honest edges.

The interesting work was the automation edges: making reminders idempotent so nobody gets a double email, handling timezones, and keeping the EventBridge/Lambda schedule reliable so a reminder never silently fails to send. Next up: SMS reminders and a tutor-facing analytics view of student progress.

Stack

  • React
  • Next.js
  • TypeScript
  • Cognito
  • DynamoDB
  • Lambda · Python
  • S3
  • SES
  • EventBridge
  • IAM