Oriel
Notes, lists and tasks that work offline first and sync live with the people you live with.
Runs on my home server, so it may be offline now and then (for example during a power or internet outage).

About the project
A calm notebook for the everyday things you don't want to forget: a shopping list, a note, a task for the weekend. It runs as a live demo on my home server and installs on a phone like an app.
The problem I wanted to solve is the shared shopping list in a shop with no signal. Every read and write goes to a SQLite database in the browser first, so the app opens instantly and keeps working offline. An account is optional: it adds sync between devices and spaces shared with others, where changes show up on the other phones within a second.
The hard part was keeping the server in charge without slowing the device down. Changes are applied locally at once, then each one is checked on the server against the member's role before it reaches anyone else; a refused change is dropped and the device gets the server's version back.
What you can try
- Quick capture at the bottom of the screen: one line like "Groceries: milk, eggs, bread" becomes a list
- Works without a connection after the first visit, with no account needed
- Shared spaces with owners, editors and viewers; who added or checked what, and who else has a list open
- Tasks with priority, status, due days, repeats and snooze; notes in Markdown with earlier versions to restore
- Search across titles, notes and list entries on the device, ignoring case and accents
- Swipe to finish or delete with undo, drag to reorder, a command palette with Ctrl+K
- Share text into Oriel from other apps, dictate with the microphone and scan a product barcode into a list
- A morning reminder of the day's tasks and notices of what others changed, as push notifications
- Sign in with a passkey, export everything as JSON or Markdown, or delete the account
- English, Hungarian and Slovak, light and dark mode
Under the hood
- Local-first data: TanStack DB collections over a SQLite database in the browser, kept in sync with PostgreSQL by PowerSync through logical replication
- Every uploaded change is validated with Zod and checked against the member's role on the server; downloads are scoped per space by sync streams
- Client-generated IDs make retried uploads safe; concurrent edits merge per field, written up as decision records
- Hand-written service worker for offline use, Web Push, Web Share Target, Badging and Barcode Detection APIs
- Store tests against real SQLite, component tests, and Playwright tests with two browsers syncing, offline emulation and axe checks
- Strict Content Security Policy with nonces; Docker image built and scanned in GitHub Actions, deployed with nightly database backups
Architecture
- 1BrowserReact UI on TanStack DB collections
- 2SQLiteLocal database in the browser, every write lands here first
- 3PowerSyncStreams each member's spaces down; uploads go through the app's checks
- 4PostgreSQLThe server's copy, replicated to PowerSync
- When
- 2026
- Type
- Personal
- Versions
- TanStack Start 1.169
- React 19.3
- PowerSync 1.27
- PostgreSQL 18
- TypeScript 7
- Stack
- TanStack Start
- React
- TypeScript
- TanStack DB
- PowerSync
- SQLite
- PostgreSQL
- Drizzle ORM
- Better Auth
- Zod
- React Aria
- Tailwind CSS
- Paraglide
Playwright
- Docker


