Skip to content

Instantly share code, notes, and snippets.

@v0ff4k
Last active May 6, 2026 17:35
Show Gist options
  • Select an option

  • Save v0ff4k/10deca9aaf6797aad362e7512525a66d to your computer and use it in GitHub Desktop.

Select an option

Save v0ff4k/10deca9aaf6797aad362e7512525a66d to your computer and use it in GitHub Desktop.
1 geo-lead-mindflow

Ход мышления


    Сущности предметной области:
        Товар (Product) — уникальный товар, не зависит от ГЕО.
        ГЕО (GeoRegion) — страна или регион со своей валютой.
        Цена товара в ГЕО (ProductPriceInGeo) — базовая цена + доставка для конкретного товара в конкретном ГЕО.
        Лид (Lead) — событие интереса к товару в определённом ГЕО (временная метка, возможно ID пользователя).
        Коэффициент цены (PriceAdjustment) — динамический множитель, зависящий от количества лидов за окно (например, 10 минут).
    Бизнес-логика:
        Цена = Базовая цена × Коэффициент.
        Коэффициент пересчитывается каждые 10 минут на основе количества лидов за предыдущие 10 минут.
        Лиды привязаны к паре (Product, GeoRegion).
        Валюта фиксируется на уровне GeoRegion.
    Требования к данным:
        Хранить историю лидов (для аналитики и пересчёта).
        Хранить текущий коэффициент (или пересчитывать "на лету").
        Обеспечить быстрый доступ к актуальной цене при показе товара.
    Архитектурные решения:
        Используем реляционную БД (PostgreSQL/MySQL).
        Коэффициент можно хранить в отдельной таблице и обновлять по расписанию (cron / scheduler).
        Альтернатива: кэшировать цену в Redis с TTL = 10 мин.

Схема:

по https://www.plantuml.com/plantuml/


@startuml
class Product {
  +id: UUID
  +name: string
  +sku: string
}

class GeoRegion {
  +id: UUID
  +name: string
  +currency: string
}

class ProductPriceInGeo {
  +id: UUID
  +base_price: decimal
  +shipping_cost: decimal
}

class Lead {
  +id: UUID
  +created_at: datetime
}

class PriceAdjustment {
  +id: UUID
  +adjustment_factor: float
  +valid_from: datetime
  +valid_to: datetime
  +leads_count: int
}

Product "1" -- "0..*" ProductPriceInGeo : has
GeoRegion "1" -- "0..*" ProductPriceInGeo : has
ProductPriceInGeo "1" -- "0..*" Lead : generates
ProductPriceInGeo "1" -- "1" PriceAdjustment : current adjustment
@enduml

Screen of a UML image

database

Регистрация лида

INSERT INTO lead (product_geo_id, created_at)
VALUES (
  (SELECT id FROM product_price_in_geo 
   WHERE product_id = 'prod-123' AND geo_id = 'geo-us'),
  NOW()
);

Пересчёт коэффициента (каждые 10 минут, фоновая задача)

-- Шаг 1: Подсчёт лидов за последние 10 минут по каждому product_geo
WITH recent_leads AS (
  SELECT 
    product_geo_id,
    COUNT(*) AS lead_count
  FROM lead
  WHERE created_at >= NOW() - INTERVAL 10 MINUTE
  GROUP BY product_geo_id
)

-- Шаг 2: Обновление коэффициента
UPDATE price_adjustment pa
SET 
  adjustment_factor = calculate_coefficient(rl.lead_count), -- функция бизнес-логики
  leads_count = rl.lead_count,
  valid_from = NOW(),
  valid_to = NOW() + INTERVAL 10 MINUTE
FROM recent_leads rl
WHERE pa.product_geo_id = rl.product_geo_id;
Функция calculate_coefficient(n) может быть, например:
factor = MAX(0.7, 1.0 - 0.01 * n) — чем больше лидов, тем ниже цена (но не ниже 70%).

Получение актуальной цены для отображения

SELECT 
  p.name,
  g.currency,
  (ppg.base_price + ppg.shipping_cost) * pa.adjustment_factor AS final_price
FROM product p
JOIN product_price_in_geo ppg ON p.id = ppg.product_id
JOIN geo_region g ON ppg.geo_id = g.id
JOIN price_adjustment pa ON ppg.id = pa.product_geo_id
WHERE 
  p.sku = 'ABC123'
  AND g.name = 'US'
  AND NOW() BETWEEN pa.valid_from AND pa.valid_to;

Хранение

Реляционная БД:

Product - Каталог товаров
GeoRegion - Справочник регионов и валют
ProductPriceInGeo - Базовые цены + доставка
Lead - История лидов (журнал событий)
PriceAdjustment - Текущий коэффициент (актуальная запись)

Redis / Memcached

Кэш final_price на 10 мин для снижения нагрузки

Планировщик (Scheduler)

Задача запускается каждые 10 минут (например, через cron или Laravel/Symfony scheduler).
Выполняет:
    Подсчёт лидов за окно.
    Пересчёт коэффициентов.
    Обновление price_adjustment.
    Инвалидация кэша (если используется).

Возможные улучшения

Историзация коэффициентов: хранить все версии PriceAdjustment для аналитики.
Очередь лидов: если нагрузка высока — писать лиды в Kafka/RabbitMQ → обрабатывать асинхронно.
Материализованное представление: для быстрого доступа к final_price.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment