GeoPhotos — агрегатор фотографий по городам, один из проектов нашей команды Revolt Lab, в которой маркетологи и дизайнеры проверяют различные гипотезы, а разработчики тестируют новые технологии. Это история win-win: если гипотеза выстрелит, получим интересный и прибыльный проект, если нет, то, как минимум, участники приобретут новые навыки и расширят текущие компетенции.
В данном проекте на разных стадиях были задействованы 5 человек:
- Денис — идея и менторство,
- Паша — код,
- Артем — SEO,
- Софья — дизайн,
- Миша — помощь по разработке и частичное ревью кода.
Хочешь участвовать в разработке без долгих согласований, пробовать новые технологии или другие роли в команде? Есть идея, которую хотелось бы реализовать? В Revolt Lab такое приветствуется — вливайся в команду.
От идеи до реализации
Этот путь занял чуть более двух месяцев. Долго, но, так как это pet-проект, занимались им в свободные от основной работы часы. В копилку трудозатрат внес лепту и «синдром перфекционизма» — желание сделать сразу хорошо и больше — привычка, приобретенная за годы работы над клиентскими проектами.
Начнем с идеи. Слово Денису:
Иногда нужно найти фотографии в определенной геолокации, например, перед туристической поездкой. Инста помогает, но в ней нет просмотра фото на карте. В Яндекс Картах эта фича есть, но фотографии пользователи добавляют редко. Решили совместить это: в MVP без карты, но с актуальными фотографиями из ВКонтакте по популярным геоточкам.
Запросов в поисковиках достаточно, чтобы проект можно было в будущем монетизировать и развивать. Для MVP цель — 100 000 посетителей в месяц через год после запуска. Пробуем.
Если MVP «выстрелит», монетизировать планируем через партнерские программы. Хватает и планов по дальнейшему развитию проекта, повышению его полезности для пользователей.
Итак, что предметно было сделано за два месяца, — погнали.
Проверка возможностей API ВКонтакте
Прежде чем полноценно запускать проект в работу, Паша поэкспериментировал над API VK: возможно ли вообще парсить фотографии с учетом геоданных и какие есть ограничения. Плюс сразу попробовал найти решения для фильтрации полученного материала, чтобы отсекать тонны фотографий макияжа и ноготочков. Без этого дальнейшие работы были бессмысленны.

Что узнали по итогу:
- VK без проблем дает получать фото (изображение). Параметры, которые можно указать в запросе, описаны в документации для разработчиков.
- Также достаются описание изображения и текст из поста с изображением, на основе которых можно отсекать ненужные фотографии.
- Для Python есть готовая библиотека по распознаванию лиц на изображении. Работает не очень быстро, примерно по одному FullHD фото в секунду, поэтому решили делать фронт не в realtime, а по заранее обработанной базе.
Комментарий Паши:
Основная проблема контентных проектов — это контент. В данном случае все звучало как приключение на 20 минут: вот есть VK API, оно умеет по координатам и ключевым словам возвращать фотографии, дело осталось за малым — взять центры городов, написать «Достопримечательность» и вот у тебя качественные и неподкупные фото в достаточном количестве. Ну, так-то оно так, только вместе с ними еще получались фотографии других городов, обнаженка, запрещенные символы и горы продаваемых товаров от детских вещей до, прошу прощения, самотыков.
Тогда стало понятно, что надо фильтровать и по белому списку ключевых слов — что точно должно быть — и по черному. Обрабатывать фотографии нейросетью, чтобы исключить как минимум личные фотографии, фотографии с номерами телефонов, ссылками на разное запрещенное и все эти факторы еще и балансировать, потому что иногда была просто превосходная фотография центра города, где в описании были вообще все стоп-факторы, которые только возможно было придумать и надо было как-то такое понимать и обрабатывать.
Выбор стека
За разработку также целиком отвечал Паша. В прошлом разработчик, сейчас работает бизнес-технологом. Паша комментирует это так:
Несколько раз мы с нашим арт-директором Машей говорили о том, что есть смысл меня повкатывать в что-нибудь, например, во фронт, но я отнекивался — это не совпадало с моими жизненными интересами. А в этом году мне внезапно стало интересно ML, и я начал потихоньку вкатываться в Python, плюсом к моим базовым знаниям React и баз данных. Full stack получился 😀
В какой-то момент я подумал, что было бы неплохо домашние занятия подкреплять практикой на работе — и мне польза, и команде польза, почему бы и нет. Предложил → договорились → погнали.
Это и предопределило стек проекта, он следующий:
Фронт
- Flask,
- Sass,
- JQuery.
Бэк
- Python,
- MySQL.
Для реализации MVP достаточно инструментов, которые понимают остальные разработчики команды (или могут разобраться за вменяемое время), а также то, с чем мне не пришлось бы долго разбираться.
Я неплохо знал Python — он имеет в наличии большую базу библиотек и готовых решений — взяли его. Сайт по большому счету статичный, на 98% для фронта достаточно было любого шаблонизатора, потому взяли Flask как самое простое и доступное. База MySQL, но тут не принципиально. Остальное — Sass, JQuery — пришло по ходу проекта.
Как стало понятно потом, возможно, имело смысл сразу завести Vue в качестве фронта — некоторые вещи было бы сделать проще. Но и Flask пока вполне достаточно.
Паша, бизнес-технолог

Проектирование структуры
После оценки возможностей API взялись за структуру ресурса.
Начали по классике — с детального анализа конкурентов: ядра, структуры, интересных решений и способов монетизации. Проектов, продвигающихся по схожей семантике, много, но крупных всего 2–3. Причем некоторые сайты ограничили свою работу на территории РФ после 24 февраля, а это значит, что Яндекс их со временем выкинет из ТОПа выдачи (что в итоге и произошло).
Артем, маркетолог
После анализа решили для проверки гипотезы в MVP взять в работу кластеры формата «фото +город», «город +фото +летом», «город +фото +зимой» и подобные. По последним ниже частотность и, соответственно, слабее конкуренция. Это значит, что страницам под эти запросы легче выбраться в ТОП, что в свою очередь даст буст в ранжировании страниц с более частотными запросами за счет перераспределения веса от грамотной перелинковки.
Что сделали:
- Собрали и кластеризовали ядро запросов с ключевыми словами «город» + «фото», «фотографии» и т. п.
- По основе данных частотности отобрали список городов и их подкатегорий, под которые будем делать посадочные страницы.
Результат этого вылился в таблицу:

Далее Артем подготовил список требований по SEO, шаблоны для генерации мета-тегов, заголовков, URL, хлебных крошек и контента страниц. Затем взялся за структуру страниц.
Чтобы на этом шаге не загружать дизайнера, я быстро накидал прототипы со структурой страниц в Miro. Так и разработчик сможет примерно оценить свои трудозатраты, и дизайнер отчетливей понять мое видение.
Артем, маркетолог

Подключаем дизайн
Для наведения дальнейшей красоты пригласили Софью. Она подготовила макеты в Zeplin, частично переиспользовав компоненты из нашей внутренней дизайн-системы.

Я подключилась к проекту, когда уже был готов черновой вариант интерфейса. Артём и Паша собрали сайт, а моей задачей была визуальная часть созданной ими структуры.
С одной стороны, Артём здорово сэкономил моё время, когда набросал макеты страниц в Miro. С другой — у Паши возникли вопросы к адаптивности некоторых блоков, которая не была предусмотрена изначально, а когда проект дошёл до меня, что-то править и переделывать было долго или больно. Решили, что включать дизайнера в работу над проектом нужно как можно раньше.
С Пашей в качестве разработчика мы работали в первый раз. Обычно я работаю с ребятами, которые уже знают все принципы и нюансы, что я закладываю в макетах. Было немного волнительно перед стартом работ: вдруг возникнут недопонимания, не случится мэтча. В результате получилось быстро найти общий язык, и мои волнения не оправдались. А ещё Паша собирал некоторые кусочки интерфейса без моего участия, это крутой скил для разработчика, когда можешь сделать сам на основе имеющихся стилей.
Софья, UX/UI-дизайнер
Эволюция дизайна наглядно:


Релиз: итоги и первые проблемы
В бой проект вылили в середине августа 2022 года. Сразу отправили страницы на индексацию роботам Яндекса и Google, через IndexNow и Indexing API, соответственно. Прошлись краулерами Screaming Frog SEO Spider и SiteAnalyzer для проверки кодов ответа у страниц и поиска других возможных ошибок после деплоя.
На этом моменте активную часть работ по проекту приостановили, оставалось мониторить результаты индексации и ранжирования.
Личные итоги
От Артема:
По структуре и сеошке сайт достаточно простой, поэтому не скажу, что приобрел здесь какие-то новые навыки. Однако это был первый проект, который я в одиночку курировал от начала и до релиза, поэтому мне он был интересен и полезен именно в плане командной работы и менеджмента.
В своей голове всегда рисуешь идеальную картину, но в реальности далеко не все из этого возможно и нужно воплощать в жизнь. Надо уметь идти на компромиссы и слушать мнение коллег, чтобы в итоге найти какую-то золотую середину. Вроде, простые истины, но к этому тоже нужно прийти.
Еще один момент, который нужно контролировать, когда ты выступаешь в роли лида — перфекционизм vs трудозатраты. Для MVP, и особенно при проверке гипотез, стремиться к идеалу во всем — избыточно. Кажется, с этим пунктом мы немного прокололись. Опять же, если учитывать, что у Паши и у меня это частично был первый опыт на ведущих позициях в проекте, то желание сразу сделать конфетку оно в целом понятно.
От Паши:
Самыми важными двумя итогами для себя считаю:
1. Совершенно по-другому начал смотреть на взаимодействие с нашим дизайнером — работать как менеджер и как разработчик это совершенно две разных истории. Именно в роли разработчика удалось лучше понять, как вообще происходит работа по макетам, что считается важным, что нет, где какие компромиссы можно допустить и так далее. Ну то есть то, что не всегда возможно увидеть из высокого менеджерского кресла, но что важно для понимания ситуации в целом и лучшего управления как следствие.
2. Обновил свой опыт разработчика в команде — на какое-то время лучше буду понимать команду, что важно, потому что работая только как менеджер становишься все дальше и дальше от как все устроено на практике, потому теряется объективность.
Ну и конечно же, это множество практического опыта по Python, Flask, MySQL и верстке как бонус.Очевидно результат не идеальный, но он приемлемый. Сложно было не только сделать, но и остановиться вовремя и сказать «Вот теперь нормально». Можно было сделать лучше — пойти в ML не только по пути определения лиц, но и людей, объектов и так далее, но это уже не MVP и железо там требуется дай бог каждому, так что пока так.
Не всё так гладко оказалось
Через две недели после релиза Яндекс начал выкидывать страницы из индекса по причине малополезного контента. К середине сентября были удалены все, кроме главной.

При этом в Google ресурс чувствовал себя отлично и уже начал приносить первые клики.

Конечно, в случае Яндекса можно было списать всё на сбои алгоритма, что ресурс еще новый и ему надо просто «отлежаться». Однако рисковать не хотелось.
Что предприняли для исправления ситуации, расскажем в следующих выпусках.