Přehled

{productName} nabízí tři metody pro detekci a sledování změn ve vašich datech. Každá metoda má jiné možnosti a je vhodná pro specifické případy použití.

Výběr správné metody

  • updatedAt — Jednoduché periodické synchronizace bez sledování odstranění
  • Changes API — Kompletní historie změn s dotazováním
  • Webhooks — Oznámení v reálném čase s automatickým doručováním

Porovnání metod

Porovnejte tři metody detekce změn a vyberte tu nejvhodnější pro váš případ použití

card: updatedAt
**Výhody**
- Jednoduchá implementace
- Nízká režie - používá standardní filtry dotazů
- Dobré pro periodické synchronizace (hodinové, denní)

**Omezení**
- Nedetekuje odstranění
- Vyžaduje dotazování
- Může zmeškat rychlé změny, pokud je interval dotazování příliš dlouhý

**Nejlepší pro:** Jednoduché integrace, kde jsou odstranění vzácná nebo nejsou kritická
card: Changes API
**Výhody**
- Zachycuje všechny operace (vytvoření, aktualizace, odstranění)
- Sledování verzí se sekvenčními ID
- Spolehlivé - nezmešká žádné změny
- Může sledovat více entit

**Omezení**
- Vyžaduje dotazování
- Je třeba udržovat ID poslední verze
- Zpoždění na základě intervalu dotazování

**Nejlepší pro:** Robustní integrace vyžadující kompletní historii změn a sledování odstranění
card: Webhooks
**Výhody**
- Oznámení v reálném čase (do 5 sekund)
- Není nutné dotazování
- Dávkové doručování (až 100 změn)
- Vestavěný mechanismus opakování
- Podporuje filtrování

**Omezení**
- Vyžaduje veřejně přístupný koncový bod
- Musí zvládnout spolehlivost webhooků
- Složitější nastavení

**Nejlepší pro:** Integrace v reálném čase vyžadující okamžitou akci při změnách dat

Metoda 1: Použití updatedAt [badge:Simple|info]

Sledujte změny pomocí pole časového razítka updatedAt, které je k dispozici u všech entit

**Důležité omezení:**
Metoda `updatedAt` nedetekuje odstranění. Pokud potřebujete sledovat odstraněné záznamy, použijte místo toho Changes API nebo Webhooks.

Dotaz na produkty aktualizované od poslední synchronizace

Načtěte všechny produkty, které byly upraveny po určitém časovém razítku

GET /c/{companyId}/products?filter=updatedAt > '2025-11-14T10:00:00Z'&limit=100

// Response
{
    "data": [
        {
            "id": "prod-123",
            "name": "Aktualizovaný produkt",
            "price": 99.99,
            "updatedAt": "2025-11-14T10:15:30Z"
        }
        // ... další produkty
    ]
}

Sledování času poslední synchronizace (správná metoda)

Uložte časové razítko z posledního načteného záznamu, abyste se vyhnuli zmeškání změn

// Inicializujte časovým razítkem z poslední synchronizace
// Pro první synchronizaci použijte časové razítko v minulosti nebo null
let lastSyncTime = '2025-01-01T00:00:00Z';

// Při každé synchronizaci
const url = `/c/{companyId}/products?filter=${encodeURIComponent(
    `updatedAt > '${lastSyncTime}'`
)}&limit=100&sort=updatedAt`;

const response = await fetch(url);
const { data } = await response.json();

if (data.length > 0) {
    // Zpracujte změněné produkty
    data.forEach(product => {
        console.log('Aktualizováno:', product.id, product.updatedAt);
    });
    
    // ✅ SPRÁVNĚ: Použijte updatedAt z posledního záznamu
    lastSyncTime = data[data.length - 1].updatedAt;
    
    // ❌ ŠPATNĚ: Nikdy nepoužívejte new Date().toISOString()
    // To může zmeškat změny z důvodu:
    // - Čas mezi dotazem a voláním new Date()
    // - Rozdílné hodiny mezi klientem a serverem
}
⚠️ Kritické: Synchronizace času

**Nikdy nepoužívejte `new Date().toISOString()` pro lastSyncTime!**

Tento přístup má dva kritické problémy:

1. **Stav závodu:** Mezi načtením dat a voláním `new Date()` může dojít ke změnám, což způsobí, že tyto změny zmeškáte při další synchronizaci.
2. **Rozdílné hodiny:** Hodiny klienta a serveru nemusí být synchronizovány. Pokud jsou hodiny klienta napřed, zmeškáte změny. Pokud jsou pozadu, získáte duplicitní data.

✅ Vždy používejte hodnotu `updatedAt` z posledního záznamu vráceného serverem.

Metoda 2: Použití Changes API [badge:Complete|success]

Sledujte všechny změny včetně odstranění pomocí protokolu změn se sledováním verzí

Klíčové výhody
- Zachycuje operace vytvoření, aktualizace a odstranění
- Sekvenční ID verzí pro spolehlivé sledování
- Dotaz na více entit v jednom požadavku
- Žádná ztráta dat ani při dlouhých intervalech dotazování

Získání nedávných změn pro produkty

Načtěte všechny změny (včetně odstranění) pro produkty se sledováním verzí

GET /c/{companyId}/changes?filter=entity = 'products' and id > 100&limit=100

// Response
{
    "data": [
        {
            "id": 101,  // číslo verze
            "entity": "products",
            "rowId": "prod-123",
            "operation": "update",
            "changeSetId": null,
            "createdAt": "2025-11-14T10:15:30Z"
        },
        {
            "id": 102,
            "entity": "products",
            "rowId": "prod-456",
            "operation": "delete",
            "changeSetId": null,
            "createdAt": "2025-11-14T10:16:45Z"
        }
    ]
}

Dotazování na změny se sledováním verzí

Nepřetržitě se dotazujte na nové změny pomocí posledního známého ID verze

// Uložte poslední zpracovanou verzi
let lastVersionId = 0;

async function pollForChanges() {
    const filter = encodeURIComponent(
        `entity = 'products' and id > ${lastVersionId}`
    );
    
    const response = await fetch(
        `/c/{companyId}/changes?filter=${filter}&limit=100&sort=id`
    );
    const { data } = await response.json();
    
    if (data.length > 0) {
        // Zpracujte změny
        for (const change of data) {
            console.log(
                `Změna #${change.id}: ${change.operation} na ${change.rowId}`
            );
            
            if (change.operation === 'delete') {
                // Zpracujte odstranění
                console.log('Produkt odstraněn:', change.rowId);
            } else {
                // Načtěte aktualizovaný produkt
                const product = await fetch(
                    `/c/{companyId}/products/${change.rowId}`
                ).then(r => r.json());
                console.log('Produkt aktualizován:', product);
            }
        }
        
        // Aktualizujte ID poslední verze
        lastVersionId = data[data.length - 1].id;
    }
}

// Dotazujte se každých 30 sekund
setInterval(pollForChanges, 30000);

Získání změn pro více entit

Monitorujte změny napříč různými typy entit

const filter = encodeURIComponent(
    `(entity = 'products' OR entity = 'categories') and id > ${lastVersionId}`
);

const response = await fetch(
    `/c/{companyId}/changes?filter=${filter}&limit=100&sort=id`
);
const { data } = await response.json();

// Seskupte změny podle entity
const changesByEntity = data.reduce((acc, change) => {
    if (!acc[change.entity]) acc[change.entity] = [];
    acc[change.entity].push(change);
    return acc;
}, {});

console.log('Změněné produkty:', changesByEntity.products?.length || 0);
console.log('Změněné kategorie:', changesByEntity.categories?.length || 0);

Metoda 3: Použití Webhooks [badge:Real-time|warning]

Získejte automatická oznámení do 5 sekund od jakékoli změny dat

**Funkce v reálném čase**
- Oznámení doručena do 5 sekund od změn
- Dávkové doručování (až 100 změn na webhook)
- Filtrování podle typu entity (konkrétní entita nebo všechny entity)
- Filtrování podle podmínek řádků (např. "price > 100")
- Filtrování podle změněných sloupců (např. ["price", "status"])
- Automatické opakování s exponenciálním zpožděním

Registrace Webhooku pro produkty

Získejte automatická oznámení při změně produktů

POST /c/{companyId}/hooks
Content-Type: application/json

{
    "entity": "products",
    "url": "https://your-api.com/webhooks/products",
    "action": "webhook"
}

// Váš koncový bod webhooku obdrží:
{
    "hookId": "hook-123",
    "tenantId": "tenant-789",
    "organisationId": "{companyId}",
    "changeSetId": null,
    "changes": [
        {
            "id": "change-001",
            "entity": "products",
            "operation": "update",
            "rowId": "prod-123",
            "changeSetId": null
        }
    ],
    "timestamp": "2025-11-14T10:30:00.000Z"
}

Příklad obslužného programu Webhooku

Zpracování příchozích oznámení webhooku

// Obslužný program webhooku Express.js
app.post('/webhooks/products', async (req, res) => {
    const { changes } = req.body;
    
    for (const change of changes) {
        console.log(
            `Webhook: ${change.operation} na ${change.rowId}`
        );
        
        if (change.operation === 'delete') {
            // Zpracujte odstranění produktu
            await deleteProductInMySystem(change.rowId);
        } else {
            // Načtěte a zpracujte aktualizovaný produkt
            const product = await fetch(
                `https://api.productsync.com/c/{companyId}/products/${change.rowId}`,
                {
                    headers: {
                        'Authorization': 'Bearer YOUR_API_KEY'
                    }
                }
            ).then(r => r.json());
            
            await updateProductInMySystem(product);
        }
    }
    
    // Vždy odpovězte kódem 200 pro potvrzení přijetí
    res.status(200).json({ received: true });
});

Webhook pro konkrétní entitu

Omezte oznámení na jeden typ entity

POST /c/{companyId}/hooks
Content-Type: application/json

{
    "entity": "products",
    "url": "https://your-api.com/webhooks/products",
    "action": "webhook"
}

// Tento webhook spustí pouze změny produktů
// Změny kategorií, jednotek atd. budou ignorovány

Webhook pro všechny entity

Monitorujte všechny změny entit v jednom webhooku

POST /c/{companyId}/hooks
Content-Type: application/json

{
    "entity": null,
    "url": "https://your-api.com/webhooks/all-changes",
    "action": "webhook"
}

// Tento webhook bude přijímat oznámení pro VŠECHNY typy entit
// Produkty, kategorie, jednotky, zákazníci, objednávky atd.

Webhook s filtrem podmínky řádku

Získejte oznámení pouze v případě, že řádky splňují specifické podmínky

POST /c/{companyId}/hooks
Content-Type: application/json

{
    "entity": "products",
    "url": "https://your-api.com/webhooks/expensive-products",
    "action": "webhook",
    "filter": "price > 100 AND status = 'active'"
}

// Webhooky obdržíte pouze v případě, že:
// - Entita je 'products'
// - A cena produktu je vyšší než 100
// - A stav produktu je 'active'

Webhook s filtrem sloupců

Spusťte pouze při změně konkrétních sloupců

POST /c/{companyId}/hooks
Content-Type: application/json

{
    "entity": "products",
    "url": "https://your-api.com/webhooks/product-pricing",
    "action": "webhook",
    "columns": ["price", "discount", "tax"]
}

// Webhook se spustí pouze při změně ceny, slevy nebo daně
// Změny názvu, popisu atd. budou ignorovány

Webhook s kombinovanými filtry

Kombinujte entity, podmínky řádků a filtry sloupců

POST /c/{companyId}/hooks
Content-Type: application/json

{
    "entity": "products",
    "url": "https://your-api.com/webhooks/premium-product-pricing",
    "action": "webhook",
    "filter": "price > 100",
    "columns": ["price", "status"]
}

// Trojité filtrování:
// 1. Pouze entita 'products'
// 2. Pouze pokud je cena > 100
// 3. Pouze při změně sloupců cena nebo stav
** Možnosti filtrování webhooku**

**1. Filtrování entity**

Nastavte `entity` pro omezení oznámení na konkrétní typ entity (např. "products", "categories"). Použijte `null` pro příjem oznámení pro všechny entity.

**2. Filtrování podmínky řádku**

Použijte `filter` s klauzulemi where podobnými SQL pro spuštění webhooků pouze v případě, že řádky splňují specifické podmínky (např. "price > 100 AND status = 'active'").

**3. Filtrování změny sloupce**

Zadejte pole `columns` pro spuštění pouze při změně těchto konkrétních sloupců. Ideální pro monitorování aktualizací cen, změn stavu atd.

**4. Kombinované filtrování**

Kombinujte všechny tři filtry pro přesné ovládání: typ entity + podmínky řádků + změny sloupců. Tím se minimalizují zbytečná volání webhooků a zpracování.

Poznámka: Kompletní dokumentaci webhooků včetně logiky opakování, možností filtrování a příkladů datové části naleznete v [navigate:/devdoc/webhooks|Dokumentaci k Webhookům].


Doporučené postupy

Kdy použít updatedAt

  • Jednoduché integrace s periodickými synchronizacemi (hodinové, denní)
  • Pokud jsou odstranění zpracovávána samostatně nebo nejsou potřeba
  • Nízkofrekvenční aktualizace dat
  • Rychlé prototypy a MVP

Kdy použít Changes API

  • Potřeba sledovat všechny operace včetně odstranění
  • Vytváření kompletního systému synchronizace dat
  • Udržování auditní stopy změn
  • Pokud není k dispozici infrastruktura webhooků
  • Dávkové zpracování změn

Kdy použít Webhooks

  • Potřeba aktualizací dat v reálném čase nebo téměř v reálném čase
  • Spouštění okamžitých akcí při změnách dat
  • Automatické udržování synchronizace externích systémů
  • Pokud můžete udržovat veřejně přístupný koncový bod
  • Vysokofrekvenční změny dat vyžadující rychlou odezvu
**Hybridní přístup:**
Zvažte použití webhooků pro aktualizace v reálném čase a Changes API jako zálohu pro zachycení všech zmeškaných změn během výpadků nebo selhání webhooků. To poskytuje to nejlepší z obou světů: aktualizace v reálném čase se zaručenou úplností.