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
363 lines
13 KiB
Markdown
363 lines
13 KiB
Markdown
# Service Architecture
|
|
|
|
The quicprochat server exposes 44 RPC methods through a single QUIC + TLS 1.3
|
|
endpoint on **port 5001**. Methods are dispatched by numeric method ID using
|
|
the v2 Protobuf framing protocol. This page documents the method reference,
|
|
connection lifecycle, storage model, and authentication flow.
|
|
|
|
---
|
|
|
|
## RPC Endpoint
|
|
|
|
A single QUIC + TLS 1.3 listener on **port 5001** serves all operations.
|
|
The ALPN identifier is `qpc`. Each RPC call uses a dedicated QUIC
|
|
bidirectional stream; calls are concurrent and do not block each other.
|
|
|
|
```text
|
|
quicprochat-server (port 5001, ALPN: "qpc")
|
|
|
|
|
+-- Auth (100-103)
|
|
| +-- 100: OpaqueRegisterStart
|
|
| +-- 101: OpaqueRegisterFinish
|
|
| +-- 102: OpaqueLoginStart
|
|
| +-- 103: OpaqueLoginFinish
|
|
|
|
|
+-- Delivery (200-205)
|
|
| +-- 200: Enqueue
|
|
| +-- 201: Fetch
|
|
| +-- 202: FetchWait
|
|
| +-- 203: Peek
|
|
| +-- 204: Ack
|
|
| +-- 205: BatchEnqueue
|
|
|
|
|
+-- Keys (300-304)
|
|
| +-- 300: UploadKeyPackage
|
|
| +-- 301: FetchKeyPackage
|
|
| +-- 302: UploadHybridKey
|
|
| +-- 303: FetchHybridKey
|
|
| +-- 304: FetchHybridKeys
|
|
|
|
|
+-- Channel (400)
|
|
| +-- 400: CreateChannel
|
|
|
|
|
+-- Group Management (410-413)
|
|
| +-- 410: RemoveMember
|
|
| +-- 411: UpdateGroupMetadata
|
|
| +-- 412: ListGroupMembers
|
|
| +-- 413: RotateKeys
|
|
|
|
|
+-- Moderation (420-424)
|
|
| +-- 420: ReportMessage
|
|
| +-- 421: BanUser
|
|
| +-- 422: UnbanUser
|
|
| +-- 423: ListReports
|
|
| +-- 424: ListBanned
|
|
|
|
|
+-- User (500-501)
|
|
| +-- 500: ResolveUser
|
|
| +-- 501: ResolveIdentity
|
|
|
|
|
+-- Key Transparency (510-520)
|
|
| +-- 510: RevokeKey
|
|
| +-- 511: CheckRevocation
|
|
| +-- 520: AuditKeyTransparency
|
|
|
|
|
+-- Blob (600-601)
|
|
| +-- 600: UploadBlob
|
|
| +-- 601: DownloadBlob
|
|
|
|
|
+-- Device (700-710)
|
|
| +-- 700: RegisterDevice
|
|
| +-- 701: ListDevices
|
|
| +-- 702: RevokeDevice
|
|
| +-- 710: RegisterPushToken
|
|
|
|
|
+-- Recovery (750-752)
|
|
| +-- 750: StoreRecoveryBundle
|
|
| +-- 751: FetchRecoveryBundle
|
|
| +-- 752: DeleteRecoveryBundle
|
|
|
|
|
+-- P2P (800-802)
|
|
| +-- 800: PublishEndpoint
|
|
| +-- 801: ResolveEndpoint
|
|
| +-- 802: Health
|
|
|
|
|
+-- Federation (900-905)
|
|
| +-- 900: RelayEnqueue
|
|
| +-- 901: RelayBatchEnqueue
|
|
| +-- 902: ProxyFetchKeyPackage
|
|
| +-- 903: ProxyFetchHybridKey
|
|
| +-- 904: ProxyResolveUser
|
|
| +-- 905: FederationHealth
|
|
|
|
|
+-- Account (950)
|
|
+-- 950: DeleteAccount
|
|
|
|
Push event types (server -> client, uni-stream):
|
|
1000: PushNewMessage
|
|
1001: PushTyping
|
|
1002: PushPresence
|
|
1003: PushMembership
|
|
```
|
|
|
|
---
|
|
|
|
## RPC Method Reference
|
|
|
|
### Auth (100-103)
|
|
|
|
OPAQUE password authentication (asymmetric PAKE). The password is never sent
|
|
to the server. Method IDs 100-103 implement the 4-step OPAQUE handshake.
|
|
|
|
| ID | Method | Description |
|
|
|-----|-------------------------|-------------|
|
|
| 100 | `OpaqueRegisterStart` | Client initiates registration with `username` and OPAQUE `registration_request` blob. Server returns `registration_response`. |
|
|
| 101 | `OpaqueRegisterFinish` | Client completes registration with `username`, OPAQUE `upload` blob, and Ed25519 `identity_key`. Server stores the OPAQUE record. |
|
|
| 102 | `OpaqueLoginStart` | Client initiates login with `username` and OPAQUE `login_request` blob. Server returns `login_response`. |
|
|
| 103 | `OpaqueLoginFinish` | Client completes login with `username`, OPAQUE `finalization` blob, and `identity_key`. Server returns a `session_token`. |
|
|
|
|
The `session_token` is an opaque bearer token used for subsequent authenticated
|
|
RPCs. It is passed in the Protobuf request body (not as a frame-level header).
|
|
|
|
### Delivery (200-205)
|
|
|
|
Store-and-forward relay. The server never inspects MLS ciphertext -- it routes
|
|
opaque byte blobs by recipient key.
|
|
|
|
| ID | Method | Description |
|
|
|-----|----------------|-------------|
|
|
| 200 | `Enqueue` | Append an opaque payload to the recipient's FIFO queue. Wakes `FetchWait` waiters. |
|
|
| 201 | `Fetch` | Drain and return all queued payloads in FIFO order. |
|
|
| 202 | `FetchWait` | Same as `Fetch`, but long-polls if the queue is empty (up to `timeout_ms`). |
|
|
| 203 | `Peek` | Return queued payloads without removing them. |
|
|
| 204 | `Ack` | Acknowledge and remove specific payloads by sequence number. |
|
|
| 205 | `BatchEnqueue` | Enqueue multiple payloads in a single RPC call. |
|
|
|
|
### Keys (300-304)
|
|
|
|
MLS KeyPackage distribution and hybrid PQ public key management.
|
|
|
|
| ID | Method | Description |
|
|
|-----|--------------------|-------------|
|
|
| 300 | `UploadKeyPackage` | Append a TLS-encoded MLS KeyPackage to the identity's queue. Single-use: each fetch atomically removes one. |
|
|
| 301 | `FetchKeyPackage` | Atomically pop and return the oldest KeyPackage for an identity. Returns empty if none. |
|
|
| 302 | `UploadHybridKey` | Store (or replace) the X25519+ML-KEM-768 hybrid public key for an identity. |
|
|
| 303 | `FetchHybridKey` | Return the stored hybrid public key for a single identity. |
|
|
| 304 | `FetchHybridKeys` | Return hybrid public keys for multiple identities in one call. |
|
|
|
|
### Group Management (400, 410-413)
|
|
|
|
| ID | Method | Description |
|
|
|-----|-----------------------|-------------|
|
|
| 400 | `CreateChannel` | Register a new channel (group) on the server. |
|
|
| 410 | `RemoveMember` | Remove a member from a group (server-side record). |
|
|
| 411 | `UpdateGroupMetadata` | Update group name, description, or settings. |
|
|
| 412 | `ListGroupMembers` | List all members of a group. |
|
|
| 413 | `RotateKeys` | Trigger a server-assisted key rotation event. |
|
|
|
|
### User / Identity (500-501)
|
|
|
|
| ID | Method | Description |
|
|
|-----|-------------------|-------------|
|
|
| 500 | `ResolveUser` | Resolve a username to an Ed25519 public key. |
|
|
| 501 | `ResolveIdentity` | Resolve an identity key to user profile information. |
|
|
|
|
### Key Transparency (510-520)
|
|
|
|
| ID | Method | Description |
|
|
|-----|--------------------------|-------------|
|
|
| 510 | `RevokeKey` | Append a key revocation record to the transparency log. |
|
|
| 511 | `CheckRevocation` | Check whether a given key has been revoked. |
|
|
| 520 | `AuditKeyTransparency` | Fetch a transparency log audit proof for a key. |
|
|
|
|
### Blob Storage (600-601)
|
|
|
|
| ID | Method | Description |
|
|
|-----|----------------|-------------|
|
|
| 600 | `UploadBlob` | Store a binary blob (file attachment, avatar, etc.). Returns a content-addressed blob ID. |
|
|
| 601 | `DownloadBlob` | Retrieve a blob by ID. |
|
|
|
|
### Device Management (700-710)
|
|
|
|
| ID | Method | Description |
|
|
|-----|-----------------------|-------------|
|
|
| 700 | `RegisterDevice` | Register a new device for a user account. |
|
|
| 701 | `ListDevices` | List all registered devices for the authenticated user. |
|
|
| 702 | `RevokeDevice` | Revoke a device, invalidating its session. |
|
|
| 710 | `RegisterPushToken` | Register a push notification token (APNs / FCM) for a device. |
|
|
|
|
### Recovery (750-752)
|
|
|
|
| ID | Method | Description |
|
|
|-----|-------------------------|-------------|
|
|
| 750 | `StoreRecoveryBundle` | Encrypt and store an account recovery bundle server-side. |
|
|
| 751 | `FetchRecoveryBundle` | Retrieve the recovery bundle (requires OPAQUE re-authentication). |
|
|
| 752 | `DeleteRecoveryBundle` | Delete the stored recovery bundle. |
|
|
|
|
### P2P and Health (800-802)
|
|
|
|
| ID | Method | Description |
|
|
|-----|--------------------|-------------|
|
|
| 800 | `PublishEndpoint` | Publish a direct P2P endpoint (iroh node address). |
|
|
| 801 | `ResolveEndpoint` | Resolve a peer's P2P endpoint by identity key. |
|
|
| 802 | `Health` | Liveness/readiness probe. Returns server uptime and status. |
|
|
|
|
### Federation (900-905)
|
|
|
|
| ID | Method | Description |
|
|
|-----|-------------------------|-------------|
|
|
| 900 | `RelayEnqueue` | Relay a single message to a user on another server. |
|
|
| 901 | `RelayBatchEnqueue` | Relay multiple messages in one request. |
|
|
| 902 | `ProxyFetchKeyPackage` | Fetch a KeyPackage from a remote server on behalf of a local client. |
|
|
| 903 | `ProxyFetchHybridKey` | Fetch a hybrid public key from a remote server. |
|
|
| 904 | `ProxyResolveUser` | Resolve a username on a remote server. |
|
|
| 905 | `FederationHealth` | Check health of the federation link to another server. |
|
|
|
|
### Moderation (420-424)
|
|
|
|
| ID | Method | Description |
|
|
|-----|----------------|-------------|
|
|
| 420 | `ReportMessage` | Submit a content moderation report. |
|
|
| 421 | `BanUser` | Ban a user from a channel or server-wide. |
|
|
| 422 | `UnbanUser` | Lift a ban. |
|
|
| 423 | `ListReports` | List pending moderation reports (admin only). |
|
|
| 424 | `ListBanned` | List banned users (admin only). |
|
|
|
|
### Account (950)
|
|
|
|
| ID | Method | Description |
|
|
|-----|-----------------|-------------|
|
|
| 950 | `DeleteAccount` | Permanently delete the authenticated account and all associated data. |
|
|
|
|
---
|
|
|
|
## Per-Connection Lifecycle
|
|
|
|
Each incoming QUIC connection follows this sequence:
|
|
|
|
```text
|
|
Client Server
|
|
------ ------
|
|
1. UDP QUIC INITIAL ->
|
|
|
|
2. <- QUIC HANDSHAKE
|
|
TLS 1.3 ServerHello +
|
|
Certificate (self-signed)
|
|
ALPN: "qpc"
|
|
|
|
3. Client verifies server cert against
|
|
pinned CA cert (--ca-cert flag)
|
|
|
|
4. QUIC connection established
|
|
|
|
5. Per RPC call:
|
|
Client opens bidirectional stream
|
|
Client writes RequestFrame:
|
|
[method_id: u16][req_id: u32][len: u32][protobuf]
|
|
Client marks end-of-write
|
|
|
|
6. Server reads RequestFrame
|
|
Server dispatches to handler by method_id
|
|
Handler processes, writes ResponseFrame:
|
|
[status: u8][req_id: u32][len: u32][protobuf]
|
|
|
|
7. For push events (server -> client):
|
|
Server opens uni-stream
|
|
Server writes PushFrame:
|
|
[event_type: u16][len: u32][protobuf]
|
|
|
|
8. Multiple RPCs run concurrently
|
|
(each on its own stream)
|
|
```
|
|
|
|
### Concurrency model
|
|
|
|
Unlike the v1 Cap'n Proto RPC (which was `!Send` due to `Rc<RefCell<>>`
|
|
internals and required `LocalSet`), the v2 RPC framework uses `Arc`-based
|
|
shared state and spawns each handler with `tokio::spawn`. The server can
|
|
handle many concurrent requests per connection without a `LocalSet`.
|
|
|
|
---
|
|
|
|
## Status Codes
|
|
|
|
Response frames carry a `status: u8` field:
|
|
|
|
| Value | Status | Meaning |
|
|
|-------|------------------|---------|
|
|
| 0 | `Ok` | Success |
|
|
| 1 | `BadRequest` | Malformed request or missing required field |
|
|
| 2 | `Unauthorized` | Missing or invalid session token |
|
|
| 3 | `Forbidden` | Valid token but insufficient permissions |
|
|
| 4 | `NotFound` | Requested resource does not exist |
|
|
| 5 | `RateLimited` | Request rate limit exceeded; retry after backoff |
|
|
| 8 | `DeadlineExceeded` | Request timed out on the server |
|
|
| 9 | `Unavailable` | Server temporarily unable to serve the request |
|
|
| 10 | `Internal` | Unexpected server error |
|
|
| 11 | `UnknownMethod` | The requested method_id is not registered |
|
|
|
|
---
|
|
|
|
## Authentication Flow
|
|
|
|
OPAQUE (RFC-compliant asymmetric PAKE) prevents the password from reaching
|
|
the server in any form:
|
|
|
|
```text
|
|
Client Server
|
|
| |
|
|
| OpaqueRegisterStart(100): |
|
|
| username, registration_request |
|
|
| --------------------------------->|
|
|
| |
|
|
| registration_response |
|
|
| <---------------------------------|
|
|
| |
|
|
| OpaqueRegisterFinish(101): |
|
|
| username, upload, identity_key |
|
|
| --------------------------------->|
|
|
| |
|
|
| success |
|
|
| <---------------------------------|
|
|
| |
|
|
| OpaqueLoginStart(102): |
|
|
| username, login_request |
|
|
| --------------------------------->|
|
|
| |
|
|
| login_response |
|
|
| <---------------------------------|
|
|
| |
|
|
| OpaqueLoginFinish(103): |
|
|
| username, finalization, |
|
|
| identity_key |
|
|
| --------------------------------->|
|
|
| |
|
|
| session_token |
|
|
| <---------------------------------|
|
|
```
|
|
|
|
The `session_token` is then passed in subsequent Protobuf requests. The server
|
|
validates it on every authenticated method call.
|
|
|
|
---
|
|
|
|
## Configuration
|
|
|
|
| Flag | Env var | Default | Description |
|
|
|----------------|----------------------------|------------------------|-------------|
|
|
| `--listen` | `QPC_LISTEN` | `0.0.0.0:5001` | QUIC listen address (host:port). |
|
|
| `--data-dir` | `QPC_DATA_DIR` | `data` | Directory for persisted state. |
|
|
| `--tls-cert` | `QPC_TLS_CERT` | `data/server-cert.der` | Path to TLS certificate (DER). Auto-generated if missing. |
|
|
| `--tls-key` | `QPC_TLS_KEY` | `data/server-key.der` | Path to TLS private key (DER). Auto-generated if missing. |
|
|
|
|
Logging level is controlled by the `RUST_LOG` environment variable (default: `info`).
|
|
|
|
---
|
|
|
|
## Further Reading
|
|
|
|
- [Architecture Overview](overview.md) -- two-service model and system diagram
|
|
- [End-to-End Data Flow](data-flow.md) -- sequence diagrams for registration, group creation, and messaging
|
|
- [Protobuf Framing](../protocol-layers/capn-proto.md) -- frame format details and method ID constants
|
|
- [Wire Format Reference](../wire-format/overview.md) -- full Protobuf schema documentation
|