App Family
Statut
En production sur family.2h15.fr — LXC 112
Vue d'ensemble
Application web PWA partagée entre Val et Milie. Installable sur iOS et Android sans passer par les stores. Accessible publiquement, sans authentification.
| Propriété | Valeur |
|---|---|
| URL | https://family.2h15.fr |
| LXC | 112 — IP 192.168.1.65 |
| Stack | PWA React/Vite + FastAPI + PostgreSQL + Nginx |
| Accès | Public, sans auth |
| Favicon | Maison violette + cœur rose |
Architecture
Internet → NPM (LXC 101) → Nginx (LXC 112, port 80)
├── / → dist/ (React build)
└── /api/ → FastAPI (port 8000)
└── PostgreSQL (local)
Fichiers principaux
| Chemin | Rôle |
|---|---|
/opt/family/backend/ |
Code FastAPI |
/opt/family/backend/.env |
Variables d'environnement (DB, ntfy token) |
/opt/family/frontend/ |
Code React/Vite |
/opt/family/frontend/dist/ |
Build servi par Nginx |
/opt/family/tokens/ |
Tokens OAuth Google (val.json, milie.json) |
/opt/family/google_client_secret.json |
Credentials OAuth app Google Cloud |
/opt/family/calendar_ids.json |
Mapping clé → ID calendrier Google |
Interface
Ordre des onglets
🏠 Aujourd'hui · 📅 Calendrier · ✅ Todos · 🛒 Courses · 🍽️ Repas · 💑 Date Night · 🔧 Maison · 📝 Mémos
Thème sombre / clair
Le bouton 🌙/☀️ en haut à droite du header bascule entre thème clair et sombre. Le choix est persisté en localStorage. Le thème sombre est appliqué globalement via la classe html.dark, avec des overrides FullCalendar inclus.
Page d'accueil — Récap du jour
Affiché à l'ouverture de l'app :
- Priorité haute — carte rouge listant les todos high non cochés (masquée si vide)
- Événements du jour — tous calendriers confondus, avec l'heure et le badge Val/Milie si assigné
- Todos du jour — items dont l'échéance est aujourd'hui, cochables directement depuis cette page
Onglet Calendrier
Affichage
- Vue Planning 7 jours par défaut (7 jours glissants à partir d'aujourd'hui)
- Toolbar : ← titre → en header pour naviguer, boutons Aujourd'hui · Mois · Semaine · Planning en footer
- Format de date en vue Planning : "mercredi 13 mai 2026"
Couleurs des calendriers
| Calendrier | Couleur |
|---|---|
| Val (personnel) | Bleu foncé #1e3a8a |
| Milie (personnel) | Orange #f97316 |
| The Floating Valley | Cyan #06b6d4 |
| Beat Cheese | Jaune #eab308 |
| Anniversaires | Rouge #dc2626 (titres commençant par 🎂 ou contenant "anniv") |
Créer un événement
- Cliquer sur + Ajouter ou directement sur une date dans le calendrier
- Champs : titre, début, fin, assigné à (Val / Milie / Les deux)
- Toute la journée : case à cocher — bascule en sélecteur de date simple, champ Fin masqué, propagé à Google Calendar en format date-only
- Types d'événement : cases à cocher — génèrent automatiquement des todos et des rappels ntfy
- Champ Notes : stocké en
description, synchronisé avec Google Calendar dans les deux sens
Modifier / supprimer un événement
- Cliquer sur un événement → formulaire d'édition
- Bouton 🗑 pour supprimer
- Toute modification/suppression est propagée immédiatement sur Google Calendar
Événements récurrents
Les occurrences affichent un badge 🔁 Événement récurrent. Un dialog propose trois portées avant toute modification ou suppression :
| Portée | Effet |
|---|---|
| Cet événement uniquement | Modifie/supprime cette occurrence seulement |
| Cet événement et les suivants | Modifie/supprime cette occurrence et toutes les suivantes |
| Toute la série | Modifie/supprime toutes les occurrences |
Recherche d'événements
Barre de recherche dans l'onglet Calendrier : param search sur GET /api/events/, résultats triés par proximité à aujourd'hui, dropdown avec debounce 300ms, clic → modal d'édition.
Synchronisation Google Calendar
La sync est bidirectionnelle :
- Google → App : import automatique toutes les 5 minutes (cron LXC 112)
- App → Google : toute création, modification ou suppression depuis l'app est propagée immédiatement
- Fenêtre de sync : 30 jours passés + 180 jours à venir
4 calendriers synchronisés :
| Clé | Calendrier | Compte OAuth |
|---|---|---|
val_primary |
valentinlucchini@gmail.com |
val |
val_floating_valley |
floatingvalley.band@gmail.com |
val |
val_beat_cheese |
beatcheese.band@gmail.com |
val |
milie_primary |
amelie.leotard@gmail.com |
milie |
Onglet Todos
Deux listes distinctes sur la même page :
Sans date
Items flottants sans échéance — triés par priorité (haute → normale → basse).
Avec date
Items datés triés par échéance. Inclut les todos générés automatiquement par les types d'événements.
Comportements
- Assignable à : Val / Milie / Personne
- Priorité : 🔴 Haute / 🟡 Normale / 🟢 Basse
- Items cochés : restent visibles en bas de liste, séparés par un trait en pointillés
- Modifier un item : cliquer sur son libellé → modal pré-remplie (titre, date, priorité, assigné)
Onglet Courses
- Organisée par rayons/catégories, dans l'ordre défini dans l'admin
- Cocher un article le barre (reste visible jusqu'à clôture)
- Modifier un article : cliquer sur son libellé → modal pré-remplie (nom, quantité, rayon)
- Clôturer la liste → archive dans l'historique, repart à zéro
Onglet Repas
Liste d'idées de repas.
- Cochables : cochés en gras en haut, non cochés en bas (chaque groupe trié alphabétiquement)
- Modifier : cliquer sur le nom → édition inline
Onglet Date Night
Liste d'activités à faire ensemble (Val + Milie).
Fonctionnalités
- Ajouter une activité : nom + notes
- Roulette : animation de sélection aléatoire, 1 respin possible ; l'activité ignorée reste dans le pool
- Planifier : date picker → crée un événement "Date Night 🌙" de 21h à 23h avec l'activité en description ; l'activité est marquée
doneà la création de l'événement (récupérable manuellement) - Activités
donefiltrées de la roulette
Notification
Chaque dimanche à 21h, ntfy topic family — rappel de planifier une soirée ensemble.
Onglet Maison
Projets maison avec checklist d'étapes.
Champs d'un projet
| Champ | Description |
|---|---|
| Nom | Titre du projet |
| Pièce | Texte libre avec autocomplete sur les pièces existantes |
| Priorité | Haute / Normale / Basse |
| Budget | Montant estimé |
| Notes | Description libre |
| URL | Lien vers un produit, un tuto, etc. |
Étapes
Chaque projet peut avoir une checklist d'étapes, avec : - Assignee par étape (Val / Milie / Les deux) - Le statut du projet est auto-dérivé des étapes (À faire / En cours / Terminé) - Pour les projets sans étapes : bouton ✓ pour marquer manuellement comme terminé, bouton ↩ pour remettre en cours
Organisation
- Tri par priorité dans chaque groupe + ordre manuel ↑↓ (boutons en colonne à gauche, occupent toute la hauteur)
- Filtre par pièce
- Budget total affiché en haut
- Projets terminés séparés en bas avec opacité réduite (séparateur "Terminés (X)"), boutons ↑↓ masqués
Onglet Mémos
Canal de communication entre Val/Milie et Claude. Accessible depuis le téléphone pour capturer des idées et retours en cours d'utilisation.
Types de mémos
| Type | Usage |
|---|---|
| Backlog Family | Fonctionnalité ou bug à traiter dans l'app Family |
| Backlog Global | Chantier homelab ou idée infrastructure |
| Note | Mémo libre sans catégorie |
Pour Claude
Administration
Accessible via le bouton ⚙️ en haut à droite.
Onglet Types d'événements
Chaque type définit : nom, délai de rappel, modèle de todo ({event} et {date}), couleur, assigné auto.
Types configurés :
| Type | Rappel | Todo généré |
|---|---|---|
| Faire garder Daphné | 2 semaines avant | "Trouver quelqu'un pour garder Daphné pour {event} le {date}" |
| Faire des courses | 3 jours avant | "Faire des courses pour {event} le {date}" |
| Emmener des jeux | 1h avant | "Emmener des jeux pour {event} le {date}" |
Onglet Rayons
Gestion des catégories de la liste de courses avec ordre d'affichage.
Onglet OAuth
Statut des comptes Google Calendar. Lien Connecter si le token est absent ou expiré.
Notifications (ntfy)
| Topic | Contenu | Déclencheur |
|---|---|---|
family |
Récap des événements du jour + todos haute priorité non cochés | Cron 7h00 quotidien |
family |
Rappel d'un événement | J-X à l'heure exacte selon le type |
family |
Rappel Date Night | Dimanche 21h |
anniversaires |
Anniversaires du jour + à venir 7j | Cron 7h05 quotidien (4 calendriers Google) |
Topic family — abonnement Milie
Milie a accès en lecture aux topics anniversaires et family sur ntfy.2h15.fr.
Timezone CronTrigger
Le LXC 112 est en UTC. Le timezone="Europe/Paris" doit être passé directement aux CronTrigger dans scheduler/jobs.py.
Gestion des tokens OAuth
Si un token expire :
- Aller dans l'admin → onglet OAuth
- Cliquer Connecter pour le compte concerné
- Se connecter avec le bon compte Google et autoriser
Les tokens sont dans /opt/family/tokens/val.json et /opt/family/tokens/milie.json.
Checklist déploiement
- [x] Créer LXC 112
- [x] Installer dépendances (Node.js 20, Python 3.11, PostgreSQL 15, Nginx)
- [x] Développer le backend FastAPI + PostgreSQL
- [x] Développer le frontend PWA React/Vite
- [x] Configurer OAuth2 Google Calendar (Val + Milie)
- [x] Configurer entrée NPM → family.2h15.fr (SSL Let's Encrypt)
- [x] Ajouter au dashboard de supervision
- [x] Créer monitor Uptime Kuma
- [x] Configurer topic ntfy
family+ accès Milie
Backlog
En attente
Rien en attente actuellement.
Terminé
| Sujet | Date | Détail |
|---|---|---|
| Marquer terminé sans étapes | 2026-07-26 | Colonne manually_done, bouton ✓/↩, statut auto-dérivé conservé pour projets avec étapes |
| Projets terminés en bas | 2026-07-26 | Séparateur "Terminés (X)", opacité réduite, boutons ↑↓ masqués |
| Onglet Maison | 2026-06-30 | Projets + étapes, priorité, budget, pièce autocomplete, assignee par étape |
| Onglet Date Night | 2026-06-30 | Roulette, planification événement, notif dimanche 21h |
| Événements all-day | 2026-05-29 | Checkbox "Toute la journée", input date simple, propagé à Google Calendar |
| Sync Google Calendar automatique | 2026-05-12 | Cron toutes les 5 min sur LXC 112 |
| Propagation App → Google Calendar | 2026-05-13 | Créations, modifications et suppressions propagées immédiatement |
| Gestion événements récurrents | 2026-05-13 | Dialog de portée (this / following / all) |
| Vue Calendrier par défaut en Planning | 2026-05-13 | Vue custom list7Days (7 jours glissants) |
| Thème sombre / clair | 2026-05-13 | Bouton 🌙/☀️ dans le header, classe html.dark |
| Todos cochés | 2026-05-13 | Actifs en haut, cochés en bas avec séparateur en pointillés |
| Canal de communication phone → Claude | 2026-05-13 | Onglet Mémos (📝) |