Commit Graph

11 Commits

Author SHA1 Message Date
cedricAbonnel ed3f8062da feat : sparklines 14j stats + filtre IPs LAN (v1.6.27)
- Admin stats : sparklines SVG par page (120×28 px, courbe + dégradé),
  carte « Pages les plus visitées » en pleine largeur
- AccessLogParser : données par jour (pages_by_day) sur 14 jours
- AccessLogParser : IPs privées/LAN exclues de la répartition réseau
- ArticleManager : suppression opérateur nullsafe superflu (PHPStan)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 18:20:19 +02:00
cedricAbonnel 3b22be94e8 feat : barre de partage articles + déduplication images uploadées (v1.6.20)
- post_view.php : barre de partage (mail, X, LinkedIn, Mastodon, copier, Web Share) sur articles publiés (#47)
- share.js : logique clipboard + navigator.share sans script tiers, compatible CSP (#47)
- addFile() : hardlink vers fichier identique si même hash16-size.ext dans un autre article (#35)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 10:56:43 +02:00
cedricAbonnel 5ce91da06a perf & ux : cache getAll, fingerprint assets, Last-Modified, 404 log, row-click bulk (v1.6.19)
- getAll() : cache fichier articles_list.json, invalidé à chaque écriture (#16)
- layout.php : fingerprinting ?v=<hash> sur CSS/JS pour invalidation navigateur (#18)
- case 'view' : Last-Modified + 304 Not Modified pour les articles publiés (#18)
- case 'not_found' : logging JSON des 404 dans _logs/not_found.jsonl (#52)
- case 'view' : echo nu → templates/404.php pour brouillons/privés (#52)
- admin.js : clic sur ligne tableau → toggle bulk-check (#86)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 10:44:08 +02:00
cedricAbonnel 11399a54a6 feat : magic link confirm, notif auteur, rate-limit IP, duplicate, cache MD, lazy img (v1.6.18)
- magic.php : GET=confirmation page, POST=consommation (protège vs scanners) (#27)
- verify_comment : email de notification à l'auteur de l'article (#44)
- login/index.php : rate limit par IP (MAGIC_MAX_PER_IP_HOUR=10) (#23)
- ArticleManager::duplicate() + route POST /duplicate/{uuid} + bouton ⧉ admin/articles (#7)
- post_view.php : cache JSON du rendu Markdown (invalidé sur mtime index.md) (#17)
- post_view.php : loading="lazy" sur toutes les <img> du contenu (#21)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 10:30:55 +02:00
cedricAbonnel 347e4be0b7 perf : getAll() sans contenu, search_index + featured, excerpts via plain (v1.6.14)
- loadArticle($dir, false) dans loadAll() — meta.json seulement, pas d'index.md
- loadAll() enrichit les articles avec plain depuis search_index (1 lecture JSON)
- rebuildSearchIndex() lit index.md directement + ajoute featured au schéma
- getSearchIndex() rebuilde automatiquement si featured absent
- post_list, author_articles, author_profile : excerpts via plain, plus de Parsedown
- Ferme #24

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 23:50:58 +02:00
cedricAbonnel 996ab3e508 fix : suppression article — permissions répertoire et gestion d'erreur (v1.6.10)
- mkArticleDir() crée les répertoires avec chmod 0775 explicite (bypass umask)
- delete() retourne bool et détecte l'échec sans reconstruire les index
- removeDir() supprime les warnings PHP (@unlink, @rmdir, @scandir)
- post_view.php affiche un message d'erreur si delete_failed=1
- index.php redirige vers l'article avec ?delete_failed=1 si échec

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 22:27:24 +02:00
cedricAbonnel 16965ee8cb feat : DATA_PATH configurable, DataGit auto-commit, UpdateChecker branche (v1.4.0)
- DATA_PATH : chemin /data hors document root, configurable via .env
  (fallback sur BASE_PATH/data si absent)
- DataGit : auto-commit git sur toutes les écritures articles/livres
  (create, update, delete, meta, tags, fichiers, liens…) sauf autosave
- UpdateChecker : getBranch() / getLastChecked() / clearCache(),
  branche configurable via FOLIO_UPDATE_BRANCH (plus de main hardcodé)
- Admin dashboard : affiche la branche suivie, date du dernier contrôle,
  bouton Vérifier pour forcer le check sans attendre le TTL
- CLAUDE.md : architecture DATA_PATH et flux de déploiement documentés

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 09:17:55 +02:00
cedricAbonnel 72cb7acae4 fix 1.2.1 : cache index.md, H1 rendu, scroll wizard, titre Modifier
- ArticleManager : invalider le cache si index.md est plus récent que meta.json
- migration_001 : touch(meta.json) après maj index.md pour forcer l'invalidation
- post_view.php : masquer le H1 initial du contenu (déjà affiché par le template)
- step1.php : en-tête "Modifier" sans le titre de l'article
- wizard.js : retirer scrollToCursor (erroné sur auto-resize) ; Ctrl+Home/End via scrollIntoView

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 23:07:15 +02:00
cedricAbonnel 6895a3bf65 feat #58 : wizard multi-étapes création/édition d'article
Remplace le formulaire unique par un wizard 5 étapes (création) et
6 étapes (édition) avec auto-sauvegarde en brouillon, détection de
tags depuis le texte (TagSuggester), aperçu SEO, diff avant validation
et plan Markdown dynamique dans l'éditeur.

Détail des changements :
- ArticleManager : +6 méthodes (updatePartialMeta, saveDraftOverlay,
  getDraftOverlay, hasDraftOverlay, discardDraftOverlay, commitDraftOverlay)
- .htaccess : routes /new/{uuid}/{1-5} et /edit/{uuid}/{1-6}
- index.php : cases create et edit réécrits en switch($step),
  nouveau case autosave_draft et edit_discard_draft
- assets/js/wizard.js : autosave debounce, auto-resize textarea,
  scroll curseur, plan TOC dynamique, toggle pills tags
- templates/wizard/ : nav.php + step1..6.php

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 21:46:11 +02:00
cedricAbonnel 0b8077e43c fix : orphelins search_index + SESSION_NAME non appliqué
- ArticleManager::getSearchIndex() : rebuild automatique si un UUID
  référencé dans search_index.json n'existe plus sur le disque (article
  supprimé hors CMS via rsync ou suppression manuelle). Même logique que
  getBySlug() qui nettoie déjà le slug_index à la volée.

- bootstrap.php : lire SESSION_NAME depuis $_ENV avant session_start(),
  permettant de personnaliser le nom du cookie de session via le .env.

- oidc/{start,callback,me}.php : inverser l'ordre des require pour charger
  config.php (dotenv) avant bootstrap.php, condition nécessaire pour que
  SESSION_NAME soit disponible au démarrage de la session.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 10:06:11 +02:00
Cedric Abonnel 8a85c15372 fix #29 : envoyer le lien magique par email (envoyer_mail_smtp) 2026-05-13 23:41:58 +02:00