# Product Sync Protocol ## The Sync Flow 1. **The POS client polls `/api/v1/init`** with its current `lastChangedProduct` cursor (e.g. `24599`). The server counts how many products have a row version greater than that cursor and returns the count. 2. **If `product_count > 0`**, the client fetches `/api/v1/product` with the same cursor and a `limit` (e.g. 20). The server returns the changed products ordered by row version ascending. 3. **The client updates its local cursor** to the highest `lastChanged` value it received in that batch (e.g. `24609`), so the next poll only fetches newer changes. ### Example from the log ``` init with lastChangedProduct=24599 -> product_count=0 (no changes) init with lastChangedProduct=24599 -> product_count=1 (a new product appeared) product fetch lastChangedProduct=24599 -> returns product with lastChanged=24609 init with lastChangedProduct=24609 -> product_count=0 (caught up) ``` ## What is `lastChangedProduct`? It's the **MSSQL `bRowversion`** value -- an auto-incrementing binary counter that SQL Server bumps whenever a row is modified. The queries in `product-count.js` and `product-list.js` filter with: ```sql WHERE CONVERT(BIGINT, a.bRowversion) > @cursor ``` The client simply persists the highest `lastChanged` value it received so it only gets new/changed rows on subsequent polls. ## How it's kept track **Server side**: The cursor is stateless -- the client sends its last-known value every time. The server just runs the SQL query filtering rows above that value. **Client side**: The POS client stores its `lastChangedProduct` (and `lastChangedCategory`, `lastChangedCustomerGroup`, etc.) persistently so it can resume syncing after a restart without re-downloading everything. ## Other entity types The same pattern applies to: - **Categories** (`lastChangedCategory` / `bRowversion` on `tKategorie`) - **Customer groups** (`lastChangedCustomerGroup` / `bRowversion` on `tKundenGruppe`) - **Composite products** (`lastChangedCompositeProduct` / `bRowversion` on `tArtikelBaugruppe`) - **Deleted entities** (`lastChangedDeletedEntity` / `bLastChanged` on `Pos.vDeletedEntity`) ## Deleted entity sync When entities are deleted in JTL-Wawi, they appear in the `Pos.vDeletedEntity` view with their entity type: | nEntityType | Entity | |---|---| | 1 | Artikel (Product) | | 2 | Kategorie (Category) | | 7 | Stückliste (Composite Product) | The client polls `/v1/init` with `lastChangedDeletedEntity` cursor, and if `deletedEntity_count > 0`, fetches `/v1/deletedentity` to get the list of deleted entities. The response format is: ```json [ { "entityId": "123", "entityType": "1", "lastChanged": "208980" } ] ``` The client then removes these entities from its local database.