feat(import): bring the account's own mood vocabulary along

A full backup carries the account's own mood tags, rated factors and
tag groups, and the JSON import left them out: a mood entry imported
into another account landed without every link to a tag the person had
made.

Before the entries are written, every key they or the file name is
resolved once. A catalogue tag or one the account owns is used as it
is; an own tag whose label the file states differently is kept, never
overwritten, and named in keptMoodTagKeys (keptMoodCategoryKeys for a
group). A tag the file defines and the account lacks is created in its
group, the group created the same way, within the account's caps of 50
tags and 12 groups. A key another account of the server holds comes
over under a key derived from the account and the file's key, so a
second import of the same file finds the copy instead of minting
another. The links are written through that resolution, own rated
factors included, inside the entry's transaction; anything unresolved
is still dropped and named. The import card names kept keys in all
nine locales.

The field-coverage guard now holds the backup's customMoodTags and
customMoodTagCategories to the import schema. The round trip moves a
backup to another server (the same seeded catalogue, none of the
account's rows), imports it into a fresh account and compares the
re-export, own tags, group and rated factor included; a second case
imports into another account of the same server, and a third keeps a
renamed own tag.
This commit is contained in:
Marc-André Bombeck committed 2026-10-23 22:41:36 +02:00
1 parent d1545cf554
commit 2357807706
25 files changed
+995 -67

No files matched your search

+122 -6
View File
@@ -33209,8 +33209,18 @@ components:
type: array
items:
$ref: "#/components/schemas/JsonImportMoodEntry"
description: "JSON import payload: the measurements and mood entries of the JSON export or the portable full backup.
Both sections optional; up to 10 000 rows each."
customMoodTagCategories:
maxItems: 10000
type: array
items:
$ref: "#/components/schemas/JsonImportMoodTagCategory"
customMoodTags:
maxItems: 10000
type: array
items:
$ref: "#/components/schemas/JsonImportMoodTag"
description: "JSON import payload: the measurements and mood entries of the JSON export or the portable full backup, and
the backup's own mood vocabulary the entries link to. Every section optional; up to 10 000 rows each."
JsonImportMeasurement:
type: object
properties:
@@ -33346,8 +33356,9 @@ components:
type: string
maxLength: 64
factors:
description: Rated factors by catalogue key; replaces the entry's rated links. A key the account cannot resolve is
dropped and named in `droppedFactorKeys`; a rating outside the factor's own scale skips the entry.
description: Rated factors by key (the catalogue's, or the account's own as for `structuredTags`); replaces the entry's
rated links. A key the account cannot resolve is dropped and named in `droppedFactorKeys`; a rating outside
the factor's own scale skips the entry.
maxItems: 30
type: array
items:
@@ -33364,8 +33375,8 @@ components:
- key
- rating
structuredTags:
description: Ticked tags by key (the catalogue or the account's own); replaces the entry's tag links. An unresolvable
key is dropped and named in `droppedTagKeys`.
description: Ticked tags by key (the catalogue, the account's own, or one the file's `customMoodTags` brings); replaces
the entry's tag links. An unresolvable key is dropped and named in `droppedTagKeys`.
maxItems: 30
type: array
items:
@@ -33538,6 +33549,100 @@ components:
- mood
- score
description: One mood-entry row of a JSON import file.
JsonImportMoodTagCategory:
type: object
properties:
id:
description: The file's own id, read only to find the group a tag names in `categoryId`.
type: string
maxLength: 120
key:
type: string
minLength: 1
maxLength: 80
labelKey:
type: string
minLength: 1
maxLength: 120
icon:
type: string
maxLength: 60
sortOrder:
type: integer
minimum: -9007199254740991
maximum: 9007199254740991
isActive:
type: boolean
label:
description: The group's own name.
type: string
maxLength: 200
labelEncrypted:
description: A disaster-recovery file's sealed name, used only when this server's keys open it.
type: string
maxLength: 2000
required:
- key
- labelKey
description: "A mood-tag group the account made itself. Matched by `key`: a group the account has is used as it is, a
missing one is created."
JsonImportMoodTag:
type: object
properties:
key:
type: string
minLength: 1
maxLength: 80
labelKey:
type: string
minLength: 1
maxLength: 120
categoryId:
type: string
minLength: 1
maxLength: 120
description: The group's id in the file; a group the file does not carry falls back to the seeded `custom` group.
kind:
type: string
enum:
- BINARY
- RATED
isActive:
type: boolean
icon:
type: string
maxLength: 60
sortOrder:
type: integer
minimum: -9007199254740991
maximum: 9007199254740991
label:
description: The tag's own name.
type: string
maxLength: 200
labelEncrypted:
description: A disaster-recovery file's sealed name, used only when this server's keys open it.
type: string
maxLength: 2000
scaleMin:
type: integer
minimum: 0
maximum: 10
scaleMax:
type: integer
minimum: 0
maximum: 10
inverse:
type: boolean
required:
- key
- labelKey
- categoryId
- kind
description: "A mood tag the account made itself, a rated factor included. Matched by `key`: the account's own tag of
that key is used and never overwritten (a different label is named in `keptMoodTagKeys`); a missing one is
created, within the account's custom-tag cap; a key another account of this server holds comes over under a key
derived from the account and the file's key, so a second import of the same file finds it."
MeasurementReminderCreate:
type: object
properties:
@@ -74085,6 +74190,17 @@ components:
type: array
items:
type: string
keptMoodTagKeys:
description: Keys of the account's own tags the file names differently. The account's tag is kept as it is. Present only
when non-empty.
type: array
items:
type: string
keptMoodCategoryKeys:
description: The same, for the account's own tag groups.
type: array
items:
type: string
required:
- measurements
- moodEntries
+11 -4
View File
@@ -72,10 +72,17 @@ in the backup and `""` in the export, reads as absent, a backup's deletion
records are skipped and counted, and a reading in a display unit (lb, °F,
mmol/L) is converted to the stored one.
A mood entry's tags and rated factors are linked by key. A key the
importing account has no tag for, typically a tag another account made
for itself, is dropped from that entry, and the response names it in
`droppedTagKeys` or `droppedFactorKeys`. The rest of the entry lands.
A mood entry's tags and rated factors are linked by key. A full backup
also carries the account's own tags, rated factors and tag groups, and the
import brings them along: a tag the importing account already has is used
as it is, and one it lacks is created (within the account's limit of 50
custom tags and 12 groups). The account's own tag is never overwritten: when
the file names it differently, the account's name stays and the response
lists the key in `keptMoodTagKeys` (`keptMoodCategoryKeys` for a group).
Moving a file between two accounts of one server works too; the tags come
over under keys of their own. A key the account cannot resolve at all is
dropped from that entry and named in `droppedTagKeys` or
`droppedFactorKeys`, and the rest of the entry lands.
### Measurement entry