Database Seeding
Relevant source files
The following files were used as context for generating this wiki page:
- Trackurr/Dependencies/Persistence/Seeding/DataSeeder.swift
- Trackurr/Dependencies/Persistence/Seeding/SeedModels.swift
- TrackurrTests/Persistence/Seeding/DataSeederTests.swift
- TrackurrTests/Persistence/Seeding/SeedVersionStoreTests.swift
- Trackurr/Dependencies/Persistence/Migration/AppMigrationPlan.swift
- README.md
Database seeding in Trackurr is the process of populating the SwiftData persistent store with initial system data and, in debug environments, sample datasets for testing. This system ensures that essential entities such as categories, payment methods, and subscription providers are available upon first launch and remain consistent across schema migrations.
The seeding architecture is built around the DataSeeder actor, which manages the ingestion of JSON-based seed files, version tracking to prevent redundant operations, and environment-specific strategies for production, UI testing, and App Store screenshots.
Sources: Trackurr/Dependencies/Persistence/Seeding/DataSeeder.swift:9-11, README.md:154-159
Seeding Architecture
The seeding process is governed by a strategy pattern that determines which data sets are applied based on the application's runtime context.
Seeding Strategies
The SeedingStrategy enum defines how the seeder behaves:
| Strategy | Behavior | Use Case |
|---|---|---|
.live | Calls seedIfNeeded(); checks versions before inserting. | Production application launch. |
.uiTests | Resets version store and calls forceSeed(). | Automated UI testing. |
.appStoreScreenshots | Resets version store, force seeds, and adds debug subscriptions. | Generating marketing materials. |
.unitTests | No-op; allows tests to manage their own data. | Service and logic unit testing. |
Sources: Trackurr/Dependencies/Persistence/Seeding/DataSeeder.swift:34-54
Data Flow Diagram
The following diagram illustrates the flow from JSON seed files to the SwiftData persistent storage.
The seeder loads JSON files from the app bundle, decodes them into intermediate SeedModels, and then translates these into PersistentModel entities after ensuring they do not already exist in the database.
Sources: Trackurr/Dependencies/Persistence/Seeding/DataSeeder.swift:65-75, Trackurr/Dependencies/Persistence/Seeding/SeedModels.swift:7-10
Core Components
DataSeeder
An actor responsible for the execution of seeding operations. It utilizes a ModelExecutor to interact with SwiftData's ModelContext in a thread-safe manner.
seedIfNeeded(): The primary entry point for standard launches. It sequences the seeding of categories, payment methods, and providers.forceSeed(): Overrides version checks to re-apply seed data.loadSeedFile(named:): A private helper that retrieves and decodes JSON resources from the specifiedBundle.
Sources: Trackurr/Dependencies/Persistence/Seeding/DataSeeder.swift:11-30, Trackurr/Dependencies/Persistence/Seeding/DataSeeder.swift:65-78
SeedVersionStore
A utility class that tracks the version of seeded data using UserDefaults. This prevents the seeder from re-processing the same files on every application launch. It stores integers associated with specific keys like "categories" or "paymentMethods".
Sources: TrackurrTests/Persistence/Seeding/SeedVersionStoreTests.swift:9-35, Trackurr/Dependencies/Persistence/Seeding/DataSeeder.swift:14
Seed Models
Intermediate data structures used during the decoding process to bridge JSON formats to domain entities.
nonisolated struct SeedFile<Item: Decodable & Sendable>: Decodable, Sendable {
let version: Int
let items: [Item]
}
Sources: Trackurr/Dependencies/Persistence/Seeding/SeedModels.swift:7-10
System Data Entities
The seeder handles three primary types of system data:
- System Categories: Seeded from
categories.json. These include standard classifications like "Finance", "Utilities", and "Entertainment". Each includes asystemId(prefixed withcategory.), a name, an icon (emoji), and a hex color. - System Payment Methods: Seeded from
payment_methods.json. These include standard methods like "Visa", "MasterCard", and "Apple Pay". They are identified bysystemId(prefixed withpaymentMethod.). - Subscription Providers: Seeded from
subscription_providers.json. These link to system categories and define default billing cycles and brand colors for known services.
Sources: Trackurr/Dependencies/Persistence/Seeding/DataSeeder.swift:80-155, TrackurrTests/Persistence/Seeding/DataSeederTests.swift:55-105
Deduplication Logic
To prevent duplicate records, the seeder performs a fetch before every insertion using a #Predicate on the entity's systemId or providerId.
Debug and Testing Support
In DEBUG builds, the DataSeeder is extended to support "Debug Subscription Sets". These are predefined lists of subscriptions used to populate the UI for testing or screenshot generation.
| Set Name | Enum Case | Description |
|---|---|---|
subscriptions_15 | .small | 15 diverse fictional subscriptions. |
subscriptions_30 | .large | 30 diverse fictional subscriptions. |
subscriptions_50 | .extraLarge | 50 subscriptions including stopped ones and various billing cycles. |
subscriptions_live | .live | 13 real-world subscriptions for realistic testing. |
Sources: Trackurr/Dependencies/Persistence/Seeding/DataSeeder.swift:195-202, README.md:162-167
Migration Integration
During schema migrations (specifically V7 to V8), the seeding system is critical. The migration plan deletes old system-level categories and payment methods that were previously mixed with user data, allowing the DataSeeder to re-populate them into new, local-only entities.
Sources: Trackurr/Dependencies/Persistence/Migration/AppMigrationPlan.swift:65-105
Conclusion
The database seeding system provides a robust foundation for Trackurr's data integrity. By separating system data from user-generated content and using a versioned, file-based approach, the application ensures a consistent user experience while providing flexible tools for development and testing. Re-seeding is automatically handled during schema updates to maintain the relationship between user subscriptions and system-defined categories.