Cozy World
Flutter-приложение, которое помогает паре быть ближе: счётчики важных дат, сообщение каждый день, карточки и история фото. Приложение написано вручную, без AI; Telegram-бот для контента сделан с помощью AI.
Зачем
Cozy World это небольшое общее пространство, которое помогает паре оставаться на связи каждый день. А ещё это доказательство, что я умею спроектировать и написать Flutter-приложение сам, без кода от AI.
Как это работает
На главном экране идут счётчики времени с важных для пары дат, и каждый день ждёт новое тёплое сообщение. Длинные записки лежат в карточках, которые переворачиваются и отмечаются прочитанными, а общие фото листаются как колода. Новые сообщения добавляются через Telegram-бота, обновлять приложение не нужно.
Что сделал я
Всё: идея, продуктовый дизайн, архитектура и код приложения, написанный вручную на Clean Architecture, GetX и GraphQL к Supabase. Telegram-бота, Supabase Edge Function на TypeScript и Deno, я сделал с помощью AI под своим руководством.
Статус
Приложение и бот работают вместе, оба открыты под MIT. Я продолжаю их развивать, последнее добавление: дневник питания с журналом состояния.
- Роль
- Автор и единственный разработчик
- Период
- 2026 – сейчас
- Статус
- В работе
- Стек
- Flutter, Dart, GetX, Navigator 2.0, Ferry, GraphQL, Supabase, PostgreSQL, Lottie, TypeScript, Deno, Supabase Edge Functions, Telegram Bot API, GitHub Actions
Главное
- Живые счётчики времени с важных для пары дат
- Новое тёплое сообщение каждый день и категории с длинными записками
- Карточки переворачиваются и отмечаются прочитанными, ничего не теряется
- История фото, которую листаешь, как колоду воспоминаний
- Новый контент приходит из Telegram-бота, а не с новым релизом
- Flutter-приложение написано полностью вручную, без единой строчки кода от AI
Вместе
1362 дней 00:00:00
Telegram-бот
- 📅 Ежедневное сообщение
- Ближайший свободный день: завтра. Пришлите текст.
- Доброе утро! Кофе сегодня с меня ☕
- Сохранено. Календарь заполнен до завтра.
1 / 4 Главный экран: живые счётчики времени с важных для пары дат.
Что это
Cozy World это маленькое общее пространство для двоих, чтобы каждый день оставаться на связи. Первый экран считает, сколько прошло с важных для пары дат, вплоть до часов, с небольшой анимацией сердечек. Каждый день ждёт новое тёплое сообщение. Записки подлиннее разложены по категориям: это карточки, которые переворачиваешь, читаешь и отмечаешь прочитанными, так что непрочитанные легко найти. На экране истории можно листать общие фотографии, как колоду карт.
Чтобы добавить сообщение, не нужно выпускать обновление приложения. Контент лежит в базе и управляется из Telegram-бота: написать сообщение на завтра можно за один разговор в чате.
Что я сделал
Небольшую систему из двух частей, обе с открытым кодом под MIT.
Flutter-приложение (репозиторий) написано полностью вручную: ни строчки кода, сгенерированного AI. Это показывает, что я могу сам, без AI, спроектировать и построить приложение, от архитектуры до последнего виджета. Основные экраны (счётчик, сообщение дня, категории с карточками, история фото) стоят на Clean Architecture со слоями данных, домена и представления. В приоритете Android, а собирается проект под все платформы Flutter.
Telegram-бот (репозиторий) это инструмент для контента за приложением. В отличие от приложения, его я делал с помощью AI под своим руководством. Он работает как Supabase Edge Function на TypeScript и Deno, управление через инлайн-кнопки:
- Сообщение дня: вводишь текст, бот предлагает ближайший свободный день, выбираешь тип (текст, видео или аудио) и подтверждаешь.
- Сообщение в категорию: выбираешь категорию или создаёшь новую и добавляешь текст.
- Редактирование и удаление: постраничные списки сообщений дня или категорий, новые сверху, с фильтром непрочитанных категорий.
- Очистка: предпросмотр прошедших сообщений дня, выгрузка их в чат и удаление.
- Проверка дат: есть ли сообщение на сегодня и завтра и до какого дня заполнен календарь.
Обе части работают с одной базой Supabase Postgres. Бот пишет сообщения, приложение читает их через GraphQL и записывает обратно только отметку о прочтении.
1 / 4 Главный экран: живые счётчики времени с важных для пары дат.
Технические решения
- Clean Architecture вручную. Сценарии вроде «получить сообщение дня» и «изменить статус прочтения», интерфейсы репозиториев в доменном слое и регистрация зависимостей по слоям: данные, домен, представление. Строки, даты и ассеты вынесены в отдельные локальные пакеты, разделённые на API и реализацию.
- GraphQL к Supabase через Ferry со сгенерированными типизированными запросами (
build_runner,ferry_generator) кpg_graphql. - Свежие данные без лишних запросов. Небольшой механизм «грязного состояния» помечает списки категорий устаревшими после смены статуса прочтения, и перезагружаются только они.
- GetX для состояния и внедрения зависимостей, Navigator 2.0 (Router API) со своим парсером маршрутов и делегатом, страницей 404 и выходом по двойному «назад».
- Конфиг и секреты из
--dart-defineс запасным вариантом черезflutter_secure_storage, локальное состояние вget_storage. CI проверяет каждый pull request и ищет утёкшие секреты. - Бот как конечный автомат. Сценарий и шаг каждого чата хранятся в JSON в таблице сессий Postgres, поэтому serverless-функция между обновлениями Telegram ничего не держит в памяти.
- Защищённый вебхук. Функция принимает только POST-запросы с секретным заголовком Telegram, остальные отклоняет.
- Учёт ведёт база. Триггер синхронизирует список категорий с таблицей сообщений, и ни приложению, ни боту не нужно поддерживать его самим.
- Доставка. У бота есть тесты на Deno, и GitHub Actions прогоняет их перед деплоем функции в Supabase.
Результат
Приложение и бот работают вместе, и я продолжаю их развивать: в приложении теперь есть и дневник питания с дневником состояния. Скриншоты сняты с отладочной сборки в симуляторе iOS. Само приложение только на русском и только в светлой теме; английская и тёмная версии отрисованы из локальной копии с переведёнными строками и тёмной темой на цветах самого приложения, только для этих скриншотов.
Моя роль
Всё: идея, продуктовый дизайн, архитектура и код приложения, написанный вручную. Бот стал осознанным шагом в незнакомый стек (TypeScript, Deno, serverless), его я делал с помощью AI под своим руководством.







