Urgent.News

What's breaking now, across thousands of outlets.

Tech

Designing an offline notes app for sync that doesn't exist yet (and a landing page with zero build tools)

I've spent the last several months building Nookly , a local-first notes app (pages, block editor, tables/kanban, full-text search) in Flutter, backed by Drift/SQLite. No account, no cloud — everything lives on the user's device. This post isn't really about the app itself. It's about two engineering decisions that might be useful outside this specific project: how to design a schema for sync you…

Over the past few months, the author has been developing Nookly, a local-first notes app built with Flutter, featuring a block editor, tables/kanban, and full-text search. The app operates entirely on the user's device without the need for any account or cloud storage. While the focus of this article is not on the app itself, it does delve into two engineering decisions that could be applied to future projects.

These decisions center around designing a schema for sync, which has yet to be implemented in Nookly but is planned for the future. Additionally, the article discusses how to create a landing page using zero build tools.

In terms of schema design, each table in Nookly includes an ID (UUID), updatedAt timestamp, isDeleted flag, and a version number. UUIDs are used instead of auto-incrementing values to prevent collision across multiple devices. The isDeleted flag allows for soft deletion, enabling the deletion status to be propagated to other devices. The version number is incremented with every write and serves as a hook for conflict resolution in the future.

When it comes to reordering items (such as pages and blocks), the author avoids updating every sibling row with each move. Instead, they employ fractional indices, calculating the average position between two existing rows. This approach eliminates the need to reindex all surrounding rows, significantly reducing the number of UPDATE statements required during drag-and-drop operations.

However, this method has a limitation: as rows are reordered repeatedly, floating-point precision may degrade, requiring periodic rebalancing of the indices in production environments.

Full-text search is handled by SQLite's FTS5 virtual table, with triggers ensuring that the search index remains in sync with the data layer at the database level. No additional Dart code is needed to maintain the search index.

The landing page for Nookly is a single HTML file, with React and Tailwind CSS loaded directly from CDN sources using Babel Standalone. There is no build process involved, as the JSX gets transpiled in the browser. While runtime Babel transpilation adds a slight overhead, it is considered acceptable for a single-page landing site. The interactive elements, such as the theme toggle and search widget, are fully functional and mirror the behavior of the actual app.

Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.

Read the original at dev.to →

More in Tech

Java Concurrency & Multithreading: 40 Interview Questions

1. Process vs Thread A process has its own memory space and OS resources; threads live inside a process and share its heap and file handles but keep their own stack and program counter.

  • Threads share process memory but have separate stacks and program counters.
  • Java provides platform threads (expensive) and lightweight virtual threads (Project Loom).
  • Java Memory Model ensures visibility guarantees for shared state between threads.

Your daily reminder needs three states, not a boolean

I built a checklist that opens itself at 8 am. The hard part wasn't opening it. It was working out when to stop. The version that fails The obvious model is a boolean.

  • The author builds a checklist app opening at 8 am.
  • Initially uses boolean flag to track window state.
  • Introduces third state for answered but not closed windows.

More from Sunday 20 September →