Commit Graph

1069 Commits

Author SHA1 Message Date
Colin Maudry 96358423df feat(admin): add /admin user list page 2026-07-03 10:13:04 +02:00
Colin Maudry e483d7af4d feat(admin): add subscription-status mutation route
Wires is_admin(), SUBSCRIPTION_STATUSES/get_current/set_status, and
log_action() into POST /admin/actions/subscription-status: validates
the requested status and that subscription_id matches the user's
current subscription, applies the change, and logs an audit entry.
Registers the admin blueprint in init_auth() and documents ADMIN_EMAIL
in .template.env.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-03 09:46:22 +02:00
Colin Maudry 2f2cd151fb feat(admin): add is_admin() access guard
Implement access control function for admin panel. Returns True only if
ADMIN_EMAIL env var is set, user is authenticated, and email matches
case-insensitively.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-03 09:41:57 +02:00
Colin Maudry c4851ff0ae refactor: format test_db.py for consistency
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-03 09:38:46 +02:00
Colin Maudry fb62c28e10 feat(admin): add admin_actions audit table and log/list functions
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-03 09:38:33 +02:00
Colin Maudry 0209ec0d5c feat(admin): add subscription history, status override, and statuses constant
Adds four new DB helpers for the admin panel:
- SUBSCRIPTION_STATUSES: tuple of valid subscription statuses
- list_by_user(): retrieve all subscriptions for a user (newest first)
- set_status(): override a subscription's status and updated_at timestamp
- get_subscriber_state(): public wrapper for internal _get_state()

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-03 09:34:09 +02:00
Colin Maudry 9ea8bee940 feat(admin): add list_users() to auth DB layer
Implements list_users(limit: int = 1000) -> list[sqlite3.Row] in the auth
DB layer to retrieve all users ordered by creation date (most recent first).

- Returns all users, optionally capped at limit (default 1000)
- Orders by created_at DESC to show newest users first
- Follows existing DB layer patterns using get_conn().execute().fetchall()

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-03 09:29:03 +02:00
Colin Maudry e820041cef Ajouter le plan d'implémentation du panneau admin (/admin) 2026-07-03 09:19:15 +02:00
Colin Maudry e678399fe7 Préciser la pagination native (20/page) du tableau /admin 2026-07-03 09:07:27 +02:00
Colin Maudry 2cbee97afb Ajouter le spec du panneau admin interne (/admin)
Design pour un panneau de support/débug (liste des comptes, historique
d'abonnements, correction manuelle de statut) protégé par ADMIN_EMAIL,
avec journal d'audit en base plutôt qu'en logs applicatifs.
2026-07-03 09:02:14 +02:00
Colin Maudry 0b88a65414 Utiliser le Checkout API pour la session de souscription (accept_url/cancel_url)
hosted_page_links.payment_info (POST /v1/subscription) n'honore pas
accept_url/cancel_url malgré la doc, même passés en query string (constaté
en test sur test.colibre.fr). On génère maintenant la page de paiement via
POST /v1/session/subscription (Checkout API), qui accepte ces champs dans
son body et redirige effectivement le navigateur — même mécanisme déjà
fonctionnel pour l'ajout de moyen de paiement (create_recurring_session).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-02 18:21:05 +02:00
Colin Maudry 14ae1a7bfb Gérer l'affichage d'un abonnement expiré (statut Frisbii "expired")
_show_active_view affichait par erreur la vue "abonnement actif" (avec un
faux "Prochaine facturation") pour un abonnement expiré. Un abonnement
expiré bascule maintenant sur l'écran de re-souscription, avec une alerte
dédiée. Jamais remarqué jusqu'ici car les webhooks Frisbii ne remontaient
pas ce changement de statut.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-02 18:13:12 +02:00
Colin Maudry 1159697c0e Fix redirection Frisbii après ajout de moyen de paiement au premier abonnement
accept_url/cancel_url n'existent pas dans le schéma de POST /v1/subscription
(ils y sont silencieusement ignorés) : Frisbii attend ces paramètres en
query string sur le lien hosted_page_links.payment_info retourné. Ajout
d'un warning loggé sur signature de webhook invalide, jusque-là silencieuse.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-02 17:56:19 +02:00
Colin Maudry ea20491e9c Changements rédactionnels : abonnement par virement, avantage abonnements 2026-07-02 16:50:33 +02:00
Colin Maudry 8a428ac1aa Ajout d'une conf de redirection nginx de test 2026-07-02 16:49:03 +02:00
Colin Maudry d08f7aeeac Nombre de jours d'essai en dur plutot que via appels HTTP 2026-07-02 13:55:22 +02:00
Colin Maudry 1bdcaaf5d8 Réactivation de l'env MAIL_SUPPRESS_SEND 2026-07-02 13:42:05 +02:00
Colin Maudry a38b2d5e71 Remplacement du Loading... screen 2026-07-02 12:03:50 +02:00
Colin Maudry 74afb7aef8 Nettoayge 2026-07-02 11:46:42 +02:00
Colin Maudry 2ed560d4e8 Nettoayge 2026-07-02 11:32:45 +02:00
Colin Maudry cd107a0213 Refactor structure modules pages/compte, petits changements de texte 2026-07-02 10:53:01 +02:00
Colin Maudry 9ff2373ccb decp.info => colibre 2026-07-01 18:00:36 +02:00
Colin Maudry 126834c7d4 fix(subscriptions): un abonnement en échec (failed) ne bloque plus le réabonnement 2026-07-01 16:56:34 +02:00
Colin Maudry 872fc33dd7 feat(subscriptions): cancel/webhook/add_payment_callback sur get_current et customer_known 2026-07-01 16:41:57 +02:00
Colin Maudry 0ffe647657 feat(subscriptions): subscribe() génère et transmet le handle, mark_failed en cas d'échec 2026-07-01 14:37:25 +02:00
Colin Maudry 179e6e436d feat(subscriptions): create_subscription_session prend le handle en paramètre 2026-07-01 14:34:09 +02:00
Colin Maudry 64158e9080 feat(subscriptions): historique multi-lignes + subscriber_state + handle abo-{user_id}-N
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01 14:29:47 +02:00
Colin Maudry f52b2b7b71 docs: plan d'implémentation pour le handle d'abonnement et l'historique
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01 14:24:42 +02:00
Colin Maudry b077fd318d docs: note la vérification de méthode de paiement réelle comme suivi séparé
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01 14:13:39 +02:00
Colin Maudry 17c379f0b3 docs: design pour le handle d'abonnement personnalisé et l'historique des abonnements
Spec pour remplacer generate_handle par un handle abo-{user_id}-N unique,
ce qui nécessite de scinder subscriptions en historique multi-lignes et
d'introduire subscriber_state pour l'état cumulatif (votes, essai).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01 14:12:11 +02:00
Colin Maudry a2c20adb4e perf: paginer/agréger les pages acheteur et titulaire côté DuckDB
Les pages acheteur/titulaire chargeaient l'intégralité des marchés d'une
organisation dans un dcc.Store côté client (jusqu'à 16k lignes pour les
plus gros acheteurs), envoyée sur le réseau à chaque interaction. Le
tableau, le top 10 et l'histogramme des distances récupèrent maintenant
leurs données via des requêtes DuckDB scopées (pagination/agrégation
poussées en SQL), sur le modèle déjà utilisé par la page tableau.

Corrige aussi le CLS des mêmes pages en réservant l'espace des
conteneurs remplis par callback (carte, top 10, histogramme).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01 13:46:44 +02:00
Colin Maudry 8515ba8d84 refactor: replace all decpinfo with colibre in test suite
Update all client and fixture references throughout the test suite
to use colibre branding instead of the legacy decpinfo naming.

- test_auth.py: token format
- benchmark.py: token format documentation
- test_routes.py: customer handles
- test_client.py: customer identifiers
- test_db.py: all database fixtures

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-07-01 11:19:25 +02:00
Colin Maudry 190b8154b4 refactor: replace decpinfo with colibre in test client identifiers
Update test fixtures and client references to use colibre branding
instead of the legacy decpinfo naming convention.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-07-01 11:17:18 +02:00
Colin Maudry a1bf0b381b fix: reduce subscribe button width to fit content
Adjust the width of the 'S'abonner' button to match the label size
using CSS width: fit-content property.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-07-01 11:10:19 +02:00
Colin Maudry 63a7ff3d89 Petites améliorations de formulation et d'UI 2026-07-01 10:17:25 +02:00
Colin Maudry 502d3b390a Icones colibre temporaires #57 2026-06-30 23:09:26 +02:00
Colin Maudry 2e9888998a Bump 3.0.0 2026-06-30 23:07:50 +02:00
Colin Maudry 7184b7768a feat(seo): index de sitemaps acheteurs/titulaires, canonical, robots
- robots.txt déclare désormais le sitemap
- /sitemap.xml devient un index de sous-sitemaps paginés (limite 50k URLs/fichier)
  générés depuis DuckDB et mis en cache 24h : pages statiques, acheteurs, titulaires
- balise canonical auto-référente (JS, car index_string Dash partagé)
- config nginx de référence : 301 decp.info → colibre.fr (chemin préservé)
- tests SEO via test client Flask

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 23:06:46 +02:00
Colin Maudry 9e8ad6c74b decp.info => colibre dans llms.md #57 2026-06-30 22:48:13 +02:00
Colin Maudry 41491159a3 Ajouts des icones colibre #57 2026-06-30 22:41:19 +02:00
Colin Maudry 64d4821fae fix(tests): met à jour le préfixe de token decpinfo_ → colibre_ #57
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 21:49:51 +02:00
Colin Maudry 9b124deeea refactor: rebrand decp.info to colibre #57
- Rename project from decp.info to colibre across all codebase
- Update domain from https://decp.info to https://colibre.fr
- Update GitHub repo references to ColinMaudry/colibre
- Rename deployment files: decpinfo-backup.* → colibre-backup.*
- Update project configuration and documentation
- Rename project assets: decp.info.png → colibre.png
- Update environment variables and constants (DOMAIN_NAME, TOKEN_PREFIX, GITHUB_REPO, etc.)
- Update URLs in all pages, tests, and configuration files
- Keep DECP acronym in text (unchanged per requirements)
- Add rebrand note to README.md

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-06-30 21:43:33 +02:00
Colin Maudry b46d5d8244 Redirection llms.txt pour les LLMS 2026-06-30 21:02:14 +02:00
Colin Maudry d8faccab46 fix: corrige bug build_database + fiabilise et isole la suite de tests
src/db.py : le remplacement des noms d'organisation nuls utilisait
.name.keep() sur une expression concat_str référençant *_id ; Polars nommait
alors le résultat d'après *_id, écrasant la colonne titulaire_id/acheteur_id et
laissant *_nom inchangée. Remplacé par .alias(col).

Suite de tests — élimination de la pollution inter-tests (callbacks/conn
globaux Dash) qui faisait échouer ~15 tests Selenium en exécution complète :
- tests/conftest.py : DUCKDB_PATH et DATA_SCHEMA_CACHE pointent sur des chemins
  de test isolés (tests/decp.duckdb, tests/schema.cache.json, gitignorés) — on
  ne touche plus jamais aux fichiers versionnés decp.duckdb et
  schema.fixture.json (qui étaient mutés et cassaient la collecte au run
  suivant). Viewport Chrome élargi à 1600px.
- tests/test_db.py : fixture module-scoped qui recharge src.db après le module
  (test_query_marches faisait importlib.reload vers une DB temporaire au schéma
  réduit, polluant le conn global → ColumnNotFoundError ensuite). Assertion mise
  à jour pour le nouveau libellé "[Inconnu de l'INSEE (...)]".

Tests périmés / fragiles corrigés :
- tests/auth/test_oauth_routes.py : mock LinkedIn aligné sur la route (userinfo
  récupéré via .get() séparé) ; destination post-login /compte/abonnement.
- tests/test_main.py : test_002 filtre sur dateNotification (uid retiré du
  tableau), scrollIntoView (colonne hors viewport), attentes de l'application du
  filtre et de la restauration de la persistance ; test_015 via
  wait_for_no_elements.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 18:22:27 +02:00
Colin Maudry 60b59d2d03 Précision sur les SIRET inconnu 2026-06-30 17:34:27 +02:00
Colin Maudry 5a64f0f682 Ordre des sections 2026-06-30 17:34:08 +02:00
Colin Maudry 69a8b847ae style(toolbar): aligne le style des boutons acheteur/titulaire/observatoire sur tableau.py
- table-menu → table-toolbar sur les 3 vues
- Boutons colonnes/télécharger : color=secondary size=sm ; html.Button → dbc.Button
- Bouton reset : color=danger outline=True size=sm, label "Réinitialiser"
- Compteur nb_rows sorti du toolbar vers un div.table-meta séparé

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 17:19:39 +02:00
Colin Maudry 8825e76101 Possible de remplacer une vue existante #95 2026-06-30 16:59:37 +02:00
Colin Maudry c4aa90b0d1 feat: améliorations UX roadmap votes #94
- Votes cappés à VOTES_PER_WEEK (pas d'accumulation) pour valoriser
  les connexions régulières
- Solde de votes affiché dans la liste (input inéditable) à la place
  du bandeau Alert, avec date de prochain rechargement
- Compteur de votes par feature affiché comme input inéditable en
  fin de ligne (avant le bouton "+")
- Animation FLIP JS (roadmap_flip.js) : seules les lignes qui changent
  de position sont animées après un vote
- Renommage votes_credited_until → votes_last_credited_at (migration 0005)
- Constantes du module utilisées dans les assertions de tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 16:39:13 +02:00
Colin Maudry f04e1b4c44 Petites améliorations tableau.py 2026-06-30 15:14:43 +02:00