SmartCommon fournit un module de synchronisation complet pour gérer le fonctionnement hors-ligne des applications PWA.
Le module sync est composé de :
| Élément | Type | Description |
|---|---|---|
useSyncClient | Hook React | Interface principale pour la synchronisation |
SyncEngine | Classe | Moteur de synchronisation (push/pull/conflits) |
SyncStorage | Classe | Couche IndexedDB pour le stockage local (Dexie) |
SyncApi | Classe | Client HTTP avec auth JWT et retry automatique |
ConflictResolver | Composant React | Interface de résolution de conflits |
Voir Hooks - useSyncClient pour la documentation complète du hook.
1. L'utilisateur modifie des données localement (create/update/remove) 2. Les changements sont stockés dans IndexedDB (pending_changes) 3. Au prochain sync.push(), les changements sont envoyés au serveur 4. Le serveur confirme ou signale des conflits 5. Les temp_id locaux sont remplacés par les ID serveur
1. sync.pull() demande les changements depuis lastSyncTime 2. Le serveur renvoie les entités modifiées 3. Les entités locales sont mises à jour 4. En cas de conflit (modification locale + serveur), un conflit est créé
Quand une entité est modifiée localement et sur le serveur, un conflit est créé.
const conflicts = await sync.getConflicts();
for (const conflict of conflicts) {
// Garder la version client
await sync.resolveConflict(conflict.conflict_id, 'client');
// Garder la version serveur
await sync.resolveConflict(conflict.conflict_id, 'server');
// Fusionner manuellement
await sync.resolveConflict(conflict.conflict_id, {
...conflict.server_data,
label: conflict.client_data.label // garder le label local
});
}
import { ConflictResolver } from '@cap-rel/smartcommon';
const MyConflictPage = () => {
const sync = useSyncClient({ /* ... */ });
const [conflicts, setConflicts] = useState([]);
useEffect(() => {
sync.getConflicts().then(setConflicts);
}, []);
if (conflicts.length === 0) return null;
return (
<ConflictResolver
conflicts={conflicts}
onResolve={async (conflictId, resolution) => {
await sync.resolveConflict(conflictId, resolution);
setConflicts(prev => prev.filter(c => c.conflict_id !== conflictId));
}}
onCancel={() => setConflicts([])}
/>
);
};
Le composant ConflictResolver affiche :
| Prop | Type | Description |
|---|---|---|
conflicts | array | Tableau de conflits (conflictid, table, objectid, clientdata, serverdata, field_conflicts) |
onResolve | function | Appelée quand un conflit est résolu |
onCancel | function | Appelée pour fermer le résolveur |
renderField | function | Rendu personnalisé d'un champ (optionnel) |
labels | object | Libellés de l'interface (optionnel, français par défaut) |
Le module sync utilise les stores suivants :
| Store | Description |
|---|---|
entities | Données synchronisées |
pendingchanges | Conflits non résolus |
syncmeta | Entités supprimées localement |