Back
Day Planner app icon

Day Planner

Personal project — live

Why I built it

I have a lot of hobbies and interests — and for a long time I kept jumping between them without much focus. I'd spend more time deciding what to work on than actually working on it. Some days the decision paralysis would get bad enough that I'd end up doing nothing at all, and the day would feel like it had no real achievements.

What I wanted was a place to map out all my recurring activities, personal projects, and habits — and a simple way to pull from that library when planning a day, without the overhead of a full project management tool.

I tried making it work with Notion and other task apps, but none of them had the exact combination of features I was imagining: a hierarchical activity library, a daily todo list linked to it, and an effort/capacity system to stop me overloading a day before it started. So I built it myself.

Features

Daily todos

At its core, Day Planner is a daily todo list. Each day is its own container — add tasks, drag to reorder, mark them complete. Completed tasks collapse to the bottom so your focus stays on what's left.

Planner

The Planner is a hierarchical library of all your recurring activities, hobbies, and projects — organised with unlimited nesting depth. Categories are grouped into swipeable tabs by tag, so you can split your life into areas (fitness, work, hobbies, etc.) and switch between them quickly.

Each plan item can be edited individually — you can rename it, set an effort value, adjust the repeat frequency, or move it within the tree. Plan items can be added directly to today's todos from the planner view.

Todos added from plan items get a completion button that marks the plan item as done — the same as completing it directly from the planner.

Repeat frequency

For recurring tasks — change bedsheets, practice guitar, go for a run — you can set a repeat frequency in days. When you're adding that item to a day, the button colour tells you where you stand: green means you've done it recently, orange means it's due soon, red means the window has passed.

Routines

Routines are named collections of tasks you want to bulk-add to a day in one tap — a morning routine, a gym session, a work day template. Routine items can be linked to plan categories so they inherit effort values and mark plan items as done when completed.

Routines can be added to a day from the routines tab or directly from the create todo screen.

Energy & effort system

Each day has an energy cap (default: 24 units — roughly one unit per half hour). Every task, plan item, and routine item carries an effort value. A progress bar at the top of the day fills up as you add tasks, turning yellow then red as you approach or exceed the cap.

It's not a hard constraint — you can go over. It's more of a gut-check before you commit to a day that's already too full. When adding a plan item, if it would push you over the cap, the button turns red to flag it.

Settings & data backup

Since everything is stored locally with no cloud sync, the app supports exporting and importing the full SQLite database file. You can back up your plans and routines, restore from a backup, or transfer data to another device. The settings page also lets you configure the default daily energy cap and selectively clear different parts of your data independently.

Technical details

Architecture

SQLite as the single source of truth. All persistent state lives in the database — there is no Redux store of app data. Redux is used only as a reload-signal layer: two slices hold boolean flags that component hooks watch to know when to re-query SQLite. This keeps the data layer simple and the UI always in sync with what's actually on disk.

6-table schema with self-referential hierarchy. The planning_categories table references itself via a parent FK, enabling unlimited nesting depth without schema changes. A parentLabel column is denormalised onto each row to avoid recursive joins at render time. A custom INSERT trigger on daily_todos auto-assigns sort order, removing the need to manage ordering on insert.

13 incremental migrations. The schema grew significantly as features were added after the initial release. All migrations run sequentially on app start against a stored schema version, keeping existing user data intact across updates.

Notable challenges

Drag-to-reorder sync with SQLite. React Native's drag libraries update UI state optimistically, but writing the new order back to SQLite without triggering redundant re-renders required a bulk SQL reorder on drop, coordinated with Redux reload flags to re-fetch cleanly after the write settled.

Recursive subcategory rendering. Rendering arbitrarily deep nested trees efficiently in React Native is tricky — recursive queries are slow and recursive components can blow the call stack. The solution was to denormalise parentLabel directly onto each row, flattening the fetch to a single query, and render the tree with a collapsible accordion that only mounts visible nodes.