В середине марта 2026 я завёл пустой репозиторий и назвал его gchat. Без команды, без инвесторов, без «давай мы тебе поможем упаковать».
Через четыре часа у меня лежал первый коммит — initial protocol sketch.md, полстраницы псевдокода X3DH, две ссылки на Signal-спецификации и TODO-список на восемьдесят пунктов.
Я делаю мессенджер с end-to-end шифрованием. В одиночку. И это осознанное решение.
Почему не выбрать Signal или Matrix и жить спокойно
Первый вопрос, который задаёт любой здравый человек. Ответ у меня банальный, но честный: я хотел увидеть весь стек своими руками. Криптопротокол — не как «вызвать библиотеку», а как матрицу ключей, которая оживает в отладчике. Серверную логику — не как «какой-то бэкенд», а как конкретную модель доставки: очереди, идемпотентность, прелюдия ключей, garbage collection неподнятых сообщений. Клиент — не как «ну там Flutter», а как стейт-машину, которая корректно работает при флёре сети, ротации ключей и фоновых уведомлениях.
Собрать это из готовых кирпичей можно. Но тогда я не буду знать, где у меня на самом деле швы. А в криптопродукте швы — это CVE с номером через полгода.
Вторая причина — практическая. Я хотел продукт, в котором решения принимаю я. Без отчётов, без комитетов, без «давайте вернёмся к этому через спринт». В одиночку двигаешься не быстрее команды — двигаешься иначе. По прямой.
Что я сделал в первые две недели
Мне важно было сразу поставить самые рискованные вещи в прод, а не писать ещё месяц «инфраструктуру». Поэтому я шёл в обратном порядке от обычного MVP.
- День 1–3. Протокол на бумаге: X3DH для handshake, Double Ratchet для forward secrecy, AES-GCM-256 для payload, Ed25519 для подписей, Argon2id для деривации из пароля. Нарисовал все переходы, все ключи, все инварианты.
- День 4–5. Чёрный ящик PyNaCl +
cryptography: собрал прототип обмена сообщениями между двумя скриптами в REPL. Пока нет ни базы, ни сети — только математика. - День 6–9. FastAPI + SQLAlchemy 2.0 async + Postgres: bundle ключей, выдача prekey, базовый relay. Ноль бизнес-фич. Цель — проверить, что мои ключи выживают в продовых колонках.
- День 10–14. Flutter-прототип: экран чата, один-к-одному, без групп, без вложений, без звонков. Но с настоящим E2E в продовой схеме.
К концу второй недели у меня было сообщение, пришедшее с одного устройства на другое, зашифрованное клиентом, расшифрованное клиентом, и сервер, который не знал о содержимом ничего. Это и есть сердцевина.
Что оказалось сложнее, чем казалось
Три вещи.
Ротация ключей при офлайне. Когда одно устройство молчит три дня, Double Ratchet всё равно должен уметь догнать. Это заставило пересмотреть, как я храню prekey-бандл на сервере и что считается «просроченным».
Идемпотентность доставки. Клиент ретрайит. Бэкенд уже дропнул сообщение, чтобы не плодить дубли. Клиент снова ретрайит. В итоге UI показывает «не доставлено» на сообщение, которое прочитал собеседник. Решение — детерминированные message_id на клиенте + дедуп-индекс на сервере с TTL.
CallKit на iOS. Не про шифрование, про операционку. Про то, что Apple считает нормой показать VoIP-пуш за 200 мс, а твоя доставка из-под VPN иногда занимает 800. И что с этим делать? Прелюдия push через APNs + фоллбэк через WebRTC relay-ICE.
Что я из этого вынес
Соло-режим — это не подвиг. Это другая экономия внимания. Ты не можешь позволить себе писать то, что потом не будешь поддерживать. Каждая абстракция, каждый слой, каждый файл — это обещание тебе же через шесть месяцев.
Поэтому GChat пишется просто. Никаких плагинов, никаких «универсальных ядер», никаких переводов на «ещё более правильную архитектуру». Один язык на бэкенд (Python), один на клиент (Dart), один протокол, одна модель доставки. И всё это держится на одном self-managed сервере, который я собственноручно обновляю раз в месяц.
Если у тебя есть вопрос по устройству GChat — пиши в Telegram. Если нужен инженер, который и криптопротокол распишет на салфетке, и бэкенд соберёт, и APNs с FCM настроит — ты попал по адресу.
В следующих заметках: как выбирал между Matrix-совместимостью и собственным форматом, почему отказался от MongoDB и почему «лендинг GChat жёстче, чем сам мессенджер» — это не комплимент.