Architecture
TablePro is built with:- SwiftUI for the UI layer
- AppKit for low-level macOS integration (windows, menus, native tabs)
- Swift Concurrency (async/await, actors) for all async work
- Native C libraries for database connectivity, linked as static
.afiles
Design Patterns
MVVM
- Models: structs (value types, Codable)
- ViewModels:
@Observableclasses - Views: SwiftUI, with AppKit bridging where needed
Protocol-Oriented Drivers
All database connectivity goes through one protocol:DatabaseType.pluginTypeId. DatabaseType is a string-based struct, not an enum, so unknown types from future plugins stay valid.
Actor Isolation
Thread-safe shared state uses Swift actors:Dependencies
Plugin System
All database drivers are.tableplugin bundles loaded at runtime. This keeps the app binary small and makes adding new databases a matter of dropping in a bundle.
Driver Plugins
Five driver plugins ship inside the app bundle:
The app bundle also carries non-driver plugins: CSVInspectorPlugin, export plugins (CSV, JSON, SQL, XLSX, MQL), and import plugins (CSV, JSON, SQL).
The remaining 14 driver plugins are downloaded on demand from the plugin registry:
PluginKit ABI
TableProPluginKit builds with Swift Library Evolution (BUILD_LIBRARY_FOR_DISTRIBUTION = YES), so its public ABI is resilient. Plugins built against an older PluginKit keep loading under a newer app: the runtime fills unimplemented protocol requirements from their defaults.
Additive changes (a new requirement with a default implementation, a new field added through a new initializer overload) need no version bump. Breaking changes bump currentPluginKitVersion (18 as of 0.57.0) in PluginManager.swift, and the loader then rejects mismatched plugins cleanly. Run scripts/check-pluginkit-abi.sh before merging any change under Plugins/TableProPluginKit/. See Plugin Development for the full rules.
Opt-in Plugin Protocols
Plugins can adopt protocols beyondPluginDatabaseDriver to expose extra capabilities. These are runtime-cast (as?), so plugins that do not conform keep working without an ABI bump.
Key Components
DatabaseManager
Connection pool and lifecycle management. Primary interface between UI and drivers. Handles connect, disconnect, reconnect, and session tracking.ConnectionHealthMonitor
Pings active connections every 30 seconds. Auto-reconnects with exponential backoff on failure.Change Tracking
- A cell edit is recorded by
DataChangeManageras a pending change - Save runs
SQLStatementGenerator, which turns pending changes into INSERT, UPDATE, and DELETE statements - Undo/redo goes through the window’s
UndoManager, registered byDataChangeManager AnyChangeManagerwraps the concrete manager behind theChangeManagingprotocol
MainContentCoordinator
The central coordinator for the main window. It is split across extension files inViews/Main/Extensions/ (MainContentCoordinator+Alerts, +Filtering, +Pagination, and so on). New coordinator functionality goes in a new extension file, not the main file.
Autocomplete Engine
- CompletionEngine: entry point, produces ranked suggestions
- SQLContextAnalyzer: parses cursor position context (table ref, column ref, keyword)
- SQLSchemaProvider: actor that caches and serves schema data
MCP Server
The MCP server lives underCore/MCP/, layered from wire types up: Codable JSON-RPC 2.0 and SSE types, transports (an NWListener HTTP server bound to 127.0.0.1 plus a stdio bridge for the tablepro-mcp CLI), actor-based session, auth, and rate-limit stores, and a protocol dispatcher that runs each inbound request in its own task. Sessions expire after 15 minutes idle. The dispatcher serves 19 tools and accepts protocol versions 2025-03-26, 2025-06-18, and 2025-11-25. See the tool catalog and Versioning.
Data Flow
Connection
Query Execution
State Management
For the repository layout, see Project Structure.
