Files
quicproquo/docs/src/architecture/crate-responsibilities.md
Christian Nennemann 2e081ead8e chore: rename quicproquo → quicprochat in docs, Docker, CI, and packaging
Rename all project references from quicproquo/qpq to quicprochat/qpc
across documentation, Docker configuration, CI workflows, packaging
scripts, operational configs, and build tooling.

- Docker: crate paths, binary names, user/group, data dirs, env vars
- CI: workflow crate references, binary names, artifact names
- Docs: all markdown files under docs/, SDK READMEs, book.toml
- Packaging: OpenWrt Makefile, init script, UCI config (file renames)
- Scripts: justfile, dev-shell, screenshot, cross-compile, ai_team
- Operations: Prometheus config, alert rules, Grafana dashboard
- Config: .env.example (QPQ_* → QPC_*), CODEOWNERS paths
- Top-level: README, CONTRIBUTING, ROADMAP, CLAUDE.md
2026-03-21 19:14:06 +01:00

13 KiB

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

              +-------------------+     +-------------------+
              | 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