223 lines
3.9 KiB
Markdown
223 lines
3.9 KiB
Markdown
# Bidirectional synchronization checkpoint
|
|
|
|
## Validated status
|
|
|
|
```text
|
|
ANDROID_LOCAL_WORKFLOWS=PASS
|
|
|
|
ANDROID_TO_PC_MTP=PASS
|
|
DESKTOP_MOBILE_IMPORT_V1=PASS
|
|
DESKTOP_MOBILE_IMPORT_IDEMPOTENT=PASS
|
|
|
|
PC_CATALOG_EXPORT_V1=PASS
|
|
PC_TO_ANDROID_MTP_PUBLISH=PASS
|
|
|
|
ANDROID_SAF_FOLDER_SELECTION=PASS
|
|
ANDROID_SAF_FOLDER_CHANGE=PASS
|
|
```
|
|
|
|
This checkpoint represents the validated synchronization foundation on the
|
|
physical Samsung device.
|
|
|
|
## Android → PC
|
|
|
|
Android produces:
|
|
|
|
```text
|
|
Download/Trainlog/trainlog-mobile-export-v1.json
|
|
```
|
|
|
|
The desktop retrieves it through direct libmtp.
|
|
|
|
No GVFS/FUSE mount is used.
|
|
|
|
The desktop importer:
|
|
|
|
```text
|
|
tools/import_mobile_export.py
|
|
```
|
|
|
|
is:
|
|
|
|
```text
|
|
strict
|
|
transactional
|
|
idempotent by stable IDs
|
|
profile-aware
|
|
```
|
|
|
|
Validated behavior:
|
|
|
|
```text
|
|
first import:
|
|
new exercise/session/body observation imported
|
|
|
|
second import:
|
|
no duplicates
|
|
existing stable IDs skipped
|
|
```
|
|
|
|
## PC → Android
|
|
|
|
The desktop produces:
|
|
|
|
```text
|
|
/tmp/trainlog-pc-catalog-v1.json
|
|
```
|
|
|
|
with:
|
|
|
|
```text
|
|
format = trainlog-pc-catalog
|
|
version = 1
|
|
```
|
|
|
|
The catalog is published by direct MTP to:
|
|
|
|
```text
|
|
Download/Trainlog/trainlog-pc-catalog-v1.json
|
|
```
|
|
|
|
Physical-device publication has been validated.
|
|
|
|
The Android application accesses the PC-created file through one persistent
|
|
Storage Access Framework grant.
|
|
|
|
The selected folder must be:
|
|
|
|
```text
|
|
Download/Trainlog
|
|
```
|
|
|
|
The Sync screen must always allow changing this folder because a wrong
|
|
persisted SAF grant must be recoverable without clearing application data.
|
|
|
|
## Important semantics
|
|
|
|
The synchronization layer exchanges versioned Trainlog domain artifacts.
|
|
|
|
It does not synchronize SQLite files.
|
|
|
|
The frozen legacy session format remains:
|
|
|
|
```text
|
|
TRAINLOG_FORMAT_V1=FROZEN
|
|
```
|
|
|
|
Profile-aware synchronization uses separate explicit synchronization artifacts.
|
|
|
|
## Current TUI state
|
|
|
|
The existing desktop Sync action can:
|
|
|
|
```text
|
|
Android → PC import
|
|
PC → Android catalog publication
|
|
```
|
|
|
|
The current status/count-oriented Sync presentation is temporary.
|
|
|
|
A snapshot file remaining on Android is not a pending queue item. Therefore
|
|
labels such as:
|
|
|
|
```text
|
|
1 JSON candidate
|
|
```
|
|
|
|
must not be considered a final synchronization UX.
|
|
|
|
## Next synchronization UX
|
|
|
|
The TUI Sync page must become a persistent synchronization history, similar to:
|
|
|
|
```text
|
|
git log
|
|
```
|
|
|
|
Example:
|
|
|
|
```text
|
|
06/09/2026 16:00 ✓ Android +1 session · PC catalog 3 exercises
|
|
06/09/2026 15:42 ✓ no changes
|
|
06/09/2026 15:31 ! device disconnected
|
|
```
|
|
|
|
A synchronization entry must be selectable.
|
|
|
|
`Enter` opens a detailed view analogous to:
|
|
|
|
```text
|
|
git show
|
|
```
|
|
|
|
The detail must include:
|
|
|
|
```text
|
|
sync ID
|
|
trigger
|
|
start/end local time
|
|
status
|
|
|
|
Android → PC
|
|
exercises imported/reconciled/skipped
|
|
sessions imported/skipped
|
|
body observations imported/skipped
|
|
|
|
PC → Android
|
|
catalog exercises published
|
|
Android catalog apply result when available
|
|
|
|
transport/artifact diagnostics
|
|
```
|
|
|
|
## Android-triggered synchronization
|
|
|
|
The final Android Sync UX must not require:
|
|
|
|
```text
|
|
Prepare export
|
|
then use the PC manually
|
|
```
|
|
|
|
Target behavior:
|
|
|
|
```text
|
|
Android data change
|
|
-> mobile snapshot maintained automatically
|
|
|
|
Android "Synchronize now"
|
|
-> synchronization request
|
|
|
|
PC trainlog-syncd
|
|
-> detects request over direct MTP
|
|
-> runs the same bidirectional sync engine
|
|
-> writes synchronization receipt
|
|
|
|
Android
|
|
-> reads receipt
|
|
-> applies PC catalog
|
|
-> displays final synchronization result
|
|
```
|
|
|
|
MTP remains host-initiated. Therefore Android-triggered synchronization needs
|
|
a small PC-side agent; it cannot directly command libmtp operations on the PC.
|
|
|
|
## Display normalization
|
|
|
|
User-facing session history must use local presentation:
|
|
|
|
```text
|
|
DD/MM/YYYY HH:MM
|
|
```
|
|
|
|
Canonical RFC3339 timestamps remain unchanged in persistence and exchange.
|
|
|
|
## Next cursor
|
|
|
|
```text
|
|
SYNC_HISTORY_GIT_LIKE=NEXT
|
|
COMMON_SYNC_ENGINE=NEXT
|
|
TRAINLOG_SYNCD=NEXT
|
|
ANDROID_SYNC_REQUEST_RECEIPT=AFTER
|
|
ANDROID_AUTO_OUTBOX=AFTER_AGENT_FOUNDATION
|
|
```
|