trainlog/docs/sync_exchange.md

7.2 KiB

Trainlog synchronization exchange

Status

MOBILE_EXPORT_V1=FROZEN_FOR_IMPLEMENTATION
TRAINLOG_FORMAT_V1=FROZEN_UNCHANGED

This document defines a synchronization artifact. It is not the frozen Trainlog session JSON v1 format.

Android → PC artifact

Shared-storage path:

Download/Trainlog/trainlog-mobile-export-v1.json

Format header:

{
  "format": "trainlog-mobile-export",
  "version": 1
}

The artifact is a complete idempotent mobile snapshot containing:

exercises
sessions
body_observations

Exercises

Each exercise contains:

exercise_id
name
recording_mode
tracking_mode
data_fields

Sessions

Each session contains:

session_id
started_at
session_type
exercises

Each session exercise snapshots:

exercise_id
name
recording_mode
tracking_mode
data_fields
load_mode
rest_seconds

For SETS:

sets[]
    reps
or
    duration_seconds

For CONTINUOUS:

continuous
    duration_seconds
    speed_kmh optional
    distance_km optional

A continuous exercise has no synthetic set.

Body observations

Each body observation contains:

observation_id
observed_at
only the metrics actually measured

Transport

Android writes its own export into shared Downloads storage.

Desktop reads the artifact through direct libmtp transport.

No filesystem mount is required.

No SQLite database file is transferred.

PC → Android

A separate canonical catalog artifact will be defined and implemented after Android → PC export is validated on physical hardware.

The PC → Android path must not overload frozen Trainlog JSON v1.

Desktop import of mobile export v1

The desktop importer is:

tools/import_mobile_export.py

It validates the complete mobile snapshot before opening a write transaction.

Properties:

transactional
idempotent by stable IDs
exercise reconciliation by normalized name
profile conflicts rejected
unknown JSON fields rejected
no SQLite file copying

For mobile SETS v1, the Android form records one uniform set metric. The desktop importer derives:

target_sets = number of logged sets
target_reps or target_duration = uniform logged value

and preserves all performed sets separately.

A v1 mobile session with heterogeneous set metrics or 0 reps is rejected rather than inventing a desktop target.

Continuous activities remain target-less and are imported only into continuous_activity.

Recommended validation sequence:

python tools/import_mobile_export.py   /tmp/trainlog-mobile-export-v1.json   --dry-run

python tools/import_mobile_export.py   /tmp/trainlog-mobile-export-v1.json

Running the real import a second time must import nothing new and report the existing IDs as skipped.

Bidirectional synchronization v1

One desktop Sync action now performs both directions:

Android → PC
    direct-MTP download
    strict transactional import

PC → Android
    canonical PC exercise catalog export
    direct-MTP publication

The Android app obtains one persistent Storage Access Framework grant for:

Download/Trainlog

After this one-time grant, Android can import the PC-created catalog without broad storage permissions.

The Sync page displays persistent synchronization history instead of remote snapshot counts. A snapshot remaining present is not a pending queue item and must not be shown as a "candidate".

User-facing session history timestamps are displayed as:

DD/MM/YYYY HH:MM

Canonical RFC3339 storage remains unchanged.

Automatic Android outbox and sync request

Android no longer requires a manual export action.

The mobile snapshot is refreshed automatically on:

application start
exercise save
session save
body observation save
PC catalog apply

The Android Sync screen exposes:

Synchroniser maintenant

This writes:

Download/Trainlog/trainlog-sync-request-v1.json

with a stable request ID and timestamp.

The next PC-agent slice consumes this request and writes a sync receipt.

Validated bidirectional transport checkpoint

Validated on the physical Samsung device:

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

Artifacts:

Android → PC
    Download/Trainlog/trainlog-mobile-export-v1.json

PC → Android
    Download/Trainlog/trainlog-pc-catalog-v1.json

Both are synchronization artifacts and remain separate from frozen TRAINLOG_FORMAT_V1.

The Android Storage Access Framework folder grant must target:

Download/Trainlog

and the UI must permit changing the stored folder selection.

Remaining synchronization work:

persistent structured sync history
selectable sync detail
common sync engine
trainlog-syncd
Android-triggered request/receipt workflow
automatic mobile snapshot maintenance

Variable repetition sets

Trainlog preserves each performed set independently.

Accepted repetition input:

5x10
4,5,6,7,8,9,10,9,8,7,6,5,4
4..10..4

4..10..4 expands to:

4,5,6,7,8,9,10,9,8,7,6,5,4

Desktop schema v5 permits targetless SETS rows for actual-only mobile observations. Synchronization therefore does not invent a uniform target when performed sets are heterogeneous.

performed_sets remains the source of truth for actual per-set values.

Existing planned desktop sessions may still carry explicit target sets/reps or target durations.

trainlog-mobile-export v1 keeps ordered heterogeneous sets[].

Frozen TRAINLOG_FORMAT_V1 is unchanged.

Variable sets and session exercise removal checkpoint

Validated functionality in this checkpoint:

VARIABLE_REPETITION_SETS=PASS
REPETITION_SHORTHAND_5x10=PASS
REPETITION_EXPLICIT_LIST=PASS
REPETITION_PYRAMID=PASS

DESKTOP_SCHEMA_V5=PASS
V4_TO_V5_MIGRATION_REGRESSION=PASS
MOBILE_HETEROGENEOUS_SET_IMPORT=PASS
MOBILE_IMPORT_IDEMPOTENCE=PASS
NO_FAKE_UNIFORM_TARGET=PASS

ANDROID_SESSION_DRAFT_EXERCISE_REMOVE=PASS
DESKTOP_SESSION_EXERCISE_REMOVE=PASS

Accepted repetition examples:

5x10
4,5,6,7,8,9,10,9,8,7,6,5,4
4..10..4

A heterogeneous mobile session is persisted as ordered performed_sets. The desktop does not invent target_sets, target_reps or target_duration_seconds for actual-only mobile observations.

On Android, an exercise already added to the current session can be removed before saving the session.

On the desktop TUI, session editing already supports:

d supprimer

for removing the selected exercise from a current or persisted session draft. The database replacement remains transactional.

TRAINLOG_FORMAT_V1 remains frozen and unchanged.