Стек: Rust / Actix-web на бэкенде; PostgreSQL + PostGIS, ScyllaDB, Qdrant, SereneDB, Iggy — пять хранилищ, каждое под свой профиль нагрузки; React + Vike на фронтенде; эскроу — смарт-контракт на Solana. Масштаб: 30 000+ объектов в каталоге на старте. Особенности: RAG-агент, который бронирует по запросу на естественном языке; чат гость↔хозяин в реальном времени; on-chain эскроу вместо ручных выплат. Продукт: pinns.io — жильё и активности от реальных хозяев.
Контекст
Pinns — travel-платформа: жильё и активности от реальных хозяев, поиск на естественном языке вместо стены фильтров, деньги гостя — в крипто-эскроу, а не на балансе платформы.
Три продуктовых решения определили всю инженерию:
- Поиск словами, а не фильтрами. Гость пишет «домик у моря на четверых, чтобы можно было готовить» — и получает реальные доступные объекты, а не результат подбора по галочкам. Значит, нужен смысловой поиск и AI-агент, который не выдумывает ответы.
- Деньги не оседают на платформе. Оплата блокируется в смарт-контракте и уходит хозяину автоматически. Значит, платёжный контур должен быть безошибочным по построению — ручных компенсаций «саппортом» здесь нет.
- Общение остаётся внутри платформы. Обсуждение заезда, документов и точного адреса не должно утекать в сторонние мессенджеры — значит, нужен собственный чат в реальном времени, который удобнее, чем «перейти в телеграм».
Ниже — почему для этого выбран именно такой стек и как эти решения устроены внутри.
Стек, выбранный под нагрузку
Принцип архитектуры: под каждой задачей — своя нагрузка, и своя технология под неё. Вместо «одна база на всё» — пять хранилищ, каждое на своём профиле:
| Технология | Зачем именно она |
|---|---|
| Rust · Actix-web | Идеальный фит под хайлоад: производительность на уровне C++ и безопасность памяти без сборщика мусора. Actix обеспечивает асинхронность поверх tokio с минимальными накладными расходами на запрос — это определяет пропускную способность под нагрузкой. |
| PostgreSQL + PostGIS | Бронирование и деньги — операции, где нужны строгие ACID-гарантии, а не eventual consistency, зависящая от порядка доставки событий. PostGIS расширяет Postgres геоиндексами: поиск по карте выполняется индексом внутри базы, а не перебором координат в коде приложения. |
| ScyllaDB | Сообщения чата и лента растут значительно быстрее каталога, и это преимущественно запись без сложных джойнов. Такой поток в Postgres упирается в дисковую подсистему раньше, чем в реальный предел нагрузки — нужен движок, изначально спроектированный под этот паттерн записи. |
| Qdrant | AI-агенту нужен поиск по смысловой близости, а не сравнение значений в колонках — принципиально другой класс запросов. В реляционной базе он либо выполняется медленно, либо требует индекса, которого там изначально не предусмотрено. |
| SereneDB | На карте с десятками тысяч объектов нельзя отрисовывать каждую точку отдельно — нужна кластеризация по мере зума. SereneDB группирует объявления по префиксу geohash прямо в запросе: кластеры на карте считаются одним SQL-запросом в базе, а не пересчитываются на клиенте. |
| Iggy | Сервисы не должны обращаться в чужую базу напрямую — только обмениваться событиями. Брокер сообщений в духе Kafka, реализованный на Rust: та же модель партиций и та же гарантия at-least-once, но без JVM в рантайме. |
| React · Vike | Vike даёт SSR на Vite без опинионированных ограничений Next.js — полный контроль над рендерингом и роутингом там, где карта, стриминг AI-чата и нестандартная гидратация требуют гибкости, а не готового каркаса. |
Каждое хранилище закрывает свой профиль: транзакции — Postgres, поток записи — Scylla, смысловой поиск — Qdrant, гео-кластеризация карты — SereneDB, шина событий — Iggy.
RAG-агент, который реально бронирует
Гость пишет так, как сказал бы другу: «домик у моря на четверых, чтобы можно было готовить». Агент не додумывает ответ — он обращается к реальному поиску по каталогу поверх Qdrant, где гео- и смысловой поиск считаются одним запросом, а затем подтягивает актуальные детали и доступность по конкретному объекту. Каждая карточка в ответе — реальный объект из каталога, а не выдумка модели.
Отвечает не одна модель, а каскад из нескольких LLM-провайдеров с прозрачным переключением внутри одного диалога: если основной недоступен, запрос уходит следующему — и гость этого даже не замечает.
Чат гость↔хозяин в реальном времени
Обсуждение заезда, документов, точного адреса идёт прямо внутри платформы, а не утекает в мессенджеры на стороне. Доставка сообщений — через WebSocket, без задержек на поллинг, а хранится поток сообщений в ScyllaDB — той самой, что рассчитана на чистую запись.
Эскроу на Solana, без ручных выплат
Оплата гостя блокируется в смарт-контракте, а не оседает на балансе компании: хозяин получает деньги автоматически по истечении окна отмены, а при споре решение выносит арбитраж on-chain.
Тонкое место таких схем — согласованность: на статус брони способны повлиять и вебхук, и планировщик одновременно. Здесь изменения проходят через единственный командный топик в Iggy — это структурно исключает гонку между конкурирующими триггерами: все команды на изменение статуса выстраиваются в одну упорядоченную очередь.
Что из этого переносимо в ваши проекты
Кейс Pinns — это три инженерных паттерна, которые применимы далеко за пределами travel:
- Хранилище под профиль нагрузки, а не «одна база на всё». Транзакции, поток записи, смысловой поиск и гео-кластеризация — разные классы задач; смешивание их в одной СУБД оплачивается деньгами на железо и инцидентами.
- RAG вместо «чат-бота, который галлюцинирует». Агент, отвечающий только реальными объектами из каталога с проверкой доступности, — рабочая схема для любого маркетплейса, каталога или базы знаний.
- События вместо прямых записей в чужие базы. Единственный командный топик для изменения критичного состояния структурно исключает целый класс гонок — независимо от того, эскроу это, баланс или статус заказа.
Если у вас похожая задача — высоконагруженный маркетплейс, платёжный контур с жёсткими гарантиями, AI-поиск по каталогу — расскажите о ней через форму на сайте: покажем, как эти паттерны лягут на ваш случай.