Architecture — the crate map

This is the one-diagram floor doc: the crates and the arrows between them. The full rationale lives in docs/planning-artifacts/architecture.md; the decisions are recorded as ADRs in docs/adr/.

Dependency direction (the invariant)

apps → {ui, domain-core, substrate}; within libraries ui → domain-core → substrate; never upward, never ui → substrate.

Build-enforced by tests/dep_direction.rs. Libraries layer strictly downward (rank substrate=0 → domain-core=1 → ui=2); apps and services are leaves that nothing internal may depend on.

        ┌─────────────────────────────────────────────┐
        │                  apps / services             │
        │                                              │
        │   apps/organizer (wasm)   apps/organizer/    │
        │   ── frontend ──┐         src-tauri (native) │   services/relay
        │                 │              │             │   (build-deferred)
        └─────────────────┼──────────────┼─────────────┘
                          │              │
              depends on  │              │ depends on
                          ▼              ▼
                  ┌───────────────┐   ┌───────────────┐
                  │   crates/ui   │   │ crates/        │
                  │  (rank 2)     │   │  substrate     │
                  └───────┬───────┘   │  (rank 0)      │
                          │           └───────▲────────┘
                depends on│                   │ (allowed, currently unused:
                          ▼                   │  domain-core → substrate)
                  ┌───────────────┐           │
                  │ crates/       │───────────┘
                  │  domain-core  │
                  │  (rank 1)     │
                  └───────────────┘

  Legend: arrows = "depends on". The ONLY internal library edge that exists today is
  ui → domain-core. substrate and domain-core depend on nothing internal. The wasm
  frontend never pulls substrate (keeps llama-cpp-2/rusqlite out of the browser build).

What each crate owns

crate kind owns depends on (internal)

substrate

lib

every trait boundary: Store, Inference, Clock, KeyTransport, CalendarProvider, Signal; concrete backends never leak above it

 — 

domain-core

lib

shared entities; no IO; Private<T>, typed IDs, Estimate, DailyBlock, …​ (from Story 1.2+)

 — 

ui

lib

Leptos component library + Tailwind v4 design tokens (single home)

domain-core

apps/organizer (frontend)

app (wasm)

the Leptos CSR shell; reaches the core via async Tauri commands

ui, domain-core

apps/organizer/src-tauri

app (native)

the Tauri host process; wires substrate

substrate, domain-core

services/relay

service

zero-knowledge sync relay (Axum) — build-deferred

 — 

Build dimensions (CI)

  • desktop-native — cargo test --workspace (incl. the dep-direction guardrail).

  • wasm-browser — trunk build + wasm-bindgen-test.

  • android-native — NDK build + emulator (nightly/on-label, not per-commit).

Current status

Story 1.1 stands up the skeleton and the guardrails only. Every member crate is a compiling stub; feature code arrives in later stories (see docs/implementation-artifacts/). The ADR floor records which decisions are ratified (0001) versus seeded-pending (0002—​0008).