Database Schema
Last Updated: 2026-02-03 | Reading Time: 15 minutes
CoreData model documentation for PasteShelf.
Table of Contents
Section titled βTable of Contentsβ- Overview
- Entity Relationship Diagram
- Core Entities
- Supporting Entities
- CloudKit Mapping
- Migration Strategy
- Performance Considerations
Overview
Section titled βOverviewβPasteShelf uses CoreData with CloudKit integration for data persistence. The schema is designed to:
- Efficiently store diverse clipboard content types
- Support fast full-text search
- Enable seamless CloudKit sync (Pro)
- Handle large binary data (images, files)
- Maintain privacy with encryption support
Data Store Architecture
Section titled βData Store Architectureβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ Data Store Architecture ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€β ββ βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ ββ β NSPersistentCloudKitContainer β ββ β β ββ β ββββββββββββββββββββββ ββββββββββββββββββββββββββ β ββ β β Local Store β β CloudKit Store β β β ββ β β ββββββββββββ β β βββββββββββββββββ β β ββ β β β β β β ββ β β ~/Library/ β β iCloud Private DB β β ββ β β Application β β Custom Zone β β ββ β β Support/ β β E2E Encrypted β β ββ β β PasteShelf/ β β β β ββ β β PasteShelf.sqlite β β β β ββ β ββββββββββββββββββββββ ββββββββββββββββββββββββββ β ββ βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ ββ ββ Store Configuration: ββ β’ Local: Always available, primary storage ββ β’ Cloud: Pro/Enterprise only, synced with iCloud ββ ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββEntity Relationship Diagram
Section titled βEntity Relationship Diagramβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ Entity Relationship Diagram ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€β ββ βββββββββββββββββββ ββ β Application β ββ β (excluded) β ββ ββββββββββ¬βββββββββ ββ β ββ β excludedApp ββ βΌ ββ ββββββββββββββββ βββββββββββββββββββ βββββββββββββββ ββ β Folder βββββββββββ ClipboardItem ββββββββββΆβ Tag β ββ β β folder β (Core) β tags β β ββ ββββββββββββββββ ββββββββββ¬βββββββββ βββββββββββββββ ββ β β β ββ β β β ββ βββββββ΄ββββββ ββββββββββ΄βββββββββ βββββββ΄ββββββ ββ β subfoldersβ β β β items β ββ βββββββββββββ β β βββββββββββββ ββ βΌ βΌ ββ βββββββββββββββββββ βββββββββββββββββββ ββ β ClipboardContentβ β ContentPreview β ββ β (Binary) β β (Thumbnail) β ββ βββββββββββββββββββ βββββββββββββββββββ ββ ββ ββ βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββββββ ββ β UserPreference β β SearchIndex β β Action β β ββ β (Settings) β β (Search Cache) β β (Automation) β ββ βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββββββ ββ ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββCore Entities
Section titled βCore EntitiesβClipboardItem π
Section titled βClipboardItem πβThe primary entity storing clipboard history entries.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ ClipboardItem ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€β ββ ATTRIBUTES ββ ββββββββββ ββ ββ id UUID Primary key, unique ββ createdAt Date When item was captured ββ modifiedAt Date Last modification time ββ accessedAt Date Last paste/view time ββ accessCount Int32 Number of times accessed ββ ββ contentType String UTI type identifier ββ contentHash String SHA-256 hash for dedup ββ textContent String? Searchable text (indexed) ββ plainText String? Plain text representation ββ ββ sourceApp String? Bundle ID of source app ββ sourceURL String? URL if copied from browser ββ title String? Auto-generated or user title ββ ββ isFavorite Bool User marked as favorite ββ isPinned Bool Pinned to top ββ isSensitive Bool Contains sensitive data ββ isEncrypted Bool Content is encrypted ββ ββ RELATIONSHIPS ββ βββββββββββββ ββ ββ content ClipboardContent 1:1 Binary content ββ preview ContentPreview 1:1 Thumbnail ββ folder Folder? N:1 Optional folder ββ tags [Tag] N:N Tag associations ββ ββ INDEXES ββ βββββββ ββ ββ β’ createdAt (descending) - Default sort ββ β’ textContent (full-text search) ββ β’ contentHash (deduplication) ββ β’ contentType (filtering) ββ β’ isFavorite, isPinned (quick access) ββ ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββCoreData Definition:
@objc(ClipboardItem)public class ClipboardItem: NSManagedObject { @NSManaged public var id: UUID @NSManaged public var createdAt: Date @NSManaged public var modifiedAt: Date @NSManaged public var accessedAt: Date @NSManaged public var accessCount: Int32
@NSManaged public var contentType: String @NSManaged public var contentHash: String @NSManaged public var textContent: String? @NSManaged public var plainText: String?
@NSManaged public var sourceApp: String? @NSManaged public var sourceURL: String? @NSManaged public var title: String?
@NSManaged public var isFavorite: Bool @NSManaged public var isPinned: Bool @NSManaged public var isSensitive: Bool @NSManaged public var isEncrypted: Bool
@NSManaged public var content: ClipboardContent? @NSManaged public var preview: ContentPreview? @NSManaged public var folder: Folder? @NSManaged public var tags: Set<Tag>}ClipboardContent π
Section titled βClipboardContent πβStores the actual binary content separately for performance.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ ClipboardContent ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€β ββ ATTRIBUTES ββ ββββββββββ ββ ββ id UUID Primary key ββ data Binary Raw content data ββ mimeType String MIME type ββ size Int64 Size in bytes ββ isCompressed Bool Compression applied ββ ββ RELATIONSHIPS ββ βββββββββββββ ββ ββ item ClipboardItem 1:1 Parent item ββ ββ NOTES ββ βββββ ββ ββ β’ External storage for data > 100KB ββ β’ Compression using LZ4 for text > 10KB ββ β’ CloudKit: Stored as CKAsset ββ ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββContentPreview π
Section titled βContentPreview πβStores thumbnails and previews for quick display.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ ContentPreview ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€β ββ ATTRIBUTES ββ ββββββββββ ββ ββ id UUID Primary key ββ thumbnail Binary Image thumbnail (256px) ββ textPreview String First 500 chars of text ββ ocrText String? β OCR extracted text ββ embedding Binary? β ML embedding vector ββ ββ RELATIONSHIPS ββ βββββββββββββ ββ ββ item ClipboardItem 1:1 Parent item ββ ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββSupporting Entities
Section titled βSupporting EntitiesβFolder π
Section titled βFolder πβOrganizes clipboard items into folders (Smart Folders in Pro).
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ Folder ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€β ββ ATTRIBUTES ββ ββββββββββ ββ ββ id UUID Primary key ββ name String Folder name ββ icon String SF Symbol name ββ color String Hex color code ββ sortOrder Int16 Display order ββ isSmartFolder Bool β Auto-populated folder ββ smartQuery String? β Query for smart folder ββ ββ RELATIONSHIPS ββ βββββββββββββ ββ ββ items [ClipboardItem] 1:N Items in folder ββ parent Folder? N:1 Parent folder ββ children [Folder] 1:N Subfolders ββ ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββTag π
Section titled βTag πβFlexible tagging system for items.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ Tag ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€β ββ ATTRIBUTES ββ ββββββββββ ββ ββ id UUID Primary key ββ name String Tag name (unique) ββ color String Hex color code ββ isAutoTag Bool System-generated tag ββ ββ RELATIONSHIPS ββ βββββββββββββ ββ ββ items [ClipboardItem] N:N Tagged items ββ ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββApplication (Excluded Apps) π
Section titled βApplication (Excluded Apps) πβApps excluded from clipboard monitoring.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ Application ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€β ββ ATTRIBUTES ββ ββββββββββ ββ ββ bundleId String App bundle identifier ββ name String App display name ββ isExcluded Bool Don't capture from this app ββ excludeReason String? Why excluded ββ ββ Default Exclusions: ββ β’ 1Password (com.1password.1password) ββ β’ Bitwarden (com.bitwarden.desktop) ββ β’ LastPass (com.lastpass.LastPass) ββ β’ Keychain Access (com.apple.keychainaccess) ββ ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββAction β
Section titled βAction ββCustom automation actions.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ Action β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€β ββ ATTRIBUTES ββ ββββββββββ ββ ββ id UUID Primary key ββ name String Action name ββ script String JavaScript code ββ trigger String When to run (manual/auto) ββ contentTypes [String] Applicable content types ββ isEnabled Bool Action enabled ββ ββ Examples: ββ β’ "Uppercase Text" ββ β’ "Shorten URL" ββ β’ "Format JSON" ββ ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββUserPreference π
Section titled βUserPreference πβUser settings stored in CoreData (synced with iCloud).
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ UserPreference ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€β ββ ATTRIBUTES ββ ββββββββββ ββ ββ key String Preference key ββ value Transformable Codable value ββ modifiedAt Date Last change ββ ββ Stored Preferences: ββ β’ historyLimit: Int ββ β’ theme: String ββ β’ globalHotkey: String ββ β’ launchAtLogin: Bool ββ ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββCloudKit Mapping β
Section titled βCloudKit Mapping ββRecord Types
Section titled βRecord Typesβ| CoreData Entity | CloudKit Record Type | Zone |
|---|---|---|
| ClipboardItem | CD_ClipboardItem | com.pasteshelf.clipboard |
| ClipboardContent | CD_ClipboardContent (CKAsset) | com.pasteshelf.clipboard |
| ContentPreview | CD_ContentPreview | com.pasteshelf.clipboard |
| Folder | CD_Folder | com.pasteshelf.clipboard |
| Tag | CD_Tag | com.pasteshelf.clipboard |
| UserPreference | CD_UserPreference | com.pasteshelf.settings |
Sync Configuration
Section titled βSync Configurationβ// CloudKit Container Setuplet container = NSPersistentCloudKitContainer(name: "PasteShelf")
let cloudStoreDescription = NSPersistentStoreDescription()cloudStoreDescription.cloudKitContainerOptions = NSPersistentCloudKitContainerOptions( containerIdentifier: "iCloud.com.pasteshelf.PasteShelf")
// Custom zone for clipboard datacloudStoreDescription.setOption( true as NSNumber, forKey: NSPersistentHistoryTrackingKey)cloudStoreDescription.setOption( true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)Encryption β
Section titled βEncryption ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ CloudKit Encryption ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€β ββ Encryption Flow: ββ ββ 1. Generate device-specific key pair ββ 2. Derive symmetric key from user's iCloud identity ββ 3. Encrypt content before CoreData save ββ 4. CoreData/CloudKit sync encrypted data ββ 5. Decrypt on other devices with same iCloud account ββ ββ ββββββββββββββ ββββββββββββββ ββββββββββββββ ββ β Plaintext βββββΆβ AES-256 βββββΆβ Ciphertext β ββ β Content β β GCM β β (synced) β ββ ββββββββββββββ ββββββββββββββ ββββββββββββββ ββ β ββ Key from Keychain ββ (iCloud Keychain) ββ ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββMigration Strategy
Section titled βMigration StrategyβVersion History
Section titled βVersion Historyβ| Version | Date | Changes |
|---|---|---|
| 1.0 | 2026-02-03 | Initial schema |
Migration Types
Section titled βMigration Typesβ// Lightweight migration (automatic)let options = [ NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true]
// Heavy migration (custom mapping model)class MigrationManager { func migrateStore(from sourceURL: URL, to destinationURL: URL) throws { let sourceModel = // ... let destinationModel = // ... let mappingModel = NSMappingModel( from: nil, forSourceModel: sourceModel, destinationModel: destinationModel )
let migrationManager = NSMigrationManager( sourceModel: sourceModel, destinationModel: destinationModel )
try migrationManager.migrateStore( from: sourceURL, sourceType: NSSQLiteStoreType, options: nil, with: mappingModel, toDestinationURL: destinationURL, destinationType: NSSQLiteStoreType, destinationOptions: nil ) }}Migration Guidelines
Section titled βMigration Guidelinesβ- Prefer lightweight migrations when possible
- Add optional attributes with default values
- Never remove attributes in minor versions
- Version the data model for each schema change
- Test migrations with production-like data
Performance Considerations
Section titled βPerformance ConsiderationsβIndexing Strategy
Section titled βIndexing Strategyβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ Index Configuration ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€β ββ ClipboardItem Indexes: ββ ββ 1. createdAt (DESC) - Default sort, recent first ββ 2. textContent (FTS) - Full-text search ββ 3. contentHash (UNIQUE) - Deduplication lookups ββ 4. contentType - Filter by type ββ 5. (isFavorite, createdAt) - Favorites query ββ 6. (isPinned, createdAt) - Pinned items query ββ 7. sourceApp - Filter by app ββ ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββFetch Optimization
Section titled βFetch Optimizationβ// Batch fetching for large listslet fetchRequest = ClipboardItem.fetchRequest()fetchRequest.fetchBatchSize = 50fetchRequest.fetchLimit = 100fetchRequest.propertiesToFetch = ["id", "textContent", "createdAt", "contentType"]fetchRequest.relationshipKeyPathsForPrefetching = ["preview"]
// Background fetchlet backgroundContext = container.newBackgroundContext()backgroundContext.perform { let items = try? backgroundContext.fetch(fetchRequest) // Process items}Storage Optimization
Section titled βStorage Optimizationβ| Content Type | Storage Strategy |
|---|---|
| Text < 10KB | Inline in SQLite |
| Text β₯ 10KB | Compressed (LZ4) |
| Images | External file, thumbnail inline |
| Files | Reference only, no duplication |
| Binary > 100KB | External storage |
Cleanup Policy
Section titled βCleanup Policyβclass StorageManager { func cleanup() async { let context = container.newBackgroundContext()
await context.perform { // Delete items older than retention period let cutoffDate = Date().addingTimeInterval(-retentionPeriod) let deleteRequest = NSBatchDeleteRequest( fetchRequest: ClipboardItem.fetchRequest( predicate: NSPredicate(format: "createdAt < %@ AND isFavorite == NO", cutoffDate as NSDate) ) )
try? context.execute(deleteRequest)
// Compact database try? context.persistentStoreCoordinator?.performAndWait { // SQLite VACUUM } } }}Related Documentation
Section titled βRelated Documentationβ| Document | Description |
|---|---|
| Architecture | System architecture |
| Tech Stack | Technology choices |
| Sync Engine | CloudKit sync |
| Performance | Optimization |
Last updated: 2026-02-03