278 lines
5 KiB
Markdown
278 lines
5 KiB
Markdown
# Desktop database
|
|
|
|
## 1. Status
|
|
|
|
```text
|
|
TRAINLOG_DATABASE_SCHEMA_VERSION=5
|
|
DATABASE_SCHEMA_V5=PASS
|
|
TRAINLOG_FORMAT_V1=FROZEN
|
|
```
|
|
|
|
The desktop SQLite database is the canonical long-term Trainlog history.
|
|
|
|
Its schema evolves independently from all JSON exchange-format versions.
|
|
|
|
## 2. Versioning
|
|
|
|
Schema version uses:
|
|
|
|
```sql
|
|
PRAGMA user_version;
|
|
```
|
|
|
|
Current value:
|
|
|
|
```text
|
|
5
|
|
```
|
|
|
|
Supported historical databases are migrated explicitly through the implemented
|
|
migration chain. A database newer than the running binary understands is
|
|
rejected.
|
|
|
|
A schema fixture must represent the real historical structure. Rewriting only
|
|
`user_version` is not an acceptable migration test.
|
|
|
|
## 3. Connection invariants
|
|
|
|
Every connection enables:
|
|
|
|
```sql
|
|
PRAGMA foreign_keys = ON;
|
|
```
|
|
|
|
A bounded SQLite busy timeout is configured by the core.
|
|
|
|
## 4. Tables
|
|
|
|
### `exercises`
|
|
|
|
Canonical desktop exercise catalog.
|
|
|
|
```text
|
|
id
|
|
exercise_id UNIQUE stable identity
|
|
name
|
|
normalized_name UNIQUE normalized display form
|
|
tracking_mode reps | duration
|
|
recording_mode sets | continuous
|
|
data_fields bounded bit mask
|
|
```
|
|
|
|
Rules include:
|
|
|
|
- continuous implies duration tracking;
|
|
- unknown supplemental field bits are rejected;
|
|
- normalized names remain unique.
|
|
|
|
### `sessions`
|
|
|
|
```text
|
|
id
|
|
session_id UNIQUE stable identity
|
|
started_at
|
|
ended_at nullable
|
|
session_type training | max_test
|
|
notes nullable
|
|
```
|
|
|
|
### `session_exercises`
|
|
|
|
Ordered exercise occurrence inside one session.
|
|
|
|
```text
|
|
session_row_id
|
|
exercise_row_id
|
|
recording_mode
|
|
data_fields
|
|
position
|
|
load_mode
|
|
rest_seconds
|
|
target_sets
|
|
target_reps
|
|
target_duration_seconds
|
|
target_weight_kg
|
|
notes
|
|
```
|
|
|
|
Current desktop history snapshots `recording_mode` and `data_fields` in the
|
|
session row. `tracking_mode` remains associated with the referenced exercise
|
|
catalog identity.
|
|
|
|
`SETS` rows support two target shapes in schema v5:
|
|
|
|
```text
|
|
explicit planned target
|
|
target_sets + exactly one target metric
|
|
|
|
actual-only mobile observation
|
|
target_sets = NULL
|
|
target_reps = NULL
|
|
target_duration_seconds = NULL
|
|
```
|
|
|
|
This v5 rule is what permits heterogeneous mobile performed sets without
|
|
inventing a fake uniform target.
|
|
|
|
`CONTINUOUS` rows are targetless and require:
|
|
|
|
```text
|
|
load_mode = none
|
|
rest_seconds = 0
|
|
target_weight_kg = NULL
|
|
```
|
|
|
|
### `performed_sets`
|
|
|
|
Ordered actual set records.
|
|
|
|
```text
|
|
session_exercise_row_id
|
|
position
|
|
reps nullable
|
|
duration_seconds nullable
|
|
weight_kg nullable
|
|
```
|
|
|
|
Exactly one primary actual metric is present:
|
|
|
|
```text
|
|
reps
|
|
or
|
|
duration_seconds
|
|
```
|
|
|
|
Actual repetitions may be zero.
|
|
|
|
Each row is independent; heterogeneous repetition sequences are first-class
|
|
data.
|
|
|
|
### `continuous_activity`
|
|
|
|
One-to-one actual record for a continuous session exercise.
|
|
|
|
```text
|
|
session_exercise_row_id UNIQUE
|
|
duration_seconds
|
|
speed_kmh nullable
|
|
distance_km nullable
|
|
```
|
|
|
|
Continuous activity never creates a fake performed set.
|
|
|
|
### `body_observations`
|
|
|
|
```text
|
|
observation_id UNIQUE
|
|
observed_at
|
|
session_row_id optional UNIQUE link
|
|
body_weight_kg
|
|
neck_cm
|
|
shoulders_cm
|
|
chest_cm
|
|
waist_cm
|
|
hips_cm
|
|
left_arm_cm
|
|
right_arm_cm
|
|
left_forearm_cm
|
|
right_forearm_cm
|
|
left_thigh_cm
|
|
right_thigh_cm
|
|
left_calf_cm
|
|
right_calf_cm
|
|
notes
|
|
```
|
|
|
|
At least one body metric must be present.
|
|
|
|
## 5. Identifier generation
|
|
|
|
Official desktop creator prefixes:
|
|
|
|
```text
|
|
ex_ exercise
|
|
se_ session
|
|
bo_ body observation
|
|
sy_ synchronization run
|
|
```
|
|
|
|
All use random UUIDv4 values.
|
|
|
|
Exchange parsers may accept other schema-valid opaque identities where their
|
|
contract explicitly permits it.
|
|
|
|
## 6. Transactions
|
|
|
|
Multi-row user operations are atomic.
|
|
|
|
Persisted session correction replaces session child rows transactionally while
|
|
preserving the parent:
|
|
|
|
```text
|
|
session_id
|
|
started_at
|
|
ended_at
|
|
session_type
|
|
session notes
|
|
linked body observation
|
|
```
|
|
|
|
Removing an exercise from a persisted session is therefore a transactional
|
|
replacement of the remaining child set.
|
|
|
|
A failed replacement rolls back to the previously persisted session.
|
|
|
|
Body-observation editing preserves its stable identity, timestamp, and optional
|
|
session link.
|
|
|
|
## 7. Mobile import semantics
|
|
|
|
`tools/import_mobile_export.py` validates the complete mobile snapshot before
|
|
committing database changes.
|
|
|
|
Properties:
|
|
|
|
```text
|
|
schema-v5 aware
|
|
transactional
|
|
idempotent by stable IDs
|
|
profile-aware catalog reconciliation
|
|
heterogeneous performed sets preserved
|
|
no fake target generated
|
|
continuous activity kept separate
|
|
```
|
|
|
|
## 8. Units
|
|
|
|
Canonical desktop persistence:
|
|
|
|
```text
|
|
weight/load kg
|
|
body circumference cm
|
|
duration/rest seconds
|
|
speed km/h
|
|
distance km
|
|
```
|
|
|
|
## 9. Android database
|
|
|
|
The Android SQLite database is independent.
|
|
|
|
Desktop and Android schema versions are not required to match.
|
|
|
|
Do not synchronize SQLite database files.
|
|
|
|
## 10. Validation
|
|
|
|
```bash
|
|
meson compile -C build
|
|
meson test -C build --print-errorlogs
|
|
```
|
|
|
|
Migration-specific regression coverage includes:
|
|
|
|
```text
|
|
schema_v5_migration
|
|
```
|
|
|
|
The current normal suite contains 19 tests.
|