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
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
- proto depends on nothing in-workspace. It is pure data definition.
- core depends on proto (for legacy envelope helpers). It does not depend on server, rpc, or sdk.
- rpc depends on proto. It does not depend on core, server, or client.
- sdk depends on rpc and core. It does not depend on server.
- server depends on core, proto, and rpc. It does not depend on client or sdk.
- client depends on sdk, core, and proto. It does not depend on server.
- server and client never depend on each other. They communicate exclusively via the v2 Protobuf framing protocol over QUIC.
- 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 -- high-level system diagram
- Service Architecture -- 44 RPC method details
- Wire Format Reference -- Protobuf schema reference
- GroupMember Lifecycle -- MLS state machine details
- Storage Backend -- SQLCipher storage internals