# Crate Responsibilities The quicprochat workspace contains nine crates. The core four (proto, core, server, client) follow strict layering rules; each owns one concern and depends only on the crates below it. The workspace also includes dedicated crates for the RPC framework, client SDK, key transparency, plugin API, and P2P. This page documents what each crate provides, what it explicitly avoids, and how the crates relate to one another. --- ## Dependency Flow Diagram ```text +-------------------+ +-------------------+ | quicprochat-client | | quicprochat-sdk | | (CLI/TUI binary) | | (QpqClient, store)| +--------+----------+ +--------+----------+ | | +----------+ +-----------+ | | v v +-----------+----------+ | quicprochat-rpc | | (framing, server, | | client, middleware) | +--------+-------------+ | +---------------+---------------+ | | v v +------------------------+ +-----------------------------+ | quicprochat-core | | quicprochat-server | | (crypto, MLS, | | (RPC server + domain | | hybrid KEM) | | services) | +----------+-------------+ +-------------+---------------+ | | | +-------------------+ | +------>| quicprochat-proto |<--+ | (capnp legacy + | | prost v2 types) | +-------------------+ (separate, no shared deps) +-------------------+ +-------------------+ +-------------------+ | quicprochat-kt | | quicprochat-p2p | | quicprochat- | | (key transparency)| | (iroh P2P) | | plugin-api | +-------------------+ +-------------------+ | (#![no_std] C-ABI)| +-------------------+ ``` **Arrows point from dependant to dependency.** The proto crate sits at the base of the dependency graph. The core crate depends on proto for legacy envelope serialisation. The rpc crate provides the framing and dispatch layer used by both the sdk and server. --- ## quicprochat-core **Role:** Pure cryptographic logic. No network I/O. No async runtime dependency. ### Modules | Module | Public API | Description | |---------------|-----------------------------------------------------------------------------|-------------| | `identity` | `IdentityKeypair` | Ed25519 signing keypair for MLS credentials. Seed stored as `Zeroizing<[u8; 32]>`. Implements `openmls_traits::Signer`. | | `group` | `GroupMember` | MLS group state machine wrapping `openmls::MlsGroup`. Lifecycle: `new` -> `generate_key_package` -> `create_group` / `join_group` -> `send_message` / `receive_message`. | | `keypackage` | `generate_key_package` | Standalone KeyPackage generation (returns TLS-encoded bytes + SHA-256 fingerprint). | | `keystore` | `DiskKeyStore`, `StoreCrypto` | `OpenMlsKeyStore` implementation backed by an in-memory `HashMap` with bincode flush to disk. `StoreCrypto` couples `RustCrypto` + `DiskKeyStore` into an `OpenMlsCryptoProvider`. | | `hybrid_kem` | `HybridKeypair`, `HybridPublicKey`, `hybrid_encrypt`, `hybrid_decrypt` | X25519 + ML-KEM-768 hybrid KEM. HKDF-SHA256 key derivation, ChaCha20-Poly1305 AEAD. Versioned envelope wire format. | | `error` | `CoreError`, `MAX_PLAINTEXT_LEN` | Unified error types covering MLS and hybrid KEM failures. | ### What this crate does NOT do - No network I/O. - No QUIC or TLS -- that is the server and client crates' concern. - No async runtime setup. - No CLI parsing. ### Key dependencies `ed25519-dalek`, `openmls`, `openmls_rust_crypto`, `openmls_traits`, `tls_codec`, `ml-kem`, `x25519-dalek`, `chacha20poly1305`, `hkdf`, `sha2`, `zeroize`, `quicprochat-proto`, `serde`, `bincode`, `thiserror`. --- ## quicprochat-proto **Role:** Protocol type definitions for both v1 (legacy Cap'n Proto) and v2 (Protobuf/prost). This crate is the single source of truth for wire types and method ID constants. ### Contents | Item | Description | |-------------------------------|-------------| | `schemas/*.capnp` | Legacy Cap'n Proto schemas (auth, delivery, node, federation). | | `proto/qpc/v1/*.proto` | 14 Protobuf files defining all v2 message types. | | `build.rs` | Invokes `capnpc` for legacy types and `prost-build` for v2 types. | | `pub mod qpc::v1` | All Protobuf-generated types, included via `prost` `include!`. | | `pub mod method_ids` | All 44 RPC method ID constants (u16) plus 4 push event type constants. | | `auth_capnp`, `node_capnp`... | Re-exported legacy Cap'n Proto generated modules. | ### method_ids ranges | Range | Category | |---|---| | 100-103 | Auth (OPAQUE register/login) | | 200-205 | Delivery (enqueue, fetch, ack) | | 300-304 | Keys (key packages, hybrid keys) | | 400 | Channel creation | | 410-413 | Group management | | 420-424 | Moderation | | 500-501 | User / identity resolution | | 510-520 | Key transparency | | 600-601 | Blob storage | | 700-710 | Device management + push tokens | | 750-752 | Recovery bundles | | 800-802 | P2P endpoints + health | | 900-905 | Federation relay | | 950 | Account deletion | | 1000-1003 | Push event types (server-to-client) | ### What this crate does NOT do - **No crypto** -- key material never enters this crate. - **No I/O** -- callers own the transport; this crate only converts bytes to types and back. - **No async** -- pure synchronous data-layer code. ### Key dependencies `capnp` (runtime), `capnpc` (build-time), `prost`, `prost-build` (build-time), `bytes`. --- ## quicprochat-rpc **Role:** v2 RPC framework. Implements the custom binary framing protocol, server-side dispatch, client-side request/response handling, and Tower middleware (rate limiting, timeouts, authentication). ### Components | Component | Description | |------------------|-------------| | `framing` | `RequestFrame`, `ResponseFrame`, `PushFrame` encode/decode with big-endian headers. Max payload: 4 MiB. | | `server` | `RpcServer` accepts QUIC connections, reads request frames, dispatches to registered handlers, writes response frames. | | `client` | `RpcClient` opens per-RPC QUIC streams, writes request frames, reads response frames. | | `middleware` | Tower `Service` wrappers: rate limiter, deadline/timeout, auth token injection. | | `error` | `RpcError`, `RpcStatus` enum (Ok=0, BadRequest=1, Unauthorized=2, ... UnknownMethod=11). | ### Frame format (implemented here) ``` Request: [method_id: u16 BE][request_id: u32 BE][payload_len: u32 BE][protobuf] Response: [status: u8][request_id: u32 BE][payload_len: u32 BE][protobuf] Push: [event_type: u16 BE][payload_len: u32 BE][protobuf] ``` ### What this crate does NOT do - No domain logic -- handlers are registered by the server crate. - No crypto operations. ### Key dependencies `quinn`, `rustls`, `tokio`, `bytes`, `tower`, `prost`, `quicprochat-proto`, `tracing`, `thiserror`. --- ## quicprochat-sdk **Role:** High-level client SDK. `QpqClient` wraps the RPC client with typed methods, an async event broadcast channel, and a `ConversationStore` for local conversation state. ### Components | Component | Description | |---------------------|-------------| | `QpqClient` | Authenticated client: `register`, `login`, `send_message`, `fetch_messages`, etc. | | Event channel | `tokio::sync::broadcast` channel delivering `ClientEvent` variants (NewMessage, Typing, Presence, Membership). | | `ConversationStore` | SQLCipher-backed local store for message history and group state. | ### What this crate does NOT do - No raw frame handling -- delegates to `quicprochat-rpc`. - No MLS group state management -- delegates to `quicprochat-core`. ### Key dependencies `quicprochat-rpc`, `quicprochat-core`, `quicprochat-proto`, `tokio`, `rusqlite`, `prost`, `tracing`, `thiserror`, `anyhow`. --- ## quicprochat-server **Role:** Network-facing server binary. Accepts QUIC + TLS 1.3 connections, dispatches 44 Protobuf RPC methods through registered handlers in `domain/`, and persists state to SQLCipher. ### Components | Component | Description | |----------------------|-------------| | `v2_handlers/` | One handler module per method category (auth, delivery, keys, channel, group, user, kt, blob, device, p2p, federation, moderation, recovery, account). | | `domain/` | Protocol-agnostic domain types and service logic (e.g., `AuthService`, `DeliveryService`, `KeyService`). | | `ServerState` | Shared state: SQLCipher connection pool, DashMap waiters, OPAQUE server state. | | TLS config | Self-signed certificate auto-generated on first run (`rcgen`). TLS 1.3 only, ALPN `qpc`. | | CLI (`clap`) | `--listen` (default `0.0.0.0:5001`), `--data-dir`, `--tls-cert`, `--tls-key`. | ### Connection lifecycle ``` QUIC accept (ALPN: "qpc") +- TLS 1.3 handshake (self-signed cert) +- Per-stream: read RequestFrame -> dispatch to handler -> write ResponseFrame +- Uni-stream (server -> client): write PushFrame for events ``` Each RPC call gets its own QUIC bidirectional stream; handlers run concurrently via `tokio::spawn`. ### What this crate does NOT do - No direct crypto beyond OPAQUE server-side operations. - No MLS processing -- all MLS payloads are opaque byte strings. ### Key dependencies `quicprochat-core`, `quicprochat-proto`, `quicprochat-rpc`, `quinn`, `rustls`, `rcgen`, `tokio`, `dashmap`, `rusqlite`, `prost`, `clap`, `tracing`, `anyhow`, `thiserror`. --- ## quicprochat-client **Role:** CLI/TUI client binary. Connects to the server, orchestrates MLS group operations via `GroupMember`, and persists identity and group state. ### What this crate does NOT do - No server-side logic. - No raw frame parsing -- delegates to `quicprochat-sdk` / `quicprochat-rpc`. ### Key dependencies `quicprochat-sdk`, `quicprochat-core`, `quicprochat-proto`, `tokio`, `clap`, `rustyline`, `tracing`, `anyhow`. --- ## quicprochat-kt **Role:** Key transparency. Implements an append-only transparency log for Ed25519 public keys with revocation checking and audit support. Methods exposed: `RevokeKey` (510), `CheckRevocation` (511), `AuditKeyTransparency` (520). --- ## quicprochat-plugin-api **Role:** `#![no_std]` C-ABI plugin interface. Defines a stable ABI for dynamically loaded plugins with 6 hook points (on_message_send, on_message_receive, on_group_join, on_group_leave, on_connect, on_disconnect). This crate has no workspace dependencies. It is intentionally `no_std` to allow plugins compiled for embedded or WASM targets. --- ## quicprochat-p2p **Role:** P2P endpoint publish and resolve via iroh. Used by the server and clients for direct peer discovery when the `mesh` feature is enabled on `quicprochat-client`. Methods exposed: `PublishEndpoint` (800), `ResolveEndpoint` (801). This crate is compiled but kept out of the default dependency graph for most build targets due to iroh's large dependency footprint (~90 extra deps). --- ## Layering Rules 1. **proto** depends on nothing in-workspace. It is pure data definition. 2. **core** depends on **proto** (for legacy envelope helpers). It does not depend on server, rpc, or sdk. 3. **rpc** depends on **proto**. It does not depend on core, server, or client. 4. **sdk** depends on **rpc** and **core**. It does not depend on server. 5. **server** depends on **core**, **proto**, and **rpc**. It does not depend on client or sdk. 6. **client** depends on **sdk**, **core**, and **proto**. It does not depend on server. 7. **server** and **client** never depend on each other. They communicate exclusively via the v2 Protobuf framing protocol over QUIC. 8. **kt**, **plugin-api**, and **p2p** are optional; they do not change the core layering. This layering ensures that: - Crypto code can be tested in isolation (`cargo test -p quicprochat-core`). - Schema changes propagate automatically through codegen. - The server binary contains no client-side MLS orchestration logic. - The client binary contains no server-side storage or listener logic. --- ## Further Reading - [Architecture Overview](overview.md) -- high-level system diagram - [Service Architecture](service-architecture.md) -- 44 RPC method details - [Wire Format Reference](../wire-format/overview.md) -- Protobuf schema reference - [GroupMember Lifecycle](../internals/group-member-lifecycle.md) -- MLS state machine details - [Storage Backend](../internals/storage-backend.md) -- SQLCipher storage internals