Guide
Persistence
The core package never assumes a storage layer. If you want SwiftData wired up for you, there's a separate product for that.
The default: you own storage
AdvancedKanban (the core product) has zero third-party dependencies and doesn't import SwiftData, Core Data, or anything else. KanbanBoard's onMove closure hands you a KanbanMove value — cardID, sourceColumnID, sourceIndex, destinationColumnID, destinationIndex — after the board has already applied the change to your in-memory columns binding. What you do with that value is entirely yours: write it to Core Data, send it to a server, log it, ignore it.
The optional adapter
AdvancedKanbanSwiftData is a second SPM product in the same package. It's never linked unless you explicitly add it — importing AdvancedKanban alone never pulls in SwiftData.
.package(url: "https://github.com/NerdSnipe-Inc/AdvancedKanban.git", from: "1.0.0") // in your target's dependencies: .product(name: "AdvancedKanban", package: "AdvancedKanban"), .product(name: "AdvancedKanbanSwiftData", package: "AdvancedKanban"), // optional
It ships two ready-made @Model types that already conform to the core protocols, plus a store that applies a move in one call:
| Type | What it is |
|---|---|
| SwiftDataKanbanCard | @Model, conforms to KanbanCard. id: UUID, title: String, sortIndex: Int. |
| SwiftDataKanbanColumn | @Model, conforms to KanbanColumn. id: UUID, title: String, wipLimit: Int?, isCollapsed: Bool. cards is a computed property over its cascade-deleting relationship, sorted by sortIndex. |
| KanbanStore | Wraps a ModelContext. apply(_ move: KanbanMove<UUID, UUID>) throws reassigns the moved card's column, renumbers every card in the destination column, and saves. |
Wiring it up
import SwiftData import AdvancedKanban import AdvancedKanbanSwiftData KanbanBoard( columns: $columns, onMove: { move in try? store.apply(move) // store: KanbanStore, built from your ModelContext }, // ... )
The board mutates your local columns binding immediately, for a responsive UI, and calls onMove as a separate step. If you're using the SwiftData models directly, calling store.apply(_:) from onMove keeps every card's sortIndex correct on disk. Skipping that call still works for local, in-memory reordering, but the persisted order won't match what's on screen after your next fetch.
Bringing your own storage instead
Don't use SwiftData? Nothing above is required. Conform your Core Data entity, your GRDB record, or your plain server-backed struct to KanbanCard/KanbanColumn directly and apply KanbanMove however your storage layer expects — the same way the SwiftData adapter does, just without the ready-made types.