Store Systems в Mockarty
Содержание
- Обзор Store систем
- Mock Store (MStore)
- Chain Store (CStore)
- Global Store (GStore)
- API для управления Store
- Примеры использования
- Лучшие практики
Совет: Примеры кода доступны для cURL, CLI и SDK-клиентов (Go, Python, Java). Смотрите Руководство по SDK для установки и настройки. Смотрите Руководство по CLI для командной утилиты.
URL-адреса в примерах: Во всех примерах используется
localhost:5770как адрес Mockarty по умолчанию. Если ваш экземпляр работает на удалённом сервере, заменитеlocalhost:5770на реальный адрес (например,https://mockarty.company.comилиhttp://192.168.1.50:5770). Подробнее — в разделе Полезные функции и советы.
Обзор Store систем
Ключевые понятия для начинающих
Прежде чем углубляться в Store-системы, вот несколько ключевых терминов:
- Мок – имитация API-эндпоинта, которая возвращает заранее заданные ответы вместо обращения к реальному сервису.
- Namespace (пространство имён) – логическая группировка моков (как папка). Моки в разных пространствах имён изолированы друг от друга.
- Chain (цепочка) – последовательность связанных моков, которые разделяют состояние. Например, «создать заказ» -> «оплатить заказ» -> «отправить заказ» образуют цепочку.
- Extract (извлечение) – процесс извлечения данных из запроса (или генерации данных) и сохранения их в хранилище для последующего использования.
- JsonPath – язык запросов (например,
$.mS.userId) для обращения к сохранённым значениям в ответах моков.
Файловые шаблоны в интерфейсе
Откройте вкладку Шаблоны на странице Хранилища, чтобы загрузить, просмотреть, скачать, отредактировать или удалить файл в выбранном пространстве имён. Ошибка загрузки списка сопровождается сообщением и кнопкой Повторить; фильтрация не заменяет её пустым списком. Закрытие просмотра или открытие другого файла не позволяет позднему ответу заменить текущий файл. Во время сохранения редактирование текста временно недоступно. Смена пространства имён закрывает просмотр и отменяет ожидающие подтверждения удаления. Уже отправленная загрузка или сохранение может завершиться: после сбоя соединения проверьте список перед повторной отправкой.
Какой Store выбрать
Не уверены, какое хранилище использовать? Вот простое руководство:
- Mock Store (mS) – Используйте, когда нужны временные данные в рамках одного вызова мока. Пример: сгенерировать UUID и использовать его в нескольких местах одного ответа. Данные исчезают после обработки запроса.
- Chain Store (cS) – Используйте, когда нужно передавать данные между связанными моками, образующими рабочий процесс. Пример: процесс регистрации пользователя, где мок регистрации сохраняет userId, а мок профиля его считывает. Данные сохраняются между вызовами в рамках одной цепочки.
- Global Store (gS) – Используйте, когда нужно общее состояние для всех моков в пространстве имён. Пример: счётчики запросов, feature-флаги или системные настройки. Данные сохраняются бессрочно до явной очистки.
Концепция Store
Store - это системы хранения данных в Mockarty, которые позволяют:
- Сохранять данные между вызовами моков
- Обмениваться данными между связанными моками
- Аккумулировать состояние для сложных сценариев
- Создавать динамические ответы на основе накопленных данных с помощью JsonPath и Faker
Архитектура Store
graph TB
subgraph "Store Hierarchy"
MSTORE["Mock Store (mS)"]
CSTORE["Chain Store (cS)"]
GSTORE["Global Store (gS)"]
end
subgraph "Scope"
MOCK_SCOPE["Single Mock"]
CHAIN_SCOPE["Chain of Mocks"]
GLOBAL_SCOPE["All Mocks in Namespace"]
end
subgraph "Persistence"
SESSION["Ephemeral (request only)"]
PERMANENT["Persistent (database)"]
NAMESPACE_ISOLATED["Persistent + Namespace Isolated"]
end
MSTORE --> MOCK_SCOPE
CSTORE --> CHAIN_SCOPE
GSTORE --> GLOBAL_SCOPE
MSTORE --> SESSION
CSTORE --> PERMANENT
GSTORE --> NAMESPACE_ISOLATED
classDef store fill:#4a90d9,stroke:#2c5f8a,color:#fff
classDef scope fill:#8e6fbf,stroke:#5e4590,color:#fff
classDef persistence fill:#5aad6e,stroke:#3a7d4e,color:#fff
class MSTORE,CSTORE,GSTORE store
class MOCK_SCOPE,CHAIN_SCOPE,GLOBAL_SCOPE scope
class SESSION,PERMANENT,NAMESPACE_ISOLATED persistence
Сравнение типов Store
| Store Type | Область видимости | Время жизни | Namespace | JsonPath доступ |
|---|---|---|---|---|
| MStore | Локальный мок | Во время обработки мока | N/A | $.mS.key |
| CStore | Все моки в Chain | Постоянный | ✅ | $.cS.key |
| GStore | Все моки в Namespace | Постоянный | ✅ | $.gS.key |
Интерфейс управления хранилищами
Страница Stores в веб-интерфейсе Mockarty предоставляет визуальный интерфейс для просмотра и управления всеми тремя типами хранилищ. Используйте вкладки вверху для переключения между Global Store, Chain Store и Mock Store.
На вкладке Mock Store нажмите Выбрать мок, чтобы найти его по понятному имени. Список содержит активные моки текущего пространства; архивные моки исключены, о чём сообщает пустое состояние пикера.

Примечание: Запись в хранилища из extract-операций выполняется асинхронно. Значения могут быть недоступны мгновенно при одновременных запросах.
Mock Store (MStore)
Что такое Mock Store?
Mock Store (MStore) - это локальное хранилище данных для конкретного мока, доступное только во время обработки этого мока.

Особенности:
- Изоляция – данные доступны только внутри конкретного мока
- Временность – данные живут только во время обработки запроса
- Быстрота – хранится в памяти мока
- Простота – не требует управления namespace или chainId
Использование MStore
Извлечение в MStore
{
"id": "user-create",
"http": {
"route": "/api/users",
"httpMethod": "POST"
},
"response": {
"payload": {
"id": "$.mS.generatedId",
"name": "$.req.name",
"email": "$.req.email",
"clientIP": "$.mS.clientIP",
"userAgent": "$.mS.userAgent"
}
},
"extract": {
"mStore": {
"generatedId": "$.fake.UUIDDigit",
"requestTime": "$.fake.RFC3339",
"clientIP": "$.reqHeader['X-Forwarded-For'][0]",
"userAgent": "$.reqHeader['User-Agent'][0]",
"requestCount": "$.increment($.gS.requestCount || 0)"
}
}
}
Доступ к MStore в ответе
{
"response": {
"payload": {
"userId": "$.mS.generatedId",
"processedAt": "$.mS.requestTime",
"metadata": {
"clientIP": "$.mS.clientIP",
"userAgent": "$.mS.userAgent",
"requestCount": "$.mS.requestCount"
}
}
}
}
Типичные случаи использования MStore
-
Генерация связанных ID:
"extract": { "mStore": { "userId": "$.fake.UUIDDigit", "profileId": "$.fake.UUIDDigit", "sessionId": "$.fake.UUID" } } -
Обработка метаданных запроса:
"extract": { "mStore": { "timestamp": "$.fake.RFC3339", "requestId": "$.fake.UUID", "traceId": "$.reqHeader['X-Trace-ID'][0]" } } -
Математические вычисления:
"extract": { "mStore": { "basePrice": "$.req.price", "tax": "$.multiply($.req.price, 0.2)", "totalPrice": "$.sum($.req.price, $.mS.tax)" } }
Chain Store (CStore)
Что такое Chain Store?
Chain Store (CStore) - это разделяемое хранилище данных между всеми моками с одинаковым chainId в рамках одного namespace.

Особенности:
- Разделяемость – данные доступны всем мокам в цепочке
- Персистентность – данные сохраняются между вызовами
- Namespace изоляция – данные изолированы по namespace
- Аккумуляция – данные накапливаются по мере выполнения цепочки
Жизненный цикл CStore
sequenceDiagram
participant M1 as Mock 1
participant CS as Chain Store
participant M2 as Mock 2
participant M3 as Mock 3
M1->>CS: Extract data (step 1)
CS-->>M1: Store updated
M2->>CS: Read data from step 1
CS-->>M2: Return step 1 data
M2->>CS: Extract additional data (step 2)
CS-->>M2: Store updated
M3->>CS: Read data from steps 1 & 2
CS-->>M3: Return accumulated data
M3->>CS: Extract final data (step 3)
CS-->>M3: Store updated (complete)
Использование CStore
Начальный мок в цепочке
{
"id": "order-start",
"chainId": "order-processing",
"namespace": "e-commerce",
"http": {
"route": "/api/orders/create",
"httpMethod": "POST"
},
"response": {
"payload": {
"orderId": "$.fake.UUIDDigit",
"status": "created",
"items": "$.req.items"
}
},
"extract": {
"cStore": {
"orderId": "$.fake.UUIDDigit",
"customerId": "$.req.customerId",
"items": "$.req.items",
"totalAmount": "$.req.totalAmount",
"createdAt": "$.fake.RFC3339",
"currentStep": "created"
}
}
}
Промежуточный мок в цепочке
{
"id": "order-payment",
"chainId": "order-processing",
"namespace": "e-commerce",
"http": {
"route": "/api/orders/payment",
"httpMethod": "POST"
},
"response": {
"payload": {
"orderId": "$.cS.orderId",
"customerId": "$.cS.customerId",
"amount": "$.cS.totalAmount",
"paymentId": "$.fake.UUIDDigit",
"status": "paid"
}
},
"extract": {
"cStore": {
"paymentId": "$.fake.UUIDDigit",
"paidAt": "$.fake.RFC3339",
"paymentMethod": "$.req.paymentMethod",
"currentStep": "paid"
}
}
}
Финальный мок в цепочке
{
"id": "order-fulfill",
"chainId": "order-processing",
"namespace": "e-commerce",
"http": {
"route": "/api/orders/fulfill",
"httpMethod": "POST"
},
"response": {
"payload": {
"orderId": "$.cS.orderId",
"customerId": "$.cS.customerId",
"paymentId": "$.cS.paymentId",
"trackingNumber": "$.fake.ZipCode",
"estimatedDelivery": "$.fake.Date",
"orderSummary": {
"items": "$.cS.items",
"totalAmount": "$.cS.totalAmount",
"createdAt": "$.cS.createdAt",
"paidAt": "$.cS.paidAt",
"fulfilledAt": "$.fake.RFC3339"
}
}
},
"extract": {
"cStore": {
"trackingNumber": "$.fake.ZipCode",
"fulfilledAt": "$.fake.RFC3339",
"currentStep": "fulfilled",
"isComplete": true
}
}
}
API для Chain Store
Как найти цепочку
Поля Chain ID (страница хранилищ, «Создать моки» из неопознанных запросов, область хранилища в темпоральной пробе) подсказывают цепочки вашего пространства имён по мере ввода — все, что используются моками или хранят ключи, с числом моков и ключей. Тот же список через API:
GET /api/v1/stores/chains?namespace=e-commerce&q=order
{"items":[{"chainId":"order-processing","mockCount":3,"storeKeys":5}]}
Получение данных Chain Store
GET /api/v1/stores/chain/{chainId}?namespace=e-commerce
Добавление данных в Chain Store
Каждый запрос добавляет одну пару ключ-значение. Для добавления неск��льких записей выполните отдельные запросы для каждого ключа.
POST /api/v1/stores/chain/order-processing
Content-Type: application/json
{
"key": "manualStep",
"value": "admin-review",
"namespace": "e-commerce"
}
Удаление данных из Chain Store
Удаление одного ключа через URL-путь:
DELETE /api/v1/stores/chain/order-processing/temporaryData?namespace=e-commerce
Global Store (GStore)
Что такое Global Store?
Global Store (GStore) - это глобальное хранилище данных, доступное всем мокам в рамках одного namespace.

Особенности:
- Глобальность – данные доступны всем мокам в namespace
- Персистентность – данные сохраняются между всеми вызовами
- Namespace изоляция – данные изолированы по namespace
- Аккумуляция – идеально для счетчиков и статистики
Использование GStore
Счетчики и статистика
{
"id": "api-request-counter",
"namespace": "monitoring",
"http": {
"route": "/api/*"
},
"response": {
"payload": {
"requestId": "$.fake.UUID",
"timestamp": "$.fake.RFC3339",
"stats": {
"totalRequests": "$.increment($.gS.totalRequests || 0)",
"todayRequests": "$.increment($.gS.todayRequests || 0)",
"uniqueUsers": "$.gS.uniqueUsers"
}
}
},
"extract": {
"gStore": {
"totalRequests": "$.increment($.gS.totalRequests || 0)",
"todayRequests": "$.increment($.gS.todayRequests || 0)",
"lastRequestAt": "$.fake.RFC3339",
"lastUserID": "$.reqHeader['X-User-ID'][0]"
}
}
}
Системные настройки
{
"id": "system-config",
"namespace": "system",
"http": {
"route": "/api/config"
},
"response": {
"payload": {
"config": {
"version": "$.gS.systemVersion",
"maintenanceMode": "$.gS.maintenanceMode",
"features": "$.gS.enabledFeatures",
"lastUpdated": "$.gS.configLastUpdated"
}
}
},
"extract": {
"gStore": {
"configAccessed": "$.increment($.gS.configAccessed || 0)",
"lastConfigAccess": "$.fake.RFC3339"
}
}
}
Глобальные состояния
{
"id": "feature-toggle",
"namespace": "features",
"http": {
"route": "/api/features/status"
},
"response": {
"payload": {
"feature": "$.req.featureName",
"enabled": "$.gS.features.newDashboard.enabled",
"config": "$.gS.features.newDashboard.config",
"rolloutPercentage": "$.gS.features.newDashboard.rollout"
}
},
"extract": {
"gStore": {
"featureAccessCount": "$.increment($.gS.featureAccessCount || 0)",
"lastFeatureAccess": "$.fake.RFC3339"
}
}
}
API для Global Store
Получение данных Global Store
GET /api/v1/stores/global?namespace=monitoring
Добавление данных в Global Store
Каждый запрос добавляет одну пару ключ-значение. Для добавления нескольких записей выполните отдельные запросы для каждого ключа.
POST /api/v1/stores/global
Content-Type: application/json
{
"key": "systemVersion",
"value": "1.2.3",
"namespace": "monitoring"
}
Удаление данных из Global Store
Удаление одного ключа через URL-путь:
DELETE /api/v1/stores/global/oldConfig?namespace=monitoring
API для управления Store
Полная справка API
Полную документацию API см. в Справочнике API.
Global Store Endpoints
| Method | Endpoint | Описание |
|---|---|---|
| GET | /api/v1/stores/global |
Получить Global Store |
| POST | /api/v1/stores/global |
Добавить пару ключ-значение в Global Store |
| DELETE | /api/v1/stores/global/{key} |
Удалить ключ из Global Store |
Query Parameters:
namespace(optional) - пространство (default: “sandbox”)
POST Body: {"key": "...", "value": "...", "namespace": "..."}
Chain Store Endpoints
| Method | Endpoint | Описание |
|---|---|---|
| GET | /api/v1/stores/chain/{chainId} |
Получить Chain Store |
| GET | /api/v1/stores/chains |
Список цепочек пространства имён (q — фильтр по id) |
| POST | /api/v1/stores/chain/{chainId} |
Добавить пару ключ-значение в Chain Store |
| DELETE | /api/v1/stores/chain/{chainId}/{key} |
Удалить ключ из Chain Store |
Path Parameters:
chainId- ID цепочкиkey- удаляемый ключ (только для DELETE)
Query Parameters:
namespace(optional) - пространство (default: “sandbox”)
POST Body: {"key": "...", "value": "...", "namespace": "..."}
Примеры API вызовов
Добавление в Global Store
Каждый вызов API добавляет одну пару ключ-значение. Для нескольких ключей выполните отдельные запросы.
cURL
# Добавить пару ключ-значение в Global Store
curl -X POST http://localhost:5770/api/v1/stores/global \
-H "Content-Type: application/json" \
-d '{"key": "appVersion", "value": "1.0.0", "namespace": "testing"}'
# Добавить ещё один ключ
curl -X POST http://localhost:5770/api/v1/stores/global \
-H "Content-Type: application/json" \
-d '{"key": "environment", "value": "testing", "namespace": "testing"}'
CLI
mockarty-cli store global set --namespace testing appVersion "1.0.0"
mockarty-cli store global set --namespace testing environment "testing"
Go
import mockarty "github.com/mockarty/mockarty-go"
client := mockarty.NewClient("http://localhost:5770", "YOUR_TOKEN")
// Namespace задаётся при создании клиента (mockarty.WithNamespace("testing"))
err := client.Stores().GlobalSet(ctx, "appVersion", "1.0.0")
err = client.Stores().GlobalSet(ctx, "environment", "testing")
Python
from mockarty import MockartyClient
client = MockartyClient("http://localhost:5770", token="YOUR_TOKEN")
# Namespace задаётся при создании клиента (MockartyClient(..., namespace="testing"))
client.stores.global_set(key="appVersion", value="1.0.0")
client.stores.global_set(key="environment", value="testing")
Java
import ru.mockarty.MockartyClient;
MockartyClient client = new MockartyClient("http://localhost:5770", "YOUR_TOKEN");
client.stores().globalSet("testing", "appVersion", "1.0.0");
client.stores().globalSet("testing", "environment", "testing");
Добавление в Chain Store
cURL
curl -X POST http://localhost:5770/api/v1/stores/chain/user-journey \
-H "Content-Type: application/json" \
-d '{"key": "journeyStarted", "value": "true", "namespace": "testing"}'
curl -X POST http://localhost:5770/api/v1/stores/chain/user-journey \
-H "Content-Type: application/json" \
-d '{"key": "startTime", "value": "2024-01-01T10:00:00Z", "namespace": "testing"}'
CLI
mockarty-cli store chain set --namespace testing user-journey journeyStarted "true"
mockarty-cli store chain set --namespace testing user-journey startTime "2024-01-01T10:00:00Z"
Go
err := client.Stores().ChainSet(ctx, "user-journey", "journeyStarted", "true")
err = client.Stores().ChainSet(ctx, "user-journey", "startTime", "2024-01-01T10:00:00Z")
Python
client.stores.chain_set(chain_id="user-journey", key="journeyStarted", value="true")
client.stores.chain_set(chain_id="user-journey", key="startTime", value="2024-01-01T10:00:00Z")
Java
client.stores().chainSet("user-journey", "testing", "journeyStarted", "true");
client.stores().chainSet("user-journey", "testing", "startTime", "2024-01-01T10:00:00Z");
Удаление данных из Store
Удаление одного ключа за запрос через URL-путь.
cURL
# Удалить ключ из Global Store
curl -X DELETE http://localhost:5770/api/v1/stores/global/tempData?namespace=testing
# Удалить ключ из Chain Store
curl -X DELETE http://localhost:5770/api/v1/stores/chain/user-journey/debugData?namespace=testing
CLI
# Удалить ключ из Global Store
mockarty-cli store global delete --namespace testing tempData
# Удалить ключ из Chain Store
mockarty-cli store chain delete --namespace testing user-journey debugData
Go
// Удалить ключ из Global Store
err := client.Stores().GlobalDelete(ctx, "tempData")
// Удалить ключ из Chain Store
err = client.Stores().ChainDelete(ctx, "user-journey", "debugData")
Python
# Удалить ключ из Global Store
client.stores.global_delete(key="tempData")
# Удалить ключ из Chain Store
client.stores.chain_delete(chain_id="user-journey", key="debugData")
Java
// Удалить ключ из Global Store
client.stores().globalDelete("testing", "tempData");
// Удалить ключ из Chain Store
client.stores().chainDelete("user-journey", "testing", "debugData");
Примеры использования
В предыдущих разделах уже показаны базовые паттерны для каждого типа хранилища – счётчики, конфигурация и цепочки моков. Примеры ниже демонстрируют более сложные сценарии, которые комбинируют несколько типов Store или показывают межхранилищное взаимодействие.
Сложные Chain сценарии
Multi-step Workflow
{
"id": "workflow-step-1",
"chainId": "approval-workflow",
"namespace": "workflows",
"http": {
"route": "/api/workflow/submit",
"httpMethod": "POST"
},
"response": {
"payload": {
"workflowId": "$.fake.UUIDDigit",
"status": "submitted",
"submittedBy": "$.req.userId",
"nextStep": "manager-review"
}
},
"extract": {
"cStore": {
"workflowId": "$.fake.UUIDDigit",
"submittedBy": "$.req.userId",
"submittedAt": "$.fake.RFC3339",
"currentStep": "submitted",
"steps": ["submitted"],
"approvalChain": ["manager", "director", "ceo"]
},
"gStore": {
"totalWorkflows": "$.increment($.gS.totalWorkflows || 0)"
}
}
}
{
"id": "workflow-step-2",
"chainId": "approval-workflow",
"namespace": "workflows",
"http": {
"route": "/api/workflow/approve",
"httpMethod": "POST"
},
"response": {
"payload": {
"workflowId": "$.cS.workflowId",
"approvedBy": "$.req.approverId",
"currentStep": "manager-approved",
"nextStep": "director-review",
"progress": {
"submittedBy": "$.cS.submittedBy",
"submittedAt": "$.cS.submittedAt",
"percentage": 33
}
}
},
"extract": {
"cStore": {
"managerApprovedBy": "$.req.approverId",
"managerApprovedAt": "$.fake.RFC3339",
"currentStep": "manager-approved"
}
}
}
Отслеживание экспериментов с Store
Отслеживание назначений экспериментов
{
"id": "experiment-tracker",
"namespace": "experiments",
"http": {
"route": "/api/experiment/assign",
"httpMethod": "POST"
},
"response": {
"payload": {
"userId": "$.req.userId",
"experiment": "new-checkout-flow",
"variant": "$.req.variant",
"assignedAt": "$.fake.RFC3339",
"totalAssignments": "$.gS.totalAssignments"
}
},
"extract": {
"gStore": {
"totalAssignments": "$.increment($.gS.totalAssignments || 0)",
"lastAssignedUser": "$.req.userId",
"lastAssignedVariant": "$.req.variant",
"lastAssignedAt": "$.fake.RFC3339"
}
}
}
Лучшие практики
Рекомендации
-
Используйте правильный тип Store для задач:
- MStore - для временных вычислений внутри мока
- CStore - для передачи данных между этапами сценария
- GStore - для глобальных счетчиков и настроек
-
Структурируйте данные в Store:
"extract": { "gStore": { "users": { "total": "$.increment($.gS.users.total || 0)", "active": "$.gS.users.active || 0", "lastRegistered": "$.fake.RFC3339" }, "stats": { "requests": "$.increment($.gS.stats.requests || 0)", "errors": "$.gS.stats.errors || 0" } } } -
Используйте осмысленные ключи:
Хорошо – описательное имя ключа, объясняющее что считается:
"userRegistrationCount": "$.increment($.gS.userRegistrationCount || 0)"Плохо – общее имя ключа, не несущее смысла:
"count": "$.increment($.gS.count || 0)" -
Инициализируйте значения по умолчанию:
С default (рекомендуется) – использует
|| 0для старта с нуля, если ключ не существует:"totalUsers": "$.increment($.gS.totalUsers || 0)"Без default (рискованно) – может завершиться ошибкой, если ключ ещё не был установлен:
"totalUsers": "$.increment($.gS.totalUsers)" -
Группируйте связанные данные:
"extract": { "cStore": { "order": { "id": "$.fake.UUIDDigit", "createdAt": "$.fake.RFC3339", "status": "created" }, "customer": { "id": "$.req.customerId", "email": "$.req.email" } } }
Что избегать
- Не храните чувствительные данные в Store (пароли, токены)
- Не создавайте слишком глубокие вложенности (>3 уровней)
- Не забывайте про namespace изоляцию
- Не используйте Store для простых статических ответов
- Не переполняйте Store большими объектами данных
Управление данными
Очистка устаревших данных
{
"id": "cleanup-stores",
"namespace": "maintenance",
"http": {
"route": "/api/maintenance/cleanup"
},
"extract": {
"gStore": {
"tempData": null,
"debugInfo": null,
"lastCleanup": "$.fake.RFC3339",
"cleanupCount": "$.increment($.gS.cleanupCount || 0)"
}
}
}
Архивация данных
{
"id": "archive-data",
"extract": {
"gStore": {
"archived": {
"data": "$.gS.currentData",
"archivedAt": "$.fake.RFC3339"
},
"currentData": null
}
}
}
Используйте Store системы для создания мощных динамических сценариев с сохранением состояния!
Смотрите также
- Руководство по JsonPath – язык запросов для доступа и манипуляции данными Store
- Справочник Faker-функций – генерация случайных данных для заполнения Store
- Справочник API – полный REST API для управления Store
- Руководство по веб-интерфейсу – управление Store через веб-интерфейс
- Вебхуки и обратные вызовы – использование данных Store в webhook-ах