LightNotes is a local-first notes and diary app — WYSIWYG Markdown editing, folders and tags, reminders, and encrypted on-device storage. The hard parts were making one Rust codebase render on six platforms and keeping a background sync loop correct against a self-hosted REST + SSE API.

~22k lines of Rust across 317 files. Six platform targets: web (WASM), macOS, Windows, Linux, Android and iOS.
web / desktop / mobile / server) and cfg(target_os) / cfg(target_arch) dependency tables.apps/web, apps/desktop and apps/mobile are ~50-line binaries around a shared packages/app; the layout adapts per platform (sidebar + top bar on desktop, compact header + bottom tabs on mobile).domain/ (entities + port traits) → application/ (commands/, queries/) → infrastructure/ (Mongo repositories, auth, telemetry, migrations) → interface/http/; the HTTP layer never touches MongoDB directly.sync-dto is compiled verbatim into both client and server, so the wire format cannot drift; api-sdk is the typed client over it.component.rs renders, use_component.rs owns state and handlers), with an explicit FooProps struct pattern enforced repo-wide.lightnotes-cd repo holds AppProject + Application and 12 Kustomize-managed manifests, with automated sync, prune, self-heal, server-side apply and retry backoff.ghcr.io/…:<sha>, then a reusable cd-bump workflow runs kustomize edit set image against the CD repo (shared concurrency group, rebase-and-retry); ArgoCD picks it up on the next poll.debian:trixie-slim for Rust binaries, nginx:1.27-alpine for the SPA with try_files fallback, gzip and hashed-asset cache tiers); Compose brings up MongoDB and mongo-express locally.rust-cache, pinned toolchains and workflow_call fan-out.ubuntu:22.04 with WebKitGTK deps baked in, which is what pins the shipped glibc floor..dmg, .msi, NSIS .exe, .AppImage, .deb, .rpm and SHA256SUMS; it publishes nothing unless every platform succeeds.grafana/otel-lgtm) as the telemetry backend, with W3C traceparent propagation and semconv-named spans; make is the single entry point for every dev, build and bundle target.Encrypted at rest with OS-keychain key custody, including a one-way migration that re-encrypts an existing plaintext database in place while preserving its schema version.
The pending-change queue, debounce window, backoff reconnect and cursor catch-up all live client-side, so the server stays a thin append-only change log.
Platform differences are isolated to per-target dependency tables and a handful of cfg blocks; notifications are the only subsystem with four native implementations behind one trait.
option_env! bakes the endpoint into the WASM bundle, with the cache-invalidation trade-off documented — a deliberate trade of runtime configurability for a fully static SPA image.
SSE fan-out is in-process tokio::broadcast; scaling out is documented as requiring Redis or Mongo change streams first, rather than left as an accidental constraint.
Export is entirely off unless OTEL_EXPORTER_OTLP_ENDPOINT is set, so dev and CI behave identically to a pre-instrumentation build.
The workflow fails when a tag disagrees with Cargo.toml, because bundlers stamp the version independently of the artifact filename.

