Reminder Me
A personal “companion agent” for daily life as a student — habits, focus sessions, tasks, exams, prayer times, health, and journalling, all in one offline-first app. Built as an installable PWA and wrapped as a real Android APK via a Trusted Web Activity. No backend, no account, no cloud — everything lives on the device.
Pendamping (Indonesian for “companion”) is one place that knows my day: habits, a focus/Pomodoro timer, tasks and deadlines, a calendar, exam countdowns, streaks, a health log, a journal, and prayer times. The home screen then surfaces the one or two things that deserve attention right now.
It's built around my life: the app runs on Malaysia time (Asia/Kuala_Lumpur) regardless of the device clock, the copy is Indonesian, and the defaults reflect a student's day. The home tab reads the time-of-day phase — morning, afternoon, evening, late night — and reorders its nudges accordingly.
localStorage on the device. That makes it private by default, instant to load, and fully usable offline — and it's the constraint that made the offline-first and packaging work the interesting part.
The app is organized into tabs, with the five most-used pinned to a bottom bar and the rest tucked under a “More” menu — phone-shaped navigation, not desktop.
Fokus (Focus) — a Pomodoro timer with a distraction-free focus mode; completed sessions feed straight into progress.
Tugas (Tasks) — to-dos with priority and deadlines; late and due-soon items get flagged.
Kalender (Calendar) — events alongside exam dates.
Ujian (Exams) — courses and exams with a live days-until countdown that drives the home-screen nudges.
Progress — current and best streak, weekly habit completion, and Pomodoro totals.
Kesehatan (Health) & Jurnal (Journal) — water/sleep style logging and short daily notes.
Atur (Settings) — edit prayer times, the daily schedule template, and export all data to JSON.
Rather than dumping everything, the home screen scores each candidate nudge by urgency (high/medium/low) and current phase, then shows the most important first. An exam two days out outranks an unchecked habit; an overdue task outranks an exam a week away.
HIGH overdue tasks -> "do or reschedule now" HIGH exam in <= 2 days -> "review key points, no cramming" MEDIUM tasks due <= 2 days -> "chip away today" MEDIUM exam in 3..7 days -> "start studying gradually" MEDIUM high-priority tasks -> "N priority tasks waiting" LOW habits left (daytime) -> "N habits not checked yet" LOW weekly target (morning) -> surface this week's goal Sorted HIGH -> MEDIUM -> LOW, then shown top-first. Phase (morning / afternoon / evening / late) gates the LOW nudges so it won't nag about habits at midnight.
Each rule produces a nudge tagged with a level and the tab it links to, so tapping a nudge jumps straight to the relevant screen. Time-of-day is computed in Malaysia time, not the device's, so the phase logic is stable no matter where the phone thinks it is. The low-priority nudges are gated by phase — an unchecked-habit reminder only appears during the day, never in the late-night window — which keeps the home screen calm instead of guilt-tripping. The whole thing is deterministic and rule-based: no model, no scoring black box, just a small ordered list of if conditions that's easy to reason about and tweak.
# Tuesday, 09:40 MYT (phase = "pagi"/morning)
state: 1 task overdue
Computer Architecture exam in 2 days
3 of 5 habits still unchecked
builds: HIGH "1 task past deadline — do or reschedule now" -> Tugas
HIGH "Computer Architecture in 2 days — review now" -> Ujian
LOW "3 habits not checked yet today" -> Hari ini
home shows the two HIGH nudges first; the habit reminder
sits below. At 23:30 (phase = "larut"/late) the habit
nudge is suppressed entirely.Getting one React app to install cleanly on a phone — both as a browser PWA and as a real APK from a single codebase — was the part that taught me the most.
vite-plugin-pwa / Workbox) makes it installable to the home screen, launchable standalone in portrait, and fully usable offline once cached.Because there's no server, the user owns their data outright — and I made that explicit rather than implicit.
localStorage. Settings includes a one-tap “Export all data (JSON)” — so the data is portable and backup-able even with no cloud behind it. Nothing is collected, nothing leaves the device unless the user chooses to export it.
The tradeoff is honest: no cross-device sync, and clearing browser storage clears the data. For a private, single-user companion app that's the right call — zero infrastructure, zero cost, instant load, and complete privacy.