Skip to content
Index

Syllabi

Case study · Personal project · Built for the IB Diploma Programme

A calendar that starts from what a school week actually commits you to, and works out what is left.

cal.charlieva.dev
Role
Design, architecture and implementation
Type
Personal project
Status
In use by a small group of students at my school
Surface
Web app
Stack
next.js · react · typescript · supabase · postgres · vercel · cloudflare · vercel ai sdk · github actions
Timeframe
Ongoing
Not included
No user numbers, no revenue, no growth charts. It's too early to have any.
01

Problem

My timetable lives in one place. My homework lives in another. Assessment dates usually live in a photo of a slide. None of them know about each other, so I was the integration layer, and I was bad at it.

Calendar apps store events. On a Tuesday evening with four hours free and a week of work behind me, a calendar can tell me what's scheduled and nothing about what to do. A free hour before a test and a free hour on a Friday afternoon look identical to it. I was doing that reasoning in my head, every day, badly.

The question I wanted answered was never what is on Thursday. It was what to do with the next two hours.

What should I actually do with my time right now?

The question the app is trying to answer

02

Idea

Start from commitments, not events. To answer that question, an app has to know four things:

Commitments
What's fixed — school, travel, the shape of a day.
Capacity
What's actually free, and how much of it there is.
Difficulty
Which classes cost me more than they cost anyone else.
Intention
What I said I wanted to get done this week.

Once it knows those, a suggestion becomes possible — one I'm free to ignore. The second idea is that capture has to be nearly free. A planner you have to feed gets abandoned in week two. Adding a term of deadlines should be a screenshot. Adding one event should be a sentence.

So I built the calendar first, to stop retyping my timetable. Then assignments, because a timetable without deadlines is half a picture. Then assessments, then study time. By then it wasn't a calendar.


03

System

It's easier to describe as five systems than as a feature list.

Structure

The school timetable syncs in and the app builds the actual shape of a day from it — lessons, travel, the gaps on either side, and events that run across multiple days. Everything else reasons about this layer, so it has to be right before anything clever is worth attempting. The point of the school and travel blocks isn't display; it's that free time shown in the app is free time that exists.

Capture

A screenshot of a timetable or an assessment slide is read by a model and turned into structured events and deadlines. A new event can be written as a sentence instead of filled into a form. Nothing is saved before I confirm it. Both exist for the same reason: putting something in should cost almost nothing.

Workload

Assignments, homework and assessments, each attached to a class, and each class carrying how difficult it actually is for me. A due date says when. Difficulty is what says how early to start.

Planning

Study blocks and study-time tracking on one side, weekly planning on the other. The app finds usable free slots and suggests what to spend them on, weighing deadlines, class difficulty, recent study time and the intentions I've set. Reminders and push notifications sit on top, so none of it depends on me remembering to open the app.

Learning signals

What I accept, move or ignore gets recorded and fed back into later recommendations. This is the part that makes it personal: the app is meant to get less wrong about me over time.

Data model

Underneath is a PostgreSQL schema in Supabase. Deciding what these tables mean and how they relate was most of the work — if the model of a school week is wrong, no amount of interface fixes it.

classes
Subjects, and how difficult each one is for me
timetable
The synced school schedule a week is built from
calendar_events
Everything on the calendar, including multi-day events
assignments
Homework and coursework, attached to a class
assessments
Tests and assessments, with dates and weight
study_blocks
Planned and tracked study time
reminders
What gets surfaced, and when
intentions
What I said I wanted to get done this week
learning_signals
Accepted, moved or ignored — feedback for later suggestions

Architecture

Architecture diagram: 3 groups of technologies, each feeding the next — Client, Server, Data. Each node below is a button: focus or press one to read what that part of the system does.

Client
Server
Data
The browser talks to the server; the server owns every read, write and scheduled job; Postgres holds the data.

Flows

  1. Screenshot
  2. Extract
  3. Review
  4. Commit

A photo of a timetable or a slide of assessment dates becomes structured rows, mapped to the right class and date.

  1. Text
  2. Parse
  3. Confirm
  4. Event

A sentence becomes an event. The form still exists; it just isn't the fast path any more.

  1. Timetable
  2. Sync
  3. Day structure

The synced timetable is turned into the shape of a day — lessons, travel and the gaps between them — which everything else reads from.

Scheduling

Free slots, workload, class difficulty, recent study time and stated intentions combine into a suggestion for a specific gap in a specific day. It suggests what to do with a free hour; it doesn't decide for you. What happens to that suggestion — accepted, moved, ignored — is recorded as a learning signal and weighed into the next one.

Infrastructure

Next.js on Vercel with Cloudflare in front, Supabase for Postgres and auth, and GitHub Actions for the jobs that need to run on a schedule rather than when someone opens a page. Reminders and push notifications are what turn a planner into something that reaches you.


04

Current state

It works, and it's early. A small group of students at my school use it alongside me, which is the most useful thing that has happened to it: a second timetable finds assumptions a single one never would. Otherwise I find bugs by using my own app, which is a method with a known limit.

I've stopped treating it as a prototype I'll throw away. That changes what I worry about: which schema decisions would be expensive to change later, what the app shows when a sync fails or a model misreads a slide, and what data it holds and whether it needs to hold it.


05

What I'm building next

Next

Failure behaviour. A missing timetable should look like a missing timetable, not an empty afternoon, and an import that gets a date wrong should be obvious and one tap to fix rather than quietly wrong in three weeks.

Next

Tests, starting with scheduling. The scheduling logic is the most worth testing and the least tested. That's the wrong way round.

Exploring

Better recommendations. The learning signals are already being collected; using them well is the real work. The goal isn't more suggestions, it's being right often enough to be worth trusting.

Exploring

Security, data handling and schema work as the tables fill up: auth edges, row-level policies, and storing less in the first place.


06

Stack

Application
Next.js, React and TypeScript
Data
Supabase and PostgreSQL, including auth and row-level policies
Running
Vercel, with Cloudflare in front
AI
Vercel AI SDK and LLM APIs for screenshot import and natural-language entry
Automation
GitHub Actions for scheduled jobs
Back to index