Format .mmap v4 : `node.side` (cote d'une branche de niveau 1) et `MindMap.relations` (relations secondaires). Migration v3 -> v4 sans perte, les cartes v1/v2/v3 restent ouvrables telles quelles. Une relation est une connexion purement visuelle : elle ne touche jamais parentId, order, les enfants, le repli ni l'auto-layout. `withEdges()` continue de deriver les liens de parentId et se contente de retirer les relations dont une extremite a disparu. Mind map bilaterale : repartition gloutonne et deterministe des branches selon la taille des sous-arbres, heritage du cote par sous-arbre, deux passes dagre recalees sur la racine. Choisir une disposition ne deplace plus la carte : seul Reorganiser applique. Ajoute aussi une galerie de huit modeles locaux, l'import Markdown (fichier ou texte, nouvelle carte ou sous-arbre) reutilisant l'analyseur d'outline existant, et l'export Markdown de la hierarchie. Corrige un bug de rendu : React Flow ne remesure pas les poignees quand elles changent de cote, ce qui faisait disparaitre les liens concernes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
OpenMind
Cartes mentales libres, local-first, sans compte et sans abonnement.
OpenMind est une alternative gratuite et open source aux services de mind mapping qui placent l'export, les themes ou le nombre de cartes derriere un abonnement. Toutes les fonctionnalites sont disponibles, sans exception et sans compte.
- Aucune limitation artificielle, aucun paiement, aucun "premium".
- Aucun compte obligatoire : il n'y a d'ailleurs aucun systeme de comptes.
- Aucune telemetrie, aucun tracker, aucune publicite.
- Vos cartes vous appartiennent : elles restent dans votre navigateur.
- Export PDF, PNG, SVG et impression : gratuits.
- Un partage par lien, uniquement si vous le demandez explicitement.
- Un seul conteneur Docker a demarrer.
Philosophie local-first
Une carte que vous creez n'est jamais envoyee au serveur.
Elle est enregistree dans l'IndexedDB de votre navigateur, automatiquement, apres une courte periode d'inactivite. Le backend n'existe que pour une seule chose : generer un lien de partage lorsque vous cliquez explicitement sur Partager.
Consequences concretes :
- Fermer le navigateur, redemarrer le PC ou redemarrer le conteneur ne fait perdre aucune carte locale.
- Une fois l'application chargee une premiere fois, elle continue de fonctionner sans reseau (PWA) : creation, edition, export, impression.
- Vider les donnees du site, ou changer de navigateur/machine, fait disparaitre
les cartes locales. Exportez vos cartes en
.mmappour en conserver une sauvegarde portable.
Demarrage rapide
Prerequis : Docker et Docker Compose.
git clone <url-du-depot>
cd Mind-Mapping
cp .env.example .env
docker compose up -d --build
Puis ouvrez :
http://localhost:8080
Verifier que le service repond :
curl http://localhost:8080/api/health
Reponse attendue : {"status":"ok"}
Etat du conteneur (le healthcheck Docker interroge /api/health) :
docker compose ps
Arreter :
docker compose down
Architecture
Un seul service applicatif. FastAPI sert a la fois l'API et les fichiers statiques du frontend compile.
Navigateur
|
+-- React / TypeScript (Vite, Tailwind, React Flow, Zustand)
|
+-- IndexedDB (Dexie)
| +-- cartes privees/locales <-- ne quittent jamais le navigateur
|
+-- API, uniquement pour les fonctions serveur (partage)
|
v
FastAPI (+ fichiers statiques du frontend)
|
v
SQLite
|
+-- cartes explicitement partagees
Choix structurants :
| Sujet | Choix | Pourquoi |
|---|---|---|
| Hierarchie | parentId fait autorite, les liens en sont derives |
un seul invariant a maintenir, pas de desynchronisation |
| Ordre des freres | node.order, renumerote a chaque modification |
une source par preoccupation : la relation d'un cote, la position de l'autre |
| Modele | types metier propres, adaptes vers React Flow a l'affichage | le format de fichier ne depend pas de la bibliotheque de rendu |
| Historique | instantanes {nodes, edges}, groupes par action |
un glisser-deposer = une seule annulation |
| Auto-layout | dagre, declenche uniquement a la demande | les deplacements manuels ne sont jamais ecrases |
| Versionnement | champ version + point d'extension de migration |
le format peut evoluer sans casser les fichiers existants |
Variables d'environnement
Toutes definies dans .env (modele : .env.example). Aucun secret n'est requis.
| Variable | Defaut | Role |
|---|---|---|
APP_NAME |
OpenMind |
Nom du produit, affiche dans l'interface et l'onglet |
APP_PORT |
8080 |
Port publie sur l'hote (le conteneur ecoute toujours 8080) |
DATABASE_URL |
sqlite:////app/data/openmind.db |
Base des cartes partagees |
MAX_MAP_SIZE_MB |
10 |
Taille maximale d'une carte envoyee au serveur |
MAX_NODES |
5000 |
Nombre maximal de noeuds par carte |
CORS_ORIGINS |
vide | Origines externes autorisees, separees par des virgules |
LOG_LEVEL |
INFO |
DEBUG, INFO, WARNING, ERROR |
Le nom du produit est centralise : cote backend via APP_NAME, cote frontend
dans frontend/src/config/app.ts. Le frontend recupere le nom a l'execution via
GET /api/config : changer APP_NAME suffit, sans recompiler.
Donnees et sauvegarde
Deux stockages totalement distincts :
| Donnee | Ou | Sauvegarde |
|---|---|---|
| Cartes privees | IndexedDB du navigateur | Export .mmap depuis le tableau de bord ou l'editeur |
| Cartes partagees | SQLite, dans ./data/openmind.db |
Copie du dossier ./data |
Le dossier ./data est monte en bind mount (aucun volume Docker nomme) :
les fichiers sont donc directement lisibles depuis l'hote.
docker compose stop
tar czf openmind-partages-$(date +%F).tar.gz data/
docker compose start
SQLite fonctionne en mode WAL : openmind.db, openmind.db-wal et
openmind.db-shm doivent etre sauvegardes ensemble.
Redemarrer le serveur n'a aucun impact sur les cartes privees locales.
Fonctionnement du partage
Une carte n'est envoyee au serveur que lorsque vous cliquez sur Partager, apres une explication et une confirmation.
Deux secrets distincts sont generes cote serveur avec le module Python
secrets :
| Jeton | Entropie | Ou il vit | A quoi il sert |
|---|---|---|---|
share_token |
secrets.token_urlsafe(12), environ 96 bits |
dans l'URL publique /s/<token> |
lecture seule |
management_token |
secrets.token_urlsafe(32), environ 256 bits |
uniquement dans l'IndexedDB du proprietaire | modification et suppression |
Regles appliquees :
- Le
management_tokenn'apparait jamais dans une URL, jamais dans un export.mmap, jamais dans les logs. - Il est transmis dans l'en-tete
X-Management-TokenpourPUTetDELETE. - Seul son hash SHA-256 est stocke en base ; la comparaison est faite en
temps constant avec
secrets.compare_digest. - Connaitre le
share_tokenne permet donc ni de modifier ni de supprimer un partage. - Le lien est non repertorie : il n'apparait dans aucune liste publique, mais toute personne qui le connait peut consulter la carte.
Cycle de vie :
- Partager : un instantane de la carte est copie sur le serveur, un lien est
renvoye, par exemple
http://localhost:8080/s/a8F3xP9k. - Mettre a jour le partage : remplace l'instantane par la version actuelle. Tant que vous ne le faites pas, le lien public montre l'ancienne version.
- Supprimer le partage : efface l'instantane serveur. Le lien affiche alors une page propre indiquant que le partage n'existe plus. La carte locale n'est pas affectee.
Si vous supprimez une carte locale, sa reference de partage locale part avec elle : supprimez d'abord le partage si vous voulez aussi retirer la copie serveur.
API
| Methode | Route | Auth | Role |
|---|---|---|---|
GET |
/api/health |
- | Etat du service |
GET |
/api/config |
- | Nom de l'application et limites |
POST |
/api/shares |
- | Creer un partage |
GET |
/api/shares/{share_token} |
- | Lire une carte partagee |
PUT |
/api/shares/{share_token} |
X-Management-Token |
Mettre a jour |
DELETE |
/api/shares/{share_token} |
X-Management-Token |
Supprimer |
Documentation interactive : http://localhost:8080/api/docs.
Fonctionnalites
Tableau de bord : creation, import, recherche, date de derniere modification, renommage, duplication, export, suppression avec confirmation. Une carte d'exemple est creee au tout premier lancement.
Editeur : canvas infini, zoom, deplacement, zoom-to-fit, minimap, grille optionnelle, creation/suppression/deplacement de noeuds, selection multiple, connexion entre noeuds avec detection de boucle, edition du texte au double-clic, undo/redo, copier/coller, duplication, sauvegarde automatique.
Mind mapping : noeud racine et noeuds standard, branches droites, courbes ou Bezier, branches repliables avec compteur d'elements masques.
Auto-layout, uniquement sur demande : mind map droite, mind map gauche, mind map bilaterale, arbre horizontal, arbre vertical. L'espacement est configurable (distance parent/enfant et espacement entre branches), avec les presets Compact, Normal et Aere. Choisir une disposition ou modifier l'espacement ne deplace rien : c'est Reorganiser qui applique, ce qui protege les positions placees a la main.
Mind map bilaterale : la racine reste au centre, les branches de niveau 1 se repartissent a gauche et a droite, et tous les descendants heritent du cote de leur branche. La repartition automatique equilibre les deux cotes selon la taille des sous-arbres ; le cote se change ensuite a la main (Placer la branche a gauche / a droite).
Relations secondaires : une connexion visuelle entre deux noeuds quelconques, independante de la hierarchie. Elle ne modifie ni le parent, ni l'ordre, ni le repli, et l'auto-layout l'ignore totalement. Libelle libre, trace (Bezier, courbe, droite), couleur, epaisseur, trait plein ou pointille, fleches aux deux extremites. Une relation dont une extremite est masquee par un repli disparait de l'affichage et revient au deploiement.
Modeles : galerie locale de huit modeles (carte vide, brainstorming, gestion de projet, architecture IT, reunion, SWOT, plan d'etude, planification personnelle). Choisir un modele en cree une copie : l'original n'est jamais modifie, et la carte obtenue est une carte comme les autres.
Markdown : import d'un fichier .md ou d'un texte colle, comme nouvelle
carte depuis le tableau de bord ou comme sous-arbre d'un noeud existant. Les
titres et les listes construisent la hierarchie ; les paragraphes et les blocs
de code rejoignent la note du noeud, en texte brut. Export inverse en .md :
contenu et hierarchie uniquement, sans positions ni couleurs, avec un
avertissement si la carte contient des relations secondaires.
Proprietes du noeud, regroupees en sections repliables (Contenu, Typographie, Apparence, Mise en page, Branche) : texte, icone, URL, notes ; police, taille, gras, italique, alignement horizontal et vertical, interligne ; couleurs de fond/texte/bordure, forme (rectangle, arrondi, capsule, cercle), ombre ; taille automatique ou personnalisee, largeur, hauteur, padding horizontal et vertical, retour a la ligne, largeur maximale du texte ; style, epaisseur et couleur de la branche. Un reglage s'applique a toute la selection, avec un etat Mixte quand les valeurs different.
Creation rapide : Ajouter plusieurs enfants (une ligne = un noeud, avec apercu), collage d'une liste multi-ligne directement sur un noeud, import d'une arborescence indentee (espaces ou tabulations, puces retirees, indentation incoherente signalee), ajout avant / apres un frere.
Hierarchie : ordre explicite des freres (monter, descendre, placer en premier / en dernier), remontee d'un niveau, Deplacer vers... avec recherche du nouveau parent, suppression d'un noeud en conservant ses enfants.
Branches : selectionner, dupliquer, copier / coller comme enfant, deplacer sur le canvas avec ses descendants, replier / developper une branche, tout replier, tout developper, replier au-dela d'un niveau donne.
Mise en page visuelle : redimensionnement des noeuds a la souris (une seule annulation par redimensionnement), taille automatique qui epouse le contenu, alignement et distribution d'une multi-selection, aimantation sur la grille, guides d'alignement pendant le deplacement, copier / coller / reinitialiser le style (Ctrl+Maj+C, Ctrl+Maj+V), menu contextuel par clic droit. Le style couvre les couleurs, la forme, la typographie, la mise en page, la presentation de l'icone et la branche ; l'icone elle-meme, comme le texte, la note et l'URL, appartient au contenu du noeud et n'est jamais remplacee par un collage.
Bibliotheque d'icones : emojis et icones integrees (Lucide), avec position (gauche, droite, au-dessus), taille et espacement configurables.
Themes : Default, Minimal, Dark, Midnight, Ocean, Forest, Pastel, Monochrome, Blueprint. Plus un mode clair/sombre pour l'interface. Changer de theme ne supprime jamais une personnalisation explicite d'un noeud.
Recherche dans la carte : resultats listes, navigation entre eux, centrage et mise en evidence temporaire du noeud, depliage automatique des branches repliees.
Exports : .mmap (format natif), Markdown (.md), PNG (x1, x2, fond transparent), SVG, PDF
(A4/A3, portrait/paysage, marges, adapter a une page ou taille reelle, fond,
titre, date), impression via @media print.
PWA : installable, et utilisable hors ligne pour les cartes locales une fois l'application chargee.
Raccourcis clavier
Cmd remplace Ctrl sur macOS.
| Raccourci | Action |
|---|---|
Tab |
Ajouter un noeud enfant |
Entree |
Ajouter un noeud frere |
Suppr / Retour arriere |
Supprimer la selection, hors saisie de texte |
F2 |
Editer le texte du noeud selectionne |
| Double-clic | Editer le texte du noeud |
Ctrl+Z |
Annuler |
Ctrl+Y ou Ctrl+Shift+Z |
Retablir |
Ctrl+C |
Copier |
Ctrl+V |
Coller |
Ctrl+D |
Dupliquer |
Ctrl+Maj+C |
Copier le style du noeud (sans son icone) |
Ctrl+Maj+V |
Coller le style sur la selection |
Maj+Tab |
Remonter le noeud d'un niveau |
Maj+Entree |
Ajouter plusieurs enfants |
Alt+Haut / Alt+Bas |
Monter / descendre parmi les freres |
Alt + glisser |
Inverser le mode de deplacement de branche |
Ctrl+V |
Coller : noeuds OpenMind, sinon liste de texte en enfants |
Ctrl+A |
Tout selectionner |
Ctrl+S |
Sauvegarde explicite |
Ctrl+F |
Rechercher dans la carte |
F |
Adapter la carte a l'ecran |
Echap |
Quitter l'edition ou deselectionner |
Format de fichier .mmap
Un .mmap est un fichier JSON UTF-8 contenant le document complet de la
carte. Il ne contient jamais de jeton de partage.
Le format est en version 3.
| Version | Apport | Migration a l'import |
|---|---|---|
| v1 | format initial | style.width devient layout.width |
| v2 | mise en page des noeuds (layout, iconStyle, branch) |
l'ordre des freres est materialise depuis leur position dans nodes |
| v3 | ordre explicite des freres (node.order) |
aucune |
| v4 | cote des branches (node.side) et relations secondaires (relations) |
aucune |
Les fichiers v1, v2 et v3 restent lisibles, et les cartes deja enregistrees dans
IndexedDB s'ouvrent sans modification. Le passage en v3 etait justifie : l'ordre
des freres fait partie de la semantique du document, et un lecteur v2
l'ignorerait en reordonnant silencieusement la carte. Les noeuds sont malgre
tout ecrits en parcours de profondeur, freres dans l'ordre, ce qui donne le bon
resultat meme a un lecteur qui ignore order.
Le passage en v4 l'est aussi : un lecteur v3 ignorerait relations et perdrait
donc une partie du document. La migration v3 -> v4 n'a en revanche rien a
inventer : aucun cote defini signifie "a repartir automatiquement", aucune
relation signifie "aucune". Une carte v3 s'affiche exactement comme avant.
Toute carte qui entre dans l'editeur passe par le meme point d'entree,
normalizeMapDocument(), quelle que soit sa provenance :
fichier .mmap ┐
IndexedDB ├─> validation -> migration de version -> normalisation -> modele courant
partage ┘
La normalisation est non destructive : le document fourni n'est jamais modifie et rien n'est reecrit en base. Une carte v1 restee en IndexedDB s'ouvre donc exactement comme avant, et n'est reenregistree au format courant que si vous la modifiez.
{
"version": 1,
"id": "uuid",
"name": "Architecture Homelab",
"createdAt": "2026-01-01T10:00:00.000Z",
"updatedAt": "2026-01-01T12:30:00.000Z",
"nodes": [
{
"id": "uuid",
"type": "root",
"text": "Infrastructure",
"position": { "x": 0, "y": 0 },
"parentId": null,
"order": 0,
"side": "right",
"collapsed": false,
"icon": "\ud83d\udda5\ufe0f",
"url": "https://exemple.fr",
"note": "Texte libre",
"style": {
"backgroundColor": "#eef2ff",
"shape": "rounded",
"textAlign": "center",
"verticalAlign": "middle",
"lineHeight": 1.35,
"fontFamily": "sans",
"shadow": "soft"
},
"layout": {
"widthMode": "fixed",
"width": 240,
"heightMode": "auto",
"paddingX": 14,
"paddingY": 8,
"wrap": true,
"maxTextWidth": 260
},
"iconStyle": { "kind": "emoji", "position": "left", "size": 16, "gap": 8 },
"branch": { "style": "bezier", "width": 2, "color": "#94a3b8" }
}
],
"edges": [{ "id": "e-a-b", "source": "a", "target": "b" }],
"relations": [
{
"id": "r-uuid",
"sourceId": "a",
"targetId": "b",
"label": "depend de",
"style": "bezier",
"color": "#a855f7",
"width": 2,
"dashed": true,
"markerEnd": "arrow"
}
],
"viewport": { "x": 0, "y": 0, "zoom": 1 },
"settings": {
"theme": "default",
"layout": "mindmap-right",
"branchStyle": "bezier",
"showGrid": true,
"layoutSpacing": { "parentGap": 100, "siblingGap": 50 },
"snapToGrid": false,
"snapGrid": 20,
"alignmentGuides": true,
"dragMovesBranch": false
}
}
Deux precisions sur ce document :
edgesest derive deparentId: il est recalcule a chaque modification et n'est jamais une source de verite.relations, au contraire, est une donnee a part entiere, que rien ne permet de deduire de la hierarchie.siden'a de sens que sur un enfant direct d'une racine. Tous ses descendants heritent du cote de leur branche, ce qui evite d'entretenir la meme information sur chaque noeud.
A l'import, le fichier est valide et normalise : structure, version, champs
essentiels, limite de noeuds, assainissement des URL (javascript: et data:
sont supprimes), rejet des styles invalides. Le contenu n'est jamais execute ni
interprete comme du HTML ; un fichier invalide produit un message clair.
Le champ version permet les migrations futures : le point d'extension se
trouve dans frontend/src/services/mapSerialization.ts, fonction migrate.
Developpement
Backend
cd backend
python -m venv .venv
source .venv/bin/activate
pip install -r requirements-dev.txt
DATABASE_URL=sqlite:///./openmind-dev.db STATIC_DIR=./static uvicorn app.main:app --reload --port 8080
Sous Windows, activez l'environnement avec .venv\Scripts\activate.
Frontend
cd frontend
npm install
npm run dev
Le serveur Vite ecoute sur http://localhost:5173 et proxyfie /api vers
http://localhost:8080.
Autres commandes :
npm run build
npm run lint
npm run typecheck
npm run test
Regenerer les icones de la PWA :
python scripts/generate_icons.py
Tests et qualite
Backend :
cd backend
python -m pytest -q
ruff check .
ruff format --check .
Frontend :
cd frontend
npm run test
npm run lint
npm run typecheck
Sans installation locale de Node ou Python, tout peut tourner via Docker :
docker run --rm -v "$PWD/backend:/work" -w /work python:3.12-slim sh -c "pip install -q -r requirements-dev.txt && ruff check . && python -m pytest -q"
docker run --rm -v "$PWD/frontend:/app" -w /app node:20-alpine sh -c "npm ci && npm run lint && npm run test && npm run build"
Les tests backend couvrent : healthcheck, creation, lecture, mise a jour et suppression d'un partage, refus avec un mauvais jeton de gestion, refus sans jeton, partage inexistant, payload invalide, limites de taille et de noeuds, non-divulgation du jeton de gestion, repli SPA, acceptation des documents v3 et v4 (ordre des freres, cotes, relations) et refus d'une relation incoherente.
Les tests frontend couvrent : stockage IndexedDB, serialisation et validation d'import, migrations v1 -> v4, non-mutation et idempotence de la normalisation, store Zustand (creation, suppression de branche, undo/redo, groupement du glisser-deposer, copier/coller, duplication, detection de boucle, recherche, auto-layout, lecture seule), repartition et heritage des cotes, auto-layout bilateral, relations secondaires (creation, refus, style, repli, duplication, independance vis-a-vis de la hierarchie), analyse et export Markdown, galerie de modeles, assainissement des URL.
Structure du projet
.
├── Dockerfile # build multi-stage : node -> python -> image finale
├── docker-compose.yml # un seul service, bind mount ./data
├── .env.example
├── README.md
├── scripts/
│ └── generate_icons.py # generation des icones PWA
├── data/ # bind mount : SQLite des partages
├── backend/
│ ├── requirements.txt
│ ├── pyproject.toml # configuration ruff et pytest
│ ├── app/
│ │ ├── main.py # assemblage uniquement
│ │ ├── config.py
│ │ ├── logging_config.py
│ │ ├── middleware.py # en-tetes de securite, limite de taille
│ │ ├── web.py # service des fichiers statiques du frontend
│ │ ├── api/ # routes health, config, shares
│ │ ├── db/ # moteur, session, initialisation du schema
│ │ ├── models/ # SharedMap (SQLAlchemy)
│ │ ├── schemas/ # validation Pydantic
│ │ └── services/ # jetons, logique de partage, erreurs metier
│ └── tests/
└── frontend/
├── index.html
├── public/ # manifest PWA, service worker, icones
└── src/
├── config/app.ts # nom du produit et constantes
├── types/map.ts # modele metier versionne
├── db/ # schema Dexie
├── services/ # depots, serialisation, client API
├── stores/ # Zustand : editeur, interface, configuration
├── hooks/ # routeur minimal, debounce
├── components/ # briques d'interface reutilisables
├── features/
│ ├── editor/ # canvas, noeud, barre d'outils, panneaux, layout, bilateral, relations, themes
│ ├── templates/ # galerie et definitions des modeles
│ ├── maps/ # tableau de bord
│ ├── export/ # PNG, SVG, PDF, impression
│ └── sharing/ # dialogue de partage, page publique
├── utils/
└── styles/
Securite
- Le texte d'un noeud est toujours traite comme du texte. Aucun
dangerouslySetInnerHTML, aucun HTML issu d'une carte n'est interprete. - Les URL sont assainies : seuls
http,httpsetmailtosont acceptes. Les liens s'ouvrent avecrel="noopener noreferrer nofollow". - Validation Pydantic de tout ce qui entre dans l'API, avec limites de taille et de nombre de noeuds ; un depassement produit un message clair, jamais un plantage.
- En-tetes de securite : CSP stricte,
X-Content-Type-Options,X-Frame-Options,Referrer-Policy,Permissions-Policy,Cross-Origin-Opener-Policy. - CORS restrictif : aucune origine externe par defaut.
- Acces SQL exclusivement via l'ORM SQLAlchemy.
- Jetons cryptographiquement aleatoires, jeton de gestion stocke hashe et jamais journalise.
- Le conteneur tourne avec un utilisateur non-root.
- Aucun secret dans le frontend.
Limitations connues
- Export SVG : les noeuds sont encapsules dans un
foreignObject(HTML embarque). Le fichier reste vectoriel et se redimensionne sans perte, les branches sont de vrais chemins SVG, mais certains editeurs vectoriels n'exploitent pas le contenu HTML des noeuds. Preferez PNG ou PDF pour un usage bureautique. - Exports image et PDF en arriere-plan : la generation s'appuie sur une frame d'animation du navigateur, qui n'est pas produite lorsque l'onglet est masque. Gardez l'onglet au premier plan pendant un export ; sinon l'operation est interrompue au bout de 45 secondes avec un message explicite.
- PDF en taille reelle : si la carte depasse la page choisie, elle est reduite pour tenir entierement plutot que d'etre coupee ; un message le signale.
- Gestion d'un partage : le jeton de gestion vit dans l'IndexedDB du navigateur d'origine. Depuis un autre appareil, un partage ne peut etre ni mis a jour ni supprime.
- Dispositions reservees :
organizationetfreeformexistent dans le modele de donnees mais ne sont pas proposees dans l'interface. - Relations et export Markdown : l'export
.mddecrit le contenu et la hierarchie. Les relations secondaires n'y ont pas de representation fidele et ne sont pas inventees ; un message le signale au moment de l'export. - Relations et minimap : la minimap n'affiche que les noeuds. Les relations y sont invisibles, comme les branches hierarchiques.
- Doublon de relation : deux relations identiques (meme source vers meme cible) se superposeraient, la seconde serait donc invisible et impossible a selectionner. Une seule est acceptee par couple ; le sens inverse, lui, reste autorise.
- Relation dupliquee : dupliquer ou coller une branche reporte les relations dont les deux extremites sont dans la branche. Une relation qui sort vers un noeud exterieur n'est pas recreee : rien ne dit que la copie doit viser la meme cible, et le deviner creerait un lien non demande.
- Bilaterale et racines multiples : le recalage des deux cotes se fait sur la premiere racine. Une carte a plusieurs racines reste affichee, mais les racines suivantes ne sont pas recentrees individuellement.
- Types de noeuds reserves :
note,image,group,linkettasksont acceptes par le format, mais la V1 ne produit querootetstandard. - Migrations de schema SQLite : la V1 initialise le schema avec
create_all, une seule table. Alembic n'est pas utilise ; il faudra l'introduire au premier changement de schema. - Guides d'alignement : ils apparaissent pendant un deplacement lorsqu'un bord ou un centre coincide (a 6 px pres) avec celui d'un autre noeud. Ils sont purement visuels : ils n'aimantent pas le noeud. Pour aimanter, activez Aimanter sur la grille.
- Alignement vertical : il n'a d'effet visible que si le noeud est plus haut que son texte, c'est-a-dire avec une hauteur fixe ou un padding vertical important.
- Cercle : un noeud circulaire garde toujours un rapport 1:1. Modifier sa largeur ajuste sa hauteur et inversement ; convertir un noeud rectangulaire en cercle le ramene a un carre. Il n'est donc pas possible d'obtenir un ovale.
- Plusieurs racines : le modele autorise depuis la v1 une carte a plusieurs racines, et certaines cartes existantes en dependent ; ce n'est donc pas interdit. Une carte mentale classique n'en a qu'une, et l'interface pousse dans ce sens : Detacher est une action explicite, et un noeud detache devient une racine a part entiere. Un noeud ne peut jamais devenir son propre parent ni celui d'un de ses ancetres.
- Reordonner ne deplace pas les noeuds sur le canvas : l'ordre est logique. Il se voit immediatement dans l'ordre des liens et dans le resultat de Reorganiser ; les positions libres, elles, restent celles choisies par l'utilisateur.
- Deplacement sur une tres grande carte : sur une carte de ~180 noeuds, une frame de glisser-deposer coute environ 60 a 80 ms car React Flow recalcule l'ensemble des noeuds controles. Le deplacement reste utilisable mais moins fluide que sur une carte de taille courante.
- Mobile : consultation et edition basique fonctionnent, mais l'interface est concue pour desktop et tablette.
- Aucun compte utilisateur : c'est voulu. Pas de connexion, pas de collaboration temps reel, pas de synchronisation cloud.
Licences des dependances
Toutes les dependances sont sous licence libre permissive, compatible avec une application publique et gratuite. Aucune bibliotheque a licence commerciale n'est utilisee.
| Dependance | Licence |
|---|---|
| React, React DOM | MIT |
@xyflow/react (React Flow) |
MIT |
| Zustand | MIT |
| Dexie | Apache-2.0 |
| dagre | MIT |
| html-to-image | MIT |
| jsPDF | MIT |
| lucide-react | ISC |
| Vite, Tailwind CSS, TypeScript, ESLint, Vitest | MIT |
| FastAPI, Starlette, Pydantic, SQLAlchemy, Uvicorn | MIT / BSD |
Licence
OpenMind est distribue sous licence MIT : voir le fichier LICENSE.