sokko-g/docs/STORAGE_SCHEMA.md
Shinuwa 025cd4bf22
All checks were successful
Deploy Sokko G / deploy (push) Successful in 6s
add new table tool
2026-07-30 11:32:33 +02:00

13 KiB

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 :

{
  "toolboxes": [],
  "links": {},
  "setting:toolboxOrder": [],
  "setting:storageBudgetBytes": 536870912,
  "setting:toastPosition": "right"
}

Entrée type dans modules :

{
  "key": "tbx1:mod1",
  "data": {}
}

Toolbox

Les toolboxes sont stockées dans kv/toolboxes.

{
  "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.

{
  "mhwilds": "tbx1",
  "diablo4": "tbx2"
}

Outil Bloc Notes

Type : notepad

{
  "html": "<p>Notes <strong>rapides</strong>...</p>",
  "text": "Notes rapides...",
  "updatedAt": "2026-07-29T12:00:00.000Z",
  "drawingMode": "permanent",
  "drawings": {
    "strokes": [
      {
        "id": "stroke1",
        "color": "#f6c453",
        "width": 4,
        "points": [
          { "x": 12.5, "y": 48 },
          { "x": 24, "y": 52.5 }
        ]
      }
    ]
  }
}

Stockage compact :

  • l'ancien format { "text": "..." } reste accepté et est converti en HTML riche au prochain enregistrement ;
  • html est nettoyé avec une allowlist de balises et de couleurs ;
  • text conserve une version texte pour les exports et les fallbacks ;
  • updatedAt est omis si vide ou invalide ;
  • drawingMode vaut temporary par défaut et est omis dans ce cas ;
  • drawings est stocké uniquement si drawingMode vaut permanent et qu'au moins un trait valide existe ;
  • les dessins temporaires du bloc-notes sont conservés dans sessionStorage, pas dans IndexedDB ;
  • si le texte, la date et les dessins permanents sont vides, l'entrée de module peut être supprimée.

Outil Checklist

Type : checklist

Format simple, sans catégorie :

{
  "items": [
    {
      "id": "item1",
      "label": "Potion",
      "qtyTarget": 10,
      "qtyCurrent": 3
    }
  ]
}

Format avec catégories :

{
  "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

{
  "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

{
  "image": "data:image/webp;base64,...",
  "markers": [
    {
      "id": "marker1",
      "x": 42.5,
      "y": 68,
      "label": "Entrée"
    }
  ],
  "drawings": {
    "strokes": [
      {
        "id": "stroke1",
        "color": "#f6c453",
        "width": 4,
        "points": [
          { "x": 18.5, "y": 32 },
          { "x": 24, "y": 40.5 }
        ]
      }
    ]
  }
}

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.
  • drawings est facultatif et omis si aucun trait valide n'existe.
  • les points des dessins sont stockés en pourcentages entre 0 et 100 pour rester alignés en aperçu réduit et en plein écran.
  • les dessins sont éditables uniquement depuis la modale plein écran ; l'aperçu réduit les affiche en lecture seule.
  • le mode temporaire des dessins d'image utilise sessionStorage et ne modifie pas drawings dans IndexedDB tant que l'utilisateur ne repasse pas en stockage permanent.

Outil Timer

Type : timer

Structure initiale :

{
  "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 Task Planner

Type : taskPlanner

{
  "weeklyResetDay": 1,
  "resetTime": "00:00",
  "lastResetAt": 1760000000000,
  "hideCompleted": true,
  "categoryOrder": ["Raid", "Farm"],
  "collapsedCategories": ["Farm"],
  "tasks": [
    {
      "id": "task1",
      "title": "Quête 1",
      "description": "Préparer la route.",
      "category": "Raid",
      "type": "daily",
      "checked": true,
      "checkedAt": 1760000000000
    },
    {
      "id": "task2",
      "title": "Quête 2",
      "type": "weekly",
      "weeklyResetDay": 3
    }
  ],
  "relations": [
    {
      "id": "relation1",
      "fromTaskId": "task1",
      "toTaskId": "task2"
    },
    {
      "id": "relation2",
      "fromTaskId": "task2",
      "toTaskId": "task1",
      "prerequisite": true
    }
  ]
}

Notes :

  • type vaut unique, daily ou weekly.
  • weeklyResetDay suit les jours JavaScript : 0 dimanche, 1 lundi, ..., 6 samedi.
  • resetTime est global à l'outil et vaut HH:MM.
  • hideCompleted masque les tâches effectuées à l'affichage, ainsi que les catégories dont toutes les tâches sont effectuées.
  • weeklyResetDay sur une tâche hebdo surcharge le jour global.
  • category sur une tâche racine est facultatif. Les tâches enfants héritent de la catégorie effective de leur parent et ne stockent pas de catégorie propre.
  • Les tâches catégorisées sont regroupées par catégorie au niveau racine.
  • categoryOrder stocke l'ordre d'affichage des catégories utilisées. Les catégories absentes des tâches sont retirées à la normalisation.
  • collapsedCategories stocke les noms des catégories repliées.
  • relations stocke les parents directionnels. fromTaskId désigne la tâche enfant, toTaskId son parent.
  • une tâche ne conserve qu'un seul parent.
  • prerequisite: true marque aussi ce parent comme pré requis.
  • Les pré requis sont non bloquants : ils affichent un avertissement si le parent requis n'est pas effectué.
  • Le drag & drop conserve l'ordre manuel, et peut aussi ajouter une tâche racine à une catégorie existante ou la sortir vers les tâches sans catégorie.

Stockage compact :

  • weeklyResetDay global est omis si la valeur vaut 1.
  • resetTime est omis si la valeur vaut 00:00.
  • lastResetAt est omis si la valeur vaut 0.
  • hideCompleted est omis si false.
  • description est omis si vide.
  • category est omis si vide ou si la tâche a un parent.
  • categoryOrder est omis si aucune catégorie n'est utilisée.
  • collapsedCategories est omis si aucune catégorie n'est repliée.
  • checked et checkedAt sont omis si la tâche n'est pas effectuée.
  • weeklyResetDay unitaire est omis si non défini.
  • relations est omis si vide.
  • relations[].prerequisite est omis si false.

Outil Liens

Type : links

{
  "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

{
  "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

{
  "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.

Outil Tableau

Type : table

{
  "rows": 12,
  "columns": 8,
  "cells": {
    "A1": "Texte libre",
    "B1": "100",
    "C1": "=A1+B1",
    "D1": "=(B1+20)/2"
  },
  "rowLabels": {
    "0": "Boss",
    "1": "Phase 2"
  },
  "columnLabels": {
    "0": "Item",
    "1": "Quantité"
  }
}

Stockage compact :

  • rows est omis si la valeur vaut 10.
  • columns est omis si la valeur vaut 6.
  • cells conserve uniquement les cellules non vides et dans les limites du tableau.
  • rows est limité entre 1 et 50.
  • columns est limité entre 1 et 20.
  • Les valeurs de cellules sont stockées sous forme de texte brut, formules incluses.
  • Les résultats calculés ne sont pas persistés.
  • rowLabels et columnLabels conservent uniquement les intitulés visuels personnalisés.
  • Les intitulés personnalisés n'impactent pas les références de formule, qui restent basées sur les adresses A1, C2, etc.

Export

L'export d'une toolbox remappe les identifiants pour produire des IDs courts et indépendants.

Exemple :

{
  "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.