384 lines
7.4 KiB
Markdown
384 lines
7.4 KiB
Markdown
# Storage Schema
|
|
|
|
Ce document décrit les données persistées dans IndexedDB pour les toolboxes.
|
|
Il doit être mis à jour à chaque ajout ou modification d'outil.
|
|
|
|
## IndexedDB
|
|
|
|
Base : `sokkog`
|
|
|
|
Object stores :
|
|
|
|
- `kv` : données globales simples.
|
|
- `modules` : données des outils, séparées par toolbox et par module.
|
|
|
|
Clés principales dans `kv` :
|
|
|
|
```json
|
|
{
|
|
"toolboxes": [],
|
|
"links": {},
|
|
"setting:toolboxOrder": [],
|
|
"setting:storageBudgetBytes": 536870912,
|
|
"setting:toastPosition": "right"
|
|
}
|
|
```
|
|
|
|
Entrée type dans `modules` :
|
|
|
|
```json
|
|
{
|
|
"key": "tbx1:mod1",
|
|
"data": {}
|
|
}
|
|
```
|
|
|
|
## Toolbox
|
|
|
|
Les toolboxes sont stockées dans `kv/toolboxes`.
|
|
|
|
```json
|
|
{
|
|
"id": "tbx1",
|
|
"name": "Monster Hunter Wilds",
|
|
"gameId": "mhwilds",
|
|
"icon": "/static/img/toolbox-icons/toolbox.png",
|
|
"modules": [
|
|
{
|
|
"id": "mod1",
|
|
"type": "checklist",
|
|
"title": "Armures"
|
|
}
|
|
],
|
|
"layout": "two",
|
|
"updatedAt": "2026-07-25T12:00:00.000Z"
|
|
}
|
|
```
|
|
|
|
Notes :
|
|
|
|
- `gameId` est vide pour une toolbox libre.
|
|
- `icon` est utilisé uniquement pour les toolboxes libres.
|
|
- `layout` vaut généralement `one` ou `two`.
|
|
- Les données lourdes des outils ne sont pas stockées dans la toolbox, mais dans `modules`.
|
|
|
|
## Liens Jeu / Toolbox
|
|
|
|
Les associations entre pages jeux et toolboxes sont stockées dans `kv/links`.
|
|
|
|
```json
|
|
{
|
|
"mhwilds": "tbx1",
|
|
"diablo4": "tbx2"
|
|
}
|
|
```
|
|
|
|
## Outil Bloc Notes
|
|
|
|
Type : `notepad`
|
|
|
|
```json
|
|
{
|
|
"text": "Notes rapides..."
|
|
}
|
|
```
|
|
|
|
Stockage compact :
|
|
|
|
- si `text` est vide, l'entrée de module peut être supprimée.
|
|
|
|
## Outil Checklist
|
|
|
|
Type : `checklist`
|
|
|
|
Format simple, sans catégorie :
|
|
|
|
```json
|
|
{
|
|
"items": [
|
|
{
|
|
"id": "item1",
|
|
"label": "Potion",
|
|
"qtyTarget": 10,
|
|
"qtyCurrent": 3
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
Format avec catégories :
|
|
|
|
```json
|
|
{
|
|
"hideCompletedSections": true,
|
|
"hideCompletedSectionsFully": false,
|
|
"sections": [
|
|
{
|
|
"id": "section1",
|
|
"title": "Rey Dau alpha",
|
|
"hideWhenComplete": false,
|
|
"collapsed": false,
|
|
"items": [
|
|
{
|
|
"id": "item1",
|
|
"label": "Casque",
|
|
"qtyTarget": 1,
|
|
"qtyCurrent": 0
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
Stockage compact :
|
|
|
|
- `qtyTarget` est omis si la valeur vaut `1`.
|
|
- `qtyCurrent` est omis si la valeur vaut `0`.
|
|
- `hideCompletedSections` est omis si `false`.
|
|
- `hideCompletedSectionsFully` est omis si `false`.
|
|
- `title` est omis si vide.
|
|
- `hideWhenComplete` est omis si non défini.
|
|
- `collapsed` est omis si `false`.
|
|
|
|
## Outil Images
|
|
|
|
Type : `images`
|
|
|
|
```json
|
|
{
|
|
"images": [
|
|
{
|
|
"id": "image1",
|
|
"label": "Map zone nord",
|
|
"dataUrl": "data:image/webp;base64,..."
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
Stockage compact :
|
|
|
|
- `label` est facultatif.
|
|
- `label` est omis si vide.
|
|
- `createdAt` n'est pas stocké.
|
|
- Le nom de fichier original n'est pas stocké.
|
|
|
|
## Outil Annotation d'images
|
|
|
|
Type : `imageAnnotation`
|
|
|
|
```json
|
|
{
|
|
"image": "data:image/webp;base64,...",
|
|
"markers": [
|
|
{
|
|
"id": "marker1",
|
|
"x": 42.5,
|
|
"y": 68,
|
|
"label": "Entrée"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
Stockage compact :
|
|
|
|
- un seul visuel par outil.
|
|
- `x` et `y` sont des pourcentages entre `0` et `100`.
|
|
- `label` est facultatif.
|
|
- `label` est omis si vide.
|
|
|
|
## Outil Timer
|
|
|
|
Type : `timer`
|
|
|
|
Structure initiale :
|
|
|
|
```json
|
|
{
|
|
"activeTab": "stopwatch",
|
|
"scrollResults": true,
|
|
"sortResults": true,
|
|
"stopwatch": {
|
|
"elapsedMs": 12000,
|
|
"startedAt": 1760000000000,
|
|
"laps": [
|
|
{
|
|
"id": "timer1",
|
|
"label": "Phase 1",
|
|
"elapsedMs": 9000
|
|
}
|
|
]
|
|
},
|
|
"countdowns": [
|
|
{
|
|
"id": "timer2",
|
|
"label": "Boss",
|
|
"type": "daily_time",
|
|
"alertMode": "visible",
|
|
"time": "12:03:00",
|
|
"targetAt": 1760000000000
|
|
},
|
|
{
|
|
"id": "timer3",
|
|
"label": "Event",
|
|
"type": "time_pattern",
|
|
"pattern": "X:45:00"
|
|
},
|
|
{
|
|
"id": "timer4",
|
|
"label": "Event",
|
|
"type": "interval",
|
|
"intervalMs": 1800000,
|
|
"anchorAt": 1760000000000
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
Types de compte à rebours :
|
|
|
|
- `duration` : durée ponctuelle, avec `durationMs` et `targetAt`.
|
|
- `daily_time` : occurrence ponctuelle à une heure précise, avec `time` au format `HH:MM:SS` et `targetAt`.
|
|
- `time_pattern` : prochaine occurrence automatique correspondant à un pattern `HH:MM:SS`, où chaque segment peut valoir `X`.
|
|
- `interval` : prochaine occurrence automatique toutes les X millisecondes, avec `intervalMs` et `anchorAt`.
|
|
|
|
Pour `time_pattern`, un segment `X` situé après un segment plus large fixé cible le premier instant de l'occurrence. Exemple : `X:24:X` cible `hh:24:00` et se répète toutes les heures.
|
|
|
|
Stockage compact :
|
|
|
|
- `activeTab` est omis si la valeur vaut `stopwatch`.
|
|
- `scrollResults` est omis si `false`.
|
|
- `sortResults` est omis si `false`.
|
|
- `stopwatch` est omis tant que le chrono est à zéro et qu'aucune étape n'est enregistrée.
|
|
- `elapsedMs` est omis si `0`.
|
|
- `startedAt` est omis si le chrono n'est pas lancé.
|
|
- `laps` est omis tant qu'aucune étape n'est enregistrée.
|
|
- `countdowns` est omis tant qu'aucun compte à rebours n'est configuré.
|
|
- `countdowns[].alertMode` vaut `off`, `visible` ou `site`, et est omis si `off`.
|
|
- L'activation d'une alerte est bloquée dans l'interface si la fréquence configurée est inférieure à 5 minutes pour les comptes à rebours récurrents (`time_pattern` et `interval`). Le blocage ne dépend pas du temps restant avant la prochaine échéance.
|
|
|
|
## Outil Liens
|
|
|
|
Type : `links`
|
|
|
|
```json
|
|
{
|
|
"links": [
|
|
{
|
|
"id": "link1",
|
|
"title": "Build rogue",
|
|
"url": "https://example.com/build"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
Stockage compact :
|
|
|
|
- `title` est facultatif.
|
|
- `title` est omis si vide.
|
|
- `url` est obligatoire.
|
|
|
|
## Outil Compteurs
|
|
|
|
Type : `counters`
|
|
|
|
```json
|
|
{
|
|
"counters": [
|
|
{
|
|
"id": "counter1",
|
|
"label": "Victoire",
|
|
"value": 12
|
|
},
|
|
{
|
|
"id": "counter2",
|
|
"label": "Défaite",
|
|
"value": -2
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
Notes :
|
|
|
|
- `value` est numérique.
|
|
- Les valeurs négatives sont acceptées.
|
|
- Les compteurs sans libellé ne sont pas conservés.
|
|
|
|
## Outil Calculateur
|
|
|
|
Type : `calculator`
|
|
|
|
```json
|
|
{
|
|
"scrollResults": true,
|
|
"entries": [
|
|
{
|
|
"id": "calc1",
|
|
"label": "Lingots de fer",
|
|
"value": 100
|
|
},
|
|
{
|
|
"id": "calc2",
|
|
"parentId": "calc1",
|
|
"label": "Minerais de fer",
|
|
"value": 500
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
Stockage compact :
|
|
|
|
- `scrollResults` est omis si `false`.
|
|
- `parentId` est omis si vide.
|
|
- `label` peut être vide.
|
|
- `value` est numérique.
|
|
- Si un `parentId` ne pointe vers aucune entrée existante, il est réinitialisé à vide.
|
|
|
|
## Export
|
|
|
|
L'export d'une toolbox remappe les identifiants pour produire des IDs courts et indépendants.
|
|
|
|
Exemple :
|
|
|
|
```json
|
|
{
|
|
"toolbox": {
|
|
"id": "t1",
|
|
"name": "MHW",
|
|
"modules": [
|
|
{
|
|
"id": "m1",
|
|
"type": "checklist",
|
|
"title": "Armures"
|
|
}
|
|
],
|
|
"updatedAt": "2026-07-25T12:00:00.000Z"
|
|
},
|
|
"modules": {
|
|
"m1": {
|
|
"items": [
|
|
{
|
|
"id": "i1",
|
|
"label": "Casque"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## A maintenir à chaque update
|
|
|
|
Quand un outil change de structure :
|
|
|
|
- mettre à jour ce document ;
|
|
- mettre à jour les normalisations dans `website/src/features/toolboxes/storage/toolboxStorage.js` ;
|
|
- mettre à jour les textes dans `website/public/data/site.json` si nécessaire ;
|
|
- mettre à jour la validation dans `tests/helpers/data-validation.mjs` si nécessaire ;
|
|
- vérifier import/export ;
|
|
- lancer `npm run check`.
|