Думал, что просто меняю сервер. Оказалось — пишу новое приложение, спецификацию на 2 500 строк и согласие на обработку персональных данных.
RedCalendar — облачный календарь женского цикла для iPhone. На днях вышло большое обновление: всё тот же календарь, но внутри от старого приложения не осталось ничего. Данные теперь хранятся в России, входить нужно по почте, а само приложение написано заново.
Почему пришлось уезжать
Раньше всё держалось на Firebase — это сервис Google для разработчиков приложений, где база данных, вход и уведомления идут готовыми кирпичиками. Удобно, быстро и почти бесплатно. Только серверы Firebase стоят в США.
Главная причина переезда — закон о персональных данных (152-ФЗ). Данные россиян нужно хранить на серверах в России, а сведения о здоровье, к которым относится и менструальный цикл, — это отдельная, особо охраняемая категория. Хранить их у Google в американском дата-центре для российского приложения становилось всё менее разумно.
Свой сервер в России
Сервер RedCalendar живёт у российского облачного хостинга NetAngels — я давно пользуюсь им в других проектах. Он хранит записи, рассылает уведомления и отправляет письма с кодом входа. Сервер я намеренно сделал скучным: только проверенные временем технологии и минимум сторонних библиотек.
Что чем заменилось:
| Что | Было | Стало |
|---|---|---|
| Сервер и база данных | Firebase, США | Свой сервер в NetAngels, Россия |
| Вход по номеру | Через Firebase | Звонок: код — последние 4 цифры номера, который звонит |
| Вход по почте | Не было | Код в письме через Yandex Cloud Postbox |
| Уведомления | Сервис Google | Свой сервер напрямую через Apple |
| Аналитика | AppMetrica |
Письма с кодом отправляет Yandex Cloud Postbox. Летом я писал про закон об иностранной почте и почему считаю, что своя система входа по почте лучше кнопок «Войти через…». Вот это она и есть.
Postbox я выбрал как самый надёжный сервис с подходящим тарифом. Чтобы письма не попадали в спам, ещё настроил для домена строгие правила DMARC — по ним почтовые сервисы проверяют, что письмо действительно отправил я, — и зарегистрировал домен в Postmaster Mail.ru. В общем, сделал всё, что мог.
Но и самый надёжный сервис может подвести. Когда дата-центры Яндекса вывели из строя, Postbox продолжал считать, что отправляет письма, а на деле они не приходили. Я поймал это на тестировании и задержал выход обновления.
Как перевезти людей, не заставив их ничего делать
Главное правило переезда: никто не должен ничего переносить вручную, заново входить в аккаунт или делать что-то ещё. Обновил приложение — и все записи на месте.
Готовиться к этому я начал больше чем за год. Летом 2025 года, в версии 2.2.2, старый RedCalendar стал при каждом запуске тихо оставлять себе записку: идентификатор аккаунта в Keychain — защищённом хранилище iPhone, которое переживает обновления, в секторе, доступном только для RedCalendar. Новое приложение вышло в App Store под тем же именем (то есть идентификатором), то есть пришло обычным обновлением. При первом запуске оно находит записку и узнаёт человека без всякого входа. От человека нужно только одно — дать согласие на обработку данных.
Сами записи телефон не перевозит: главная копия хранилась в Firebase, поэтому за ними идёт сервер. Он выгружает историю, приводит её к новому формату, проверяет по тем же правилам, что и любые правки с телефона, и складывает в свою базу. Пока это происходит, вместо пустого календаря крутится значок синхронизации. Когда всё готово, история приезжает целиком.
Сломать переезд на полпути нельзя. Записка стирается только после того, как сервер выдал телефону новый ключ входа: пропала сеть или приложение закрыли — при следующем запуске всё начнётся заново. А записи для каждого аккаунта переносятся один раз, поэтому второй телефон или повторный вход ничего не скопируют дважды и не вернут то, что уже удалено.
Если записки нет — например, старую версию не открывали с лета 2025 года, — можно войти по номеру телефона, как раньше. Новый сервер сохранил идентификаторы аккаунтов из Firebase, так что по номеру находится тот же самый аккаунт, и дальше всё идёт точно так же.
Закон: согласие и удаление
Переезд — это не только про серверы, но и про документы.
Согласие перед входом. С 1 сентября 2025 года согласие на обработку персональных данных должно быть отдельным документом, а не строчкой в правилах. Поэтому перед входом приложение просит его явно, а сервер записывает, кто, когда и какую версию документа принял. Без этой записи войти нельзя.
Удаление аккаунта. По закону на уничтожение данных есть 30 дней. Резервные копии у хостинга хранятся около трёх недель. Поэтому аккаунт удаляется через 7 дней после запроса: 7 дней плюс примерно 23 дня жизни копий как раз дают 30. Передумали в течение недели — просто войдите снова, и удаление отменится.
Новое приложение с нуля
Старый RedCalendar был написан на UIKit — прежнем способе делать интерфейсы для iPhone. Новый написан на SwiftUI, современном инструменте Apple. Переносить старый код не стал: проще и надёжнее было начать заново.
Главное, что хотелось получить, — предсказуемость. Всё, что знает приложение — какой день открыт, что в нём отмечено, выполнен ли вход, — лежит в одном месте. Экраны ничего не меняют сами: они только показывают это состояние и отправляют заявки вроде «отмечено начало месячных», а заявки выполняются строго по очереди. Поэтому, если на экране что-то не так, причину не нужно искать по всему приложению. Программисты узнают в этом схему Redux и, на мой взгляд, она идеальна для SwiftUI.
Самая сложная часть нового приложения глазами не видна — это синхронизация. Все записи хранятся прямо на телефоне, поэтому календарь работает и без интернета, а изменения уходят на сервер, как только появится связь. Звучит просто, пока не начинаешь задавать вопросы. Что делать, если интернет пропал посреди отправки? Как не дать удалённой записи «воскреснуть» на другом телефоне? Чья правка победит, если одну и ту же запись поменяли на двух устройствах? Ответы я сначала записал в документ на 2 500 строк и только потом начал писать код.
Интерфейс тоже сделан заново. Прогноз месячных теперь нарисован контуром, а отмеченные дни — сплошной полосой, так что прошлое с прогнозом не спутать. Цветные точки под днями остались: каждая показывает цвет категории тегов, а какой смысл вложить в каждую категорию, решает сам пользователь. Появился и модный эффект стекла.
Теги и комментарий показываются прямо в карточке дня. Открытый день, как и раньше, можно листать свайпом, но теперь можно и просто нажать на другой день в календаре — сразу откроется его карточка. В старой версии на UIKit сделать так у меня не получилось: нажатие на календарь закрывало карточку, и чтобы выбрать другой день, приходилось нажимать ещё раз. А акцентный цвет приложения можно выбрать в настройках.
Так выглядел старый RedCalendar:
А так — новый:
Была задача освежить приложение, но оставить узнаваемым.
Что дальше
Регистрации по номеру телефона в новом приложении нет: этот вход оставлен только для тех, кто пользовался старой версией, а новые пользователи входят по почте.
Сама идея входа по номеру мне нравилась больше, но стала плохо работать. Дело не только в деньгах: SMS с кодом теперь стоит очень дорого, а приходит не обязательно SMS (звонок робота, сообщение в Telegram, WhatsApp или, упаси Господи, в Max). А может и не прийти вооьще. Вход по звонку — хорошая штука, но заботливые операторы теперь блокируют такие звонки, а человек думает, что это приложение кривое, и может поставить одну звезду:
Письмо тоже может попасть в спам, но к этому давно привыкли. Поэтому со временем я попрошу пользователей добавить почту и выключу вход по номеру. Экран для привязки уже готов.
Firebase тоже пока работает: в нём остаются аккаунты и записи тех, кто ещё не открыл новую версию. Когда переезжать станет некому, старый проект можно будет удалить. После этого RedCalendar окончательно станет российским — от сервера до последней резервной копии.