Aller au contenu

Prototype PowerSync sous Capacitor

Version 1, 29 septembre 2026. Prépare les cinq points du §15 du protocole de synchronisation. Le code est dans prototypes/powersync-capacitor/, hors des workspaces du socle.

30/09/2026 (EC-041). Le test sur téléphone est reporté à un lot ultérieur (Lot 3). Il ne compte plus dans les critères de fin du Lot 0.

  • Tout est préparé et vérifié dans un navigateur. Il reste à l’exécuter sur un vrai téléphone Android : c’est la partie manuelle.
  • Le prototype réutilise les tables du socle (sync.commande, sync.commande_resultat, app.appareil, app.parametre) et un petit schéma jetable proto (producteurs, parcelles, affectation).
  • Aucune règle métier dans le serveur du prototype : il fait l’idempotence, contrôle l’ordre des séquences et écrit le résultat.
  • Aucune dépendance n’entre dans le socle. Les ADR (SDK Capacitor, service PowerSync) sont à rédiger seulement si le prototype conclut.
Élément Emplacement
Service PowerSync (Open Edition 1.26.1), profil powersync du compose infra/docker-compose.yml, infra/powersync/
Stockage des compartiments : PostgreSQL, base powersync_storage infra/postgres/init-powersync.sql
Tables de test, graine, volume, nouvel appareil, nettoyage prototypes/powersync-capacitor/sql/
Serveur : JWKS, jeton de 5 minutes, réception des commandes prototypes/powersync-capacitor/serveur/
Application (Vite, TypeScript, Capacitor 8) prototypes/powersync-capacitor/app/
Essais du serveur et de la validation du jeton pnpm essai:serveur

Vérifications faites dans le navigateur intégré (WA-SQLite), avec le service PowerSync réel.

Point du §15 Résultat
1. Table en insertion seule Une commande est inscrite dans commande et commande_locale en une transaction locale. La file survit à un rechargement, part dans l’ordre par lots de 50, et le résultat redescend par commande_resultat (« prov. » disparaît). 300 commandes : saisie 0,7 s, envoi et résultats 6,3 s ; 306 commandes et 306 résultats côté serveur, séquences 1 à 306, aucun doublon
3. Colonne GeoJSON Le déclencheur tient le texte GeoJSON ; la géométrie PostGIS n’est pas envoyée (colonnes explicites dans les règles). 3 499 parcelles reçues, 2,30 Mo de GeoJSON
4. Jeton de l’API validé par JWKS PowerSync lit la clé publique du serveur et accepte le jeton. Il refuse un jeton expiré, une signature d’une autre clé et une audience inconnue. Le serveur refuse tout jeton à un appareil révoqué (403)
5. Volume 2 000 producteurs et 3 499 parcelles dans le périmètre : 8,1 Mo de stockage dans le navigateur, pour une cible de 20 Mo. Les 500 producteurs d’un autre groupement ne descendent pas

Le serveur applique aussi SP-01 (même commande envoyée deux fois : un seul enregistrement), SP-03 (trou de séquence : arrêt avant la commande) et SP-04 (même identifiant, contenu modifié : rejet), et borne la date d’opération à l’heure de réception (§6.4, règle 5).

Le point 2 ne se vérifie pas dans un navigateur : SQLite natif contre WA-SQLite, tenue sur trois jours de données, redémarrage de l’application. Les mesures de performance et de volume du point 5 doivent aussi être refaites sur un téléphone d’entrée de gamme.

  • Un téléphone Android (API 24 ou plus), mode développeur et débogage USB activés, sur le même réseau Wi-Fi que le poste.
  • Android Studio, un JDK 17 ou plus, et adb (paquet platform-tools, absent du SDK local au moment de la préparation).
  • Docker et Node 22.
  1. Démarrer la base et le service :

    Fenêtre de terminal
    docker compose -f infra/docker-compose.yml up -d --wait postgres
    # migrations (dbmate), puis :
    psql "$DATABASE_URL" -f prototypes/powersync-capacitor/sql/prototype.sql
    psql "$DATABASE_URL" -f prototypes/powersync-capacitor/sql/graine.sql
    psql "$DATABASE_URL" -f prototypes/powersync-capacitor/sql/volume.sql
    docker compose -f infra/docker-compose.yml --profile powersync up -d powersync

    La base powersync_storage n’est créée que sur un volume neuf (down -v avant, si le volume existe déjà).

  2. Démarrer le serveur du prototype :

    Fenêtre de terminal
    cd prototypes/powersync-capacitor
    pnpm install && pnpm cles && pnpm serveur # écoute sur 0.0.0.0:3100
    pnpm essai:serveur # doit afficher « ok » partout, y compris PowerSync

    Si la base n’est pas sur le port 5432, définir APP_DATABASE_URL et DATABASE_URL.

  3. Trouver l’adresse IP du poste sur le réseau Wi-Fi. Le service PowerSync (8081) et le serveur (3100) doivent être joignables depuis le téléphone (pare-feu du poste).

Fenêtre de terminal
cd prototypes/powersync-capacitor
pnpm android:ajouter # une fois : génère le projet Android
pnpm android:lancer # construit, synchronise et lance sur le téléphone branché en USB

Dans l’application, saisir http://<IP du poste>:3100 et http://<IP du poste>:8081, puis « Se connecter ». Le code d’appareil est PROT1. Sans réseau au premier lancement, l’application refuse d’enregistrer : l’enrôlement se fait en ligne.

Le paramètre ?sdk=web dans l’adresse (navigateur) ou le choix du SDK dans le code permet de comparer avec le SDK web seul dans la WebView.

N° Test Résultat attendu
T1 Connexion en ligne « Connecté » ; 2 000 producteurs, 3 499 parcelles, environ 2,3 Mo de GeoJSON
T2 Enregistrer une commande en ligne Résultat « acceptee » en moins de 5 s
T3 Mode avion, enregistrer 10 commandes, fermer et rouvrir l’application 10 commandes en attente conservées, dans l’ordre
T4 Rétablir le réseau 10 résultats reçus, aucun doublon côté serveur, séquences continues
T5 Trois jours de données : « Générer 300 commandes » plusieurs fois hors ligne, puis reconnexion Envoi complet sans perte ni doublon ; noter durée et volume (SP-14)
T6 Redémarrer le téléphone hors ligne, puis se reconnecter Aucune perte, séquences continues
T7 Jeton : laisser l’application connectée plus de 5 minutes Jeton renouvelé sans coupure
T8 Révoquer l’appareil côté base, puis se reconnecter Plus de jeton (403) ; les commandes restent sur le téléphone

Après avoir vidé les données de l’application, l’appareil doit être enrôlé à nouveau : psql -v code=PROT2 -f sql/nouvel-appareil.sql, puis saisir PROT2. Sinon le serveur signale un trou de séquence, ce qui est le comportement voulu (protocole §12).

Point du §15 Test Constat sur téléphone Décision
1. Table en insertion seule T3, T4, T6
2. SDK Capacitor (natif) ou SDK web T1 à T6, comparaison ?sdk=web
3. Colonne GeoJSON T1
4. Jeton de l’API T7, T8
5. Volume et performance (téléphone d’entrée de gamme) T1, T5
  • SDK Capacitor en bêta (version 0.9.x). Il exige Capacitor 8. Pas de chiffrement de la base sur mobile. Sur Android, execute ne traite comme requête qu’une instruction qui commence par select : pas d’INSERT … RETURNING. Le prototype s’y conforme.
  • Règles de synchronisation. Le prototype utilise le format bucket_definitions du protocole (§7.2). PowerSync recommande désormais les « sync streams » ; à trancher avant d’écrire les règles définitives.
  • Navigateur intégré de l’application Claude. Il bloque le réseau des workers partagés : le prototype s’y ouvre avec ?monotab=1. Ce réglage ne concerne pas Android.
  • Licence. Le service PowerSync est sous licence FSL, à faire relire (ADR 0017). Hors périmètre du prototype.
  • Authentification. Le serveur du prototype n’appelle pas Keycloak : l’organisation vient de la requête, là où l’API la tirera du jeton Keycloak (protocole §12). À remplacer, pas à réutiliser.
  • Trafic en clair. L’application autorise le HTTP vers le réseau local (développement uniquement).
  • SDK natif ou SDK web dans la WebView (point 2) : critère, tenue sur trois jours et après redémarrage.
  • Budget de 20 Mo par téléphone : à confirmer sur un périmètre réel de 2 000 producteurs (point 5).
  • Fusion des règles de synchronisation en « sync streams » ou maintien de bucket_definitions.
  • ADR à rédiger si le prototype conclut : jeton PowerSync émis par l’API, écriture par commandes et file de contrôle, application terrain sous Capacitor.
  • Le protocole est modifié si un point échoue (par exemple l’ordre de la file d’une table en insertion seule).

psql "$DATABASE_URL" -f prototypes/powersync-capacitor/sql/nettoyage.sql, puis suppression du dossier prototypes/ et du profil powersync du compose si le prototype est abandonné.