.tasks/core/LSYNC-007-syncable-trait.md
Create the Syncable trait that database models implement to enable automatic sync. In the leaderless model, the trait must distinguish between device-owned and shared resources.
Architecture Update: Trait now indicates ownership to determine sync strategy (state-based vs log-based).
Syncable trait with:
SYNC_MODEL: &'static str - Model identifiersync_id() -> Uuid - Global resource IDis_device_owned() -> bool - Determines sync strategydevice_id() -> Option<Uuid> - Owner device (if device-owned)exclude_fields() - Optional field exclusion#[derive(Syncable)] macrocore/src/infra/sync/syncable.rscrates/sync-derive/src/lib.rsimpl Syncable for locations::Model {
const SYNC_MODEL: &'static str = "location";
fn sync_id(&self) -> Uuid { self.uuid }
fn is_device_owned(&self) -> bool { true }
fn device_id(&self) -> Option<Uuid> { Some(self.device_id) }
fn exclude_fields() -> Option<&'static [&'static str]> {
Some(&["id", "created_at", "updated_at"])
}
}
// Sync strategy: State broadcast (no log)
impl Syncable for tags::Model {
const SYNC_MODEL: &'static str = "tag";
fn sync_id(&self) -> Uuid { self.uuid }
fn is_device_owned(&self) -> bool { false } // Shared!
fn device_id(&self) -> Option<Uuid> { None }
fn exclude_fields() -> Option<&'static [&'static str]> {
Some(&["id", "created_at"])
}
}
// Sync strategy: HLC-based log
impl TransactionManager {
pub async fn commit<M: Syncable>(&self, model: M) -> Result<M> {
if model.is_device_owned() {
self.commit_device_owned(model).await // State-based
} else {
self.commit_shared(model).await // Log-based with HLC
}
}
}
Syncable trait defined with ownership methodscore/src/infra/sync/NEW_SYNC.md - Data ownership classification