Sonodex Development Planning, Technical Architecture, and Implementation Specifications (v1.0)
1. Project Overview
Sonodex is a native MIDI and audio sample management system designed specifically for music producers. Its core mission is to efficiently index, retrieve, and manage hundreds of thousands of media assets distributed across local disks. It aims to provide sub-second search responses and ensure a strict, high degree of consistency between the data state and the physical files.
1.1 Core Principles
- Stability First: Implicit caching is strictly prohibited; all data mutations must be transparent and traceable.
- Performance-Oriented: Optimized for 100,000+ records to ensure the UI thread is never blocked.
- Data Sovereignty: Utilizes an open-format SQL database and refuses to rely on opaque, black-box frameworks.
2. Technology Stack Selection (Tech Stack)
| Dimension | Technology Selection | Description |
|---|---|---|
| Programming Language | Swift 5.9+ | Utilizes strong typing, value semantics, and the modern Concurrency model. |
| UI Framework | SwiftUI | Declarative UI for handling state-driven, complex views. |
| Persistence Layer | GRDB.swift (SQLite) | Ditches SwiftData in favor of a type-safe, native SQL wrapper. |
| Concurrency | Swift Concurrency | Uses async/await to handle file I/O and heavy retrieval tasks. |
| Development Platform | macOS 14.0+ | Optimized for Apple Silicon and native system features. |
3. System Architecture Design
The system adopts a layered, decoupled architecture to ensure clear boundaries between the database persistence layer and the UI presentation layer, completely eliminating the issue of “phantom caches.”
3.1 Entity Model
Class-based reference semantics are abandoned, and Value-based Structs are utilized throughout the application.
struct SonodexEntry: Codable, FetchableRecord, MutablePersistableRecord {
var id: Int64?
var fileName: String // Filename (core index)
var relativePath: String // Relative/Absolute path
var duration: Double // Audio length
var fileType: String // wav, mid, aif, etc.
var tags: String? // Reserved tags field
var bookmarkData: Data? // macOS permission persistence (crucial)
}
4. Persistence Layer Implementation Path (The SQL Path)
4.1 Database Initialization and Migration
We use DatabasePool to support multi-threaded concurrent reads, and manage Schema versions via DatabaseMigrator.
class DatabaseManager {
static let shared = DatabaseManager()
let dbPool: DatabasePool
private init() {
// The configuration database is stored in Application Support
let path = try! FileManager.default
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
.appendingPathComponent("sonodex.sqlite").path
dbPool = try! DatabasePool(path: path)
try! setupMigrations()
}
private func setupMigrations() throws {
var migrator = DatabaseMigrator()
migrator.registerMigration("v1_create_entries") { db in
try db.create(table: "sonodex_entries") { t in
t.autoIncrementedPrimaryKey("id")
t.column("fileName", .text).notNull().indexed()
t.column("relativePath", .text).notNull().unique()
t.column("duration", .double)
t.column("fileType", .text)
}
}
try migrator.migrate(dbPool)
}
}
4.2 High-Performance Search Strategy (FTS5)
Traditional LIKE queries perform poorly against massive text datasets spanning hundreds of thousands of records. Sonodex must enable the FTS5 (Full-Text Search) extension module for SQLite.
- Implementation Method: Create a Virtual Table and map the filenames to the full-text search index.
- Expected Performance: With 500,000 records, keyword search response times must be kept under 10ms.
5. Key Technical Solutions
5.1 macOS Permissions and Path Consistency
The macOS sandbox mechanism can frequently cause direct file paths to become invalid.
- Solution: Utilize
Security-Scoped Bookmarks. By storing these asData, Sonodex can successfully re-parse and resolve the correct URL even if the external parent folder is renamed, provided the file’s UUID remains unchanged.
5.2 Zero-Cache UI Updates
Leveraging GRDB’s ValueObservation.
- Mechanism: Subscribe to SQLite’s transaction commit notifications. When the background file Scanner writes new samples into the database, the UI automatically triggers a re-query.
- Data Isolation: Query results are immediately mapped into
Snapshot Structsusingmap, guaranteeing that the View layer cannot accidentally mutate or tamper with the core database entities.
6. Development Platform and Environment Suggestions
- IDE: Xcode 15.0+
- Database Debugging: I strongly recommend using TablePlus. You can open the
.sqlitefiles directly to monitor the data streams written by the scanner in real-time. - Performance Monitoring: Use the Core Data (SQLite) instrument in Xcode Instruments to observe I/O spikes and query execution times.
7. Next Steps / Implementation Plan
- Infrastructure Setup: Introduce the GRDB framework into the Xcode project and configure the
DatabaseManagersingleton. - Schema Migration: Map the original Python (LMA) fields into Swift Structs.
- Scan Engine Development: Implement a recursive scanner based on
FileManager, utilizingdbPool.writeto perform batch asynchronous inserts into the database. - FTS5 Integration: Add full-text search capabilities to the search bar.