SpeakMap: карта «где говорят по-русски» на Kotlin и PostGIS за 47 дней

· ·

SpeakMap: карта «где говорят по-русски» на Kotlin и PostGIS за 47 дней

PrimeCoder · 2026 · формат: tech

Разбор новинки простыми словами: что это, кому нужно и брать ли.

Кейс для Solo/SMB-разработки: продукт выжил не за счёт фич, а за счёт урезания скоупа втрое при честной статистике доверия к данным.

Связанные услуги: каталог, AI Boost Team, стать клиентом.

47 дней вместо двух с половиной лет

3 сентября 2026 года Евгений, десять лет в тестировании и до недавнего времени QA Lead сервиса транспорта 2ГИС, начал делать карту. Через 47 дней на Android вышла SpeakMap — карта мест, где вас обслужат по-русски: стоматолог, нотариус, автосервис, парикмахер, сантехник на выезде. Открыты Белград и Нови-Сад, в планах Таиланд и Аргентина.

География и пиксельная графика тут вторичны. Первична арифметика, которую автор посчитал до первой строки кода и потом не стал обманывать.

Ядро продукта — достоверность метки

Google Maps знает, что на углу есть стоматология. Он не знает, что администратор там говорит по-русски. Такая информация живёт в чатах релокантов, в бесконечных «посоветуйте русскоязычного врача», и через полгода половина ответов устаревает. Каждый новый человек ищет заново.

Главное в продукте — не карта, а честность метки «здесь говорят по-русски».

Дальше начинается инженерия доверия. Голосовать «да» или «нет» можно без регистрации: форма входа в момент, когда человек стоит на кассе, убивает конверсию голоса, а без голосов у карты нет данных. Доверие к метке считается по нижней границе интервала Уилсона. Один голос «да» ничего не подтверждает. Пять «да» при двух «нет» — тоже.

Такое решение отсекает целый класс сервисов, где «подтверждено» продаётся. Здесь метку нельзя купить, выпросить донатом или получить за статус. Это написано прямо на странице поддержки проекта.

Что под капотом и почему не Google Maps

Kotlin 2.4 с Kotlin Multiplatform — общий слой один на Android и бэкенд. Jetpack Compose на клиенте, Ktor на сервере, PostgreSQL 16 с PostGIS 3.4, MapLibre и собственные векторные тайлы PMTiles вместо Google Maps. Последнее не поза: свои тайлы дают офлайн и свой стиль, а чужая лицензия диктует и цены, и внешний вид.

Бэкенд — модульный монолит в Docker (Caddy, Ktor, PostgreSQL) на одном сервере. 12 архитектурных решений зафиксированы в docs/adr/. Room работает источником правды, поэтому офлайн достаётся без отдельной разработки.

Инфраструктура стоит как один сервер. Для продукта, который живёт на добровольных голосах, это условие выживания, а не статья экономии.

Урезание скоупа втрое — вот главная фича

Спецификация была красивой: шесть городов в трёх странах, кабинет владельца бизнеса, верификация по звонку, очередь модерации, фото, часы работы, три языка. Честный расчёт по ней: 1000–1200 человеко-часов. При 8 часах в неделю и примерно 360 часах в год — около 2,5 года до релиза.

Два с половиной года без единого пользователя это не долгий проект. Это проект, который не доживёт.

В релиз пошло другое. Два города вместо шести, остальные лежат в справочнике выключенными. Один язык вместо трёх, выбор спрятан за флагом, а не удалён. Ноль аккаунтов, ноль OTP, голоса и жалобы привязаны к устройству. Кабинет владельца заменён Google-формой. «Добавить место» — булавка в центре карты, кнопка «Заполнить форму», заранее подставленные город и ссылка на точку в OpenStreetMap, импорт скриптом form_to_import.py.

Не резали три вещи: Kotlin Multiplatform (переделывать потом втрое дороже), Room (даёт офлайн бесплатно) и уровни доверия к метке (это и есть продукт).

Около 45 000 строк кода и больше сотни тестовых файлов. Инфраструктура стоит как один сервер.

Вывод, который переносится на любой соло-проект в SMB: скоуп — единственная переменная, которой вы реально управляете. Всё остальное — сроки, бюджет, нервы — производные от неё.

Кому нужно и что с этим делать

  • Владельцу бизнеса в Белграде или Нови-Саде с русскоязычным персоналом: проверить, есть ли точка на карте, и добавить через форму, если нет. Стоит ноль.
  • Маркетологу, который собирает локальный спрос в диаспоре: метка — точка входа, но не канал трафика. Рекламы и подсветки в релизе нет, ретаргетинга тоже.
  • Разработчику, который планирует сроки: методика «полная оценка → деление на доступные часы в неделю → беспощадное урезание» работает и без Kotlin.

Где подвох

Первый — Google-форма. Пересоздали вопрос, у поля сменился номер entry.*, предзаполнение молча пропало. Ни ошибки, ни лога. Ловится только ручным открытием формы из приложения.

Второй — приватность. Точный адрес частного мастера, который работает из дома, не хранится даже в базе. Для карты это правильно. Для пользователя означает, что часть мест вы найдёте только через контакт, а не по адресу.

Третий — масштабирование руками. Белград компактный, полторы сотни мест там реально обойти ногами. Бангкок и Пхукет так не обойдёшь, а спецификация на них уже сворачивалась. Монетизация в планах — платная подсветка одного места на категорию, и это упирается в принцип «доверие не продаётся»: разницу между подсветкой и меткой придётся объяснять публично.

Четвёртый — аудитория. Это приложение для переезжающих, не инструмент для бизнеса. Трекеров нет, Sentry собирает только ошибки: аналитику по вашей карточке вам никто не покажет.

Брать или подождать

Вердикт за 30 секунд. Вы в Белграде или Нови-Саде, у вас русскоязычный персонал — берите сейчас: добавить точку бесплатно, карта пока не забита. Ждёте канал продаж — ждите: рекламных форматов в релизе нет. Вы разработчик — читайте разбор скоупа, а не код.

Вердикт

Маленький продукт с неожиданно взрослым решением внутри: статистика доверия вместо звёздочек и отзывов. Отзывы, бронирование, оплату и чат с бизнесом не сделали намеренно — каждый пункт удваивает сложность и уводит от вопроса «где меня поймут». Карта без шести городов выглядит скромно. Зато она не врёт про метку, а это здесь единственный актив.

FAQ

Это платно?

Доступ и добавление мест бесплатные. Рекламы в первом релизе нет. Платная подсветка одного места на категорию — планы, не факт.

Нужна регистрация, чтобы проголосовать?

Нет. Голоса и жалобы анонимные, привязаны к устройству.

Почему только Android?

Так собран скоуп. Kotlin Multiplatform держит общий слой готовым к другим платформам, но в релизе одна.

Где хранятся данные?

На своём сервере, PostgreSQL 16 с PostGIS 3.4. Трекеров нет, ошибки собирает Sentry.

Что сделать на этой неделе

Откройте карту и найдите свою категорию в Белграде или Нови-Саде. Нет вашей точки — добавьте через форму, это десять минут и ноль денег. Нет города — заберите отсюда другое: посчитайте свой полный скоуп в человеко-часах, разделите на реальные часы в неделю и посмотрите на получившийся срок. Если он измеряется годами, режьте спецификацию, пока не станет неделями.

Читайте также