Contributing

Prerequisites

Finia is a Rust workspace targeting native desktop plus wasm32 for the frontend. You need a Rust toolchain with the wasm32-unknown-unknown target, the Tauri CLI (cargo tauri), and Trunk for the frontend build.

Common commands

# Run the desktop app in dev mode (hot-reload frontend + Rust watch)
cargo tauri dev

# Build the desktop app for release
cargo tauri build

# Run all Rust tests
cargo test --workspace

# Run a single test
cargo test -p <crate> <test_name>

# Start the standalone sync server
cd sync-server && docker compose up -d

Pre-commit gates

All four gates must be green before every commit:

cargo test --workspace                                                   (1)
(cd sync-server && cargo build)                                          (2)
cargo check -p ui -p tauri-ipc -p app --target wasm32-unknown-unknown   (3)
(cd crates/app && trunk build)                                          (4)
1 UI primitives, IPC round-trips, and src-tauri unit tests.
2 The standalone sync server compiles on its own.
3 The wasm-shipping crates compile for wasm32.
4 The full frontend build — Tailwind + wasm-bindgen — and the single source of truth for "does the frontend compile."

The wasm32 check is scoped to ui + tauri-ipc + app on purpose. src-tauri pulls tokio/mio, which reject wasm32 and must not be included.

Workspace crates

See Architecture & Decisions for the full crate map. The short version:

  • crates/ui, crates/tauri-ipc, crates/app build for wasm32.

  • src-tauri/ (the Tauri shell + SQLite handlers) does not.

  • crates/csv-import is a pure-Rust parser crate.

  • sync-server/ is a standalone binary with its own Cargo.toml.

Adding a synced entity

Sync is opt-in per entity. When you add a new entity, a new field on a synced entity, or a new mutation handler, you must decide its sync behavior:

  1. Add it to src-tauri/src/sync/registry.rs (the single source of truth),

  2. emit it from the handler (sync::emit::emit / emit_tombstone, inside the row’s transaction), and

  3. confirm the apply path materializes it.

A synced field with no emit call silently never replicates; a handler that mutates a synced entity without an emit call is a sync bug. Scoping an entity out is a valid choice — just make it consciously.

Documentation

Documentation for the punkt portal is authored in AsciiDoc under docs/modules/ROOT/pages/. Every new page needs an xref: line in nav.adoc. Process and AI artifacts do not belong in docs/modules/ — see the "Documentation: Antora / punkt portal conventions" section of CLAUDE.md for the full rules.