> ## Documentation Index
> Fetch the complete documentation index at: https://docs.twenty.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Úložiště typu klíč–hodnota

> Ukládejte průběžné výsledky, kešujte data a sdílejte stav mezi spuštěními logických funkcí pomocí vestavěného aplikačního úložiště typu klíč–hodnota.

Logické funkce běží v izolovaných, krátce žijících procesech Node.js — jakmile běh skončí, nic, co bylo v paměti, nepřežije. Když potřebujete **něco zapamatovat mezi běhy** (kešovat nákladnou odpověď z API, uložit kurzor pro inkrementální synchronizace, odložit práci nebo předat stav z jedné funkce do druhé), uložte to do vestavěného úložiště typu klíč–hodnota.

Každá aplikace má svůj vlastní izolovaný jmenný prostor: položky jsou svázané s ověřenou aplikací, takže vaše klíče nikdy nemohou kolidovat s klíči jiné aplikace ani je jiná aplikace nemůže číst.

```text theme={null}
  ┌─────────────────┐   kv.set(key, value)   ┌──────────────────────────┐
  │ Logic function  │ ─────────────────────▶ │ Application KV store     │
  │ (your handler)  │ ◀───────────────────── │  key (unique)  │  value  │
  └─────────────────┘   kv.get(key)          └──────────────────────────┘
```

## Get, set, delete

Importujte `kv` z `twenty-sdk/logic-function`. Hodnoty mohou být libovolná JSON-serializovatelná data.

```ts src/logic-functions/sync-linear-issues.ts theme={null}
import { kv } from 'twenty-sdk/logic-function';

// Read a value. Returns null when the key is missing.
const cursor = await kv.get<string>('sync-cursor:linear');

// Write a value. Creates the entry on first write, updates it afterwards.
await kv.set('sync-cursor:linear', newCursor);

// Delete an entry. Returns true when an entry was removed.
await kv.delete('sync-cursor:linear');
```

## Rozsahy

Každá položka má rozsah, který se předává jako volba při každém volání. Výchozí hodnota je `WORKSPACE`.

* **`WORKSPACE`** (výchozí) — položka je soukromá pro aktuální instalaci vaší aplikace v pracovním prostoru. Každý pracovní prostor, který aplikaci nainstaluje, získá vlastní nezávislou sadu klíčů. To je to, co chcete pro keše, kurzory a stav na úrovni pracovního prostoru.
* **`SERVER`** — položka je sdílena napříč **všemi instalacemi** vaší aplikace na serveru. Serverové položky se chovají jako **nároky (claims)**: uloženou hodnotou je vždy workspaceId, které klíč nárokuje (vynechte `value` při `set`, abyste klíč nárokovali pro aktuální pracovní prostor) a pouze tento pracovní prostor ji může přepsat nebo smazat. Každá instalace může položku číst.

Serverové nároky existují pro směrování napříč pracovními prostory. [Server-route resolver](/l/cs/developers/extend/apps/logic/logic-functions#server-route-trigger) běží v pracovním prostoru vlastníka registrace aplikace, ale příchozí webhook obvykle nese pouze externí id účtu — nikoli Twenty workspaceId. Nechte každý pracovní prostor, aby si při připojení nárokoval své externí id, a poté ho v routě rozřešte:

```ts theme={null}
// In the connected workspace, when the external account is linked:
await kv.set(`slack:team:${teamId}`, undefined, { scope: 'SERVER' });

// In the server-route resolver (owner workspace), on each webhook:
const workspaceId = await kv.get<string>(`slack:team:${teamId}`, {
  scope: 'SERVER',
});
```

Protože serverový klíč může být nárokován pouze pro vlastní pracovní prostor volajícího a nikdy nemůže být přepsán jiným, pracovní prostor nemůže převzít mapování, které patří někomu jinému. `kv.set` vyvolá výjimku, když je klíč už nárokován jiným pracovním prostorem.

## Použití: kešujte nákladné volání

Typickým použitím je kešování pomalé nebo omezované (rate-limited) odpovědi třetí strany, aby opakované běhy znovu použily výsledek místo placení nákladů při každém spuštění.

```ts src/logic-functions/getExchangeRate.logic-function.ts theme={null}
import { defineLogicFunction } from 'twenty-sdk/define';
import { kv } from 'twenty-sdk/logic-function';

const ONE_HOUR_MS = 60 * 60 * 1000;

type CachedRate = { rate: number; fetchedAt: number };

const handler = async (params: { from: string; to: string }) => {
  const cacheKey = `cache:exchange-rate:${params.from}:${params.to}`;
  const cached = await kv.get<CachedRate>(cacheKey);

  if (cached && Date.now() - cached.fetchedAt < ONE_HOUR_MS) {
    return { rate: cached.rate, cached: true };
  }

  const response = await fetch(
    `https://api.example.com/rate?from=${params.from}&to=${params.to}`,
  );
  const { rate } = (await response.json()) as { rate: number };

  await kv.set(cacheKey, { rate, fetchedAt: Date.now() });

  return { rate, cached: false };
};

export default defineLogicFunction({
  universalIdentifier: 'd9b2f4e6-1c83-4a07-9e52-6b1d3c8a0f47',
  name: 'get-exchange-rate',
  timeoutSeconds: 10,
  handler,
});
```

## Vzorové postupy a tipy

* **Jmenné prostory.** Přidávejte prefixy ke klíčům, abyste oddělili různé oblasti — `sync-cursor:linear`, `cache:exchange-rate:USD:EUR`, `lock:nightly-report`.
* **Expirace (TTL).** Úložiště nemá vestavěnou expiraci. Uložte časové razítko dovnitř hodnoty (jako v příkladu s keší) a při čtení ho kontrolujte, nebo čistěte zastaralé klíče z [funkce spouštěné cronem](/l/cs/developers/extend/apps/logic/logic-functions).
* **Co ukládat.** Jakákoli JSON-serializovatelná hodnota — čísla, řetězce, pole, objekty. Držte záznamy malé; toto je určeno pro koordinaci a kešování, ne pro velké objekty blob nebo soubory. Pro soubory použijte pole `FILES` a [`uploadFile`](/l/cs/developers/extend/apps/logic/logic-functions#uploading-files).
* **Viditelnost.** Položky žijí v databázi instance, ne jako záznamy pracovního prostoru — nikdy se neobjevují v uživatelském rozhraní pracovního prostoru, nejsou součástí datového modelu vaší aplikace a nevyžadují žádná oprávnění k rolím ani objektům.

## Alternativa: dotazovatelný objekt úložiště

Vestavěné úložiště je záměrně neprůhledné: položky nejsou záznamy, takže je nemůžete procházet v UI, propojovat s jinými objekty nebo filtrovat pomocí dotazů na záznamy. Kdykoli něco z toho potřebujete — například viditelný log synchronizace nebo stav na úrovni záznamu — definujte místo toho malý **technický objekt** s jedinečným polem `key` a polem `value` typu `RAW_JSON` a dotazujte ho přes [typovaný API klient](/l/cs/developers/extend/apps/logic/logic-functions#typed-api-clients-twenty-client-sdk). Viz [Objects](/l/cs/developers/extend/apps/data/objects) pro referenci k `defineObject` a [Data → Unique indexes](/l/cs/developers/extend/apps/data/overview#unique-indexes) pro vynucení jedinečnosti klíče.

* **Omezení na záznam.** Přidejte [relaci](/l/cs/developers/extend/apps/data/relations) z objektu úložiště na cílový objekt namísto zakódování id do klíče.
* **Viditelnost a oprávnění.** Řádky žijí v databázi pracovního prostoru jako jakýkoli jiný záznam, takže je lze dotazovat přes API a respektují [role](/l/cs/developers/extend/apps/config/roles) vaší aplikace. Aby se úložiště neobjevovalo v hlavním rozhraní, neuvádějte ho v [navigačním menu](/l/cs/developers/extend/apps/layout/navigation-menu-items).

<Note>
  Na rozdíl od vestavěného úložiště je vlastní objekt vždy omezený na jeden pracovní prostor — nemůže sdílet položky napříč instalacemi tak, jako to dělají klíče `SERVER`.
</Note>
