Commit Graph

886 Commits

Author SHA1 Message Date
Colin Maudry 6144e3c18d feat(auth): route delete-account avec confirmation par mot de passe (#73) 2026-06-24 18:49:52 +02:00
Colin Maudry 558df9627b feat(auth): routes change-email + confirm-email-change (#73)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 18:48:08 +02:00
Colin Maudry 90261d4f31 feat(auth): email de confirmation de changement d'adresse (#73)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 18:45:37 +02:00
Colin Maudry 4602b45f30 feat(compte): coquille account_shell (sidebar + offcanvas + garde d'accès) (#73)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 18:43:53 +02:00
Colin Maudry f301a0a336 feat(auth): email en attente (pending_email) + migration (#73)
Adds pending_email column to users table with idempotent migration.
Implements set_pending_email() and promote_pending_email() for email-change workflow.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 18:43:04 +02:00
Colin Maudry 442192cb35 docs(compte): plan d'implémentation de l'espace compte (#73)
Refs #73

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 18:38:09 +02:00
Colin Maudry ba5ad2c2ac docs(compte): design de l'espace compte multi-sections (#73)
Design validé en brainstorming : coquille account_shell (sidebar +
offcanvas), routage /compte/* (une page par section), 3 niveaux d'accès
avec stub d'abonnement, section Compte (email avec re-vérification,
mot de passe, suppression via modale).

Refs #73

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 18:32:17 +02:00
Colin Maudry 816c6d67b0 Changelog 2.9.0 2026-06-24 18:01:59 +02:00
Colin Maudry 9baf02810f Merge branch 'feature/89_backup' into dev 2026-06-24 17:49:15 +02:00
Colin Maudry 6161a103b0 Fix README 2026-06-24 17:49:08 +02:00
Colin Maudry ac3ba89c0a fix(backup): retirer users.sqlite du suivi git, logging, test restore CLI, garde snapshot (#89)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 17:45:40 +02:00
Colin Maudry 02df6c10a0 feat(backup): unités systemd, variables d'env et doc de déploiement (#89)
Ajoute les artefacts de déploiement finaux pour la sauvegarde systématisée
de users.sqlite sur S3 :
- Service systemd pour exécuter le backup (oneshot)
- Timer systemd pour le déclencher toutes les heures
- Variables d'env pour configuration S3 et chiffrement
- Documentation d'installation et restauration dans CLAUDE.md
- Guide rapide dans README.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 17:29:03 +02:00
Colin Maudry 196a9db8c1 refactor(backup): retirer le return 1 inaccessible dans main() (#89)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 17:26:37 +02:00
Colin Maudry 1453990f7a feat(backup): CLI backup/list/restore (#89)
Implement CLI interface for the backup module with three subcommands:
- backup: create a backup and apply rotation
- list: list available backups
- restore: restore a specific backup

Also add __main__.py to enable 'python -m src.backup'.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 17:23:57 +02:00
Colin Maudry ded5e66ccc fix(backup): nettoyer le fichier temporaire en cas d'erreur dans restore (#89)
Wraps temp file operations in try/except to ensure the temporary database file is always cleaned up, even if an exception occurs during write_snapshot or verify_integrity.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 17:21:28 +02:00
Colin Maudry cae0a528f3 feat(backup): orchestration backup/list/restore (#89)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 17:18:47 +02:00
Colin Maudry 0234505932 refactor(backup): type hints sur FakeStorage (#89) 2026-06-24 17:16:40 +02:00
Colin Maudry 108592f289 feat(backup): wrapper de stockage S3 (boto3) + faux stockage de test (#89) 2026-06-24 17:13:17 +02:00
Colin Maudry efefc3f5b0 feat(backup): snapshot SQLite cohérent et contrôle d'intégrité (#89)
Implémente les trois fonctions de gestion de snapshots SQLite:
- make_snapshot: crée un snapshot gzippé cohérent via sqlite3.Connection.backup()
- write_snapshot: écrit le snapshot décompressé à destination
- verify_integrity: valide l'intégrité d'une base avec PRAGMA integrity_check

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 17:10:22 +02:00
Colin Maudry 2a691e37b7 feat(backup): chiffrement Fernet des sauvegardes
- Ajouter encrypt() et decrypt() avec clés Fernet urlsafe-base64
- Tests de roundtrip et échec avec mauvaise clé

Fixes #89
2026-06-24 17:08:34 +02:00
Colin Maudry 927f56cb1c feat(backup): rotation multi-paliers (fonction pure)
Implémente la fonction select_retained() pour la rétention multi-paliers:
- Paliers fixes: horaire/12h, 12h/72h, quotidien/21j
- Palier mensuel: 12 mois calendaires
- Fonction pure, pas de dépendances sur d'autres modules backup

Fixes #89
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 17:06:27 +02:00
Colin Maudry 48c0649a68 feat(backup): nommage horodaté des clés S3 (#89)
Ajoute les fonctions make_key() et parse_timestamp() pour gérer
le format des clés S3 avec horodatage UTC.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 17:02:47 +02:00
Colin Maudry 1d2a945aa1 feat(backup): config et dépendances pour la sauvegarde S3 (#89) 2026-06-24 17:00:34 +02:00
Colin Maudry 3ad328103c docs(backup): plan d'implémentation sauvegarde S3 (#89) 2026-06-24 16:57:11 +02:00
Colin Maudry 555a87fdf7 docs(backup): conception sauvegarde base utilisateurs sur S3
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 16:51:45 +02:00
Colin Maudry 3f1c39d5a6 fix(brevo): passer X-Sib-Sandbox dans le body email, pas en header HTTP (#87)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 16:22:42 +02:00
Colin Maudry c3408ecc3c refactor(brevo): utiliser DEVELOPMENT pour le mode sandbox Brevo (#87)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 15:40:46 +02:00
Colin Maudry c0927c718d test(brevo): test d'intégration sandbox optionnel (#87)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 15:35:23 +02:00
Colin Maudry 162bc550c0 chore(brevo): retirer la config SMTP et les templates Jinja d'email (#87)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 15:34:45 +02:00
Colin Maudry e4c291a785 feat(brevo): envoyer les emails transactionnels via l'API Brevo v5 (#87)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 15:33:14 +02:00
Colin Maudry 570f9f4153 build(brevo): remplacer flask-mail par brevo-python v5 (#87)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 15:30:48 +02:00
Colin Maudry 99abdfed0b docs(brevo): plan d'implémentation + maj spec avec l'API v5 vérifiée (#87)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 15:19:42 +02:00
Colin Maudry f41ee64c32 docs(brevo): spec de migration des emails transactionnels vers Brevo (#87)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 15:08:09 +02:00
Colin Maudry afe99ea79f fix(auth): utiliser threading.local() pour les connexions SQLite par thread
La connexion singleton partagée entre threads causait sqlite3.InterfaceError
lors de requêtes concurrentes sur la page compte.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 12:23:55 +02:00
Colin Maudry 7be0332f02 Merge branch 'dev' into feature/73_compte_utilisateur 2026-06-24 05:34:27 +02:00
Colin Maudry 8830b2ac91 fix(test): mettre à jour les assertions de compute_considerations_stats pour le retour en 3-tuple
La fonction retourne désormais (count_ren, count_pos_ren, pct) pour les clés
_renseignees, mais les tests attendaient encore l'ancien format (count_ren, pct).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 05:34:03 +02:00
Colin Maudry b1c33c29ed Env MAIL_SUPPRESS_SEND 2026-06-24 05:29:24 +02:00
Colin Maudry c99f4d970e fix(csrf): centraliser l'injection des tokens CSRF via un dcc.Store et un callback pattern-matching
Remplace les 7 callbacks CSRF individuels (un par formulaire, avec IDs string
page-spécifiques) par un seul dcc.Store(id="csrf-token") dans le layout principal
et un callback pattern-matching Output({"type": "csrf-input", "index": ALL}).
Évite les erreurs Dash "id non trouvé dans le layout" sans recourir à
suppress_callback_exceptions=True.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 05:26:07 +02:00
Colin Maudry c228f7be55 fix(auth): corriger le lien de validation email et l'isolation des tests
Le lien de vérification pointait vers la page Dash /verification-email
(qui se contente de rediriger vers /connexion) au lieu de la route
backend /auth/verify-email qui consomme réellement le token et marque
l'email comme vérifié. Conséquence : l'email n'était jamais validé et le
login renvoyait email_not_verified en boucle.

Ajoute aussi MAIL_SUPPRESS_SEND=true au bloc env de pytest : sans cela,
le load_dotenv() de src.app injectait MAIL_SUPPRESS_SEND=false depuis le
.env local, désactivant la suppression d'envoi et faisant échouer les
tests d'auth qui envoient un email (selon l'ordre d'import).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 03:55:52 +02:00
Colin Maudry 4e1c610405 feat(auth): découpler MAIL_SUPPRESS_SEND de DEVELOPMENT et logger les emails supprimés
Ajoute la variable MAIL_SUPPRESS_SEND pour pouvoir tester l'envoi d'emails
en mode développement sans toucher au flag DEVELOPMENT. Un warning est loggé
à chaque tentative d'envoi supprimée avec la cause et les détails du message.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 03:43:55 +02:00
Colin Maudry cbce646fd8 Merge branch 'dev' into feature/73_compte_utilisateur 2026-06-24 03:01:43 +02:00
Colin Maudry a6f60ce3c4 Cache le champ de filtrage pour la colonne 'Marché' 2026-06-24 02:56:42 +02:00
Colin Maudry f9aefb55d8 feat(titulaire): afficher le libellé d'activité NAF en sous-titre gris
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 22:32:12 +02:00
Colin Maudry d99bb00d6c Compactage 2026-06-23 20:16:51 +02:00
Colin Maudry afdd3c8904 Ajout de openpyxl explicite #83 2026-06-23 20:16:24 +02:00
Colin Maudry ad0a220953 feat(tableaux): scroll horizontal ergonomique + barre custom (#82)
- Barre de défilement JS orange (12px) injectée en haut de chaque
  .marches_table, collée avec position:sticky, masquée si le tableau
  tient dans le viewport
- Scroll contenu dans .dash-spreadsheet-container (overflow-x:hidden)
  → plus de scrollbar navigateur en bas de page
- Drag souris + tactile, clic sur le track, molette/trackpad
- Recalcul automatique au resize et aux re-renders Dash (MutationObserver)
- Test Selenium de non-régression (overflow-x:hidden sur le conteneur)

Sticky headers abandonnés (incompatibles avec scroll contenu).
Portée : 4 pages via la classe partagée .marches_table.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 20:12:47 +02:00
Colin Maudry f508c821c2 test(tableaux): adapter test post-abandon sticky headers #82
Le test ne vérifie plus position:sticky sur th (sticky abandonné car
incompatible avec scroll contenu). Vérifie à la place que overflow-x:hidden
est bien en place sur le conteneur Dash — garantit l'absence de scrollbar
navigateur en bas de page.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 20:00:41 +02:00
Colin Maudry 45526f7c7b fix(tableaux): restaurer position:sticky sur la barre, 12px #82
Le retrait de position:sticky sur .dt-hscroll avait cassé le layout
(bouton Remettre à zéro visible au mauvais endroit, z-index perdu).
La barre redevient sticky top:0 z-index:11 — les th.dash-header restent
sans sticky ni z-index (ils ne fonctionnaient de toute façon pas en
scroll contenu).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 19:52:42 +02:00
Colin Maudry 5e64a4553d fix(tableaux): supprimer sticky headers, barre 12px #82
- Retire position:sticky/z-index sur th.dash-header (abandonnés avec
  le scroll contenu : overflow-x:hidden crée un scroll container qui
  empêche le sticky page-level, et le z-index provoquait un recouvrement
  des champs de filtre)
- Retire la règle :has() devenue inutile
- Barre de scroll réduite à 12px

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 19:46:43 +02:00
Colin Maudry 2e22fcabe9 fix(tableaux): scroll contenu dans dashContainer, plus de scrollbar page #82
Remplace le scroll de page (window.scrollTo) par dashContainer.scrollLeft :
- overflow-x:hidden sur .dash-spreadsheet-container → la table ne déborde
  plus la page → scrollbar navigateur en bas éliminée
- overflow-y:clip évite la conversion CSS visible→auto (pas de scrollbar
  vertical parasite sur le conteneur)
- metrics(), syncThumb, drag et clic utilisent tous dashContainer
- wheel handler capture les gestures trackpad horizontaux et les redirige
  vers dashContainer.scrollLeft

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 19:20:41 +02:00