> ## Documentation Index
> Fetch the complete documentation index at: https://shareclick.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Decision log

> Lightweight architecture decision records (ADRs) — the settled 'why' behind ShareClick's design, so future changes don't re-litigate them.

Lightweight architecture decision records. Newest supersedes oldest — we never
delete an entry; if a decision changes, a new one references it. This is the
"why" that keeps future changes from re-litigating settled questions.

Each record: **decision · rationale · consequences.**

<AccordionGroup>
  <Accordion title="1. Hybrid transport: UDP for input, TCP for bulk" icon="network-wired">
    **Rationale:** input tolerates loss and demands lowest latency; a dropped
    mouse move is irrelevant a millisecond later, so UDP avoids head-of-line
    blocking. Clipboard/files need reliable ordered delivery → TCP.
    **Consequences:** two code paths and two sets of keys, but the fast path never
    waits on the slow path. This is the core latency decision.
  </Accordion>

  <Accordion title="2. Rust" icon="rust">
    **Rationale:** predictable low-latency (no GC pauses), single static binary,
    easy cross-compilation, strong cross-platform input crates
    (rdev/enigo/arboard). **Consequences:** contributors need Rust; end users get
    a tiny dependency-free binary.
  </Accordion>

  <Accordion title="3. Dedicated blocking UDP socket, not async" icon="microchip">
    **Rationale:** an async runtime adds scheduler jitter on the hot path. A
    dedicated thread with a blocking socket has the most predictable latency.
    **Consequences:** `transport.rs` is intentionally synchronous; measured \~6 µs
    one-way overhead confirms it.
  </Accordion>

  <Accordion title="4. Relative mouse motion, not absolute" icon="arrows-up-down-left-right">
    **Rationale:** absolute coordinates couple the two machines' screen
    geometries and break on differing resolutions/DPI. Relative deltas "just
    work" and are tiny on the wire. **Consequences:** the client integrates deltas
    to know its cursor position (`cursor.rs`).
  </Accordion>

  <Accordion title="5. Portable Key enum, never raw scancodes" icon="keyboard">
    **Rationale:** macOS and Windows use different raw keycodes; forwarding them
    raw would mistranslate keys. We map native → portable `Key` → native (the
    Synergy/Deskflow approach). **Consequences:** `keymap.rs` maintains the
    translation tables; unmapped keys degrade to `Unknown` and are dropped.
  </Accordion>

  <Accordion title="6. Per-tick event coalescing" icon="layer-group">
    **Rationale:** high mouse polling rates (1000+ Hz) would flood the network and
    cause "jumpiness" when polling exceeds display refresh. Coalescing a tick's
    events into one packet fixes both. **Consequences:**
    `InputMsg::Events(Vec<..>)` carries a batch.
  </Accordion>

  <Accordion title="7. Control model: server-authoritative, Enter/Leave signalling" icon="right-left">
    **Rationale:** exactly one machine must own input at a time to avoid feedback
    loops. The server holds the truth (`Control.active`), hands off on edge/F12,
    and signals the client with `Enter`; the client auto-returns by sending
    `Leave`. **Consequences:** `rdev` grab must *swallow* local input while the
    client is active — hence the `unstable_grab` feature rather than passive
    `listen`.
  </Accordion>

  <Accordion title="8. WireGuard-style crypto: X25519 + PSK + ChaCha20-Poly1305" icon="shield-halved">
    **Rationale:** ephemeral ECDH gives forward secrecy; a PSK mixed into the
    HKDF salt authenticates peers without a PKI (MITM-resistant); ChaCha is fast
    in software so encryption costs \~20 ns per input packet. See
    [Security](/concepts/security). **Consequences:** users share a passphrase; no
    certificate infrastructure needed.
  </Accordion>

  <Accordion title="9. Nonce counters are implicit where possible" icon="hashtag">
    **Rationale:** transmitting a nonce per packet wastes bytes. TCP is ordered →
    both peers keep in-sync counters (transmit nothing). UDP reuses the packet
    `seq` as the counter. **Consequences:** never reuse a `(key, nonce)` pair;
    per-direction keys guarantee this.
  </Accordion>

  <Accordion title="10. mDNS for discovery, PSK for identity" icon="tower-broadcast">
    **Rationale:** typing IPs is bad UX; mDNS finds peers automatically. Security
    is unaffected because discovery only yields a candidate address — the PSK
    handshake still authenticates. **Consequences:** an imposter can advertise the
    service but cannot complete the handshake.
  </Accordion>

  <Accordion title="11. native / tray feature split" icon="toggle-on">
    **Rationale:** keep a testable, permissionless core that CI can build and
    unit-test headlessly; isolate heavy GUI + OS deps behind opt-in flags.
    **Consequences:** 23 unit tests run without a display; the GUI is built only
    for releases.
  </Accordion>

  <Accordion title="12. No-argument launch opens the tray" icon="window-restore">
    **Rationale:** a double-clicked `.app`/`.exe` passes no CLI args; end users
    expect a GUI, not a help dump. **Consequences:** `main.rs` routes
    no-subcommand → `tray::run()` (or help if built without `tray`).
  </Accordion>

  <Accordion title="13. Ship one-click installers, not source" icon="box-open">
    **Rationale:** end users won't install Rust. CI builds a universal macOS
    `.dmg` and a Windows `.exe` installer on every tag and publishes them to
    GitHub Releases. **Consequences:** see [Releasing](/develop/releasing);
    unsigned until certificates are acquired.
  </Accordion>
</AccordionGroup>

## Known open questions

* Sliding-window anti-replay for UDP (currently monotonic-counter only).
* Multiple simultaneous clients (needs swappable per-session UDP cipher).
* Code signing / notarization once certificates are available.
