Lokale und datenschutzfreundliche Terrarienverwaltung
This document defines the portable TerraManager backup format.
The backup format is designed to preserve TerraManager data independently from the underlying Drift/SQLite database implementation and from platform-specific file paths.
The same backup format is intended to be usable on all supported TerraManager platforms.
TerraManager backups use the following file extension:
.tmbackup
A backup file is an archive containing structured data and optional media.
Example filename:
TerraManager_Backup_2026-09-02_15-30.tmbackup
The backup format must:
New archives retain format version 2 and encode every event/metadata instant
(fedAt, measuredAt, shedAt, capturedAt, reminder baselines, creation,
update and archive times) as UTC ISO-8601 ending in Z. Storage preserves the
instant; clients convert it once to their local time for display. No fixed
two-hour adjustment is applied. These archives restore in standalone and
Shared Care, and a subsequent export does not add another offset.
Versions 1 and 2 remain supported. Older archives can contain local wall-clock
timestamps with no offset. Their original source time zone cannot be inferred
from the archive. Shared Care therefore asks the administrator to confirm the
original device’s IANA zone (for example Europe/Berlin), suggesting the
browser zone when available. The restore API requires X-Backup-Time-Zone
for such files and rejects the file before replacement if it is omitted or
invalid. Each timestamp uses that zone’s historical daylight-saving rule.
An ambiguous repeated autumn hour uses the earlier occurrence; a nonexistent
spring-transition time is rejected instead of silently moved. Standalone
retains the documented legacy rule of interpreting offset-free timestamps in
the importing device’s local zone. Explicit Z or numeric offsets always take
precedence over the legacy source-zone selection.
Birth dates are calendar dates (YYYY-MM-DD), never UTC instants. Old date
strings with a time/offset retain their written calendar components. Birth-date
accuracy is unchanged. Existing collection rows are not guessed or shifted:
to repair previously shifted care history, restore the original backup with
the correct source zone, following the normal safety-copy workflow.
The backup format has its own version number:
backupFormatVersion
This value is independent from the Drift database schema version:
databaseSchemaVersion
For example:
backupFormatVersion = 1
databaseSchemaVersion = 2
A database schema change does not automatically require a new backup format version.
The backup format version changes only when the external portable backup representation becomes incompatible with the previous format.
The current backup format version is:
2
TerraManager currently supports restore of:
Backup Format 1
Backup Format 2
New backups are always created as Backup Format Version 2.
New .tmbackup files may be plain ZIP archives or password-protected
containers. The inner ZIP remains portable format 2 in either case. Plain
format-1 and format-2 ZIP files remain readable. The outer container has its
own version and does not change backupFormatVersion.
All integer fields below are unsigned. Multi-byte fields are little-endian unless stated otherwise. The 42-byte header is:
| Offset | Bytes | Content |
|---|---|---|
| 0 | 8 | ASCII TMBKENC! |
| 8 | 1 | Container version 1 |
| 9 | 1 | KDF 1 = Argon2id |
| 10 | 1 | Cipher 1 = AES-256-GCM |
| 11 | 4 | Maximum plaintext frame size, 262144 |
| 15 | 4 | Argon2id memory in KiB, currently 19456 |
| 19 | 2 | Argon2id iterations, currently 2 |
| 21 | 1 | Argon2id parallelism, currently 1 |
| 22 | 16 | Fresh random salt |
| 38 | 4 | Fresh random nonce prefix |
Argon2id derives a 32-byte key from the entered password and the header salt. Each frame is a four-byte plaintext length followed by that many ciphertext bytes and a 16-byte GCM tag. The AES-GCM nonce is the header nonce prefix followed by the zero-based 64-bit frame number in big-endian order. Additional authenticated data is the entire header, the frame number in big-endian order, and the plaintext length in little-endian order. The last frame has length zero and an authenticated tag. Readers reject missing final frames, extra bytes, invalid lengths and unsupported header parameters. A wrong password and modified ciphertext intentionally have the same authentication error. No filename, manifest, media or settings appear outside the encrypted payload; the container header reveals only its format and KDF settings.
The password is never stored in a backup, settings, account data or server request and is not written to application or Shared Care server logs. It is kept only for the active operation and cannot be recovered. Shared Care encrypts the downloaded ZIP in the browser and decrypts a selected protected file before submitting the ordinary portable ZIP to the server over its authenticated connection. The Shared Care server therefore processes the inner ZIP and is not a password-recovery service. Native encrypted export writes only encrypted bytes to its temporary save file. A stream-only encrypted selection is staged as ciphertext and removed after restore or cancellation.
Backup Format Version 1 remains supported for backward compatibility with backups created by TerraManager 0.6.x.
Backup Format Version 1 is the legacy format created by TerraManager 0.6.x.
It remains supported for restore compatibility.
Version 1 uses the following archive structure:
TerraManager_Backup_YYYY-MM-DD_HH-mm.tmbackup
├── manifest.json
├── data.json
├── settings.json
└── media/
└── animals/
Backup Format Version 2 is the current format.
It extends portable Box data with dimensions and Box pictures. Current Version
2 records can additionally contain optional Box names, lifecycle metadata,
temperature zones and notes. Animal records can contain optional profile fields
plus stable category and subcategory values. Animal and Box records can also
contain additive ordered pictures lists for local picture histories. Current
Animal records can additionally contain nighttime minimum/maximum values and a
timestamped weightHistory list.
Archive structure:
TerraManager_Backup_YYYY-MM-DD_HH-mm.tmbackup
├── manifest.json
├── data.json
├── settings.json
└── media/
├── animals/
└── boxes/
The tree describes required paths, not ZIP entry order. Exporters may write media entries before the JSON entries; restore resolves entries by path.
Version 2 adds the following portable Box fields. name, lifecycle metadata,
temperatureZones and notes are later, backward-compatible extensions of the
same format:
name
status
archiveReason
archivedAt
archiveNotes
widthCm
heightCm
depthCm
temperatureZones
notes
pictureMediaPath
pictures
Version 2 does not preserve internal MediaAsset.id values.
Box and Animal pictures are stored as portable archive media and recreated as
new MediaAssets during restore.
manifest.json contains metadata required to identify and validate a backup
before any restore operation begins.
Required fields:
backupFormatVersion
appVersion
databaseSchemaVersion
createdAt
Example:
{
"backupFormatVersion": 2,
"appVersion": "1.1.1",
"databaseSchemaVersion": 8,
"createdAt": "2026-09-08T13:30:00.000Z"
}
Identifies the external TerraManager backup format.
Backup Format Version 2 uses:
2
Current TerraManager builds accept Backup Format Versions 1 and 2 for restore.
Version 1 is interpreted using the legacy Box representation. Missing Version 2
Box fields are mapped to null, except missing status, which defaults to
active.
Unsupported older or future format versions must be rejected before restore.
Contains the TerraManager application version that created the backup.
Example:
1.0.4
This value is informational and may also be used during compatibility validation.
Contains the Drift database schema version used by the TerraManager version that created the backup.
This value does not define the backup structure.
It exists as metadata to assist with diagnostics and compatibility handling.
Contains the backup creation timestamp.
Timestamps in the backup format use ISO 8601 strings.
Example:
2026-09-02T13:30:00.000Z
Event and metadata instants use ISO 8601. From v1.14.1, every new export
normalizes those values to UTC with an explicit Z suffix:
dateTime.toUtc().toIso8601String()
Explicit-offset values can be parsed with:
DateTime.parse(...)
Clients convert an instant to local time once for display. Legacy offset-free
values in Versions 1 and 2 first follow the source-zone rules described above;
they must not be assumed to be UTC. Offset-free examples below illustrate
supported legacy data, not the current export representation. Birth dates use
YYYY-MM-DD and do not pass through UTC conversion.
Raw Drift or SQLite timestamp representations must not be exposed as the portable backup representation.
data.json contains portable representations of TerraManager domain data.
Backup Format Versions 1 and 2 contain:
boxes
animals
feedingEvents
Example top-level structure:
{
"boxes": [],
"animals": [],
"feedingEvents": []
}
The three collections must always be present, including when they are empty.
Backup Format Versions 1 and 2 preserve the integer IDs of Boxes, Animals and FeedingEvents. Current Format 2 exports also preserve each nested Animal weight entry ID.
This is possible because the current restore model uses full replacement rather than merge semantics.
Preserving IDs keeps existing relationships deterministic:
Box.id
↑
Animal.boxId
Animal.id
↑
FeedingEvent.animalId
For example:
Box.id = 4
Animal.boxId = 4
Animal.id = 17
FeedingEvent.animalId = 17
A future merge-import implementation must not assume that source database IDs can be inserted unchanged.
Such an implementation may require a separate source-to-target ID mapping strategy.
Current exports include status, archiveReason, archivedAt and
archiveNotes for every Box, including explicit nulls for empty metadata.
The backup format remains Version 2.
| Field | Portable value |
|---|---|
status |
active or archived |
archiveReason |
sold, replaced, damaged, stored, other, or null |
archivedAt |
ISO 8601 timestamp or null |
archiveNotes |
Optional string or null |
Archived Boxes require an archive reason and timestamp. Active Boxes must have all three archive metadata fields set to null. The validator rejects unknown or localized enum strings, invalid field types, invalid timestamps and inconsistent lifecycle metadata before restore begins. Active Animals must reference active Boxes; backups assigning them to archived Boxes are rejected. Archive notes are independent of ordinary Box notes.
Older Format 1 and Format 2 records without status default to active, with
absent archive metadata defaulting to null. An explicitly null status is
invalid. Restore recreates every lifecycle field and preserves the Box QR
identifier, other attributes and picture media just as it does for active
Boxes. Compatibility here means that the new application reads old backups;
old application versions do not understand the new lifecycle fields.
stored is a new stable Box archive reason in Format 2. A client from before
this value was introduced rejects a backup containing "archiveReason":
"stored" as an unsupported enum during validation, before restoring data.
It does not convert the value to other. Restore that backup with a client
that supports stored; older backups and existing archive reasons retain
their original meanings.
A Version 1 Box contains:
id
qrId
createdAt
updatedAt
Example:
{
"id": 1,
"qrId": "TM:BOX:11111111-1111-4111-8111-111111111111",
"createdAt": "2026-08-01T10:00:00.000",
"updatedAt": "2026-08-02T12:00:00.000"
}
When a Version 1 backup is restored by the current TerraManager build, absent fields introduced in Version 2 are initialized as:
widthCm = null
heightCm = null
depthCm = null
name = null
status = active
archiveReason = null
archivedAt = null
archiveNotes = null
temperatureZones = null
notes = null
pictureMediaPath = null
A Version 2 Box contains:
id
qrId
name
status
archiveReason
archivedAt
archiveNotes
widthCm
heightCm
depthCm
temperatureZones
notes
pictureMediaPath
pictures
createdAt
updatedAt
Example:
{
"id": 1,
"qrId": "TM:BOX:11111111-1111-4111-8111-111111111111",
"name": "Rainforest",
"status": "active",
"archiveReason": null,
"archivedAt": null,
"archiveNotes": null,
"widthCm": 60.0,
"heightCm": 40.0,
"depthCm": 45.0,
"temperatureZones": "Warm side 28 °C",
"notes": "Quarantine enclosure near the window",
"pictureMediaPath": "media/boxes/1.jpg",
"pictures": [
{
"mediaPath": "media/boxes/1_gallery_0_17.webp",
"capturedAt": "2026-07-01T09:00:00.000Z"
},
{
"mediaPath": "media/boxes/1.jpg",
"capturedAt": "2026-08-01T10:00:00.000Z"
}
],
"createdAt": "2026-08-01T10:00:00.000",
"updatedAt": "2026-08-02T12:00:00.000"
}
Box names, dimensions, temperature zones and notes are optional.
When present, name contains free-form text. Missing or explicit null values
restore as an unnamed Box.
When present, dimensions must be greater than zero.
When present, temperatureZones contains free-form text. Missing or explicit
null values restore as an empty Box temperature-zone note.
When present, notes contains free-form text. Missing or explicit null
values restore as empty Box notes.
pictureMediaPath is optional.
pictures is an optional ordered list. Each entry contains a portable
mediaPath and ISO 8601 capturedAt timestamp. When pictureMediaPath is
non-null, it identifies one path in pictures as the primary detail image.
Missing pictures in an older backup is interpreted as a one-entry gallery
when pictureMediaPath exists.
qrId is the permanent TerraManager Box identifier.
Format:
TM:BOX:<UUID-v4>
The QR identifier survives backup and restore unchanged.
Generated QR images are not stored because they can be regenerated from the
permanent qrId.
An Animal is serialized with the following fields:
id
boxId
status
commonName
latinName
category
subcategory
sex
birthDate
birthDateAccuracy
tempMin
tempMax
nighttimeTemperature
nighttimeTemperatureMin
nighttimeTemperatureMax
humidityMin
humidityMax
originHabitat
weight
weightHistory
sheddingNotes
sheddingHistory
showWeightOnDetail
showSheddingOnDetail
restOrDormancyPeriods
temperatureZones
pictureMediaPath
pictures
notes
archiveReason
archivedAt
archiveNotes
feedingReminderIntervalDays
feedingReminderBaseline
feedingReminderWeekdays
feedingReminderMinuteOfDay
feedingReminderTimeZone
createdAt
updatedAt
Example active Animal:
{
"id": 10,
"boxId": 1,
"status": "active",
"commonName": "Test Snake",
"latinName": "Pantherophis guttatus",
"category": "reptile",
"subcategory": "snake",
"sex": "female",
"birthDate": "2024-01-01T00:00:00.000",
"birthDateAccuracy": "yearKnown",
"tempMin": 24.0,
"tempMax": 28.0,
"nighttimeTemperature": null,
"nighttimeTemperatureMin": 18.0,
"nighttimeTemperatureMax": 20.0,
"humidityMin": 40.0,
"humidityMax": 60.0,
"originHabitat": "North America",
"weight": null,
"weightHistory": [
{
"id": 7,
"weightGrams": 140.5,
"measuredAt": "2026-09-08T12:00:00.000"
}
],
"sheddingHistory": [
{
"id": 12,
"shedAt": "2026-09-18T18:30:00.000",
"notes": "Complete shed",
"createdAt": "2026-09-18T18:35:00.000",
"updatedAt": "2026-09-18T18:35:00.000"
}
],
"sheddingNotes": null,
"showWeightOnDetail": true,
"showSheddingOnDetail": true,
"restOrDormancyPeriods": "Less active in winter",
"temperatureZones": null,
"pictureMediaPath": "media/animals/10.jpg",
"pictures": [
{
"mediaPath": "media/animals/10.jpg",
"capturedAt": "2026-08-01T10:00:00.000Z"
},
{
"mediaPath": "media/animals/10_gallery_1_42.webp",
"capturedAt": "2026-08-15T14:30:00.000Z"
}
],
"notes": "Test animal",
"archiveReason": null,
"archivedAt": null,
"archiveNotes": null,
"feedingReminderIntervalDays": 7,
"feedingReminderBaseline": "2026-09-08T12:00:00.000",
"createdAt": "2026-08-01T10:00:00.000",
"updatedAt": "2026-08-02T12:00:00.000"
}
Example archived Animal:
{
"id": 11,
"boxId": null,
"status": "archived",
"commonName": "Archived Snake",
"latinName": "Pantherophis guttatus",
"category": "reptile",
"subcategory": "snake",
"sex": null,
"birthDate": null,
"birthDateAccuracy": null,
"tempMin": 24.0,
"tempMax": 28.0,
"nighttimeTemperature": null,
"nighttimeTemperatureMin": null,
"nighttimeTemperatureMax": null,
"humidityMin": 40.0,
"humidityMax": 60.0,
"originHabitat": null,
"weight": null,
"weightHistory": [],
"sheddingNotes": null,
"sheddingHistory": [],
"showWeightOnDetail": true,
"showSheddingOnDetail": true,
"restOrDormancyPeriods": null,
"temperatureZones": null,
"pictureMediaPath": null,
"notes": null,
"archiveReason": "rehomed",
"archivedAt": "2026-09-01T00:00:00.000",
"archiveNotes": "Moved to another keeper",
"feedingReminderIntervalDays": 14,
"feedingReminderBaseline": "2026-08-25T09:00:00.000",
"createdAt": "2026-08-01T10:00:00.000",
"updatedAt": "2026-09-01T00:00:00.000"
}
TerraManager 1.4.0 added five optional strings without changing Backup Format Version 2. In current forms, four remain Animal fields:
originHabitat
weight
sheddingNotes
restOrDormancyPeriods
TerraManager 1.7.1 moves current temperature-zone ownership to the Box without
changing Backup Format Version 2. temperatureZones remains accepted on Animal
records only as a legacy key. Current input and display belong to
BackupBox.temperatureZones. During restore, a legacy non-empty Animal value
seeds its assigned Box only when that Box has no value; the lowest Animal ID
wins deterministically. Export preserves any legacy Animal value already
present so old data is not silently discarded.
null represents an empty legacy string value. Restore accepts older Format 1
and Format 2 records where any or all optional keys are absent and maps those
fields to null. A present non-string legacy value is invalid application data.
TerraManager v1.8.0 adds nullable numeric nighttimeTemperature without
changing Backup Format Version 2. Missing and explicit null values restore as
no nighttime temperature. Present values must be finite and within the same
inclusive 0–60 °C range as the daytime temperature fields. The existing
tempMin and tempMax keys represent minimum and maximum daytime temperature.
TerraManager v1.9.0 adds nullable nighttimeTemperatureMin and
nighttimeTemperatureMax without changing Backup Format Version 2. When both
new keys are absent, restore uses a valid legacy nighttimeTemperature value
for both bounds. Each populated bound must be finite and within 0–60 °C, and a
populated minimum must not exceed a populated maximum.
Current exports retain the legacy weight key for compatibility and add a
weightHistory list. Every entry contains a unique integer id, positive
finite weightGrams and an ISO 8601 measuredAt timestamp. Missing history
restores as an empty list. If an older record has no history, restore converts
an unambiguous positive gram string such as 140 g into one timestamped entry;
ambiguous free-form text remains in the legacy field until it is replaced.
Archiving retains the full list, and current duplication creates one new
measurement rather than copying historical entries.
TerraManager v1.10.0 adds a sheddingHistory list without changing Backup
Format Version 2.
Each entry contains:
id
shedAt
notes
createdAt
updatedAt
id is a unique positive integer. shedAt, createdAt and updatedAt are ISO
8601 timestamps. notes is either a string or null.
A missing sheddingHistory field restores as an empty list. Archiving an Animal
retains every shedding event. Permanently deleting the Animal removes its
associated shedding history through the database relationship.
Restore validates event IDs, timestamps, field types and Animal ownership. Duplicate event IDs, invalid timestamps and non-string notes are invalid application data.
The legacy nullable sheddingNotes key remains accepted for compatibility.
When no timestamped history is available, a compatible non-empty legacy value
can be migrated to one event using the Animal’s existing update timestamp. New
exports, Animal creation and duplication do not create new free-form shedding
notes.
TerraManager v1.10.2 adds two optional Boolean fields to Animal backup records:
showWeightOnDetail
showSheddingOnDetail
Current exports always write both fields. A missing field in an older Version 1
or Version 2 backup restores as true, preserving the detail presentation used
before these preferences existed.
A present non-Boolean value is invalid application data. The values affect only Animal-detail presentation. They do not remove Weight or Shedding history from the backup.
TerraManager 1.7.0 adds a required category string and nullable
subcategory string without changing Backup Format Version 2. Export writes
stable portable values rather than localized labels. Format 1 and older Format
2 records where category is absent restore as other with no subcategory.
Supported categories and compatible subcategories are:
amphibian: frogOrToad, newtOrSalamander, other
reptile: snake, lizard, turtle, other
arachnid: tarantula, otherSpider, scorpion,
whipSpiderOrWhipScorpion, other
insect: beetle, cockroach, mantis, grasshopperOrCricket, other
myriapod: millipede, centipede, other
crustacean: isopod, crab, other
mollusc: snail, other
otherInvertebrate: no subcategory
other: no subcategory
An unknown value, localized label or subcategory that does not belong to the selected category is invalid application data. An explicit null or non-string category is also invalid; only a missing legacy category receives the fallback.
TerraManager 0.12.1 adds two optional Animal fields without changing Backup Format Version 2:
feedingReminderIntervalDays
feedingReminderBaseline
A disabled reminder uses null for both fields. An enabled reminder requires a
positive whole-day interval and an ISO 8601 baseline timestamp. A backup with
only one field or with a non-positive interval is invalid.
Archived Animals may retain a valid reminder configuration. They remain excluded from active reminder results by application logic.
Backups created before these fields were introduced omit them. Missing fields
are decoded as null, which restores the Animal with reminders disabled. The
change is additive and therefore does not require Backup Format Version 3.
Weekday reminders add three optional Animal fields within Backup Format 2:
feedingReminderWeekdays (bit mask 1–127, Monday bit 0),
feedingReminderMinuteOfDay (0–1439), and feedingReminderTimeZone (valid
IANA zone). They require a baseline and a null interval. All three must be
present together; a partial or conflicting configuration is invalid. Older
backups omit these fields and keep their interval reminders unchanged.
Lifecycle consistency is part of backup validation.
An active Animal uses:
status = "active"
boxId = valid Box ID
archiveReason = null
archivedAt = null
archiveNotes = null
The referenced Box must exist in the backup.
An archived Animal uses:
status = "archived"
boxId = null
archiveReason = defined archive reason
archivedAt = defined timestamp
archiveNotes = optional
Archived Animals retain their Animal record and FeedingEvent history.
Unknown or contradictory lifecycle combinations must cause backup validation to fail before restore begins.
A FeedingEvent is serialized with the following fields:
id
animalId
fedAt
notes
Example:
{
"id": 100,
"animalId": 10,
"fedAt": "2026-08-20T18:30:00.000",
"notes": "Mouse"
}
animalId must reference an Animal contained in the same backup.
The chronological latest feeding remains derived from FeedingEvents and is not stored separately.
Enum values stored in backups are part of the external backup format.
They must not be generated implicitly from Dart enum names during export.
TerraManager uses explicit encoding and decoding for backup enum values.
This allows internal Dart enum names to evolve independently while preserving compatibility with existing backup files.
Unknown enum values must cause backup validation to fail instead of being silently replaced with default values.
Backup Format Version 2 defines:
sold
replaced
damaged
stored
other
Mapping:
BoxArchiveReason.sold -> "sold"
BoxArchiveReason.replaced -> "replaced"
BoxArchiveReason.damaged -> "damaged"
BoxArchiveReason.stored -> "stored"
BoxArchiveReason.other -> "other"
Backup Format Versions 1 and 2 define:
active
archived
Mapping:
AnimalStatus.active -> "active"
AnimalStatus.archived -> "archived"
Backup Format Versions 1 and 2 define:
sold
traded
deceased
rehomed
other
Mapping:
AnimalArchiveReason.sold -> "sold"
AnimalArchiveReason.traded -> "traded"
AnimalArchiveReason.deceased -> "deceased"
AnimalArchiveReason.rehomed -> "rehomed"
AnimalArchiveReason.other -> "other"
Backup Format Versions 1 and 2 define:
exact
monthKnown
yearKnown
Mapping:
BirthDateAccuracy.exact -> "exact"
BirthDateAccuracy.monthKnown -> "monthKnown"
BirthDateAccuracy.yearKnown -> "yearKnown"
Backup Format Versions 1 and 2 define:
male
female
unknown
Mapping:
Sex.male -> "male"
Sex.female -> "female"
Sex.unknown -> "unknown"
Internal MediaAsset.id values and device-specific filesystem paths are not
part of the portable backup format.
Backup Format Version 2 supports portable media for both Animals and Boxes:
media/
├── animals/
│ ├── <animalId>.<extension>
│ └── <animalId>_gallery_<order>_<mediaId>.<extension>
└── boxes/
├── <boxId>.<extension>
└── <boxId>_gallery_<order>_<mediaId>.<extension>
Animal representation:
{
"pictureMediaPath": "media/animals/10.jpg"
}
Box representation:
{
"pictureMediaPath": "media/boxes/1.jpg"
}
Current records can additionally contain an ordered gallery:
{
"pictureMediaPath": "media/animals/10.webp",
"pictures": [
{
"mediaPath": "media/animals/10.webp",
"capturedAt": "2026-08-01T10:00:00.000Z"
},
{
"mediaPath": "media/animals/10_gallery_1_42.webp",
"capturedAt": "2026-09-01T10:00:00.000Z"
}
]
}
List order is the gallery order. pictureMediaPath remains the backward-
compatible primary-image pointer and can be null while pictures retains
historical entries. Validation rejects duplicate gallery paths and a primary
path that is not part of the same gallery. Restore recreates one MediaAsset and
one owner association for every list entry, preserving order, timestamps and
primary selection. Backups without pictures retain the earlier single-image
restore behavior.
For persistent MediaAssets, the archive extension is derived from the stored
filename or MIME type.
New and replaced pictures are normally stored and exported as .webp files.
Pictures created by earlier versions can remain JPEG, PNG or another supported
format and retain that format during export. Restore accepts these mixed media
formats and recreates the matching filename and MIME metadata, so Backup Format
Version 2 does not require a migration.
The shared backup media mapping recognizes:
.jpg / .jpeg -> image/jpeg
.png -> image/png
.webp -> image/webp
.gif -> image/gif
.bmp -> image/bmp
.heic -> image/heic
.heif -> image/heif
.img -> application/octet-stream
When a supported stored filename extension agrees with its MIME type, the
extension is preserved. If known MIME metadata conflicts with a stale filename,
the MIME type determines the exported extension. A legacy source without known
extension or MIME metadata uses .img. Media bytes are copied into and out of
the archive unchanged; backup operations never recompress them.
Current exports ZIP the structured JSON and every referenced gallery picture. New or replaced pictures normally reach the backup already reduced to WebP with a 1920-pixel maximum edge; legacy pictures keep their original format and bytes. The primary gallery picture is referenced, not exported twice. Generated QR images are omitted because they can be recreated from Box QR identifiers. Duplicated records can still carry separate copies of identical picture bytes. Further size reduction must be measured against complete archives and must not silently discard media or history. Backup-size work precedes the proposed password-encrypted container (ADR-036); even smaller archives still require bounded-memory export and restore for large collections.
Legacy Animal picturePath data may still be read during export as a
compatibility fallback.
Boxes have no legacy filesystem picture path.
During restore:
archive media
│
▼
MediaAssets
│
├──► Box.pictureMediaId
│
└──► Animal.pictureMediaId
New local MediaAsset.id values are created during restore.
Internal MediaAsset IDs are not portable domain identities and are therefore not preserved.
If a pictureMediaPath is present, the referenced archive entry must exist,
must not be empty and must use the correct media directory for its record type.
Animals without pictures use:
{
"pictureMediaPath": null
}
If pictureMediaPath contains a media reference, the referenced file must exist
inside the backup archive.
A missing referenced media file makes the backup invalid.
Generated QR PNG files are not included in TerraManager backups.
QR images are derived from:
Box.qrId
and can therefore be regenerated after restore.
Excluding generated QR images:
settings.json contains portable application preferences. Archives exported
from the shared server include the optional scope: collectionOnly value and
neutral required settings fields. They contain the shared collection, not any
caregiver’s account preferences. Importing such an archive into a standalone
installation preserves that installation’s personal preferences. Older archives
without scope retain their established personal-settings behavior.
Shared Care administrators export this archive through Shared Settings. A
restore replaces the server collection only after validating the archive and
checking a safety token against concurrent changes; the account database is
not replaced. The archive includes collection picture media but excludes
server accounts, password hashes, sessions and personal account preferences.
For server disaster recovery, the operator must separately back up both
SQLite databases in deploy/data/ while the server is stopped. Neither the
portable archive nor the host-volume archive is encrypted by TerraManager.
See Shared Care deployment for an isolated restore
test and the update/rollback procedure.
The required settings fields in Backup Format Versions 1 and 2 are:
themeMode
accent
TerraManager 0.10.0 adds the optional field:
language
TerraManager 0.11.0 adds another optional field:
animalNameOrder
TerraManager 0.13.3 adds another optional field:
boxSortOrder
TerraManager 0.13.4 adds another optional field:
animalSortOrder
TerraManager v1.9.1 adds another optional field:
animalCategoryViewEnabled
TerraManager v1.10.0 adds the optional field:
bigPictureModeEnabled
TerraManager v1.10.2 adds the optional field:
nextFeedingSummaryEnabled
These additive fields remain part of Backup Format Version 2. Older Version 1 and Version 2 backups without these optional settings remain compatible. Missing values use the following defaults:
language = system
animalNameOrder = commonNameFirst
boxSortOrder = labelAscending
animalSortOrder = createdOldestFirst
animalCategoryViewEnabled = false
bigPictureModeEnabled = false
nextFeedingSummaryEnabled = false
A legacy Category sort value enables category grouping while it is migrated to the corresponding displayed-name order.
{
"themeMode": "dark",
"accent": "green",
"language": "german",
"animalNameOrder": "latinNameFirst",
"animalSortOrder": "latestFeedingOldestFirst",
"animalCategoryViewEnabled": true,
"bigPictureModeEnabled": true,
"nextFeedingSummaryEnabled": true,
"boxSortOrder": "labelDescending"
}
Settings values are also part of the backup format contract and must be explicitly encoded and validated.
Backup Format Versions 1 and 2 define:
system
light
dark
Mapping:
ThemeMode.system -> "system"
ThemeMode.light -> "light"
ThemeMode.dark -> "dark"
Unknown theme mode values must cause validation to fail.
Backup Format Versions 1 and 2 define:
green
blue
teal
orange
purple
red
These correspond to the predefined TerraManager application accent choices.
Unknown accent values must cause validation to fail.
The optional language field defines:
system
english
german
Mapping:
AppLanguage.system -> "system"
AppLanguage.english -> "english"
AppLanguage.german -> "german"
If the field is absent, restore uses AppLanguage.system. If the field is
present with an unknown value, backup validation must fail.
The optional Animal name-order field defines:
commonNameFirst
latinNameFirst
Mapping:
AnimalNameOrder.commonNameFirst -> "commonNameFirst"
AnimalNameOrder.latinNameFirst -> "latinNameFirst"
If the field is absent, restore uses AnimalNameOrder.commonNameFirst. If the
field is present with an unknown value, backup validation must fail.
The optional Animal sort-order field defines:
createdOldestFirst
createdNewestFirst
displayNameAscending
displayNameDescending
ageOldestFirst
ageYoungestFirst
latestFeedingNewestFirst
latestFeedingOldestFirst
If the field is absent, restore uses AnimalSortOrder.createdOldestFirst. If
the field is present with an unknown value, backup validation must fail. The
legacy values categoryAscending and categoryDescending remain accepted for
older backups. They enable category grouping and map to
displayNameAscending and displayNameDescending, respectively; new backups
do not write either legacy value.
The optional Boolean animalCategoryViewEnabled field controls whether the
Animal Overview displays the flat list or canonical category groups. If the
field is absent, restore uses false, except for a legacy Category sort value,
which enables the grouped view during migration. A present non-Boolean value is
invalid. The setting affects presentation only and does not change stored
Animal taxonomy or Backup Format Version 2.
The optional Boolean bigPictureModeEnabled field controls the large-picture
presentation used by Box and Animal overviews. It applies to flat and
category-grouped Animal views.
If the field is absent, restore uses false. A present non-Boolean value is
invalid. The setting affects presentation only and does not change stored
pictures, picture associations, taxonomy or overview ordering.
The optional Boolean nextFeedingSummaryEnabled field controls whether the
Animal Overview displays the next upcoming feeding for an active Animal with an
enabled reminder.
If the field is absent, restore uses false. A present non-Boolean value is
invalid. The setting does not change reminder configuration, calculated due
timestamps or FeedingEvents.
Due reminders remain visible according to their existing rules regardless of this optional summary setting.
Animal History and Box History sort preferences are stored locally as presentation preferences. They are not included in Portable Backup Format Version 2.
Restoring a backup therefore does not overwrite the archive order selected on the current installation.
The optional Box sort-order field defines:
labelAscending
labelDescending
nameAscending
nameDescending
volumeAscending
volumeDescending
If the field is absent, restore uses BoxSortOrder.labelAscending. Legacy
createdOldestFirst values map to labelAscending, while
createdNewestFirst maps to labelDescending. If the field is present with any
other unknown value, backup validation must fail. New backups write one of the
six current label, name or calculated-volume values. Volume ordering remains a
presentation setting; no calculated volume is stored in the backup.
Before restore, the complete backup archive must be validated.
Validation includes at least:
manifest.json existsdata.json existssettings.json existsbackupFormatVersionsheddingHistory lists and event ownershipValidation must complete successfully before existing TerraManager data is modified.
Archive entry paths must be portable relative paths using / as separator.
The following are rejected:
. path segments.. path segmentsThis prevents backup archives from referencing files outside their intended restore location.
The following relationships must be valid.
For every active Animal:
Animal.boxId
must reference an existing Box.
Archived Animals must use:
boxId = null
Every:
FeedingEvent.animalId
must reference an existing Animal.
Broken references make the backup invalid.
Supported backup formats must not contain conflicting identities.
At minimum:
A backup containing duplicate required identities must be rejected.
The current restore implementation uses full replacement for Backup Format Versions 1 and 2.
Existing TerraManager domain data is not merged with backup data.
Merge restore is explicitly outside the current restore semantics.
The restore sequence is:
Select backup
│
▼
Read archive
│
▼
Validate complete backup
│
▼
Show backup information
│
▼
Request explicit confirmation
and safety-backup choice
│
▼
Create and persist safety backup
when enabled
│
▼
Restore application settings
│
▼
Transactional database replacement
│
├── Boxes
├── MediaAssets
├── Animals
└── FeedingEvents
│
▼
Foreign-key integrity check
│
▼
Restore complete
No destructive database operation begins before validation and explicit user confirmation succeed.
Before replacing existing TerraManager data, the confirmation dialog offers a safety backup of the current state. The option is enabled by default for each Restore attempt and can be disabled for that operation, for example when the current database is empty.
The safety backup exists to reduce the risk of accidental data loss caused by:
When enabled, a failure to create or persist the safety backup stops Restore before destructive changes begin. When disabled, no safety-backup archive is created and no save destination is requested. Backup validation, explicit confirmation, settings rollback and transactional database replacement remain unchanged.
An invalid backup must never modify existing TerraManager data.
If validation fails:
existing database = unchanged
existing media = unchanged
existing settings = unchanged
Restore implementation must avoid leaving the application in an apparently successful but partially restored state.
Exact transactional and recovery behavior is defined by the restore implementation.
Domain data and persistent media replacement are performed inside a Drift transaction.
Existing records are deleted in dependency-safe order:
Delete FeedingEvents
Delete Animals
Delete Boxes
Delete MediaAssets
Reset autoincrement sequences
Restore insertion order is:
For each Box picture:
Insert MediaAsset
obtain new MediaAsset.id
Insert Boxes using pictureMediaId
For each Animal picture:
Insert MediaAsset
obtain new MediaAsset.id
Insert Animals using pictureMediaId
Insert FeedingEvents
Run foreign-key integrity check
Box and Animal MediaAsset IDs are recreated locally and may differ from IDs in the source installation.
If any insertion or integrity check fails, the Drift transaction is rolled back.
If database replacement fails after application settings were changed, the previous application settings are restored.
When created, the pre-restore safety backup is never deleted automatically as part of rollback.
Backup Format Versions 1 and 2 intentionally use full replacement.
Merge restore is not supported.
This avoids ambiguity around:
A future merge implementation will require explicit conflict-resolution and ID mapping rules.
The backup representation does not depend on:
Box and Animal pictures are exported as archive media entries and restored into
the local MediaAssets persistence layer.
The same restore model is therefore used on Android and Web.
Backup Format Version 2 has been manually validated for:
Android → Android
Web → Web
Android → Web
Web → Android
TerraManager must reject backup format versions that it does not understand.
For example, an application that supports only:
backupFormatVersion = 1
must reject:
backupFormatVersion = 2
unless explicit support for Version 2 has been implemented.
Unsupported backups must never trigger destructive restore operations.
databaseSchemaVersion is metadata and is not itself the backup parser version.
A future TerraManager version may restore a backup created from an older database schema if it still understands that backup format.
For example:
Backup:
backupFormatVersion = 1
databaseSchemaVersion = 2
Future application:
backupFormatVersion 1 supported
databaseSchemaVersion = 4
This can remain compatible if the application provides the required mapping from Backup Format Version 1 into its current domain model.
Future TerraManager versions may add data such as:
Where possible, new application versions should preserve support for older backup formats.
A new backup format version should be introduced when the external portable representation changes incompatibly.
Application versions and backup format versions evolve independently.
For example:
TerraManager 0.6.0 -> Backup Format 1
TerraManager 0.7.x -> Backup Format 2
TerraManager 0.10.0 -> Backup Format 2 with an optional language setting
TerraManager 0.12.1 -> Backup Format 2 with optional Animal reminder fields
TerraManager 0.13.3 -> Backup Format 2 with an optional Box sort-order setting
TerraManager 0.13.4 -> Backup Format 2 with an optional Animal sort-order setting
TerraManager 0.14.0 -> Backup Format 2 (unchanged)
TerraManager 0.14.1 -> Backup Format 2 with legacy Box-sort value mapping
TerraManager 1.4.0 -> Backup Format 2 with optional Animal profile fields
TerraManager 1.7.0 -> Backup Format 2 with stable Animal taxonomy fields
TerraManager 1.7.1 -> Backup Format 2 with Box temperature-zone ownership
TerraManager 1.9.0 -> Backup Format 2 with nighttime ranges and weight history
A later application release may continue to use Backup Format 2 if its portable representation remains compatible, or introduce a new format version when the external representation changes incompatibly.
A new application release does not automatically require:
backupFormatVersion + 1
The portable backup representation is the compatibility boundary.
Internal implementation details such as:
must not be treated as stable external backup values unless explicitly defined by this document.
Version 1 contains:
manifest.json
├── backupFormatVersion
├── appVersion
├── databaseSchemaVersion
└── createdAt
data.json
├── boxes
├── animals
└── feedingEvents
settings.json
├── themeMode
├── accent
├── language (optional; exported by TerraManager 0.10.0 and later)
├── animalNameOrder (optional; exported by TerraManager 0.11.0 and later)
├── animalSortOrder (optional; exported by TerraManager 0.13.4 and later)
├── animalCategoryViewEnabled (optional; exported by TerraManager v1.9.1 and later)
├── bigPictureModeEnabled (optional; exported by TerraManager v1.10.0 and later)
├── nextFeedingSummaryEnabled (optional; exported by TerraManager v1.10.2 and later)
└── boxSortOrder (optional; exported by TerraManager 0.13.3 and later)
media/
└── animals/
Version 1 preserves:
Version 1 excludes:
Version 2 contains:
manifest.json
├── backupFormatVersion
├── appVersion
├── databaseSchemaVersion
└── createdAt
data.json
├── boxes
├── animals
└── feedingEvents
settings.json
├── themeMode
├── accent
├── language (optional; exported by TerraManager 0.10.0 and later)
├── animalNameOrder (optional; exported by TerraManager 0.11.0 and later)
├── animalSortOrder (optional; exported by TerraManager 0.13.4 and later)
├── animalCategoryViewEnabled (optional; exported by TerraManager v1.9.1 and later)
└── boxSortOrder (optional; exported by TerraManager 0.13.3 and later)
media/
├── animals/
└── boxes/
Version 2 preserves:
Version 2 excludes:
TerraManager 0.10.x and later continue to restore Backup Format Version 1.
Version 1 Box records do not contain names, lifecycle metadata, dimensions, temperature zones, notes or Box pictures. During restore, the missing Version 2 fields are mapped to their documented null or active defaults.
Animal media, IDs, relationships, lifecycle state, FeedingEvents and settings from Version 1 retain their existing restore semantics.
Version 1 and older Version 2 backups do not contain language, Animal
name-order, Animal sort-order or Box sort-order settings. Missing language is
restored as system; missing Animal name order as commonNameFirst; and
missing Animal sort order as createdOldestFirst; and missing Box sort order as
labelAscending. Legacy Box creation-order values map to their corresponding
ascending or descending Box-number direction.
Backups created before TerraManager 0.12.1 do not contain Animal reminder
fields. Missing reminder interval and baseline values restore as null, so the
reminder remains disabled.
Backups created before TerraManager 1.0.4 do not contain Box notes. A missing
notes field restores as null, so older Backup Format Version 1 and Version 2
archives remain compatible without a format-version increase.
TerraManager 0.10.x and later create new backups exclusively as Backup Format Version 2.
Applications that support only Version 1 must reject Version 2 backups rather than silently restore them while discarding Version 2 Box data.
Backups created before TerraManager v1.10.0 do not contain
bigPictureModeEnabled or sheddingHistory. Missing Big Picture Mode uses
false, and missing shedding history restores as an empty list before any
compatible legacy shedding-note migration is applied.
Backups created before TerraManager v1.10.2 do not contain
showWeightOnDetail, showSheddingOnDetail or
nextFeedingSummaryEnabled. Missing detail-visibility fields restore as
true, while the missing next-feeding-summary setting restores as false.