Skip to content

Architecture Overview

Chris Funderburg edited this page Oct 1, 2026 · 1 revision

A short map of how Bòcan is built, for people who want to read or change the code. The detail is in the main repository; this page tells you where to look.

The shape of the app

Bòcan is a native Swift 6 app with strict concurrency. The app target (App/) is thin. Almost all the code is in twelve Swift packages under Modules/, and each package has its own tests.

Modules/<Name>/
├── Package.swift
├── Sources/<Name>/
└── Tests/<Name>Tests/

The Xcode project is generated from project.yml with XcodeGen. Do not edit the .pbxproj file by hand.

Modules

Module What it contains
Observability Structured logging (AppLogger), the in-process log buffer behind the Log Console, telemetry signposts, MetricKit, log redaction
Persistence The GRDB database, schema migrations, repositories, FTS5 search, reactive ValueObservation streams
AudioEngine The AudioEngine actor, the AVFoundation and FFmpeg decoders, the buffer pump, the DSP chain
Metadata Tag read and write with TagLib, cover-art extraction, the LRC lyrics parser
Acoustics Chromaprint fingerprinting, AcoustID and MusicBrainz lookup
Library The folder scanner, the FSEvents watcher, the conflict resolver, the cover-art cache
Playback The QueuePlayer actor, queue, history, shuffle strategies, gapless and crossfade scheduling, system Now Playing, the sleep timer
Scrobble The Last.fm, ListenBrainz, and Rocksky providers, and the offline scrobble queue
Subsonic The Subsonic, Navidrome, and Airsonic client, capability detection, Keychain credentials
Podcasts Feed refresh, search through Podcast Index and iTunes, subscriptions, episode downloads, Podcasting 2.0 extras
SyncServer Phone Sync: pairing, the trust store, the mutual-TLS HTTP server, manifest and file serving
UI SwiftUI views, view models, the mini player, settings, theming, snapshot tests

Dependencies between modules

No module imports a module above it. Observability is at the bottom and every other module uses it. UI is at the top, and the app target is above UI.

flowchart BT
    Observability
    Persistence --> Observability
    AudioEngine --> Observability
    Metadata --> Observability
    Acoustics --> Observability
    Library --> Persistence
    Library --> Metadata
    Library --> Acoustics
    Playback --> Persistence
    Playback --> AudioEngine
    Scrobble --> Playback
    Subsonic --> Persistence
    Podcasts --> Persistence
    SyncServer --> Library
    SyncServer --> Podcasts
    SyncServer --> AudioEngine
    UI --> Library
    UI --> Playback
    UI --> Scrobble
    UI --> Subsonic
    App --> UI
    App --> Podcasts
    App --> SyncServer
Loading

The diagram shows the main edges only. The exact list is in the Package.swift file of each module.

Main third-party dependencies

Dependency Used for
GRDB SQLite access, migrations, observation
FFmpeg (LGPL-only build, bundled) Decoding of the formats AVFoundation does not handle, and all network streams
TagLib Tag read and write
Chromaprint (fpcalc) Audio fingerprints for AcoustID
FeedKit RSS and Atom feed parsing
SwiftSonic The Subsonic API client
Sparkle 2 In-app updates

The full list with licences is in NOTICES.md.

Platform decisions

Dimension Decision
Minimum macOS macOS 15. Development needs Xcode 27, but the built app runs on macOS 15 and later.
Architecture arm64 only. The bundled FFmpeg libraries and fpcalc come from arm64 Homebrew.
Intel (x86_64) Not supported

Where the design is written down

Document What it is
Design docs index The architecture decision records (ADRs), numbered in dependency order. Each one covers one subsystem or feature slice: goals, contracts, test plan, acceptance criteria.
_standards.md The engineering rules that bind all code
GOTCHAS.md Traps that each cost a debugging session: the symptom, the rule, the cause, and the file to look at
data-dictionary.md The database schema, generated from a freshly migrated database
CLAUDE.md files Conventions for the repository root, App/, and several modules. They are written for a coding assistant but are plain markdown.

Some ADRs to start with:

Topic ADR
Audio engine ADR-002, ADR-006 (queue and gapless), ADR-095 (crossfade)
Persistence ADR-003
Library scanning ADR-004
Subsonic ADR-035
Podcasts ADR-037 (read this one first)
Phone Sync ADR-060
CI and releases ADR-033
End-to-end tests ADR-079

Related pages

Clone this wiki locally