Module Map
DraftThis is the developer’s first stop. It maps every Capsule workspace crate and module to the design doc(s) that govern its behavior, and to the validation tier (Unit / Smoke / E2E — see Validation Tiers) it ships with. The E2E test surface at the bottom is bounded: adding a test there means adding the test to the relevant doc’s Validation section and justifying why the cross-module surface is irreducible.
The mapping reflects the design intent. Modules not yet implemented are annotated (planned) — or (blocked) where a named upstream dependency gates them — per the status convention; every unannotated module exists in the codebase today. The repo-root SLICES.md indexes the planned modules as executable implementation slices.
Crate Roster
Section titled “Crate Roster”| Crate | Purpose |
|---|---|
capsule-core | Shared logic across server and clients: cryptography, library layout, import pipeline, metadata, ML orchestration |
capsule-sdk | Client SDK: the sanctioned network path (auth/session + token refresh, upload protocol, sync, LAN-peering glue); typed REST client generated by spargen from OpenAPI 3.1 (in development) |
capsule-core-ffi | uniffi bindings crate for native Swift/Kotlin consumers (sidecar Catalog surface; the HardwareSigner foreign trait ships under capsule-core’s ffi feature) |
capsule-api | Server entry-point + routing |
capsule-api-auth | Authentication, sessions, OIDC, device directory |
capsule-api-library | Legacy GraphQL API for UI queries — frozen and retiring; rich queries move client-side onto library.sqlite (see API Surfaces) |
capsule-api-upload | TUS-like resumable upload protocol server |
capsule-api-media | Media serving (ciphertext blobs, public shares) |
capsule-api-sync | gRPC sync API + federation |
capsule-api-service | Higher-level service layer over the entity model (album, asset, friendship, passkey, stack, user, quota) |
capsule-api-entity | Sea-ORM entities (Postgres schema) |
capsule-api-model | Business-logic models on top of entities |
capsule-api-migration | Sea-ORM migrations |
capsule-api-environment | Configuration, env vars, feature flags |
capsule-api-testing | Shared test utilities (testcontainer setup, schema fixtures) |
capsule-cli | Command-line client |
capsule-i18n | Runtime localization (locale negotiation + ICU message formatting) for the server and CLI |
capsule-web | Browser/WASM web-upload client: guest drop sealing + upload (planned) |
capsule-vision | Python research package for on-device ML experimentation (not a cargo crate) |
Native app and harness packages — capsule-android, capsule-swift, capsule-core-swift, capsule-core-kotlin — are not cargo crates and carry no design owner of their own; the two harness packages hold the per-platform HardwareSigner reference adapters (Keys — Device Keys).
Module → Design Doc
Section titled “Module → Design Doc”capsule-core
Section titled “capsule-core”| Module | Owning design doc | Validation tier |
|---|---|---|
crypto::primitives | Cryptography — Primitives | Unit (RFC vectors) |
crypto::keys | Cryptography — Keys, Device Enrollment | Unit + Smoke (hardware per-platform) |
crypto::authority | Cryptography — Keys: Write Authority Interface | Unit (epoch-ledger round-trip) |
crypto::mls (blocked upstream — see the MLS status note) | Cryptography — MLS, MLS Resilience | Unit + Smoke (protocol round-trip) |
crypto::encryption | Cryptography — Encryption | Unit (KAT, round-trip) |
crypto::provenance | Cryptography — Provenance | Unit (exhaustive negative cases) + Smoke |
crypto::verify_asset | Cryptography — Write Authorization | Unit (the single chokepoint; exhaustive) |
validation | Threat Model — Validation | Unit (pure key-free invariants) |
cbor | Metadata — Canonical CBOR | Unit (RFC 8949 §4.2 vectors) |
lifecycle | Filesystem — Client, Import — Pipeline | Unit + Smoke (capsule demo end-to-end) |
backup | Backup and Recovery | Unit + Smoke |
library::{init,open,rebuild,lock,paths,scrub,trash} | Filesystem — Client, Filesystem — Maintenance | Unit + Smoke |
import::{scanner,planner,executor,plan,upload,group,progress,special} (streaming upload loop planned) | Import — Pipeline | Unit (planner determinism) + Smoke (executor) |
metadata::{file,filter,types} | Metadata | Unit (filtering) |
sidecar::* | Metadata — Sidecar Schema | Unit (serde determinism) |
exif::{extract,timezone} | Metadata | Unit |
db::{driver,schema,rows} | Filesystem — Client | Unit (SQLite ops) |
domain::* (enums) | Organization, Authorization, Metadata | Unit (closed-enum rejection) |
models::* | Metadata, Import — Pipeline | Unit |
ml (planned) | AI/ML Integrations | Unit + Smoke (inference parity per-platform) |
sharing (planned) | Share Links | Unit |
drop (planned) | Web Upload | Unit (seal round-trip + adoption rewrap) |
capsule-sdk
Section titled “capsule-sdk”| Module | Owning design doc | Validation tier |
|---|---|---|
| (auto-generated client) | Clients | Smoke (re-generated; not unit-tested) |
upload (client stub) | Import — Upload Protocol | Unit + Smoke (client side) |
peering (planned) | Peering | Unit + Smoke per platform |
Hardware-key adapters do not live in capsule-sdk: the Signer/HardwareSigner seams and the software + TPM reference adapters are in capsule-core::crypto::keys, and the Secure Enclave / StrongBox adapters live in the capsule-core-swift / capsule-core-kotlin harness packages (see Keys — Device Keys).
capsule-api (root + sub-crates)
Section titled “capsule-api (root + sub-crates)”| Module | Owning design doc | Validation tier |
|---|---|---|
capsule-api (routing) | Filesystem — Server | Smoke |
capsule-api-auth::{oidc,session,claims,roles} | Authentication, Authorization | Unit + Smoke (testcontainer Postgres/Valkey) |
capsule-api-auth::devices (planned for enrollment) | Device Enrollment | Smoke |
capsule-api-library::schema::* (legacy, retiring) | API Surfaces | frozen (no new surface) |
capsule-api-library::loaders (legacy, retiring) | API Surfaces | frozen (no new surface) |
capsule-api-upload | Import — Upload Protocol | Unit + Smoke + 1 E2E |
capsule-api-upload::ops (planned) | Authorization, Threat Model — Validation | Unit + Smoke (+ E2E case 7) |
capsule-api-media::routes | Filesystem — Server, Thumbnails | Smoke |
capsule-api-media::verify (planned) | Import — Storage Verification | Unit + Smoke |
capsule-api-media::shares (planned) | Share Links | Unit + Smoke |
capsule-api-media::drops (planned) | Web Upload | Unit + Smoke |
capsule-api-sync (sync feed) | Import — Download & Sync | Unit + Smoke + 1 E2E |
capsule-api-sync::federation | Federation | Unit + Smoke + 1 E2E |
capsule-api-service::album | Organization | Unit |
capsule-api-service::asset | Authorization, Organization | Unit + Smoke |
capsule-api-service::quota (planned) | Quota | Unit |
capsule-api::moderation (planned) | Moderation | Smoke |
capsule-api-entity::* (Sea-ORM) | Filesystem — Server | Unit (Sea-ORM CRUD) |
capsule-api-migration | Versioning (forward-only migrations) | Smoke (migration run) |
capsule-api-environment | (configuration; no design owner) | Unit |
capsule-api-testing | (test utilities; no design owner) | n/a |
capsule-cli, capsule-i18n, capsule-web
Section titled “capsule-cli, capsule-i18n, capsule-web”| Crate | Owning design doc | Validation tier |
|---|---|---|
capsule-cli | Clients (treats CLI as a client) | Smoke |
capsule-core::media (behind the non-default media feature) | Thumbnails and Previews (decode/encode utilities; only JPEG decode is implemented today) | Unit |
capsule-i18n | Internationalization | Unit + Smoke |
capsule-web | Web Upload, Clients | Smoke (browser/WASM) |
Design Doc → Module (Reverse Lookup)
Section titled “Design Doc → Module (Reverse Lookup)”Navigation from a design doc back to where the code lives.
| Design doc | Implementing modules |
|---|---|
| Principles | (meta — no specific code module) |
| Cryptography — Primitives | capsule-core::crypto::primitives |
| Cryptography — Keys | capsule-core::crypto::keys (Signer/HardwareSigner seams; software + TPM reference adapters; Secure Enclave / StrongBox adapters in capsule-core-swift/-kotlin; P-256 hybrid-DSK variant planned) |
| Cryptography — Keys: Write Authority Interface | capsule-core::crypto::authority (AlbumAuthority trait + ReferenceAuthority epoch ledger; OpenMlsAuthority blocked with MLS) |
| Cryptography — MLS | capsule-core::crypto::mls (blocked upstream; see the MLS status note) |
| Cryptography — Encryption | capsule-core::crypto::encryption |
| Cryptography — Provenance | capsule-core::crypto::provenance + verify_asset chokepoint |
| Cryptography — Failure Modes | Cross-cutting: capsule-core::backup, capsule-core::library, capsule-core::crypto::* |
| MLS Resilience | capsule-core::crypto::mls (extends main MLS module; blocked with it) |
| Device Enrollment | capsule-core::crypto::keys, capsule-api-auth::devices |
| Authentication | capsule-api-auth::{oidc,session,claims} |
| Authorization | capsule-api-auth::roles, capsule-core::crypto::provenance (verify_asset), capsule-api-upload::ops (lifecycle-write surface, planned) |
| Clients | capsule-sdk + per-platform native code |
| Internationalization | capsule-i18n (runtime) + xtask::i18n (codegen) + locales/ source + per-platform generated catalogs |
| Versioning | Cross-cutting: capsule-api (header enforcement), capsule-core::crypto::mls (upgrade ceremony), capsule-api-migration |
| Backup and Recovery | capsule-core::backup, capsule-api-auth (escrow surface, planned) |
| Metadata | capsule-core::{metadata,sidecar,exif}, capsule-api-library::schema |
| Filesystem — Server | capsule-api, capsule-api-entity, blob store glue |
| Filesystem — Client | capsule-core::{library,db}, per-platform native code |
| Filesystem — Maintenance | capsule-core::library::{scrub,rebuild,trash}, server-side scrub in capsule-api-upload |
| Import — Pipeline | capsule-core::import::*; the streaming import-upload loop, the capsule-core::library::available_bytes free-space probe, and the import::importers third-party source adapters are planned |
| Import — Camera Import | capsule-core::import::camera (planned, post-v1) over the gated in-house ptpip-rs crate |
| Import — Upload Protocol | capsule-sdk::upload (client) + capsule-api-upload (server) |
| Import — Download & Sync | capsule-sdk (client) + capsule-api-sync (server) |
| Import — Storage Verification | capsule-api-media::verify (route) + capsule-sdk (client) + capsule-core (verify-before-destroy predicate) |
| Federation | capsule-api-sync::federation |
| Peering | capsule-sdk::peering (planned) + capsule-core::backup (artifact format) |
| Organization | capsule-core::domain::stack_type, capsule-api-service::{album,stack} |
| AI/ML Integrations | capsule-core::ml (planned), capsule-vision (Python research), model registry + per-platform inference runners |
| Thumbnails | Client-side gen in capsule-sdk (planned) over capsule_core::media decode/encode utilities + serving in capsule-api-media |
| Share Links | capsule-core::sharing (planned), capsule-api-media::shares (planned) |
| Web Upload | capsule-core::drop (planned), capsule-api-media::drops (planned), capsule-web (planned); reuses capsule-api-upload for drop chunks |
| Moderation | capsule-api::moderation (planned) |
| Quota | capsule-api-service::quota (planned) |
| Threat Model | Enforced across every validation chokepoint: capsule-core::crypto::verify_asset (client), capsule-api validators (server) |
| Threat Model — Scenarios | (catalog; each row maps to the owner doc’s module) |
| Threat Model — Validation | capsule-api envelope checks (server-side), capsule-core::crypto::verify_asset (client-side) |
| Threat Model — Schema Rules | capsule-core::crypto decoders + capsule-api validators (closed-enum + Postel asymmetry) |
E2E Test Surface
Section titled “E2E Test Surface”The bounded global list of cross-module integration tests. Editing this list requires updating the relevant doc’s Validation section. Adding an E2E case past this list is a signal the design has unwanted coupling worth examining before adding the test.
Target count: ≤ 13 cases. Each one is named by what it proves — not “test X” but “X works through Y and Z.”
Status: none of the 13 cases is runnable today — every one crosses at least one planned surface (the networked server/client wiring, MLS, or ML), even where its capsule-core half is implemented and unit/smoke-tested. The bound starts governing with the first implementation slice that makes a case live; until then this list is the contract the slices build toward.
- Auth → sync → client-side library query. Log in via OIDC → access token → gRPC
Syncreturns the account’s album entries → the client applies them and a locallibrary.sqlitequery lists the expected albums (rich queries are client-side per API Surfaces). Coverscapsule-api-auth::oidc + session×capsule-api-sync×capsule-core::library. Made live by sliceS-D5. - Full import + upload + finalize. Local scan → plan → execute → upload session → finalize → blob present at
blobs/{hash}+ index row marked uploaded. Coverscapsule-core::import×capsule-sdk::upload×capsule-api-upload×capsule-api-entity. - Sync feed pickup. Upload from device A → device B’s sync feed advances → device B fetches metadata blob and (per scope) the original. Covers
capsule-api-sync×capsule-sdkdownload path ×capsule-core::librarywrite. - Federation cross-server pull. Alice on
home.tldshares to Bob onother.tld→ capability token → Bob’s server pulls metadata + blobs → Bob’s client renders. Coverscapsule-api-sync::federation(both sides) ×capsule-api-auth(capability issue). - LAN peering A→B. Two devices on the same LAN; mDNS discovery → TLS handshake → delta-scoped artifact → restore on receiver → byte-equal libraries. Covers
capsule-sdk::peering×capsule-core::backup×capsule-core::library. - Backup → restore on a fresh device. Export full backup → bootstrap new device via passphrase + escrow → import backup → assert every asset present and verifiable. Covers
capsule-core::backup×capsule-core::crypto::keys×capsule-core::library. Made live by sliceS-C12(the escrow surface — the core halves already ship). - Full lifecycle. Create → metadata-update → trash → restore → re-delete → hard-purge after retention. Provenance chain advances through every transition; server refuses purge before
retention_until. Coverscapsule-api-upload::ops(lifecycle-write surface) ×capsule-core::crypto::provenance× server purge worker. Made live by slicesS-C16+S-C11(withS-D2). - Album upgrade ceremony. Multi-member album; admin initiates upgrade → quiesce → drain → tombstone → fork → queued writes replay. Includes one resume-from-crash mid-ceremony. Covers
capsule-core::crypto::mls×capsule-api× client UI. - Cross-version protocol gate. Client with
protocol_versionoutside server’s range attempts upload; receives426; UI surfaces actionable error. Coverscapsule-apihandshake ×capsule-sdkerror handling. Made live by sliceS-D1(its426abort-with-upgrade recovery path). - Model regen after version bump. Bump canonical model version; assert stale embeddings excluded from queries; background regen produces fresh embeddings; queries return correct results post-regen. Covers
capsule-core::ml×capsule-core::dbvector index. - Server crash mid-finalization. Inject crash between blob rename and Postgres transaction commit; restart; assert session moves to
FailedProcessingcleanly, no orphaned blob, no zombie pending row. Coverscapsule-api-upload×capsule-api-entity×capsule-api’s startup scrub. - Cross-device enrollment. Existing device A authorizes new device B over a verified channel (enrollment code + safety-code check) → B generates hardware keys → A cross-signs B into the device directory → B joins each album’s MLS group → B’s library matches A’s. Includes one MITM-on-relay abort. Covers
capsule-api-auth::devices×capsule-core::crypto::keys×capsule-sdk::hardware-keys. - Web drop → adopt. A browser/WASM web client seals a drop to an upload link → the provisioning user’s native client decapsulates, rewraps the key under the album AMK, and adopts it in place → the asset appears in the library and
verify_asset-accepts on a second device. The only case exercising the web/WASM client and the wrapped-key path. Coverscapsule-web×capsule-api-media::drops×capsule-core::drop×capsule-api-upload(drop chunks) ×capsule-core::crypto(rewrap +verify_asset) ×capsule-core::library.
Using This Map
Section titled “Using This Map”- When implementing a module: find it in Module → Design Doc, open the owning doc, read the contracts and the validation tier expectations. The unit + smoke surface defined in that doc should be authorable without leaving the module.
- When adding a feature: find the relevant design doc via the reverse lookup; confirm the feature fits within an existing module’s scope or warrants a new one. If new, add a row here.
- When considering an E2E test: check this list first. If your proposed test isn’t here, either it’s an existing case in disguise (use that), or the design has cross-module coupling worth surfacing — discuss before adding.