Documentation complète des formats de données pour tous les modules
KERN stocke toutes ses données dans le localStorage du navigateur. Chaque type de données a sa propre clé.
Les clés doivent correspondre exactement. Une erreur de nom = données invisibles.
| Clé localStorage | Type | Module(s) | Requis |
|---|---|---|---|
kern_agent_profile |
Object | Tous (profil agent) | ✅ Oui |
kern_dossiers |
Array | DOSSIERS, NEXUS | Non |
kern_entities |
Array | PANOPTICON | Non |
kern_network_contacts |
Array | Contact Network | Non |
kern_knowledge |
Array | Knowledge Graph | Non |
kern_missions |
Array | Missions | Non |
kern_journal |
Array | Journal | Non |
kern_partners |
Array | Partners | Non |
kern_protocole |
Object | Protocole Insurrection | Non |
La clé est kern_agent_profile (pas kern_agent). C'est la cause #1 des plantages !
Le profil agent est obligatoire. Sans lui, KERN plante.
kern_agent_profile
{
"codename": "GANDALF-PRIME", // Requis - Nom de code
"level": 12, // Requis - Niveau actuel
"xp": 15420, // Requis - XP actuel
"xpToNext": 20000, // Requis - XP pour niveau suivant
"clearance": 4, // Niveau d'habilitation (0-7)
"streak": 42, // Jours consécutifs
"lastLogin": "2026-01-06", // Date dernière connexion
// ⚠️ OBLIGATOIRE - Skills
"skills": {
"investigation": { "level": 8, "xp": 720 },
"network": { "level": 10, "xp": 890 },
"analysis": { "level": 7, "xp": 650 },
"documentation": { "level": 9, "xp": 810 },
"fieldwork": { "level": 6, "xp": 520 },
"opsec": { "level": 11, "xp": 980 }
},
// ⚠️ OBLIGATOIRE - Stats (cause des plantages si absent !)
"stats": {
"dossiersCreated": 6,
"entitiesCreated": 21,
"contactsAdded": 16,
"notesWritten": 10,
"missionsCompleted": 3,
"linksDiscovered": 45,
"daysActive": 42,
"totalActions": 150
},
// ⚠️ OBLIGATOIRE - Achievements (peut être vide)
"achievements": [],
// ⚠️ OBLIGATOIRE - Settings
"settings": {
"theme": "dark",
"notifications": true,
"soundEffects": true
}
}
stats — Sans ça : Cannot read properties of undefined (reading 'dossiersCreated')skills — Requis pour l'affichage du profilachievements — Peut être [] mais doit existersettings — Requis pour les préférences{
"codename": "NOUVEAU-AGENT",
"level": 1,
"xp": 0,
"xpToNext": 1000,
"clearance": 0,
"lastLogin": "2026-01-06",
"skills": {
"investigation": { "level": 1, "xp": 0 },
"network": { "level": 1, "xp": 0 },
"analysis": { "level": 1, "xp": 0 },
"documentation": { "level": 1, "xp": 0 },
"fieldwork": { "level": 1, "xp": 0 },
"opsec": { "level": 1, "xp": 0 }
},
"stats": {
"dossiersCreated": 0,
"entitiesCreated": 0,
"contactsAdded": 0,
"notesWritten": 0,
"missionsCompleted": 0,
"linksDiscovered": 0,
"daysActive": 1,
"totalActions": 0
},
"achievements": [],
"settings": {
"theme": "dark",
"notifications": true,
"soundEffects": true
}
}
kern_dossiers
Array d'objets dossier
{
"id": "dossier_xxx_001", // Requis - ID unique
"created": "2025-06-15T10:00:00.000Z", // ISO date
"updated": "2026-01-05T18:30:00.000Z", // ISO date
"title": "🔥 Titre du dossier", // Requis
"description": "Description longue...", // Texte
"status": "active", // active|completed|archived
"priority": "critical", // critical|high|medium|low
"tags": ["tag1", "tag2"], // Array de strings
// Timeline - événements chronologiques
"timeline": [
{
"date": "2025-06-15",
"event": "Description de l'événement",
"type": "discovery" // discovery|breakthrough|intel|critical|meeting|incident
}
],
// Preuves
"evidence": [
{
"id": "ev_001",
"type": "document", // document|artifact|testimony|data
"title": "Titre preuve",
"source": "Source",
"reliability": 4 // 1-5
}
],
// Liens vers autres éléments
"linkedEntities": ["entity_xxx"], // IDs d'entités
"linkedContacts": ["contact_xxx"] // IDs de contacts
}
| Valeur | Description |
|---|---|
active | Dossier en cours |
completed | Dossier terminé |
archived | Dossier archivé |
| Valeur | Couleur |
|---|---|
critical | 🔴 Rouge |
high | 🟠 Orange |
medium | 🟡 Jaune |
low | 🟢 Vert |
kern_entities
Array d'objets entité
{
"id": "entity_xxx", // Requis - ID unique
"name": "Nom de l'entité", // Requis
"type": "person", // Requis - voir types
"subtype": "Sous-catégorie", // Optionnel
"emoji": "👤", // Optionnel - icône
"description": "Description...", // Texte
"tags": ["tag1", "tag2"], // Array
"created": "2025-01-01T00:00:00.000Z", // ISO date
// Liens vers autres entités
"links": [
{
"targetId": "entity_yyy", // ID cible
"type": "controls", // Type de relation
"label": "Contrôle" // Label affiché
}
]
}
| Type | Icône | Couleur |
|---|---|---|
person | 👤 | #6366f1 (indigo) |
organization | 🏛️ | #22d3ee (cyan) |
company | 🏢 | #4ade80 (vert) |
media | 📰 | #fbbf24 (ambre) |
institution | 🏦 | #a78bfa (violet) |
event | 📅 | #f87171 (rouge) |
document | 📄 | #f472b6 (rose) |
location | 📍 | #38bdf8 (bleu) |
other | ❓ | #888 (gris) |
Les types de liens sont libres. Exemples courants :
controls / controlled_byowns / owned_byworks_with / partneropposes / enemyserves / employscreated / created_bykern_network_contacts
Array d'objets contact
{
"id": "contact_xxx", // Requis - ID unique
"firstName": "Prénom", // Requis
"lastName": "Nom", // Requis
"emoji": "🧙♂️", // Avatar emoji
"organization": "Nom organisation", // Employeur
"role": "Poste/Fonction", // Titre
"category": "ally", // Voir catégories
"strength": 5, // Force du lien 1-5
// Coordonnées
"email": "email@example.com",
"phone": "+32 XXX XX XX XX",
"location": "Ville, Pays",
"notes": "Notes sur le contact...",
"tags": ["tag1", "tag2"],
"lastContact": "2026-01-05", // Date YYYY-MM-DD
// Connexions avec autres contacts
"connections": ["contact_yyy", "contact_zzz"]
}
| Catégorie | Icône | Description |
|---|---|---|
ally | 🤝 | Allié, soutien actif |
source | 🎭 | Source d'information |
professional | 💼 | Contact professionnel |
official | 🏛️ | Officiel, institutionnel |
media | 📰 | Journaliste, média |
academic | 🎓 | Académique, chercheur |
other | 👤 | Autre |
kern_knowledge
Array d'objets note
{
"id": "note_xxx", // Requis - ID unique
"title": "Titre de la note", // Requis
"content": "Contenu en **Markdown**...", // Markdown supporté
"tags": ["tag1", "tag2"],
"created": "2025-06-20T10:00:00.000Z",
"updated": "2026-01-05T14:00:00.000Z",
// Liens vers autres notes (par titre)
"linkedNotes": ["note_yyy", "note_zzz"]
}
Dans le contenu, utilisez [[Titre de note]] pour créer des liens :
Voir aussi [[L'Anneau Unique]] et [[Sauron]].
# Titre, ## Sous-titre**gras**, *italique*- liste, 1. liste numérotée[lien](url)`code`kern_missions
Array d'objets mission
{
"id": "mission_001", // Requis - ID unique
"emoji": "🔥", // Icône
"name": "Nom de la mission", // Requis
"description": "Description...", // Texte
"difficulty": "hard", // easy|medium|hard|expert
"xpReward": 2000, // XP gagnés
"status": "active", // active|completed
"created": "2025-12-25T00:00:00.000Z",
// Liste des objectifs
"requirements": [
"Objectif 1",
"Objectif 2",
"Objectif 3"
],
// Indices des objectifs complétés (0-based)
"completedReqs": [0, 1] // Objectifs 1 et 2 faits
}
| Difficulté | XP typique |
|---|---|
easy | 100-500 |
medium | 500-1500 |
hard | 1500-3000 |
expert | 3000-10000 |
kern_journal
Array d'objets entrée
{
"id": "journal_001", // Requis - ID unique
"content": "Contenu de l'entrée...\n\nSupporte le Markdown.",
"tags": ["tag1", "tag2"],
"createdAt": "2025-12-25T18:00:00.000Z",
"updatedAt": "2025-12-25T18:00:00.000Z"
}
kern_partners
Array d'objets partenaire
{
"id": "partner_xxx",
"emoji": "🏭",
"name": "Nom du partenaire",
"tagline": "Slogan ou accroche",
"sector": "Industrie",
"revenue": 15000000, // CA en euros
"tier": "platinum", // free|silver|gold|platinum|diamond
"status": "active", // active|prospect|negotiation|premium
"website": "https://example.com",
"description": "Description...",
"email": "contact@example.com",
"phone": "+32 XXX",
"address": "Adresse",
// Produits/Services
"products": [
{
"name": "Nom produit",
"icon": "⚙️",
"price": "€2,499",
"description": "Description"
}
]
}
kern_protocole
Object (pas un Array !)
{
// Missions du protocole
"missions": [
{
"id": "proto_mission_01",
"type": "tutorial", // tutorial|campaign
"name": "LA MÉGA-CORPORATION",
"target": "Colruyt Group",
"objective": "Description...",
"difficulty": 60, // 0-100
"xp": 500,
// Pour type "tutorial" - phases
"phases": [
{
"name": "SCAN",
"status": "completed", // completed|active|pending
"steps": ["Étape 1", "Étape 2"]
}
],
// Pour type "campaign" - niveaux
"levels": [
{
"name": "OPÉRATEUR",
"status": "active",
"actions": ["Action 1"]
}
]
}
],
// Flashcards
"flashcards": [
{
"q": "Question ?",
"a": "Réponse",
"category": "partenariat"
}
],
// Données spécifiques (ex: Colruyt)
"colruyt": {
"portes": [...],
"kpis": [...],
"winWinWin": {...}
}
}
Un export complet KERN est un fichier JSON avec toutes les clés :
{
"kern_agent_profile": { ... }, // ⚠️ Pas "kern_agent" !
"kern_dossiers": [ ... ],
"kern_entities": [ ... ],
"kern_network_contacts": [ ... ],
"kern_knowledge": [ ... ],
"kern_missions": [ ... ],
"kern_journal": [ ... ],
"kern_partners": [ ... ],
"kern_protocole": { ... }
}
kern_agent → kern_agent_profilestats est obligatoire(function(){...})()La page import.html corrige automatiquement :
kern_agent → kern_agent_profilestats si manquantachievements si manquantsettings si manquant// Exporter toutes les données KERN
const exportData = {
kern_agent_profile: JSON.parse(localStorage.getItem('kern_agent_profile')),
kern_dossiers: JSON.parse(localStorage.getItem('kern_dossiers') || '[]'),
kern_entities: JSON.parse(localStorage.getItem('kern_entities') || '[]'),
kern_network_contacts: JSON.parse(localStorage.getItem('kern_network_contacts') || '[]'),
kern_knowledge: JSON.parse(localStorage.getItem('kern_knowledge') || '[]'),
kern_missions: JSON.parse(localStorage.getItem('kern_missions') || '[]'),
kern_journal: JSON.parse(localStorage.getItem('kern_journal') || '[]'),
kern_partners: JSON.parse(localStorage.getItem('kern_partners') || '[]'),
kern_protocole: JSON.parse(localStorage.getItem('kern_protocole') || 'null')
};
// Télécharger
const blob = new Blob([JSON.stringify(exportData, null, 2)], {type: 'application/json'});
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = 'kern-backup-' + new Date().toISOString().slice(0,10) + '.json';
a.click();
// Coller le JSON dans la variable 'data'
const data = { /* votre JSON ici */ };
// Importer
Object.keys(data).forEach(key => {
if (data[key]) {
// Corriger la clé agent si nécessaire
const targetKey = key === 'kern_agent' ? 'kern_agent_profile' : key;
localStorage.setItem(targetKey, JSON.stringify(data[key]));
console.log('Imported:', targetKey);
}
});
// Recharger
location.reload();
Cause : L'objet stats manque dans le profil agent.
Solution :
import.htmlstatsCause : Mauvaise clé localStorage.
Vérifier :
kern_agent_profile (pas kern_agent)kern_network_contacts (pas kern_contacts)kern_knowledge (pas kern_notes)Cause : Le fichier n'est pas du JSON valide.
Vérifier :
// ou /* */(function(){...})()" partout (pas simples ')// Dans la console du navigateur (F12)
// Voir toutes les clés KERN
Object.keys(localStorage).filter(k => k.startsWith('kern_'));
// Voir le contenu d'une clé
JSON.parse(localStorage.getItem('kern_agent_profile'));
// Tout effacer
Object.keys(localStorage).filter(k => k.startsWith('kern_'))
.forEach(k => localStorage.removeItem(k));
// Supprimer TOUTES les données KERN
Object.keys(localStorage)
.filter(k => k.startsWith('kern_'))
.forEach(k => localStorage.removeItem(k));
// Recharger la page
location.reload();
Avant d'importer, validez votre JSON :