Architecture
A Swift Package Manager workspace with a strictly downward dependency graph.
The app depends on the packages. The packages depend on DBCore. DBCore depends on Foundation and swift-log, and nothing else. Scripts/ci.sh lints the import statements to keep it that way.
App/Tinker SwiftUI shell, AppKit grid and editor, menus, commands │ ├── DBGrid Grid model, edit tracking, paging, DML generation ├── DBSQL Statement splitter, tokenizer, quoting, formatter, filter compiler ├── DBPostgres SQLDriver over postgres-nio (PostgresClient, binary results) ├── DBMySQL SQLDriver over mysql-nio (prepared-statement protocol, text fallback) ├── DBSQLite SQLDriver over the system libsqlite3, one dedicated thread per file ├── DBTunnel SSH port forwarding over Citadel, known-hosts, TLS helpers ├── DBStore Connection store, Keychain, query history, settings ├── DBTestKit Fixtures, env-var server resolution, skip-with-reason helpers │ └── DBCore Driver protocol, value model, errors, ConnectionSession
Load-bearing decisions
Each is recorded as an architecture decision record in DECISIONS.md.
- All database I/O runs in actors.
@MainActoris reserved for views and view models. NoDispatchQueueanywhere. - One driver-neutral value model. Every native type maps to exactly one
DBValuecase. Unknown types surface as.rawwith their type name rather than being guessed at. Decimals and timestamps keep the server’s text. - Two execution paths, chosen by whether the statement streams rows, so a
SELECTover a million rows and aCREATE PROCEDUREare both first-class. - Binary results on PostgreSQL, with text rendered losslessly by the driver. Prepared statements on MySQL, with a text fallback for statements the protocol cannot prepare.
- Pooled connections are reset before reuse, and history and error logs are redacted.
- No `try!`, no force unwraps outside tests, no `print`. Swift 6 with
-strict-concurrency=completeand zero warnings, enforced in CI.
Dependencies
Nothing else is added without an ADR.
Persistence
DBStore is a SQLite database at ~/Library/Application Support/Tinker/store.sqlite in WAL mode: connections (without secrets), groups, query history, grid preferences and settings. Migrations are numbered SQL files tracked in PRAGMA user_version. No ORM; a small typed layer over the SQLite3 C API.
Definition of done
A feature is done when the build is warning-free under strict concurrency, the tests are green, the driver feature has an integration test that actually ran against a local server, and the performance criteria are measured with signposts rather than by eye.