Rappels récurrents : comment gérer la complexité cachée
"Ajoute un rappel tous les mardis." Six mots. Facile à dire. Mais derrière cette phrase se cache l'un des problèmes les plus sous-estimés du développement d'applications : les règles de récurrence. J'ai passé des jours entiers à gérer des cas limites que personne n'anticipe avant de les rencontrer.
Points clés à retenir :
- Les rappels récurrents semblent simples mais cachent une complexité énorme (gestion des mois inégaux, fuseaux horaires, exceptions).
- Le stockage hybride (règle sur le parent, occurrences générées à la demande) est le meilleur compromis performance/flexibilité.
- L'UX progressive — simple par défaut, puissant en option — est la clé pour ne perdre aucun utilisateur.
- Un bon système de récurrence nécessite au minimum 4 types de règles et une gestion robuste des cas limites.
Pourquoi les rappels récurrents sont-ils si complexes à implémenter ?
Quand tu penses "rappel récurrent", tu imagines probablement un simple setInterval ou un cron job. La réalité est bien plus tordue. TAMSIV supporte quatre types de récurrence : quotidien, hebdomadaire, mensuel et personnalisé. Le cas quotidien prend 10 minutes à coder. Le cas "le dernier vendredi de chaque mois" ? Des jours.
Le problème fondamental, c'est que le calendrier n'est pas régulier. Les mois ont 28, 29, 30 ou 31 jours. Les semaines chevauchent les mois. Les années bissextiles existent. Et les fuseaux horaires ajoutent une couche supplémentaire de chaos.
En tant que développeur solo de TAMSIV, j'ai dû prendre des décisions architecturales critiques dès le début pour éviter de tout refactorer plus tard.
Comment gérer le problème du "31 de chaque mois" ?
C'est le cas classique que tout développeur de calendrier redoute. L'utilisateur crée un rappel le 31 janvier avec récurrence mensuelle. Que se passe-t-il en février ? En avril ?
Trois approches existent :
- Sauter le mois : pas de rappel en février. Mauvaise UX — l'utilisateur pense que c'est un bug.
- Décalage au dernier jour : le rappel passe au 28 (ou 29) février, 30 avril, etc. C'est intuitif.
- Forcer le 1er du mois suivant : logique pour certains cas, mais déroutant.
J'ai choisi l'option 2 — le décalage automatique au dernier jour du mois. Pourquoi ? Parce que c'est ce que l'utilisateur attend sans y réfléchir. Quand quelqu'un dit "tous les mois", il veut dire "à peu près à la même date chaque mois". Le pragmatisme bat la rigueur mathématique.
Ce choix a un impact direct sur le code. Pour chaque occurrence, je calcule d'abord la date théorique, puis je vérifie si elle existe dans le mois cible avec Math.min(jourOriginal, dernierJourDuMois). Simple en apparence, mais il faut le faire pour chaque occurrence générée.
Quel est le meilleur modèle de stockage pour les événements récurrents ?
C'est la question architecturale clé. Deux écoles s'affrontent :
Option A : stocker toutes les occurrences. Tu génères 365 lignes en base pour un rappel quotidien annuel. Avantage : requêtes simples. Inconvénient : explosion de la base de données et complexité de modification (changer l'heure du rappel = modifier 365 lignes).
Option B : stocker uniquement la règle. Tu gardes "chaque mardi à 9h" et tu calcules à la volée. Avantage : base de données légère. Inconvénient : queries complexes pour savoir "quels rappels tombent cette semaine ?".
J'ai opté pour un modèle hybride dans TAMSIV : la règle de récurrence est stockée sur l'événement parent, et les occurrences sont générées à la demande. Quand un rappel est converti en événement calendrier — par exemple via le système d'agenda avec filtres — une occurrence concrète est créée en base.
Concrètement, la structure de la base de données ressemble à ça :
- Table parent : contient le titre, la description, et un champ JSON avec la règle de récurrence (
type,interval,daysOfWeek,endDate) - Table occurrences : créée à la demande quand l'utilisateur interagit (complète, reporte, modifie)
- Calcul dynamique : pour l'affichage calendrier, les occurrences futures sont calculées côté client
Ce modèle hybride permet d'éviter les N+1 queries tout en gardant la base de données sous contrôle. Avec le système de cache optimisé, les performances restent excellentes même avec des centaines de rappels.
Comment créer un rappel récurrent par la voix ?
L'un des avantages uniques de TAMSIV, c'est que tu peux créer des rappels complexes en parlant naturellement. Le pipeline vocal IA analyse ta phrase et extrait automatiquement la règle de récurrence.
Exemples concrets :
- "Rappelle-moi d'arroser les plantes tous les 3 jours" → récurrence personnalisée, intervalle 3 jours
- "Réunion d'équipe chaque lundi et mercredi à 10h" → hebdomadaire, jours spécifiques
- "Payer le loyer le premier de chaque mois" → mensuel, jour fixe avec gestion des cas limites
- "Anniversaire de Marie le 15 mars chaque année" → annuel
Le LLM (via OpenRouter) décompose la phrase en intentions structurées. La fonction create_calendar_event reçoit ensuite un objet avec les paramètres de récurrence déjà extraits. L'utilisateur n'a qu'à valider — ou modifier — avant la sauvegarde en base.
C'est la force du dictaphone intégré : rendre invisible la complexité technique pour l'utilisateur final.
Quels sont les pièges des fuseaux horaires avec les rappels ?
Si tu penses que les mois irréguliers sont pénibles, attends de voir les fuseaux horaires. Un rappel quotidien à 9h se déclenche à 9h heure locale. Mais qu'est-ce que "9h heure locale" quand l'utilisateur voyage ? Quand le changement d'heure été/hiver intervient ?
Deux stratégies possibles :
- Stocker en UTC et convertir au rendu : propre mais problématique pour "9h tous les jours" (qui peut devenir 8h ou 10h selon la saison)
- Stocker en heure locale avec timezone : plus fidèle à l'intention mais plus complexe à gérer en base
Dans TAMSIV, j'ai opté pour le stockage en UTC avec le fuseau horaire de référence de l'utilisateur. Quand le calcul d'occurrence tombe sur un jour de changement d'heure, le système ajuste pour garder l'heure locale stable. C'est le comportement qu'attendent les utilisateurs de Google Calendar ou Apple Calendar.
Comment concevoir l'UX des rappels sans submerger l'utilisateur ?
Le défi UX est tout aussi important que le défi technique. Comment présenter des règles de récurrence potentiellement complexes sans perdre l'utilisateur occasionnel ?
La réponse : le design progressif (progressive disclosure).
Voici comment je l'ai implémenté dans TAMSIV :
- Niveau 1 — 4 boutons simples : Tous les jours, Toutes les semaines, Tous les mois, Pas de récurrence. Couvre 80% des besoins.
- Niveau 2 — Panneau avancé : accessible via "Personnaliser". Jours de la semaine sélectionnables, intervalle personnalisé (tous les N jours/semaines/mois), date de fin optionnelle.
- Niveau 3 — Cas complexes : "Le dernier vendredi du mois", "Le 2e mardi de chaque mois". Interface spécialisée pour ces règles rares.
Le principe directeur : simple par défaut, puissant en option. L'utilisateur occasionnel ne doit jamais se sentir perdu. L'utilisateur avancé ne doit jamais se sentir limité. Ce principe guide aussi le système d'onboarding de l'application.
J'ai également implémenté la navigation par swipe sur les écrans de rappels pour fluidifier l'expérience.
Quelle différence avec les rappels de Google Calendar ou Todoist ?
Les solutions existantes comme Todoist ou Google Calendar gèrent bien les récurrences. Mais elles ont toutes le même défaut : la saisie manuelle.
Avec TAMSIV, la création vocale change fondamentalement l'équation. Dire "rappelle-moi d'envoyer le rapport tous les vendredis à 17h" est incomparablement plus rapide que naviguer dans 3 menus pour configurer la même chose manuellement.
De plus, le système de gamification récompense la complétion des rappels récurrents, ce qui crée un cercle vertueux de productivité. Chaque tâche récurrente complétée alimente ton streak et te rapproche du prochain niveau.
Quelles leçons retenir de l'implémentation des récurrences ?
Après avoir codé ce système, voici les leçons que je retiens :
- Ne pas sous-estimer les cas limites : le "31 du mois", les années bissextiles, les changements d'heure — chaque cas semble rare individuellement, mais collectivement ils touchent des milliers d'utilisateurs.
- Tester avec de vraies données : les tests unitaires ne suffisent pas. Il faut simuler une année entière d'occurrences et vérifier visuellement.
- Le modèle hybride est le bon compromis : ni tout-en-base, ni tout-calculé. Le mix offre le meilleur des deux mondes.
- L'UX progressive sauve des vies : cacher la complexité derrière des niveaux de détail est la seule approche viable pour une app grand public.
Si tu développes une app de productivité ou un système de calendrier, ne sous-estime jamais les rappels récurrents. Ce qui semble être une feature de 2 jours peut facilement en prendre 10.
FAQ
Combien de types de récurrence TAMSIV supporte-t-il ?
TAMSIV supporte quatre types principaux : quotidien, hebdomadaire, mensuel et personnalisé. Le mode personnalisé permet de définir n'importe quel intervalle (tous les N jours, certains jours de la semaine, etc.) et couvre des cas avancés comme "le dernier vendredi du mois".
Peut-on créer un rappel récurrent par la voix ?
Oui, c'est même l'un des points forts de TAMSIV. Tu peux dire "rappelle-moi d'envoyer le rapport tous les lundis à 9h" et l'IA comprend automatiquement le type de récurrence, le jour et l'heure. Il suffit de valider pour que le rappel soit créé.
Que se passe-t-il si un rappel mensuel tombe un jour qui n'existe pas ?
TAMSIV décale automatiquement le rappel au dernier jour du mois. Par exemple, un rappel le 31 sera avancé au 28 ou 29 en février, et au 30 en avril, juin, septembre et novembre. C'est le comportement le plus intuitif pour l'utilisateur.
Les rappels récurrents fonctionnent-ils avec la gamification ?
Absolument. Chaque complétion d'un rappel récurrent rapporte des points d'expérience et alimente ton streak quotidien. C'est un excellent moyen de maintenir une routine productive et de rester motivé sur la durée.
Comment modifier ou supprimer une seule occurrence d'un rappel récurrent ?
Tu peux modifier ou supprimer une occurrence spécifique sans affecter les autres. Le système crée alors une "exception" pour cette date. Le reste de la série continue normalement selon la règle définie.