Every student at the University of Ghana runs their academic life through Sakai, and Sakai does almost nothing to help. It holds the assignments, the quizzes, the grades, the resources and the announcements, and it surfaces none of them unless you go looking. It does not tell you a deadline is tomorrow. It does not work on a patchy connection. Its web UI on a phone is a desktop page you pinch at.
So the actual failure mode is not missing information — it is that the information exists and nobody sees it in time. DueSoon is the app that closes that gap: the same data, restructured around a student's week instead of an institution's content model. It is the project on this list closest to being a product rather than a piece of engineering, and I am building it as one.

Two pieces: a React Native app, and a Cloudflare Worker sitting between it and the university.
┌──────────────────────────────────────────────────┐
│ React Native app │
│ AsyncStorage (creds) · SQLite (cache) · notifs │
└───────────────────────┬──────────────────────────┘
│ HTTPS
▼
┌──────────────────────────────────────────────────┐
│ Cloudflare Worker · duesoon-edge │
│ Hono router · Durable Objects · AI router │
└────────┬──────────────────┬──────────────────┬───┘
▼ ▼ ▼
sakai.ug.edu.gh Supabase LLM providersThe app never talks to Sakai directly. Everything goes through the worker, and that boundary is doing real work: Sakai is a session-cookie system that was never designed to be a backend for anything, so a per-user Durable Object (SakaiSession) holds the authenticated session in its own SQLite storage and re-uses it across requests. Without that, every screen would be a fresh login.
On the device, SQLite caches everything the app has ever fetched, and the UI reads from the cache first. Deadline reminders are scheduled locally rather than pushed, so they fire whether or not there is a network — which matters, because the moment a student most needs the reminder is not reliably a moment they have data.
The AI assistant is grounded in the student's own course data: the worker assembles a context pack from the cached assignments, deadlines and announcements and routes it to a provider behind one interface. It answers questions about your term, which is the only version of that feature worth shipping.
The central one is that DueSoon is built on an integration the university did not publish. There is no documented Sakai API surface for this; the worker reads what the LMS actually serves and normalises it. That is fragile by construction — an upstream change can break a screen — and it is the reason the boundary is a single worker rather than logic spread through the app. When Sakai shifts, one deployment fixes every installed client, with no app-store round trip.
A recent example of that fragility, and the honest version of what building on someone else's system looks like: implementing quiz deadline reminders meant discovering that the JSON feed cannot supply quizzes at all, then that the UI had been treating a quiz's time field as a deadline when it is not. Both were found by walking the app on a real device, and both are the kind of bug no amount of local testing against a mock would have surfaced — so the quiz path is now injectable, and tested against a recorded contract rather than a guess.
The other trade is credentials. The app authenticates with the student's own Sakai login, which is the only thing that could work and also the thing that has to be handled most carefully. It is the design decision I would most want a second pair of eyes on before this goes anywhere near a public release.
Version 1.0.10, running on device on both platforms, in beta with real students. The current phase is offline reminders and the quiz path; the last few commits are Android crash fixes, settings reconciliation, and UI defects found by using the app rather than by reading it.
What is next is the part that decides whether this is a project or a company: multi-institution support. Everything Sakai-specific already lives behind the worker, so a second university is a new adapter and not a new app — that was the point of the boundary.