Skip to content

Module Map

Draft

This 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.

CratePurpose
capsule-coreShared logic across server and clients: cryptography, library layout, import pipeline, metadata, ML orchestration
capsule-sdkClient 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-ffiuniffi bindings crate for native Swift/Kotlin consumers (sidecar Catalog surface; the HardwareSigner foreign trait ships under capsule-core’s ffi feature)
capsule-apiServer entry-point + routing
capsule-api-authAuthentication, sessions, OIDC, device directory
capsule-api-libraryLegacy GraphQL API for UI queries — frozen and retiring; rich queries move client-side onto library.sqlite (see API Surfaces)
capsule-api-uploadTUS-like resumable upload protocol server
capsule-api-mediaMedia serving (ciphertext blobs, public shares)
capsule-api-syncgRPC sync API + federation
capsule-api-serviceHigher-level service layer over the entity model (album, asset, friendship, passkey, stack, user, quota)
capsule-api-entitySea-ORM entities (Postgres schema)
capsule-api-modelBusiness-logic models on top of entities
capsule-api-migrationSea-ORM migrations
capsule-api-environmentConfiguration, env vars, feature flags
capsule-api-testingShared test utilities (testcontainer setup, schema fixtures)
capsule-cliCommand-line client
capsule-i18nRuntime localization (locale negotiation + ICU message formatting) for the server and CLI
capsule-webBrowser/WASM web-upload client: guest drop sealing + upload (planned)
capsule-visionPython 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).

ModuleOwning design docValidation tier
crypto::primitivesCryptography — PrimitivesUnit (RFC vectors)
crypto::keysCryptography — Keys, Device EnrollmentUnit + Smoke (hardware per-platform)
crypto::authorityCryptography — Keys: Write Authority InterfaceUnit (epoch-ledger round-trip)
crypto::mls (blocked upstream — see the MLS status note)Cryptography — MLS, MLS ResilienceUnit + Smoke (protocol round-trip)
crypto::encryptionCryptography — EncryptionUnit (KAT, round-trip)
crypto::provenanceCryptography — ProvenanceUnit (exhaustive negative cases) + Smoke
crypto::verify_assetCryptography — Write AuthorizationUnit (the single chokepoint; exhaustive)
validationThreat Model — ValidationUnit (pure key-free invariants)
cborMetadata — Canonical CBORUnit (RFC 8949 §4.2 vectors)
lifecycleFilesystem — Client, Import — PipelineUnit + Smoke (capsule demo end-to-end)
backupBackup and RecoveryUnit + Smoke
library::{init,open,rebuild,lock,paths,scrub,trash}Filesystem — Client, Filesystem — MaintenanceUnit + Smoke
import::{scanner,planner,executor,plan,upload,group,progress,special} (streaming upload loop planned)Import — PipelineUnit (planner determinism) + Smoke (executor)
metadata::{file,filter,types}MetadataUnit (filtering)
sidecar::*Metadata — Sidecar SchemaUnit (serde determinism)
exif::{extract,timezone}MetadataUnit
db::{driver,schema,rows}Filesystem — ClientUnit (SQLite ops)
domain::* (enums)Organization, Authorization, MetadataUnit (closed-enum rejection)
models::*Metadata, Import — PipelineUnit
ml (planned)AI/ML IntegrationsUnit + Smoke (inference parity per-platform)
sharing (planned)Share LinksUnit
drop (planned)Web UploadUnit (seal round-trip + adoption rewrap)
ModuleOwning design docValidation tier
(auto-generated client)ClientsSmoke (re-generated; not unit-tested)
upload (client stub)Import — Upload ProtocolUnit + Smoke (client side)
peering (planned)PeeringUnit + 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).

ModuleOwning design docValidation tier
capsule-api (routing)Filesystem — ServerSmoke
capsule-api-auth::{oidc,session,claims,roles}Authentication, AuthorizationUnit + Smoke (testcontainer Postgres/Valkey)
capsule-api-auth::devices (planned for enrollment)Device EnrollmentSmoke
capsule-api-library::schema::* (legacy, retiring)API Surfacesfrozen (no new surface)
capsule-api-library::loaders (legacy, retiring)API Surfacesfrozen (no new surface)
capsule-api-uploadImport — Upload ProtocolUnit + Smoke + 1 E2E
capsule-api-upload::ops (planned)Authorization, Threat Model — ValidationUnit + Smoke (+ E2E case 7)
capsule-api-media::routesFilesystem — Server, ThumbnailsSmoke
capsule-api-media::verify (planned)Import — Storage VerificationUnit + Smoke
capsule-api-media::shares (planned)Share LinksUnit + Smoke
capsule-api-media::drops (planned)Web UploadUnit + Smoke
capsule-api-sync (sync feed)Import — Download & SyncUnit + Smoke + 1 E2E
capsule-api-sync::federationFederationUnit + Smoke + 1 E2E
capsule-api-service::albumOrganizationUnit
capsule-api-service::assetAuthorization, OrganizationUnit + Smoke
capsule-api-service::quota (planned)QuotaUnit
capsule-api::moderation (planned)ModerationSmoke
capsule-api-entity::* (Sea-ORM)Filesystem — ServerUnit (Sea-ORM CRUD)
capsule-api-migrationVersioning (forward-only migrations)Smoke (migration run)
capsule-api-environment(configuration; no design owner)Unit
capsule-api-testing(test utilities; no design owner)n/a
CrateOwning design docValidation tier
capsule-cliClients (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-i18nInternationalizationUnit + Smoke
capsule-webWeb Upload, ClientsSmoke (browser/WASM)

Navigation from a design doc back to where the code lives.

Design docImplementing modules
Principles(meta — no specific code module)
Cryptography — Primitivescapsule-core::crypto::primitives
Cryptography — Keyscapsule-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 Interfacecapsule-core::crypto::authority (AlbumAuthority trait + ReferenceAuthority epoch ledger; OpenMlsAuthority blocked with MLS)
Cryptography — MLScapsule-core::crypto::mls (blocked upstream; see the MLS status note)
Cryptography — Encryptioncapsule-core::crypto::encryption
Cryptography — Provenancecapsule-core::crypto::provenance + verify_asset chokepoint
Cryptography — Failure ModesCross-cutting: capsule-core::backup, capsule-core::library, capsule-core::crypto::*
MLS Resiliencecapsule-core::crypto::mls (extends main MLS module; blocked with it)
Device Enrollmentcapsule-core::crypto::keys, capsule-api-auth::devices
Authenticationcapsule-api-auth::{oidc,session,claims}
Authorizationcapsule-api-auth::roles, capsule-core::crypto::provenance (verify_asset), capsule-api-upload::ops (lifecycle-write surface, planned)
Clientscapsule-sdk + per-platform native code
Internationalizationcapsule-i18n (runtime) + xtask::i18n (codegen) + locales/ source + per-platform generated catalogs
VersioningCross-cutting: capsule-api (header enforcement), capsule-core::crypto::mls (upgrade ceremony), capsule-api-migration
Backup and Recoverycapsule-core::backup, capsule-api-auth (escrow surface, planned)
Metadatacapsule-core::{metadata,sidecar,exif}, capsule-api-library::schema
Filesystem — Servercapsule-api, capsule-api-entity, blob store glue
Filesystem — Clientcapsule-core::{library,db}, per-platform native code
Filesystem — Maintenancecapsule-core::library::{scrub,rebuild,trash}, server-side scrub in capsule-api-upload
Import — Pipelinecapsule-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 Importcapsule-core::import::camera (planned, post-v1) over the gated in-house ptpip-rs crate
Import — Upload Protocolcapsule-sdk::upload (client) + capsule-api-upload (server)
Import — Download & Synccapsule-sdk (client) + capsule-api-sync (server)
Import — Storage Verificationcapsule-api-media::verify (route) + capsule-sdk (client) + capsule-core (verify-before-destroy predicate)
Federationcapsule-api-sync::federation
Peeringcapsule-sdk::peering (planned) + capsule-core::backup (artifact format)
Organizationcapsule-core::domain::stack_type, capsule-api-service::{album,stack}
AI/ML Integrationscapsule-core::ml (planned), capsule-vision (Python research), model registry + per-platform inference runners
ThumbnailsClient-side gen in capsule-sdk (planned) over capsule_core::media decode/encode utilities + serving in capsule-api-media
Share Linkscapsule-core::sharing (planned), capsule-api-media::shares (planned)
Web Uploadcapsule-core::drop (planned), capsule-api-media::drops (planned), capsule-web (planned); reuses capsule-api-upload for drop chunks
Moderationcapsule-api::moderation (planned)
Quotacapsule-api-service::quota (planned)
Threat ModelEnforced 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 — Validationcapsule-api envelope checks (server-side), capsule-core::crypto::verify_asset (client-side)
Threat Model — Schema Rulescapsule-core::crypto decoders + capsule-api validators (closed-enum + Postel asymmetry)

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.

  1. Auth → sync → client-side library query. Log in via OIDC → access token → gRPC Sync returns the account’s album entries → the client applies them and a local library.sqlite query lists the expected albums (rich queries are client-side per API Surfaces). Covers capsule-api-auth::oidc + session × capsule-api-sync × capsule-core::library. Made live by slice S-D5.
  2. Full import + upload + finalize. Local scan → plan → execute → upload session → finalize → blob present at blobs/{hash} + index row marked uploaded. Covers capsule-core::import × capsule-sdk::upload × capsule-api-upload × capsule-api-entity.
  3. 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-sdk download path × capsule-core::library write.
  4. Federation cross-server pull. Alice on home.tld shares to Bob on other.tld → capability token → Bob’s server pulls metadata + blobs → Bob’s client renders. Covers capsule-api-sync::federation (both sides) × capsule-api-auth (capability issue).
  5. 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.
  6. 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 slice S-C12 (the escrow surface — the core halves already ship).
  7. 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. Covers capsule-api-upload::ops (lifecycle-write surface) × capsule-core::crypto::provenance × server purge worker. Made live by slices S-C16 + S-C11 (with S-D2).
  8. 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.
  9. Cross-version protocol gate. Client with protocol_version outside server’s range attempts upload; receives 426; UI surfaces actionable error. Covers capsule-api handshake × capsule-sdk error handling. Made live by slice S-D1 (its 426 abort-with-upgrade recovery path).
  10. 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::db vector index.
  11. Server crash mid-finalization. Inject crash between blob rename and Postgres transaction commit; restart; assert session moves to FailedProcessing cleanly, no orphaned blob, no zombie pending row. Covers capsule-api-upload × capsule-api-entity × capsule-api’s startup scrub.
  12. 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.
  13. 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. Covers capsule-web × capsule-api-media::drops × capsule-core::drop × capsule-api-upload (drop chunks) × capsule-core::crypto (rewrap + verify_asset) × capsule-core::library.
  • 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.