Lynavo Drive Data Model And Statistics Semantics
July 15, 2026 ยท View on GitHub
This document records the core persistence structures, identity semantics, and statistics semantics on mobile and sidecar.
1. Identity Semantics
1.1 Device Identity
- Mobile identity:
clientId - Generated by mobile and persisted in platform secure storage.
- Desktop uses it to identify the same phone, not device name or IP.
1.2 Device Display Name
- System device names are not reliable on iOS 16+.
- The current implementation generates a stable unique name for generic names,
for example
Phone 9C2A. - User-edited display names are stored in Keychain.
1.3 deviceId On Each Side
The shared HistoryLedgerCardDTO.deviceId points in different directions on
each side:
- desktop:
deviceId = mobile clientId - mobile:
deviceId = desktop serverId
Keep this directional difference in mind when reading code.
2. Sidecar Database
The sidecar SQLite initial migration is defined at:
services/sidecar-go/internal/store/migrations/001_initial.sql
2.1 paired_devices
Purpose:
- Store paired devices.
- Store
client_name / device_alias / last_ip / pairing_id / pairing_token_hash. - Serve as the primary device index for dashboard and detail views.
2.2 sessions
Purpose:
- Current sync sessions from the sidecar perspective.
- Record
state / active_file_key / active_offset / started_at / updated_at.
2.3 uploads
Purpose:
- One final upload record per
file_key. - Record final path, hash, completion time, transfer duration, and committed bytes.
Key fields:
statuspart_pathfinal_pathcommitted_bytesactive_transmission_mscompleted_atupdated_at
2.4 device_daily_stats
Purpose:
- Aggregate completed records by device plus date.
- Provide fast statistics for desktop dashboard/history.
Key fields:
stat_dateclient_idclient_name_snapshotclient_ip_snapshotfile_counttotal_bytesactive_transmission_ms
2.5 settings / share_config
Purpose:
- Basic sidecar settings.
- Shared directory detection and SMB URL status.
3. Mobile Database
Mobile SQLite is managed by UploadStore.swift.
3.1 binding
Purpose:
- Current bound desktop information.
- Includes
device_id / host / port / pairing_id / share_name / last_bound_at.
3.2 upload_items
Purpose:
- Local upload queue and file-level state machine.
- Real data source for the current sync main loop.
Key fields:
asset_local_idmodified_atmedia_typeoriginal_filenamefile_keyfile_sizestatusacked_offsetlast_error_codeupdated_at
Important constraints:
- The pending queue comes from
status in ('queued','discovered','preparing','ready','cloud_downloading','uploading'). - The real upload set must be read from this table.
- Do not use only assets newly scanned in the current round as the upload set.
3.3 sync_sessions
Purpose:
- Sync session snapshots from the mobile perspective.
- Store
queue_total_count / queue_total_bytes / completed_count / completed_bytes / active_file_key.
3.4 daily_ledgers
Purpose:
- Mobile history page and home page statistics.
- Store which desktop, which day, and how much was transferred.
Key fields:
ledger_datedevice_iddevice_name_snapshotdevice_ip_snapshotfile_counttotal_bytesactive_transmission_ms
4. Statistics Semantics
4.1 Which Day A Transfer Belongs To
Current unified rule:
- Use the sidecar / desktop completion day.
Reasons:
- The real write happens in the desktop sidecar receive directory.
- Desktop statistics already depend on the sidecar.
- Mobile previously bucketed by its own UTC date, which caused drift from desktop buckets.
Current implementation:
- The sidecar returns
ledgerDateinFILE_END_RES. - Mobile prefers that
ledgerDate. - Local date is used only as an exceptional fallback.
4.2 Completion Time
Desktop detail completion time comes from:
- Prefer
uploads.completed_at. - Fall back to
updated_ator filesystemmodTime.
Notes:
- The UI currently defaults to minute precision,
HH:mm. - Therefore files completed within the same minute can appear to have the same time.
4.3 Queue Count
- The mobile home queue count comes from the local
upload_itemspending set. - The sidecar
queueCountcomes from the current sync session'sSYNC_BEGIN_REQ.
These values should match in theory.
If this happens:
- The UI shows many queued items.
- Sidecar
queueCount=1or0.
It usually means the app main loop is using the wrong data source, not that the sidecar lost data.
5. Filesystem Layout
Default receive root:
- macOS:
~/Library/Application Support/Lynavo Drive/received - Windows:
%AppData%\\Lynavo Drive\\received
These defaults come from the sidecar's os.UserConfigDir()/Lynavo Drive/received.
Actual layout:
received/
<devicePath>/
<YYYY-MM-DD>/
<original file>
Notes:
storagePathis the receive root.devicePathis the device-specific directory.- Desktop detail should prefer opening
<devicePath>/<selectedDate>.
6. Device Naming And Receive Directory
6.1 Device Identity
Device identity depends only on clientId. It does not depend on clientName,
deviceAlias, receiveDirName, or IP. Device name changes do not create a new
device identity.
6.2 Display Name
The display name is only for UI and diagnostics. It does not participate in receive-path calculation.
Derivation:
displayName = deviceAlias ?? clientName ?? clientId
deviceAlias: user-set alias in the product, preferred for display.clientName: system device name reported by mobile on each connection.clientId: final fallback, used only when data is abnormal or initialization is incomplete.
When clientName or deviceAlias changes, the UI display name updates
immediately, but no disk operation is triggered.
6.3 Receive Directory Name (receiveDirName)
receiveDirName is a storage-layer field mapped to
paired_devices.receive_dir_name. It is a stable storage key and does not
change automatically once set for a device.
When it is generated:
- New device: generated and written atomically by
PairDeviceWithDirNameduring pairing. Directory-name generation and paired-device persistence happen in the same critical section. - Old device with empty
receive_dir_name: lazily backfilled byEnsureReceiveDirName, preferring to claim an existing legacy directory and generating a new name only if none is found.
Immutability constraints:
clientNamechanges do not trigger directory rename.deviceAliaschanges do not trigger directory rename.- The sidecar does not perform full rename or full directory rebuild at startup.
6.4 displayName And receiveDirName Can Differ
The UI display name may differ from the folder name shown in Finder / Explorer. This is a design decision, not a bug. The presentation layer and storage layer are intentionally decoupled to keep external backups, indexing, and script paths stable.
When troubleshooting, use device detail or diagnostics to confirm the mapping
between displayName, receiveDirName, and devicePath.
7. iCloud Assets
iCloud assets have special handling, but they do not change data-model primary keys:
- They are queued normally during scanning.
- During export, the system may download them from iCloud to a local temporary file.
- Queue items can carry the
isCloudAssetmarker. - Export enters the
cloud_downloadingstate.
This means:
- iCloud assets affect preparation time.
- They should not change
queueCountstatistics semantics.