Skip to content

Architecture

CodingJeff edited this page Sep 25, 2026 · 3 revisions

Architecture

apps/where_flutter ──dart:ffi──► where_ffi ──► where_search ──► where_storage (SQLite + FTS5)
                                                     ▲                  ▲
                          where_cli ─────────────────┘      where_indexer ┘
                                                     all built on where_core
browser extension ──HTTP 127.0.0.1:47771──► app (browser bridge)

Rust does the engine: storage, search and indexing. Flutter does the desktop app. They talk through a small C interface that passes JSON.

The parts

Folder What it does
crates/where_core The data model: objects (project, task, note, file, folder, person, website, bookmark, image, video, repository…) and relations (contains, involves, references).
crates/where_storage SQLite database with migrations, the FTS5 full-text index, and export (JSON, Markdown, CSV, SQLite copy).
crates/where_search Parses queries (words + kind: filters), builds safe FTS5 queries, ranks results and adds the containers (projects) of what matched.
crates/where_indexer Walks folders the user chose, with BLAKE3 fingerprints. Incremental: unchanged files are skipped, and deleted files are removed.
crates/where_ffi C functions for the app (where_open, where_search, where_create, where_update, where_relate, where_index_folder, where_export…). Everything in and out is JSON.
crates/where_cli The where-cli command-line tool.
apps/where_flutter The desktop app: loading screen, sidebar, pages, command palette, browser bridge.
browser-extension Manifest V3 extension for Chromium browsers.
scripts, installer Packaging for Mac/Linux and the Windows installer (Inno Setup).
server, plugins Placeholders for future sync and plugins. Nothing here yet.

Data model

  • objects: id (UUID v7), kind, title, body, properties (JSON: path, URL, status, size…), search_extra (extra searchable words such as paths and addresses), timestamps, and an optional unique source_key so the same file or URL isn't added twice.
  • relations: from, kind, to (deleting an object removes its relations).
  • objects_fts: FTS5 index over title, body and search_extra, kept in sync by triggers, with accents ignored.
  • index_roots: the folders the user chose.

Key rules

  • Local-first: the SQLite file is the source of truth.
  • Never touch user files: the indexer only reads. Deleting in Where only deletes Where's record.
  • Safe search: user input is always quoted before it reaches FTS5.
  • Browser bridge: loopback only; each browser is paired once (the user clicks Allow) and gets its own token. Web-page origins are rejected, only http(s) links are accepted, and requests are size-capped.
  • The app never blocks: indexing runs in a background isolate.

Decisions

Why things are the way they are, in docs/adr:

  1. Record architecture decisions
  2. Rust core with SQLite + FTS5 as the local source of truth
  3. Flutter ↔ Rust through a small JSON-over-C-ABI boundary
  4. The CLI is where-cli, not where
  5. The browser extension talks to Where over a paired, loopback-only HTTP bridge

The full product vision is in the spec.

Clone this wiki locally