Привет, сообщество! Уже долгое время я отмечал на для себя на карте бесплатные парковочные места в центре города; Этот список быстро начал "ходить по рукам" среди друзей и знакомых. Мне пришла в голову идея, а что если развить "списочек для друзей" в какой-то более общественно полезный проект? И с какими техническими челленджами придется столкнуться при попытке навайбкодить мало-мальски production-ready приложение?

Так появилась ГдеПарковка — карта бесплатных парковок, которую наполняют сами водители. Без регистрации: открыл, нашёл место рядом, поехал. Можно добавить точку, фото, комментарий, проголосовать «место живо / места нет», уточнить вместимость и построить маршрут в Яндекс Картах, 2ГИС или Google Maps.

Но ведь платные парковки существуют не просто так!

Легко понять негодование жителей центральных районов, которые не любят шум машин под окнами, а для своей машины, как зеницу ока, оберегают бесплатные "островки". Но треть пробок в центре — это машины, которые уже приехали. Они не едут из точки А в точку Б, они кружат по кварталу в поисках места. Классические исследования городского трафика (Дональд Шуп, UCLA) оценивают долю «поискового» трафика в загруженных районах в 20–30%. Водитель, который заранее знает, где встать, проезжает по вашему району один раз, а не наматывает пять кругов мимо окон, дворов и детских площадок. Карта парковок не добавляет машин в город. Она сокращает самый бессмысленный и раздражающий их пробег.

Да и даже жители центра зачастую стеснены в перемещениях платными парковками. Тот же житель Центрального района Санкт-Петербурга, даже имея прописку, не может просто так поехать по делам в Адмиралтейский район, даже если он начинается через квартал - льготные разрешения действуют только в рамках одного района.

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

Это социальный сервис, а не игрушка. Платная парковка в центре Петербурга стоит до 360 рублей в час, а в Москве еще в пару раз дороже. И пускай для офисного работника с парковкой от работодателя это мелочь, то для медсестры на смене, курьера, сантехника по вызову, человека, который возит родственника в больницу через день, это тысячи рублей в месяц из семейного бюджета. Информация о бесплатных местах всегда существовала — просто раньше она была привилегией местных и «своих». Цель сервиса - устранить эту несправедливость.

  • «Понаедут чужие в наш двор» — двор публикует только тот, кто хочет. Ваш двор без вас на карте не появится, а если появился и мешает, то жалуйтесь, уберём.

  • «Из-за вас больше машин» — количество машин определяется работой и делами, а не картой. Карта сокращает круги по кварталу, а не создаёт поездки.

  • «Пусть платят за парковку» — платят те, кто может. Остальные и так ищут бесплатные места, только медленно и объезжая по три раза ваш квартал.

  • «Вы легализуете парковку где попало» — наоборот: рейтинг и комментарии топят плохие места, а дисклеймер прямо требует проверять знаки. У хаоса появился фильтр.

Техническая часть

Я не написал руками ни строчки кода. Весь проект — от схемы БД до деплоя — сделан в диалоге с Claude Code, за пару вечеров, с помощью модели Fable.

Босяцкий хак проекта: импорт из закладок Яндекс Карт

У меня была своя подборка из 68 бесплатных парковок Петербурга в закладках Яндекс Карт. Экспорта у Яндекса нет. Зато можно поделиться своей подборкой по ссылке, и публичная подборка это SSR, и в HTML лежит <script class="state-view"> с полным JSON-состоянием, включая все точки:

const state = JSON.parse(html.match(/<script[^>]*class="state-view"[^>]*>(.*?)<\/script>/s)[1]);
const items = state.config.bookmarksPublicList.children;
// { title: "Парковка", uri: "ymapsbm1://pin?ll=30.290309%2C59.970660",
//   description: "Санкт-Петербург, улица Профессора Попова, 40" }

Координаты достаются прямо из ymapsbm1://pin?ll=.... Скрипт импорта идемпотентен — точки ближе 30 метров к существующим пропускаются, так что его можно гонять повторно. Так у сервиса в день запуска появился стартовый каталог по Петербургу, а не пустая карта.

Стек

Я придерживаюсь мнения, что при кодинге с ИИ-шкой лучше использовать хорошо задокументированные и скучные технологии. Грубо говоря, используя модный и не сильно хорошо описанный фреймворк, либо сильно меняющийся между версиями, то он будет слабее отражен в весах модели, и будут возникать ошибки. Помню, как я писал экспорт скрипты для KIWI TCMS, и клод вообще не мог сконструировать валидный запрос, пока я не копипастнул ему в контекст избранные файлы из имплементации самого KIWI TCMS, только тогда он разобрался в формате апишки. Поэтому в промпте был заложен принцип: никаких фреймворков. Такое тривиальное архитектурное решение сработало вполне хорошо!

  • Бэкенд: Node.js + Express + SQLite. Причём не better-sqlite3, а встроенный node:sqlite из Node 22+ — ноль нативных зависимостей, npm install не может сломаться в принципе.

  • Фронтенд: vanilla JS + Leaflet с тайлами OSM. Без сборки вообще — файлы из public/ отдаются как есть. Никакого вебпака, вайта, транспиляции. Деплой фронта — это git pull.

  • Зависимостей в package.json — четыре: express, multer, sharp, compression. И leaflet, который отдаётся статикой из node_modules.

В сумме: один процесс, одна БД-файл, один каталог data/ со всем состоянием. Бэкап — это sqlite3.backup плюс rsync каталога фотографий, восстановление — скопировать каталог обратно.

Хостинг — VPS на RuVDS за ~300 ₽/мес: 1 vCPU, 1 ГБ RAM. Перед Node стоит Caddy, HTTPS с автопродлением сертификата из коробки. Кстати, HTTPS тут не опция: браузеры отдают navigator.geolocation только в secure context.

Простота использования и секьюрность

Секьюрности нет)))

Защита от накрутки простенькая. «Без регистрации» и «один голос на человека» — требования, противоречащие друг другу. Разрешение конфликта — анонимный clientId (UUID в localStorage) плюс второй рубеж: в таблице голосов хранится солёный хэш IP, и с одного адреса на одну точку принимается не больше пяти голосов от разных «клиентов». Запас — на CGNAT и общий Wi-Fi, сырые IP не хранятся вообще. Это не защита от целеустремлённого ботовода, это защита от накрутки «за пять минут скриптом». Для моего кейса это осознанно достаточный уровень.

Фотографии: сжимаем варварски, и это фича

Пользовательские фото парковок — это «общий план двора». Качество не нужно от слова совсем, поэтому сжатие агрессивное: JPEG quality 45 (mozjpeg), ресайз до 1024px по большей стороне. Телефонное фото на 6 МБ превращается в 50–150 КБ.

await sharp(buffer, { limitInputPixels: 30_000_000 })
  .rotate() // применить EXIF-ориентацию до удаления метаданных
  .resize({ width: 1024, height: 1024, fit: 'inside', withoutEnlargement: true })
  .jpeg({ quality: 45, mozjpeg: true })
  .toFile(path);

В этих пяти строчках три неочевидных решения:

  1. limitInputPixels — защита от pixel-flood. JPEG 50000×50000 весит меньше 15 МБ, но при декодировании разворачивается в гигабайты RAM. На VPS с гигабайтом памяти это гарантированный OOM. Лимит в 30 мегапикселей режет бомбу на этапе чтения заголовка.

  2. Пересжатие как санитайзер. Что бы ни прислали под видом картинки — полиглот-файл, картинку со скриптом в метаданных — на диск ложится честный JPEG, собранный заново.

  3. Re-encode убивает EXIF — включая GPS-координаты автора снимка. Для краудсорсингового сервиса это не мелочь: человек фотографирует парковку у дома.

Плюс все фото проходят через последовательную очередь (sharp.concurrency(1)) — два параллельных декода больших снимков на маленьком VPS складывают процесс, проверено намеренно.

А поскольку имена файлов — UUID и не меняются никогда, отдаются они с Cache-Control: immutable, max-age=1y: повторные открытия карточек не трогают сервер вообще.

Автомодерация комментариев: 70 строк вместо npm-пакета

Хотелось автоматом резать мат и спам-дубликаты до того, как они падают в очередь модератору. Готовые пакеты для русского мата на npm оказались заброшены и наивны, ML-API — платная зависимость с латентностью на каждый комментарий. В итоге — собственный модуль на 70 строк: словарь корней + нормализация против обфускации.

Нормализация делает из «м у д @ к» и «сууукааа» канонические формы: латиница-двойники и цифры приводятся к кириллице, символы-маски выбрасываются, повторы букв схлопываются, «р а з р я д к а» склеивается обратно в слово. А анкеры в регулярках подобраны так, чтобы «курс рубля», «колебание», «обед», «веб-камера» и «не психуй» проходили спокойно. На 24 тестовых кейсах — ноль промахов в обе стороны.

Дубликаты ловятся сравнением нормализованного текста: повтор у той же точки или три одинаковых текста за сутки по всем точкам — до свидания. Отклонённое автоматикой в БД не пишется вообще: спамер не растит нам диск.

Интерфейс

Интерфейс mobile-first и бессовестно вдохновлён ГдеБЕНЗом: сверху компактная плашка-дисклеймер, дальше карта на весь экран с зелёными, красными и серыми пинами — цвет считается из баланса голосов «место живо / места нет». На телефоне между картой и списком переключаешься пилюлей сверху, на десктопе список висит слева постоянно.

Тап по пину открывает нижнюю шторку-карточку, и в ней весь функционал: описание, вместимость по категориям (от «маленькая, 1–4 места» до «огромная, 50+»), голосование с возможностью передумать, фото, комментарии и история голосов. Там же кнопка «Построить маршрут», которая пробрасывает точные координаты точки в Яндекс Карты, 2ГИС или Google Maps: на телефоне ссылку перехватывает установленное приложение и сразу строит маршрут. Добавление парковки — три действия: кнопка, тап по карте, короткая форма с опциональным фото. Регистрации нет нигде, «личность» пользователя — UUID в localStorage. Ну и PWA: сайт ставится на домашний экран и открывается как приложение, без адресной строки. Также есть админка со статистикой: посещения по дням, счётчики действий, топ точек по рейтингу и «самые спорные» — места, у которых много и ?, и ?, то есть парковки-лотереи.

Выводы

Проект от «а сделаю-ка я» до продакшена с доменом, HTTPS, PWA, SEO и стартовым каталогом занял, суммарно, пару вечеров диалога. Что показывает, что говнопалочные пет-проекты сейчас стало делать проще, чем никогда - в целом, с новыми моделями уже не особо важны технические знания, даже первая итерация по расплывчатому ТЗ более-менее работала и даже неплохо выглядела. Но имея инженерные знания, можно промптить модель так чтобы она закрывала бреши в производительности и безопасности, делать ей всякие замечания и тп. Ну и главное, работает стабильно, лучше чем мои курсовые с первого курса :)

Что еще помогло не накосячить с ИИшкой: скучный стек, коммиты на каждый шаг и живое тестирование руками на реальном устройстве.

Сервис живой: gdeparkovka.ru. По Петербургу каталог уже есть, по другим городам карта ждёт ваших точек, добавление занимает полминуты и не требует регистрации. Критику проекта жду в комментариях! Ну и пользуйтесь на здоровье, информация это общественное благо :)

Комментарии (28)


  1. max9
    07.07.2026 08:49

    Цель сервиса - выровнять это неравенство.

    вы техническими методами пытаетесь забороть плату за воздух и воровство бесплатных парковок у людей.
    тем более, что из года в год эти места будут сокращаться в перспективе до 0.


    1. boriswinner Автор
      07.07.2026 08:49

      Действуем в рамках наших возможностей :)


      1. Mishootk
        07.07.2026 08:49

        Разве это не то же самое по смыслу в ЯндексКартах?


        1. boriswinner Автор
          07.07.2026 08:49

          там нет многих локаций, и нет возможности отметить свои точки для всех. Конкретно всякие углы-дворы в центральных районах Петербурга на Яндекс картах не отмечены


          1. Mishootk
            07.07.2026 08:49

            У ЯК есть API взять их базу, и уже к ней сделать свое дополнение и добавочные свойства в вашем приложении?


            1. boriswinner Автор
              07.07.2026 08:49

              можно сдампить их бесплатные парковки, да. Но только не все бесплатные парковки имеют ценность - скорее только те, которые окружены платными в каком-то радиусе


    1. salnicoff
      07.07.2026 08:49

      Вот-вот. Успешно решена не та задача.

      Ну и вдогонку еще пару соображений.

      1) Я в своем городе знаю все места, где можно стоять. После того, как нам сделали подарок на Новый год и ввели платные парковки, смотрю карту платных парковок и запоминаю, что еше в одном месте нельзя стоять.

      2) Знакомые не раз уже вертли всяким навигаторам и вставали, а им прилетал штраф, и было это еще до эпидемии платных парковок. Ваша система абсолютно не защищена от ложной информации, кто-то наверняка будет ставить точки парковки на местах парковки платной. Мало того, есть даже люди, которые заинтересованы в таких подставах.


      1. Petroleum_man
        07.07.2026 08:49

        Штраф за что прилетал? Платная парковка всегда либо знаком, либо разметкой отмечена. Нет знака, нет разметки - значит бесплатная. То же самое - про то, а можно ли там вообще парковаться (ПДД, знаки, разметка)


        1. salnicoff
          07.07.2026 08:49

          Штраф прилетал за ротозейство. На улице в самом начале повесили знак «Остановка запрещена», в навигаторе этого не было. Водитель знак проигнорировал, встал, поймали.


      1. alcanoid
        07.07.2026 08:49

        Ну глаза-то у водителя есть бай дизайн, так сказать. Приехал, увидел, что бесплатной парковки нет, поехал дальше. Может, ещё и в приложение написал, что точка недействительна. Хуже никому не стало.


        1. salnicoff
          07.07.2026 08:49

          Ну глаза-то у водителя есть бай дизайн, так сказать.

          Глаза-то есть, только не все водители умеют ими пользоваться. Равно как руками и ногами.

          Приехал, увидел, что бесплатной парковки нет, поехал дальше. Может, ещё и в приложение написал, что точка недействительна. Хуже никому не стало.

          Это сценарий для адекватного водителя. А если там между рулем и сиденьем прокладка?


          1. alcanoid
            07.07.2026 08:49

            Это уже слегка выходит за рамки проблем, решаемых приложением. Прокладка и так будет ездить, страдать, а потом припаркуется под знаком.


            1. salnicoff
              07.07.2026 08:49

              Потом — штраф прокладке, а затем прокладка выкатит претензии автору.


              1. alcanoid
                07.07.2026 08:49

                Ну какие там претензии? Кол поставит в маркете приложений?


                1. salnicoff
                  07.07.2026 08:49

                  Почитайте тут: https://habr.com/ru/articles/1049576/ Человек сделал приложение с расписанием, а на него накатали бумаги, что он в свою деревню не дает автобусов — все же думают, что он злобный перевозчик. И это в деревне посреди Сибири. А тут — центр СПб...


                  1. alcanoid
                    07.07.2026 08:49

                    Ну не накатали на него бумаги, это ваше личное допущение из комментариев к статье.


                    1. salnicoff
                      07.07.2026 08:49

                      Ну он уже в одном шаге от этого. С учетом населения СПб этот шаг будет сделан довольно быстро.


                      1. alcanoid
                        07.07.2026 08:49

                        У меня из этого разговора складывается впечатление, что вы уже в шаге от того, чтобы сделать это самостоятельно, лишь бы обосновать данную точку зрения.


  1. Mishootk
    07.07.2026 08:49

    Похоже, что уже отработан стандартный промпт: "сделай приложение [где_хрень]". Карта, точки, метрика точки, список, рейтинг, достоверность, серверная часть.
    Бензин, парковки, гречка, дождь...

    Предлагаю на развитие идеи: большая "соцсеть гдехрень?", которая уже запрограммирована, запущен сервер, есть приложение. Любой пользователь регистрируется, может создать свой тип точек интереса или присоединиться к информированию существующих. Дальше стандартный сценарий администрируем, модерируем, монетизируем, продаем платформу заинтересованным серьезным людям, хороним когда-то хорошую идею и тратим схайпованные деньги.


    1. boriswinner Автор
      07.07.2026 08:49

      Не для всех типов точек это подойдет :) тот же "гдебенз" дает много функционала по типу бензина, обновлению его в наличии (все меняется динамически) и тд. У каждого типа точек своя специфика


      1. Mishootk
        07.07.2026 08:49

        Вы же понимаете, что если не "вайбкодить за вечер", а запрограммировать с головой и создать продукт, то в нем будут мультисвойства (на "вайбкодерном" - это тип бензина), и актуальность по множественному критерию: время, количество отзывов, расчет расхода, т.е. устаревание (на "вайбкодерном" - все менятеся динамически). И это не "специфика", а абстрактная модель с настраиваемыми параметрами.


  1. Petroleum_man
    07.07.2026 08:49

    С бензом история завелась, но будут ли люди делиться бесплатными местами - большой вопрос


    1. pozhilou
      07.07.2026 08:49

      Думаю будут, я тоже решил внести свой вклад и добавил точку, о которой знал, но она была не отмечена)


    1. boriswinner Автор
      07.07.2026 08:49

      для Петербурга я уже добавил свою личную коллекцию, которую год собирал) так что в масштабах Спб сервис уже полезен. А дальше зависит от сообщества - но сегодня уже начали появляться точки в Москве, Красноярске, Екатеринбурге!


    1. Mishootk
      07.07.2026 08:49

      С бензом история завелась на хайпе и любопытстве. Практически такой информатор сам себя губит и практической пользы нет. Заправку у дома все местные будут помечать как пустую. Немного удаленные от дома - как полную. Чтобы лично для себя уменьшить очередь и повысить вероятность заправиться. А гоняться по зеленым кружочкам будут доверчивые и не понимающие механику процесса.

      Польза для клиентов от аналога "гдебенза" может быть только в приложении топливной компании по актуальным данным наличия (с остатком) и онлайн картинки с камеры на территории. Как, например, сделано на автомобильной госгранице - при существовавшей альтернативе заезда в Финляндию через 2-3 КПП я уже по дороге выбирал маршрут с учетом загрузки пунктов.

      Вопрос только в том, является ли данная опция выгодной для топливной компании. Я думаю, если бы она давала хорошую прибыль, информатор о наличии уже бы появился сразу же как начались проблемы.


      1. alcanoid
        07.07.2026 08:49

        Если бы она давала прибыль, то появилась бы раньше. В текущих же условиях заправка практически гарантированно распродаст имеющийся бензин безо всех этих телодвижений, а кричать о избытке топлива может быть тупо небезопасно.


  1. Bardakan
    07.07.2026 08:49

    Цель сервиса - выровнять это неравенство.

    во первых, вырАвнять, во-вторых, неравенства не выравнивают, а устраняют, исправляют и т.п.


    1. boriswinner Автор
      07.07.2026 08:49

      вы правы :)

      исправил в статье