Skip to main content

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 .a files

Design Patterns

MVVM

  • Models: structs (value types, Codable)
  • ViewModels: @Observable classes
  • Views: SwiftUI, with AppKit bridging where needed

Protocol-Oriented Drivers

All database connectivity goes through one protocol:
No switch statements on database type. No hardcoded driver list. Plugins register themselves, and the factory resolves them by 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 beyond PluginDatabaseDriver 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

  1. A cell edit is recorded by DataChangeManager as a pending change
  2. Save runs SQLStatementGenerator, which turns pending changes into INSERT, UPDATE, and DELETE statements
  3. Undo/redo goes through the window’s UndoManager, registered by DataChangeManager
  4. AnyChangeManager wraps the concrete manager behind the ChangeManaging protocol

MainContentCoordinator

The central coordinator for the main window. It is split across extension files in Views/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 under Core/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.