- user-select:none global (index.css) + reset sur input/textarea/select
- ItemRow: swipe gauche → édition (fond bleu), suppression long press,
bouton ✕ toujours visible sur mobile
- SwipeableRow: prop onSwipeLeft, révèle rightContent entre seuil/2 et seuil,
déclenche onSwipeLeft au seuil complet
- TodosPage: onSwipeLeft → édition (remplace double-tap)
- inputMode=decimal sur tous les champs quantité et prix
- formatQty: affiche "2" au lieu de "2.000"
- Versionnage: __APP_VERSION__ injecté par Vite depuis package.json v0.4.0
- HomePage: version affichée à côté du titre (v0.4.0)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Backend :
- Migration 004 : last_purchased_at (DATE) + avg_interval_days (NUMERIC)
sur shopping.products
- update_item : met à jour les stats au premier cochage d'un article
lié à un produit (moyenne mobile exp. 70/30)
- ProductResponse expose les deux nouveaux champs
Frontend :
- ItemRow : long press 500ms → onEdit() (mobile) ; crayon + croix (laptop)
- ShoppingPage : modal édition quantité/unité, état editingItem
- api/shopping.ts : Product inclut last_purchased_at + avg_interval_days
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Quand un article tapé n'existe pas dans le catalogue et qu'aucun produit
n'est sélectionné, une case "Ajouter au catalogue" apparaît (cochée par
défaut). Si cochée, le produit est créé via POST /api/shopping/products
avant l'ajout à la liste, avec l'unité pré-remplie si saisie.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Upload photo (context=product → thumbnail 150×150) dans CatalogueModal
- Miniature affichée dans la liste et dans le formulaire
- Schémas ProductCreate/Update/Response exposent image_path + thumbnail_path
- Backend sert /media/* via StaticFiles (FastAPI)
- Proxy /media → backend dans vite.config et nginx.conf
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Supprime le bouton "Nouvelle tâche" laptop, remplace par le même FAB
circulaire que mobile — position adaptée (bottom: 72px mobile, 24px laptop).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Liste scrollable alphabétique filtrée en temps réel, sélection en un tap
(pré-remplit l'unité), ou saisie libre si article hors catalogue.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- UX : vue par défaut = liste en cours, landing si pas de liste (+ vert +
baguette magique), suppression des vues "listes" et "mode magasin" séparés
- Articles cochés barrés et déplacés en bas, tri alphabétique par section
- Nom de liste auto avec numéro de semaine ISO (S21 2026)
- Wake lock activé dès qu'une liste est ouverte
- CRUD boutiques : POST/PATCH/DELETE /stores + modal Boutiques
- CRUD articles : POST/PATCH/DELETE /products + modal Catalogue
- Champs enrichis produits : description, prix, quantité/unité, boutique défaut
- Champs enrichis boutiques : url, store_type (alimentaire, bricolage…)
- Migration 003 : nouveaux champs en base
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- TodoForm : domaines en chips multi-select colorés, priorité en 3 boutons
colorés (haute/moyenne/basse), date initialisée à aujourd'hui, description
et URL toujours visibles, boutons photo et GPS
- TodosPage : suppression filtres domaine/priorité, tags colorés par domaine
dans les lignes, userSelect:none, groupage multi-domaines
- todos.ts : ajout domains[], photo_path, gps_lat/lng dans les interfaces TS
- index.html : viewport maximum-scale=1.0, user-scalable=no
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Ajoute POST /api/shopping/lists/generate qui calcule un score retard/intervalle
par article (achats_with_lag CTE pour contourner la limite PostgreSQL sur
AVG+LAG imbriqués) et génère une liste draft avec les articles >= 0.7.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Ajoute backend/app/api/shopping.py avec les routes :
- GET/POST /api/shopping/lists
- GET/PATCH/DELETE /api/shopping/lists/{id}
- POST/PATCH/DELETE /api/shopping/lists/{id}/items
- GET /api/shopping/stores
- GET /api/shopping/products
- POST /api/shopping/lists/{id}/finish (report des articles non cochés)
Enregistre le router dans main.py avec le prefix /api/shopping.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Ajoute location /api/ dans nginx.conf pour proxifier les requêtes API
- Crée ShoppingPage et NotesPage (placeholders phase suivante)
- Enregistre les routes /shopping et /notes dans App.tsx
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Changer due_after/due_before de str | None vers datetime | None pour typage FastAPI
- FastAPI parse et valide automatiquement, retourne 422 si format invalide (pas 500)
- Supprimer le parsing manuel datetime.fromisoformat() qui levait ValueError brute
- Ajouter ORDER BY déterministe: due_date ASC NULLS LAST, created_at DESC
évite les réordonnances aléatoires entre requêtes PostgreSQL
Tests: 15/15 passent ✓
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Ajoute les 5 endpoints REST (list, create, update, delete, postpone),
enregistre le routeur sur /api/todos, et corrige l'isolation des sessions
de test via NullPool + dependency_overrides dans conftest.py.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>