diff --git a/docs/AUDIT-2026-09-22.md b/docs/AUDIT-2026-09-22.md index 6b7627b..f958b1f 100644 --- a/docs/AUDIT-2026-09-22.md +++ b/docs/AUDIT-2026-09-22.md @@ -244,40 +244,58 @@ du device comme *nom de topic*. L'en-tête du fichier annonce « V2+ : remplacer par APNs (iOS) + FCM (Android) » — ce n'est pas fait. Voir §5.1bis, qui est le vrai sujet. -### 5.1bis [vérifié] La chaîne de notifications push natives n'existe pas de bout en bout +### 5.1bis [vérifié] Les rappels sont natifs et fonctionnent ; c'est le chemin ntfy qui est résiduel -Trois constats, chacun vérifié par recherche dans les deux dépôts : +⚠️ **Correction d'une première version de cette section, qui affirmait que « la +chaîne de notifications natives n'existe pas ». C'était faux**, et la méthode +qui a produit l'erreur mérite d'être notée : j'avais cherché +`PushNotifications` (le plugin *distant*) sans chercher `LocalNotifications`. +Conclure d'un grep négatif qu'une fonctionnalité est absente suppose d'avoir +cherché le bon terme. -1. `web/push_notify.py:47-52` — le canal est **ntfy**. `platform == "web"` - rend `False` (« Web Push : à implémenter (V2) »). -2. **Aucun enregistrement de token APNs côté serveur.** Recherche de - `registerToken` / `/api/devices` / `device_token` dans `web/` : **zéro - résultat**. -3. **Le web n'appelle jamais `PushNotifications`** de Capacitor. Recherche dans - `web/**/*.js` et `web/**/*.html` : **zéro résultat**. +**Ce qui marche, en natif** — `web/static/local-notifications.js` programme via +`Capacitor.Plugins.LocalNotifications` : -Côté natif, tout est pourtant en place : `@capacitor/push-notifications` est -installé, `aps-environment` est déclaré, `UIBackgroundModes` contient -`remote-notification`. **La moitié native est prête et personne ne la branche.** -Pour recevoir un rappel, l'utilisateur doit installer l'app **ntfy** et -s'abonner à un topic — ce n'est pas une notification de l'app. +- rappel « Séance pas encore faite » (l. 97) ; +- résumé du jour : sport + durée, « Jour OFF », « Peu récupéré » (l. 150-171) ; +- hydratation à 10 h / 13 h / 16 h (l. 184) ; +- « Heure de te coucher ? » à 23 h (l. 197). -Deux conséquences : +Ce sont de vraies notifications locales iOS, planifiées sur l'appareil, sans +serveur. **Le README a donc raison sur le fond** (les rappels de séance sont +natifs), mais il attribue la fonction au mauvais plugin : c'est +`@capacitor/local-notifications` qui la rend, pas +`@capacitor/push-notifications`. -- **Le README se trompe.** Il liste « ✅ Push notifications natives (rappel - séances) — implémenté côté iOS » **dans la section anti-rejet Guideline - 4.2**. C'est le premier argument de la liste, et il ne tient pas : un - examinateur qui teste les rappels ne verra rien. Or 4.2 est précisément le - risque de cette architecture wrapper (§5.3). -- **Une capability déclarée et inutilisée** est au mieux inerte. Apple 2.3.1(a) : - « Don't include any hidden, dormant, or undocumented features in your app ». +**Ce qui reste du chemin ntfy** — `web/push_notify.py` envoie via ntfy (le +`token` du device sert de *nom de topic*), et il a deux appelants vivants : -**Décision à prendre**, et elle est produit avant d'être technique : soit -brancher la chaîne APNs (demande de permission + récupération du token côté -web, endpoint d'enregistrement, envoi via APNs côté serveur), soit assumer ntfy -et **retirer le plugin, l'entitlement et la ligne du README**. La situation -actuelle — déclarer une capability qu'on n'utilise pas et l'annoncer comme -implémentée — est la seule qui cumule les inconvénients des deux. +| Appelant | Ce qu'il expose | +|---|---| +| `web/routers/api_notifications.py:16` | `POST /register-device`, `GET /devices`, `DELETE /devices/{id}`, `POST /test` | +| `tools/notify_morning.py:24` | notification matinale, déclenchée par cron | + +L'intention est que **plus rien ne passe par ntfy** (confirmé par Sylvain le +2026-09-22). Ce chemin est donc du code résiduel qui double une fonction déjà +assurée en natif. + +⚠️ **Ne pas supprimer avant d'avoir vérifié le cron sur nexus.** Si +`notify_morning.py` y est encore planifié, retirer le module casserait le cron +— et un cron cassé dans ce projet a déjà tenu quatre mois sans être vu. La +vérification n'a **pas** pu être faite depuis le conteneur de dev (pas de +résolution DNS pour `nexus`) : + +``` +ssh nexus "crontab -l | grep -i notify; systemctl list-timers --all | grep -i notify" +``` + +**Ce qui reste vrai de la remarque App Store** : `@capacitor/push-notifications` +est installé et `aps-environment` déclaré, alors que **rien n'appelle ce +plugin** (aucun enregistrement de token APNs côté serveur, aucun appel +`PushNotifications` côté web). Une capability déclarée sans usage tombe sous +2.3.1(a) (« hidden, dormant, or undocumented features »). Les rappels étant +couverts par les notifications locales, le plus simple est de **retirer le +plugin distant et l'entitlement** — sauf si des push serveur sont prévues. ### 5.2 [doc] Ce qu'Apple exige, et où on en est @@ -504,10 +522,11 @@ chiffre mort :** **Avant soumission :** -9. **Trancher la question des push (§5.1bis)** — brancher APNs, ou assumer ntfy - et retirer plugin + entitlement + la ligne du README. C'est une décision - produit, et elle conditionne l'argument anti-4.2. Puis vérifier - `aps-environment` dans le Summary de l'archive (§5.1). +9. **Nettoyer le résiduel de notifications (§5.1bis)** — vérifier le cron + `notify_morning` sur nexus, puis retirer le chemin ntfy et le plugin + `@capacitor/push-notifications` + son entitlement, que rien n'appelle. + Corriger la ligne du README qui attribue les rappels au mauvais plugin. + Puis vérifier `aps-environment` dans le Summary de l'archive (§5.1). 10. Nutrition labels, Notes for Review nommant les fonctions natives, compte de démo avec backend allumé (§5.2).