feat(mobile): ruban d'edition style Obsidian + correctifs mobile (#83, BUG-017 a BUG-020)
CI / lint (push) Successful in 1m13s
CI / security (push) Successful in 47s
CI / test (push) Successful in 2m41s
CI / build (push) Successful in 43s
CI / e2e (push) Successful in 11m14s

- #83: ruban horizontal defilable ancre au-dessus du clavier, commandes
  etendues (titres, barre, surligne, code bloc, citation, listes, cases,
  wikilinks, tags, pieces jointes, undo/redo, colle, police) et
  personnalisation persistee via l'icone engrenage
- BUG-017: cartes du tableau de bord compressibles (min-width:0)
- BUG-018: en-tete editeur mobile compact, boutons Annuler/Sauvegarder
  accessibles, barre IA plus tactile
- BUG-019: ancrage du ruban via visualViewport (--kb-offset)
- BUG-020: suppression de la double barre de defilement

Tests: mobile-editor 35/35, ai 50/50, 9 suites JSDOM, validate-imports,
pytest 961 passed / 6 skipped, ruff + mypy 0.
This commit is contained in:
2026-09-13 11:49:45 -04:00
parent 162a5b4acc
commit 520059d866
11 changed files with 841 additions and 126 deletions
+5 -4
View File
@@ -126,10 +126,10 @@ Avant de corriger quoi que ce soit, un agent IA doit :
| *BUG-014* | Assistant IA : les flèches ↑/↓ ne naviguent pas dans les menus `/` et `@` | 🟢 corrigé | P1 | 📱 frontend | IA | `frontend/js/bookslm.js` | Ouvrir `/`, puis ↑/↓ (y compris après un clic hors zone de texte) | Navigation gérée au niveau du **panneau en phase de capture** (`panel.addEventListener('keydown', ..., true)`), donc indépendante du focus | Le `keydown` n'était écouté que sur la zone de texte ; dès que le focus changeait, les flèches étaient ignorées. Tests : `tests/frontend/ai.test.mjs` (+1) |
| *BUG-015* | Assistant IA : la ligne sélectionnée des menus `/` et `@` est invisible au clavier | 🟢 corrigé | P2 | 📱 frontend | IA | `frontend/style.css` | Ouvrir `/` ou `@`, naviguer avec ↑/↓ | État `.active` en `--bg-hover` + barre d'accent à gauche (`inset 3px 0 0 var(--accent)`) au lieu de `--surface2` | `--surface2` est identique à `--bg-primary` (fond du menu) en thème sombre : la sélection ne se voyait pas. Idem pour la liste de modèles |
| *BUG-016* | Mobile : le bouton « mode lecture » flottant recouvre le bouton d'envoi de l'assistant IA | 🟢 corrigé | P2 | 📱 frontend | IA | `frontend/js/mobile-editor.js`, `frontend/style.css` | Mobile, sans fichier ouvert : ouvrir l'assistant puis constater que `📖` masque `✈️` | `updateReadingButtonVisibility()` n'affiche `#me-reading-btn` que si `state.currentPath` est défini **et** que le panneau assistant est fermé ; resynchronisé à chaque mutation de `#content-area` et sur `bookslm:opened`/`bookslm:closed` ; règle `.me-reading-btn[hidden]{display:none}` | Le bouton flottant (z-index 890) passait au-dessus du panneau plein écran mobile (z-index 100). Tests : `tests/frontend/mobile-editor.test.mjs` (+2) |
| *BUG-017* | Accueil mobile : les tuiles de « Favoris » et « Récents » ne s'affichent pas correctement en largeur (l'onglet « Partagés » s'affiche correctement) | 🔴 ouvert | P2 | 📱 frontend | IA | `frontend/js/dashboard.js`, `frontend/js/viewer.js`, `frontend/style.css` | Mobile : page d'accueil → onglets Favoris / Récents | — | Grille de tuiles non adaptée au viewport (largeur / nombre de colonnes) ; l'onglet « Partagés » (`.shared-card`) est conforme |
| *BUG-018* | Éditeur mobile : mise en page inadaptée — boutons « Annuler » / « Sauvegarder » inaccessibles et barre d'outils IA non optimisée | 🔴 ouvert | P1 | 📱 frontend | IA | `frontend/index.html`, `frontend/style.css`, `frontend/js/ai.js` | Mobile : ouvrir un fichier → barre d'outils de l'éditeur puis panneau assistant | — | Boutons de l'éditeur hors écran / masqués sur petit écran ; barre d'outils IA trop dense ou mal positionnée |
| *BUG-019* | Éditeur mobile : la barre d'outils du bas n'est pas toujours visible au-dessus du clavier quand le curseur n'est pas en bas de l'éditeur | 🔴 ouvert | P1 | 📱 frontend | IA | `frontend/js/mobile-editor.js`, `frontend/style.css` | Mobile : ouvrir un fichier, placer le curseur au milieu du document, afficher le clavier | — | La barre ne suit pas la position du curseur / n'est pas ancrée au-dessus du clavier virtuel |
| *BUG-020* | Éditeur mobile : deux barres de défilement verticales à droite de la page en mode édition | 🔴 ouvert | P3 | 📱 frontend | IA | `frontend/style.css` | Mobile : ouvrir l'éditeur et observer le bord droit | — | Double scrollbar (conteneur de l'éditeur + `.cm-scroller`) peu naturelle pour un éditeur |
| *BUG-017* | Accueil mobile : les tuiles de « Favoris » et « Récents » ne s'affichent pas correctement en largeur (l'onglet « Partagés » s'affiche correctement) | 🟢 corrigé | P2 | 📱 frontend | IA | `frontend/style.css` | Mobile : page d'accueil → onglets Favoris / Récents | `frontend/style.css` : `min-width:0` + `overflow:hidden` sur `.dashboard-card` (et header/footer) → la grille 1 colonne ne déborde plus | Cause : titre/chemin `nowrap` forçaient la largeur mini de la carte |
| *BUG-018* | Éditeur mobile : mise en page inadaptée — boutons « Annuler » / « Sauvegarder » inaccessibles et barre d'outils IA non optimisée | 🟢 corrigé | P1 | 📱 frontend | IA | `frontend/style.css` | Mobile : ouvrir un fichier → barre d'outils de l'éditeur puis panneau assistant | `frontend/style.css` : en-tête mobile compact (marque/séparateur/espaceur/présence masqués, champs compressibles, libellé « Saved » masqué) + cibles tactiles `.ai-toolbar-btn` agrandies | Les 3 boutons d'action restent accessibles ; voir aussi #83 pour le ruban |
| *BUG-019* | Éditeur mobile : la barre d'outils du bas n'est pas toujours visible au-dessus du clavier quand le curseur n'est pas en bas de l'éditeur | 🟢 corrigé | P1 | 📱 frontend | IA | `frontend/js/mobile-editor.js`, `frontend/style.css` | Mobile : ouvrir un fichier, placer le curseur au milieu du document, afficher le clavier | `initKeyboardAnchor()` utilise `window.visualViewport` (`--kb-offset`) pour ancrer le ruban au-dessus du clavier ; `padding-bottom` sur `.cm-scroller` | Fonctionne quel que soit le défilement / la position du curseur |
| *BUG-020* | Éditeur mobile : deux barres de défilement verticales à droite de la page en mode édition | 🟢 corrigé | P3 | 📱 frontend | IA | `frontend/style.css` | Mobile : ouvrir l'éditeur et observer le bord droit | `frontend/style.css` : `.editor-body` en `overflow:hidden` + colonne flex ; seul `.cm-scroller` défile | Une seule barre de défilement |
| *BUG-021* | [🔴 CRITIQUE] XSS stocké via le rendu markdown (`escape=False`) | 🟢 corrigé | P0 | 🔐 sécurité | IA | `backend/services/sanitizer.py`, `backend/main.py` | Ouvrir une note contenant `<img src=x onerror=alert(1)>` | `backend/services/sanitizer.py` (whitelist stdlib) appliqué après `_add_heading_ids` dans `_render_markdown` ; tests `tests/test_security_hardening.py` | HTML brut d'un vault injecté dans le DOM → JS dans le navigateur de chaque utilisateur. DOMPurify client non ajouté (défense serveur suffisante) |
| *BUG-022* | [🔴 CRITIQUE] XSS stocké sur la page publique `/s/{token}` (title + frontmatter non échappés) | 🟢 corrigé | P0 | 🔐 sécurité | IA | `backend/main.py` | Partager une note dont le frontmatter contient un `title` avec `<script>` | `backend/main.py` : `html.escape()` sur `title`/frontmatter + JSON échappé (`\u003c`) pour le bloc `<script>` et `a.download` | `a.download="{title}.md"` se trouvait dans un bloc script → breakout JS. Test d'intégration dans `tests/test_security_hardening.py` |
| *BUG-023* | [🔴 CRITIQUE] Brute-force MFA sans rate-limit ni verrouillage | 🟢 corrigé | P0 | 🔐 sécurité | IA | `backend/auth/router.py` | `POST /api/auth/mfa/totp/verify` en boucle avec des codes aléatoires | `_enforce_mfa_rate_limit` + `_record_mfa_failure` sur `totp/verify`, `recovery`, `webauthn/verify` (IP + compte + lockout) | TOTP 6 chiffres brute-forceable ; le login était protégé, pas le second facteur |
@@ -185,6 +185,7 @@ Avant de corriger quoi que ce soit, un agent IA doit :
| 2026-09-13 | BUG-017, BUG-018, BUG-019, BUG-020, #83 | Enregistrement | `docs/ISSUES_TODOLIST.md`, `docs/ROADMAP.md` | Signalements mobile consignés : accueil (tuiles Favoris/Récents), éditeur (boutons Annuler/Sauvegarder inaccessibles + barre IA), visibilité de la barre d'outils au-dessus du clavier, double barre de défilement. Feature #83 ajoutée : barre d'outils d'édition mobile style Obsidian Android. | 🔴 ouvert (à traiter) |
| 2026-09-13 | Revue sécurité statique (BUG-021 → BUG-040, roadmap #84 → #87) | Enregistrement | `docs/ISSUES_TODOLIST.md`, `docs/ROADMAP.md` | Revue statique 2026-09-13 consignée : XSS markdown (`escape=False`) + page de partage publique, brute-force MFA, traversal par préfixe `paths.py`, ReDoS, SSRF webhooks, cycle de vie des sessions, politique de mot de passe, races `users.json`, audits IP, rate-limit, indexation symlinks, recherche O(N), CSP. BUG-021→BUG-040 ouverts au registre ; roadmap #84→#87 (consolidation/sécurité, refonte architecturale, performance, CI/CD). | 🔴 ouvert (à traiter) |
| 2026-09-13 | BUG-021 → BUG-034 (#84 phase 1) | Correction | `backend/services/sanitizer.py`, `backend/services/paths.py`, `backend/services/net.py`, `backend/services/regex_safety.py`, `backend/main.py`, `backend/search.py`, `backend/webhooks.py`, `backend/indexer.py`, `backend/ratelimit.py`, `backend/auth/{router,user_store,password,jwt_handler,middleware}.py`, `frontend/js/{auth,admin,sync}.js`, `tests/test_security_hardening.py`, `tests/test_auth_api.py` | Sanitizer XSS serveur (markdown + page de partage), rate-limit/lockout MFA, isolation vaults par segments, caps regex (ReDoS), SSRF webhooks + secrets externalisés, rotation/révocation des jetons, politique de mot de passe + invalidation des sessions, verrous `users.json`, IP réelle dans les audits, rate-limit par compte, symlinks d'index ignorés, recherche simple via inverted index, token en mémoire + cookie HttpOnly + CSP durcie. Vérifié : pytest 961 passed / 6 skipped, ruff 0, mypy 0, tests frontend 36 modules + 9 JSDOM suites verts. | 🟢 corrigé (en attente vérif utilisateur) |
| 2026-09-13 | BUG-017 → BUG-020, #83 | Correction + feature | `frontend/js/mobile-editor.js`, `frontend/style.css`, `frontend/index.html`, `frontend/locales/{fr,en}.json`, `tests/frontend/mobile-editor.test.mjs`, `tests/e2e/mobile-editor.spec.js` | BUG-017 : cartes de tableau de bord compressibles (`min-width:0`) ; BUG-018 : en-tête éditeur mobile compact + barre IA tactile ; BUG-019 : ancrage du ruban via `visualViewport` ; BUG-020 : suppression de la double scrollbar. #83 : ruban d'édition horizontal défilable style Obsidian (commandes étendues + personnalisation ⚙ persistée). Vérifié : tests frontend 35/35 (mobile) + 50/50 (IA) + 9 JSDOM suites. | 🟢 corrigé (en attente vérif utilisateur) |
---