Вкуснолаб, или Как мы писали мобильное приложение. От концепции к результату. django.. django. flutter.. django. flutter. programming.. django. flutter. programming. project.. django. flutter. programming. project. project management.. django. flutter. programming. project. project management. Программирование.. django. flutter. programming. project. project management. Программирование. Разработка мобильных приложений.. django. flutter. programming. project. project management. Программирование. Разработка мобильных приложений. Управление проектами.

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

Именно поэтому у нас, как у будущих и нынешних программистов, в университете есть дисциплина по созданию мобильных приложений – обучение идёт созданию Java-приложений. Но в рамках дисциплины можно не идти простым путём – просто выполняя практики по методичке на Java – можно выбрать сложный путь, путь ниндзя – создать собственное мобильное приложение в команде. И мы пошли именно этим путём.

Вкуснолаб, или Как мы писали мобильное приложение. От концепции к результату - 1

*Данная статья является обзором пути длиной 4 месяца – не рекламой продукта. Наше приложение нельзя нигде скачать, оно не приносит дохода. Цель данной статьи: описать весь процесс разработки и работы в команде, в комментариях получить советы, рекомендации более опытных разработчиков. Все упоминания хостингов не являются рекламой, я рассказываю про свой опыт, в том числе, учитывая используемые сервисы. Это учебный проект, его цель – научиться новому. Мне как тимлиду и бэкендеру, сокомандникам своим сферам.

**Здесь не будет везде примеров кода и примеров реализации конкретных вещей. Я описываю процесс создания приложения, а не один из этапов – кодинг.

Концепция

У нас как у людей нетворческих было не очень много идей. Собственно, идея – и была самая сложная часть поначалу. Попросили помочь искусственный интеллект: он выдал ряд предложений. Одним из них и было то, что мы взяли на вооружение и с чем имели дело 4 месяца – приложение с рецептами.

Но таких десятки. Я сел за техническое задание, в процессе написания которого мы командой придумывали, какая же киллерфича должна быть. Мы решили встроить ИИ, который бы генерировал интересные рецепты* (*за возможные последствия приготовления сгенерированных рецептов не ручаемся).

Параллельно с написанием техзадания, после того, как были продуманы функциональные требования, наша дизайнер сделала в Figma вид результата работы. Я, ни разу ранее не пользовавшись Adobe Illustrator, открыл его и по какой-то обучалке сделал простое лого. Его добавили в дизайн в Фигме и мы получили внешний вид того, к чему мы должны прийти в течение следующих 3 месяцев труда.

*Ремарка: в процессе придумывания названия для приложения мы остановились на вариантах “Вкуснолаб” и “Вкусолаб”. Так как отличие лишь в одну букву, а репозитории уже были созданы, название может быть где-то одним, где-то другим.

Несколько страничек нашего приложения в Фигме
Несколько страничек нашего приложения в Фигме

В техзадании прописывается также и стек технологий. Нами был Flutter ради кроссплатформенности (спойлер на будущее: она не была использована, я не успел сделать порт на iOS) и Python Django на бэкенде. Конечно, приложение не приложение без серверной части. Иначе как юзерам смотреть рецепты не только свои сохранённые локально, но и рецепты других пользователей?

Немного про архитектуру приложения

Коротко архитектуру приложения можно обрисовать схемой.

Вся архитектура в одной картинке

Вся архитектура в одной картинке

Есть часть, которую я назвал основной, Main, – собственно, мобильное приложение и backend с базой данных, которые обмениваются данными. По запросу мобильного приложения бэкенд отсылает картинки на отдельно стоящий сервер S3, записывая в базу данных путь к файлу. Сам сервер S3 публичный, там не хранится критически важная информация пользователей, поэтому мобильное приложение может без авторизации получать доступ к картинкам на S3 по публичным ссылкам.

В Elasticsearch записываются только логи через Filebeat и Logstash. Тут всё просто. На самом деле для таких целей можно было найти сильно более легковесный сервис для красивого просмотра логов, но я захотел и решил поэкспериментировать с Эластиком на отдельном сервере и с отправкой логов с Nginx’а в него.

Разработка

При наличии готового дизайна фронтендеры приступили к созданию приложения. Необходимо было перенести дизайн из Фигмы по Флаттер, временно без логики нажатия на кнопки.

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

Схема базы данных

Схема базы данных

Мы приступили к написанию самого бэкенда. Для этого выбрали django rest framework, который позволяет нам быстро писать эндпоинты целыми пачками. В процессе возникали сложности, например, связанные с тем, что моя коллега использовала ИИ DeepSeek при выполнении задач, но во-первых, сама не вникла в суть задачи, из-за чего в коде были логические ошибки, во-вторых, неправильно формулировала задачу ИИ, – эта проблема вытекает из пункта 1. В итоге часть “мусорной”, “неправильной” логики отсеялась во время моего ревью, а часть из того, что я посчитал нормальным, но таковым не являлось, проникло в master ветку и оттуда на сервер.

Я добавил в приложение на бэкенд с помощью библиотеки yasg визуальный красивый swagger, чтобы можно было сразу тестировать написанные эндпоинты.

Swagger, сформированный с помощью yasg

Swagger, сформированный с помощью yasg

По сути, этот UI-swagger – основной способ коммуникации с фронтендерами. Я описывал им эндпоинты отдельно в нашем чате, при необходимости, но тестировать они всегда могли тут. Буквально один раз я выгрузил .json и .yaml форматы сваггера, но из-за недостаточной опытности коллег читать описание API в таком формате было сложно, да и ко всему прочему, как я уже писал, в web-ui можно сразу тестировать эндпоинты, а не только видеть их описание.

Нашей киллерфичей я уже называл встроенный AI – его интеграция оказалось простой задачей. Я просто подключил AI от Сбера, и он генерировал ответ на запрос пользователя учитывая “техническую инструкцию” – всегда генерировать только рецепты. Ниже реализация этого в коде и итоговый результат генерации:

messages = [
  SystemMessage(
    content="Ты бот, который придумывает рецепты. На любой запрос придумай рецепт"
  ),
  HumanMessage(
    content=serializer.data["text"]
  )
]

response = self.ai_client.invoke(messages)
Ответ от AI

Ответ от AI

DevOps

На определённом этапе разработки я понял, что пора кидать бэкенд на сервер. Я арендовал VPS на Aeza. Настроил nginx на нём. Захотел настроить CI/CD. Посмотрел-почитал про Ansible, настроил его в GH Workflow. В процессе разработки были добавлены тесты в бэкенде – CI/CD настраивал с учётом их. При пуше в master ветку вызывается workflow, который сначала прогоняет все тесты, а потом по SSH отправляет файлы на сервер, делает миграции и перезапускает gunicorn.

В качестве СУБД я выбрал MySQL.

Следующим шагом является настройка S3. Я арендовал его на Timeweb, настроил в Django. Теперь картинки отправляются из бэкенда в облачное S3 хранилище, в базу данных сохраняется ссылка, которую получает фронтенд и фронтенд подгружает картинку напрямую из S3.

Elasticsearch

Небольшое ответвление в разделе девопса. Elasticsearch я решил использовать для сбора логов с nginx. Чтобы поднять Эластик, я арендовал отдельный для этого сервер на Timeweb, нашел репозиторий на GitHub с настроенным стеком ELK: “Elasticsearch, logstash, kibana”. Донастроил пользователей под себя – и Kibana запустилась.

Необходимо было настроить конфигурацию nginx на сервере с бэкендом и формат получаемых логов в самом Elasticsearch (logstash pipeline):

input {
  beats {
    port => 5044
  }
  tcp {
    port => 50000
  }
}

filter {
  grok {
    match => { "message" => '"%{WORD:method} %{URIPATH:request} HTTP/%{NUMBER:http_version}" %{NUMBER:status} %{NUMBER:bytes_sent} "%{DATA:referrer}" "%{DATA:user_agent}"' }
  }
  mutate {
    convert => {
      "status" => "integer"
      "bytes_sent" => "integer"
    }
    remove_field => ["message"]
  }
}

output {
  elasticsearch {
    hosts => "elasticsearch:9200"
    user => "logstash_internal"
    password => "${LOGSTASH_INTERNAL_PASSWORD}"
    index => "weblogs-%{+YYYY.MM.dd}"
  }
}

После применения этих настроек логи пошли в систему:

Список логов в Kibana

Список логов в Kibana

Далее для большего интереса и большей наглядности я настроил один дэшборд:

Дэшборд в Kibana

Дэшборд в Kibana

Я понимаю, что для моей цели: получение и анализ логов, их нормализация – можно было взять другой инструмент, сильно более легковесный (например, VictoriaLogs или Loki, как мне подсказали во время редакции статьи).

Но я решил посмотреть Эластик, как с ним работать в Kibana, как настроить получение логов в нём с удалённого сервера из Nginx. Данный пункт основан исключительно на моём интересе и не требуется в проекте (по крайней мере, в такой реализации).

Результат

Приближался конец семестра, наша работа подходила к концу. Оставались мелкие правки, немного дополнений и работа была успешно сдана. В самом конце вскрылась небольшая проблема – кэширование. Django почему-то решил полностью кэшировать все запросы, из-за чего после создания, например, нового элемента в корзине, он там появлялся только спустя время, если исполнять запрос на одном клиенте. Как только я полностью выключил всё кэширование на стороне Django – всё заработало как надо.

Как итог мы получили работающее приложение: с возможностью выкладывать рецепты, добавлять ингредиенты в корзину, с AI, который сгенерирует рецепты, с профилями пользователей.

Скриншоты самого приложения

Скриншоты самого приложения

Спасибо за работу бэкендеру Евгении, дизайнеру-фронтендеру Алисе и фронтендеру Вячеславу. Я получил кайф от данного проекта. И спасибо за прочтение, уважаемый читатель!

Автор: jottygroups

Источник

Rambler's Top100