diff --git a/kanban.html b/kanban.html index 8a066cb..16e43f4 100644 --- a/kanban.html +++ b/kanban.html @@ -975,15 +975,22 @@ todo-features.md — AR -
-
visitappmatérielNouveau 16/09 · le gros du coût est les Universal/App Links, partagés avec le QR
-

Tags NFC comme déclencheurs de section

-

Troisième déclencheur physique, à côté du QR et du beacon. Analyse et faisabilité : v2/nfc-triggers-plan.md.

-

⚠️ Deux recadrages par rapport à la formulation initiale. (1) Le déclencheur n'est pas un « POI » : dans MyInfoMate le POI est un point posé sur un GLB (VR/3D, immersif-frontiere-plan.md). Le déclencheur physique est une SectionSection.IsBeacon / BeaconId, lu par geo_beacon_trigger_service.dart:177. Le tag NFC se branche au même endroit que le beacon. (2) L'URL /t/{instanceId}/{code} et sa table de mapping n'ont pas d'équivalent existant à réutiliser : les QR d'aujourd'hui portent l'id de section directement dans l'URL (trois formats coexistants, ScannerDialog.dart:31-38), il n'y a aucun endpoint de résolution code → section. v1 = le tag porte la même URL que le QR, donc zéro entité, zéro endpoint, zéro CRUD ; l'indirection ne se justifie que si un client demande un parc de tags réassignables — et elle vaut bien moins qu'en QR, puisque réécrire un NTAG prend deux secondes alors qu'un QR se réimprime.

-

Le vrai coût est ailleurs : les Universal Links (iOS) et App Links (Android) n'existent pas. Aucun assetlinks.json ni apple-app-site-association sur nos domaines (le seul du workspace est dans OpenGlasses, qui n'est pas à nous), et app_links n'est branché que sur le retour de deep link Meta AI (main.dart:69). ✅ Ce lot bénéficie autant au QR : aujourd'hui un QR scanné par l'appareil photo natif n'ouvre pas l'app.

-

Dépendance : le fallback web d'un tag scanné sans app installée, c'est visitapp-webpas encore déployé (carte « Déployer le visiteur web »). Sans lui, un tag scanné par un visiteur sans l'app tombe dans le vide.

-

Ce qui ne marchera pas, à dire au commercial : pas de lecture NFC depuis visitapp-web (WebNFC est Chrome/Android uniquement, jamais Safari), et l'écriture de tags depuis iOS est trop contrainte — l'écran admin de programmation sera Android-only. En contrepartie, iPhone XS+ lit un tag NDEF sans aucune app, ce qui est l'argument réel du canal.

- nfc-triggers-plan.md · ScannerDialog.dart:31-38 · Section.cs:57 · main.dart:69 +
+
visitappmatérielArrêté 16/09 · 4,5 j · prérequis dur = déployer app.myinfomate.be
+

Tags NFC — la colle des liens universels (et le QR en profite)

+

Comportement retenu : le tag porte l'URL du QR ; app installée → elle s'ouvre sur la section, app absente → la page « installez l'application », conservée telle quelle. Pas d'entité NfcTag, pas de code opaque, pas de colonne sur Section. Analyse : v2/nfc-triggers-plan.md.

+

Aucun code NFC à écrire pour le cas nominal : l'OS lit le tag, affiche une bannière et ouvre l'URL — c'est le lien universel qui aiguille vers l'app. nfc_manager ne sert qu'au bouton « Scanner un tag » in-app.

+

La colle, c'est ça — et les deux premiers points réparent aussi le QR, qui aujourd'hui n'ouvre jamais l'app quand on le scanne à l'appareil photo :

+ +

À savoir avant de vendre : iPhone XS+ lisent un tag sans app (7/8/X non) ; l'OS affiche une bannière à taper, pas d'ouverture magique ; un tag à plat sur du métal ne se lit pas ; pas de WebNFC sur Safari, donc rien sur visitapp-web ; et le NFC ne remplace pas le beacon (geste volontaire à 1-2 cm).

+ nfc-triggers-plan.md · main.dart:68 · ScannerDialog.dart:107 · ApplicationInstance.cs:57
diff --git a/kanban/cards/5-planifie/265-tags-nfc-comme-declencheurs-de-section.md b/kanban/cards/5-planifie/265-tags-nfc-comme-declencheurs-de-section.md index 68a277a..83c8209 100644 --- a/kanban/cards/5-planifie/265-tags-nfc-comme-declencheurs-de-section.md +++ b/kanban/cards/5-planifie/265-tags-nfc-comme-declencheurs-de-section.md @@ -1,13 +1,20 @@ --- -title: Tags NFC comme déclencheurs de section -area: backend manager visitapp -horizon: v2 +title: Tags NFC — la colle des liens universels (et le QR en profite) +area: visitapp manager backend +horizon: v1 tags: visitapp, matériel -flag: warn | Nouveau 16/09 · le gros du coût est les Universal/App Links, partagés avec le QR -src: nfc-triggers-plan.md · ScannerDialog.dart:31-38 · Section.cs:57 · main.dart:69 +flag: warn | Arrêté 16/09 · 4,5 j · prérequis dur = déployer app.myinfomate.be +src: nfc-triggers-plan.md · main.dart:68 · ScannerDialog.dart:107 · ApplicationInstance.cs:57 --- -

Troisième déclencheur physique, à côté du QR et du beacon. Analyse et faisabilité : v2/nfc-triggers-plan.md.

-

⚠️ Deux recadrages par rapport à la formulation initiale. (1) Le déclencheur n'est pas un « POI » : dans MyInfoMate le POI est un point posé sur un GLB (VR/3D, immersif-frontiere-plan.md). Le déclencheur physique est une SectionSection.IsBeacon / BeaconId, lu par geo_beacon_trigger_service.dart:177. Le tag NFC se branche au même endroit que le beacon. (2) L'URL /t/{instanceId}/{code} et sa table de mapping n'ont pas d'équivalent existant à réutiliser : les QR d'aujourd'hui portent l'id de section directement dans l'URL (trois formats coexistants, ScannerDialog.dart:31-38), il n'y a aucun endpoint de résolution code → section. v1 = le tag porte la même URL que le QR, donc zéro entité, zéro endpoint, zéro CRUD ; l'indirection ne se justifie que si un client demande un parc de tags réassignables — et elle vaut bien moins qu'en QR, puisque réécrire un NTAG prend deux secondes alors qu'un QR se réimprime.

-

Le vrai coût est ailleurs : les Universal Links (iOS) et App Links (Android) n'existent pas. Aucun assetlinks.json ni apple-app-site-association sur nos domaines (le seul du workspace est dans OpenGlasses, qui n'est pas à nous), et app_links n'est branché que sur le retour de deep link Meta AI (main.dart:69). ✅ Ce lot bénéficie autant au QR : aujourd'hui un QR scanné par l'appareil photo natif n'ouvre pas l'app.

-

Dépendance : le fallback web d'un tag scanné sans app installée, c'est visitapp-webpas encore déployé (carte « Déployer le visiteur web »). Sans lui, un tag scanné par un visiteur sans l'app tombe dans le vide.

-

Ce qui ne marchera pas, à dire au commercial : pas de lecture NFC depuis visitapp-web (WebNFC est Chrome/Android uniquement, jamais Safari), et l'écriture de tags depuis iOS est trop contrainte — l'écran admin de programmation sera Android-only. En contrepartie, iPhone XS+ lit un tag NDEF sans aucune app, ce qui est l'argument réel du canal.

+

Comportement retenu : le tag porte l'URL du QR ; app installée → elle s'ouvre sur la section, app absente → la page « installez l'application », conservée telle quelle. Pas d'entité NfcTag, pas de code opaque, pas de colonne sur Section. Analyse : v2/nfc-triggers-plan.md.

+

Aucun code NFC à écrire pour le cas nominal : l'OS lit le tag, affiche une bannière et ouvre l'URL — c'est le lien universel qui aiguille vers l'app. nfc_manager ne sert qu'au bouton « Scanner un tag » in-app.

+

La colle, c'est ça — et les deux premiers points réparent aussi le QR, qui aujourd'hui n'ouvre jamais l'app quand on le scanne à l'appareil photo :

+ +

À savoir avant de vendre : iPhone XS+ lisent un tag sans app (7/8/X non) ; l'OS affiche une bannière à taper, pas d'ouverture magique ; un tag à plat sur du métal ne se lit pas ; pas de WebNFC sur Safari, donc rien sur visitapp-web ; et le NFC ne remplace pas le beacon (geste volontaire à 1-2 cm).

diff --git a/status/roadmap-canaux.md b/status/roadmap-canaux.md index c3c53b5..a4c6e4b 100644 --- a/status/roadmap-canaux.md +++ b/status/roadmap-canaux.md @@ -24,7 +24,7 @@ Plans détaillés, pas encore démarrés en dev (sauf mention contraire) : | AI Persona par venue (guide IA personnalisable) | [v2/myinfomate-ai-persona-analysis.md](../v2/myinfomate-ai-persona-analysis.md) | Architecture de référence pour les chantiers IA ci-dessus | | Lunettes Ray-Ban Meta | [roadmap.md](../roadmap.md) (section XR), [rayban-meta-integration.md](../rayban-meta-integration.md) | 🔨 **POC fonctionnel — bien plus avancé que ce que cette ligne disait jusqu'au 2026-08-09.** Voir §5bis | | VR Meta Quest (borne office tourisme) | [v2/vr-quest-unity-plan.md](../v2/vr-quest-unity-plan.md) · [roadmap.md](../roadmap.md) (section XR) | 📦 **V2** — ⚠️ **« zéro ligne de code » était faux** (corrigé le 2026-08-31, relevé dans le code). Le canal VR est déjà dans le modèle : `AppType.VR`, `Instance.IsVR` en base depuis juillet 2025, sous-menu « VR » branché dans `main_screen.dart:65`, filtre stats + i18n `statsChannelVR` prêts. **Ce qui manque** : l'écran de flotte (`main_screen.dart:704` = `Text("TODO vr")`), un `Device.AppType` (le `DeviceController` est hardcodé sur `Tablet`), et l'app Unity. Back-office XR : **8-12 j**. App Unity : **3-4 mois**. La landing annonce « Meta Quest — Bientôt » en 4 langues (`translations.ts`, clé `mode4Desc`) | -| Tags NFC (déclencheur de section) | [v2/nfc-triggers-plan.md](../v2/nfc-triggers-plan.md) | 📦 **V2** — analysé dans le code le 2026-09-16. Troisième déclencheur physique à côté du QR et du beacon. ⚠️ **Le coût n'est pas le NFC** : les **Universal Links / App Links n'existent pas** (aucun `assetlinks.json` ni `apple-app-site-association`, `app_links` branché seulement sur le retour Meta AI, `main.dart:69`) — ce lot-là **sert aussi au QR**, qui aujourd'hui n'ouvre pas l'app quand il est scanné par l'appareil photo natif. Le tag porte **la même URL que le QR** : aucune entité, aucun endpoint de résolution en v1. Dépend du **déploiement de `visitapp-web`** pour le fallback sans app. 4-7 j | +| Tags NFC (déclencheur de contenu) | [v2/nfc-triggers-plan.md](../v2/nfc-triggers-plan.md) | ⚠️ **V1 — 4,5 j** (arrêté le 2026-09-16). Le tag porte **l'URL du QR** ; app installée → elle s'ouvre sur la section, app absente → la page « installez l'application », conservée. **Aucune entité, aucune colonne sur `Section`, et aucun code NFC pour le cas nominal** : c'est le **lien universel** qui aiguille. ✅ Le travail réel (`assetlinks.json`/AASA, routage du deep link entrant, extraction de `ScannerDialog._onDetect`) **répare aussi le QR**, qui aujourd'hui n'ouvre jamais l'app depuis l'appareil photo. Plus `IsNFCEnabled` calqué sur `IsQRCodeEnabled`. ⚠️ **Prérequis dur : déployer `app.myinfomate.be`**, qui doit servir les `.well-known` | | Canal subsides | [plan-import-ia-stats-subsides.md](../plan-import-ia-stats-subsides.md) | Actions administratives/réseau, pas de dev | --- diff --git a/v2/nfc-triggers-plan.md b/v2/nfc-triggers-plan.md index a1943b3..14d23e5 100644 --- a/v2/nfc-triggers-plan.md +++ b/v2/nfc-triggers-plan.md @@ -1,43 +1,104 @@ -# Tags NFC comme déclencheurs de section +# Tags NFC — déclencher le contenu depuis un tag -> Chantier **V2**, **analysé dans le code le 2026-09-16** à partir d'une spec d'intention. -> Carte kanban : `cards/5-planifie/265-…` -> Ce document **corrige la spec d'origine sur deux points de réalité** (le mot « POI », et -> le schéma d'URL avec table de mapping), puis dit comment on le fait. +> **Analysé dans le code le 2026-09-16.** Carte kanban : `cards/5-planifie/265-…` +> ⚠️ **Document retourné trois fois** par les précisions de Thomas. Version arrêtée ci-dessous : +> le tag ouvre **l'app mobile sur le bon contenu**, et la page de téléchargement web reste +> le fallback quand l'app n'est pas installée. --- -## Ce que la spec d'origine supposait, et ce que dit le code +## Le comportement retenu -| Hypothèse de la spec | Réalité relevée | -|---|---| -| « Déclencher un **POI** » | Dans MyInfoMate, un **POI est un point posé sur un GLB** (3D/VR — voir `immersif-frontiere-plan.md` §9). Le déclencheur physique d'un contenu, c'est une **`Section`** : `Section.IsBeacon` / `Section.BeaconId` (`Section.cs:57`), lue côté visiteur par `geo_beacon_trigger_service.dart:177` et `configuration_page.dart:205`. Le NFC se branche **au même endroit que le beacon**, pas ailleurs | -| « Réutiliser l'endpoint de résolution des QR, s'ils utilisent déjà une URL de ce format » | **Il n'y en a aucun.** Les QR portent l'id de section **directement dans l'URL**, et trois formats coexistent sur le terrain (`ScannerDialog.dart:31-38`) : `app.myinfomate.be/download/{instanceId}/{configId}/{sectionId}`, `web.mymuseum.be/{instanceId}/{configId}/{sectionId}` (déjà imprimé, MDLF), et un **id de section brut** (déjà imprimé, Fort Saint-Héribert). Il n'y a donc rien à réutiliser : l'entité « tag », le code opaque et l'endpoint `code → section` seraient **du neuf intégral** | -| « Déclarer les URLs en Universal Links / App Links » | **Rien n'existe.** Aucun `assetlinks.json` ni `apple-app-site-association` sur nos domaines (le seul du workspace est dans `OpenGlasses`, qui n'est pas à nous). `app_links` est bien au `pubspec.yaml:89` mais branché **uniquement sur le retour de deep link Meta AI** (`main.dart:69` → `MetaGlassesService.handleDeepLink`), et `AndroidManifest.xml` n'a pas d'intent-filter `autoVerify` sur un domaine http | -| « Si l'app n'est pas installée, l'URL affiche une page web utile » | `visitapp-web` fait exactement ça (`app.myinfomate.be/[slug]`), mais **il n'est pas déployé** — il manque le Dockerfile et l'entrée dans le compose (carte « Déployer le visiteur web »). Le fallback est une **dépendance**, pas un acquis | +``` +tag NFC (NDEF : URL du QR) + │ + ├─ app installée → App Link / Universal Link → mymuseum-visitapp s'ouvre sur la section + │ + └─ app absente → app.myinfomate.be/download/{instanceId}/{configId}/{sectionId} + → page « installez l'application » ← comportement actuel, conservé +``` + +**Le tag porte exactement l'URL du QR.** Pas d'entité `NfcTag`, pas de code opaque, pas +d'endpoint de résolution, pas de colonne sur `Section`. Un tag NFC est un QR code sans caméra — +c'est ce qui rend ce chantier petit. + +✅ **Et il n'y a aucun code NFC à écrire pour le cas nominal.** Sur iOS (iPhone XS+) comme sur +Android, l'OS lit le tag NDEF, affiche une bannière et **ouvre l'URL** ; c'est le lien universel +qui aiguille vers l'app. `nfc_manager`, la permission NFC et l'entitlement Core NFC ne servent +qu'à la lecture **in-app** — utile seulement pour le bouton « Scanner un tag » du lot 4. --- -## Décisions +## Ce qui manque vraiment : la colle -| Décision | Conséquence | -|---|---| -| **1. Le tag porte la même URL que le QR** | Pas d'entité `NfcTag`, pas de code opaque, pas d'endpoint de résolution, pas de CRUD manager. Le mapping tag → section, c'est l'URL écrite sur le tag. **Zéro ligne de backend pour la v1** | -| **2. L'indirection `code → section` est reportée, pas refusée** | L'argument « réassigner sans réécrire le tag » est réel, mais il vaut **beaucoup moins en NFC qu'en QR** : réécrire un NTAG prend deux secondes avec un téléphone, alors qu'un QR se réimprime, se replastifie et se recolle. On ouvrira l'indirection le jour où un client gère un parc de tags — et ce jour-là elle devra couvrir **QR et NFC ensemble**, pas le NFC seul | -| **3. Le lot utile est celui des liens, pas celui du NFC** | Universal Links + App Links + routage du deep link entrant vers la section. ✅ **Le QR en bénéficie autant** : aujourd'hui un QR scanné par l'appareil photo natif n'ouvre pas l'app, il ouvre le navigateur. C'est ce lot qui porte la valeur, le NFC n'en est qu'un second émetteur | -| **4. Lecture in-app en fallback seulement** | `nfc_manager` derrière le bouton Scanner existant (`ScannerBouton.dart`), à côté du QR. Le cas nominal reste **le tag lu sans ouvrir l'app** — c'est tout l'intérêt du canal | -| **5. Écran de programmation des tags : Android-only** | L'écriture NDEF depuis iOS est trop contrainte pour un outil de terrain, et le public visé est **l'admin qui pose les tags**, pas le visiteur. Un seul appareil de programmation suffit à un lieu | -| **6. Verrouillage en écriture : hors v1** | Irréversible, donc une erreur de pose coûte le tag. À ouvrir après un vrai déploiement, avec double confirmation | -| **7. Pas de lecture par UID** | Confirmé : l'UID n'est pas réassignable et impose une table de correspondance — donc tous les inconvénients de la décision 2 sans son bénéfice | +### 1. Les liens universels n'existent pas — c'est le cœur du chantier ---- +Aucun `assetlinks.json` (Android) ni `apple-app-site-association` (iOS) n'est servi sur nos +domaines. Le seul du workspace est dans `OpenGlasses`, qui n'est pas à nous. -## Ce qui ne marchera pas — à savoir avant de le vendre +⚠️ **Ils doivent être servis par le domaine de l'URL du tag**, donc par `app.myinfomate.be` — +qui **n'est pas déployé** (absent de `docker-compose-myinfomate.yml`, qui route `myinfomate.be`, +`api.`, `manager.` et `monitor.`). La carte « Déployer le visiteur web », déjà `critical`, reste +un **prérequis dur**. -- **Aucune lecture NFC sur `visitapp-web`.** WebNFC est Chrome/Android uniquement, jamais Safari. Le plan **Essentiel étant web-only**, le NFC ne s'y vend pas comme « scan dans l'app » — il s'y vend comme « on approche le téléphone, une page s'ouvre », ce qui est vrai et ne demande rien de plus que la décision 1. -- **iPhone 7 / 8 / X** ne lisent pas les tags en arrière-plan : il leur faut l'app ouverte. iPhone **XS et plus** lisent un NDEF sans aucune app installée — c'est l'argument commercial réel, et il est bon. -- **Un tag à plat sur du métal ne se lit pas.** Prévoir des tags sur mousse ou des NTAG « on-metal » ; le raccourci du bois transparent au BLE (carte beacons) n'a pas d'équivalent ici. -- **Le NFC ne remplace pas le beacon** : il demande un geste volontaire à 1-2 cm, il ne déclenche rien à l'approche. Les trois déclencheurs se cumulent, ils ne se substituent pas. +À réunir avant d'écrire les fichiers : le **SHA-256 de la clé de signature de release** Android +(l'APK se construit par `tool/build_apk.sh`) et le **Team ID + bundle id** iOS. Une empreinte +fausse ne produit aucune erreur visible — le lien s'ouvre simplement dans le navigateur. + +### 2. L'app n'écoute pas les deep links entrants + +`app_links` est bien au `pubspec.yaml:89`, mais : + +```dart +void _listenGlassesDeepLinks() { + if (!kEnableGlasses || !Platform.isAndroid) return; // ← main.dart:68 + _deepLinkSub = AppLinks().uriLinkStream.listen( + (uri) => MetaGlassesService.instance.handleDeepLink(uri.toString()), + ); +} +``` + +Tout part vers `MetaGlassesService`, le listener est **coupé sur iOS** et conditionné à +`kEnableGlasses`. Il faut router **par motif d'URL**, sans casser le retour de registration Meta. + +### 3. La résolution d'un code est enfermée dans le dialogue du scanner + +`ScannerDialog._onDetect` (`ScannerDialog.dart:107`) fait déjà **tout** ce qu'il faut : parsing +des trois formats de QR du terrain, section appartenant ou non à la visite en cours, +`_findConfigurationIdOfSection` quand l'id est brut, proposition d'ouvrir une **autre visite** du +site, et télémétrie. Mais c'est un `State` : la méthode manipule `context`, `Navigator`, +`ScaffoldMessenger`, et capture le navigator **avant** le `pop` pour survivre au démontage. + +**Extraire cette résolution dans un service** est le vrai morceau de travail — et il **profite +au QR autant qu'au NFC**. À faire sans perdre les cas limites, qui sont tous des corrections de +bugs réels documentées en commentaires dans le fichier. + +### 4. `IsNFCEnabled`, sur le modèle exact de `IsQRCodeEnabled` + +`ApplicationInstance.IsQRCodeEnabled` (`ApplicationInstance.cs:57`, défaut `true`) est piloté par +un switch dans `app_configuration_link_screen.dart:400` et consommé là où le bouton scanner +s'affiche : `home_3.0.dart:651`, `configuration_page.dart:433`, `menu_page.dart:302`, et +`visitapp-web` (`[slug]/page.tsx:44`). On ajoute `IsNFCEnabled` au même endroit, même défaut, +même switch. + +⚠️ **Ce que le flag pilote, et ce qu'il ne pilote pas.** Il masque le **bouton « Scanner un +tag »** in-app et sert de déclaration commerciale. Il **ne peut pas** empêcher un tag posé au mur +d'ouvrir l'app : le deep link vient de l'OS, et l'app le reçoit sans savoir s'il vient d'un tag +ou d'un QR. Ne pas lui prêter un rôle de verrou qu'il n'aura pas. + +⚠️ `Configuration.IsQRCode` (`Configuration.cs:52`) existe aussi mais **n'est lu par aucune app** — +code mort. Ne pas dupliquer l'erreur en posant un flag NFC au niveau `Configuration`. + +### 5. Sans quoi le NFC sera compté comme du QR dans les stats + +`_onDetect` émet `VisitEventType.qrScan`. Un tag qui ouvre l'app par deep link n'a aucun moyen de +se distinguer — sauf à ajouter un paramètre à l'URL encodée sur le tag (`?src=nfc`) et une valeur +`NfcScan` à l'enum (`VisitEvent.cs:48`). ⚠️ L'enum passe par le client généré de +`manager_api_new`, **à éditer à la main**. Sans ça, le canal NFC est invisible dans les stats et +on ne saura jamais s'il sert. + +*(À traiter avec :* la page de téléchargement dit « scannez à nouveau le QR code depuis +l'application » — faux pour un tag. Le `?src=nfc` permet aussi d'adapter ce texte.*)* --- @@ -45,10 +106,23 @@ | Lot | Contenu | Estimation | |---|---|---| -| **A — Liens universels** (le seul indispensable) | `assetlinks.json` + `apple-app-site-association` servis sur le domaine, intent-filter `autoVerify` + capability Associated Domains, routage du deep link entrant vers la section (logique partagée avec le parsing de `ScannerDialog`, à extraire du dialogue). **Bénéficie au QR dès la livraison** | 2-3 j | -| **B — NFC** | Permission et intent-filter NDEF Android, capability NFC Tag Reading + `NFCReaderUsageDescription` + entitlement iOS, `nfc_manager` derrière le bouton Scanner | 1-2 j | -| **C — Écran de programmation admin** | Choisir une section → approcher un tag → écrire l'URL NDEF. Android-only, NTAG213/215/216 | 1-2 j | -| **D — Fallback web** | Rien à écrire : c'est le déploiement de `visitapp-web`. **Dépendance externe** | — | -| *(reporté)* **E — Indirection `code → section`** | Entité, CRUD manager, endpoint de résolution — et alors **pour QR et NFC ensemble** | 3-4 j | +| **0 — Déployer `app.myinfomate.be`** | Carte existante, déjà `critical`. **Prérequis dur** : c'est ce domaine qui sert les `.well-known` | (carte 210) | +| **1 — Liens universels** | `assetlinks.json` + `apple-app-site-association` servis sur `app.myinfomate.be`, intent-filter `autoVerify` Android, Associated Domains iOS. Demande le SHA-256 de la clé de release et le Team ID | **1 j** | +| **2 — Router le deep link entrant** | Découpler `main.dart:68` de `MetaGlassesService`, activer le listener sur iOS, router par motif | **0,5 j** | +| **3 — Extraire la résolution du scanner** | Sortir `_onDetect` de `ScannerDialog` vers un service, sans perdre les cas limites. ✅ **Profite au QR** | **1,5 j** | +| **4 — `IsNFCEnabled`** | Colonne + DTO + client généré à la main + switch manager + i18n FR/EN/NL, et le bouton « Scanner un tag » qu'il pilote (`nfc_manager`, permission Android, entitlement iOS `NDEF`) | **1 j** | +| **5 — Distinguer le canal** | `?src=nfc` sur l'URL encodée, `VisitEventType.NfcScan`, texte de la page de téléchargement | **0,5 j** | +| **6 — Encoder les tags** | **NFC Tools**, 2 s par tag, une URL par point. Geste d'exploitation | **0 j de dev** | -**Total v1 (A+B+C) : 4-7 jours**, dont A porte à lui seul la moitié de la valeur et sert déjà au QR. +**Total : 4,5 j**, dont les lots 2 et 3 **réparent aussi le QR** — aujourd'hui un QR scanné à +l'appareil photo n'ouvre jamais l'app, même installée. + +--- + +## À savoir avant de le vendre + +- **iPhone XS et plus** lisent un tag sans aucune app. Les **iPhone 7 / 8 / X**, non : il leur faut une app ouverte. Android : le NFC doit être activé dans les réglages, ce qui n'est pas universel. +- **L'ouverture n'est pas automatique** : l'OS affiche une **bannière que le visiteur tape**. C'est l'expérience de l'appareil photo sur un QR, pas mieux. +- **Un tag à plat sur du métal ne se lit pas** — tags sur mousse ou NTAG « on-metal ». NTAG213 (144 o) suffit largement pour l'URL. +- **Aucune lecture NFC sur `visitapp-web`** : WebNFC est Chrome/Android uniquement, jamais Safari. Le plan **Essentiel étant web-only**, le NFC ne s'y vend pas — sauf comme « le tag ouvre la page web », qui reste vrai et gratuit. +- **Le NFC ne remplace pas le beacon** : geste volontaire à 1-2 cm, aucun déclenchement à l'approche. Les déclencheurs se cumulent.