Skip to content

Architecture

QenTerra edited this page Jul 29, 2026 · 2 revisions

Architecture

Unspool separates presentation, domain rules, Telegram transport, persistence, credentials, and filesystem mutations. SwiftUI views render observable state and send intents; they do not call TDLib, Keychain, or mutating filesystem APIs directly.

flowchart LR
    V["SwiftUI Features"] -->|"intents"| A["AppModel<br/>@MainActor"]
    A --> S["SetupModel<br/>@MainActor"]
    A --> H["AttachmentHistoryService<br/>actor"]
    A --> D["DownloadCoordinator<br/>actor"]
    A --> P["Persistence actors"]
    S --> K["KeychainCredentialStore<br/>actor"]
    S --> T["TelegramSessionController<br/>actor"]
    H --> C["TDLibClient<br/>actor"]
    D --> C
    T --> C
    C --> R["TDLibReceiveLoop"]
    R --> B["TDLibBridge<br/>C++"]
    B --> L["TDLib / Telegram"]
    D --> F["DestinationAccess<br/>actor"]
    F --> U["User-selected folder"]
Loading

Presentation layer

UnspoolRootView selects setup or the three-destination application shell. Feature views are grouped into:

  • Setup;
  • Browse;
  • Downloads;
  • Settings;
  • Shared components and design-system primitives.

AppModel is the main-actor application orchestrator. Extensions separate:

  • attachments and selection;
  • downloads and recovery;
  • runtime lifecycle;
  • presentation-derived properties and product error copy.

SetupModel owns setup progress and delegates account-state input to AuthorizationCoordinator.

Domain layer

Domain values encode behavior without importing SwiftUI or TDLib:

  • TelegramAttachment and AttachmentIdentity;
  • filename value and provenance;
  • categories, filters, sort, and selection;
  • scan limits;
  • credentials and validation errors;
  • preflight, conflicts, progress, outcomes, history, and pending batches.

These are predominantly immutable value types and conform to Sendable when they cross actor boundaries.

Infrastructure layer

TDLib

Owns JSON request/response correlation, receive ordering, authorization, connection state, chat updates, pagination, and attachment mapping.

Downloads

Owns destination planning, capacity, safe path construction, TDLib file download, bounded scheduling, cancellation, and atomic placement.

Persistence

Actor-backed JSON stores provide cached chats, attachment snapshots, download history, and interrupted-batch recovery.

Security

The Keychain actor stores the Telegram API credential pair.

Dependency injection

Production types accept protocols or concrete dependencies in initializers. Tests replace TDLib transport, session service, stores, preferences, and destination roots with deterministic fakes or temporary files.

Preview fixtures are activated only through an explicit preview/UI-test environment. Ordinary app launches construct the live Telegram environment.

Source-of-truth rules

  • project.yml defines targets, settings, entitlements, and source membership.
  • Unspool.xcodeproj is generated and committed for convenience.
  • Domain and infrastructure code define runtime behavior.
  • Regression tests protect important invariants.
  • Documentation explains those sources but does not override them.

Continue with TDLib Integration, Concurrency, Cancellation, and Errors, and Codebase Map.

Clone this wiki locally