RELAY / ЗАПИСКИ01

Записки Архитектора

Почему прикрутить игру к лендингу оказалось сложнее, чем написать её и выкатить на сервер

История одной кнопки, трёх серверов, нескольких инфраструктур и вопроса: «А это что за самодеятельность?»

Саму игру мы написали довольно логично.

Есть мир. Есть Узел. Есть станции. Есть миссии. Участник приходит, получает ключ, будит систему, что-нибудь ломает, чинит, находит питомца, пугается, радуется и идёт дальше.

После этого мы посмотрели на лендинг и сказали:

— Теперь просто добавим кнопку «Начать».

И тут началась настоящая игра.

Кнопка должна куда-то вести

Не в письмо «Здравствуйте, я хочу поучаствовать», а в место, где человек действительно становится участником.

Значит, нужна регистрация.

01Регистрация — это email02Email — это подтверждение03Подтверждение — это письмо04Письмо — это почтовый провайдер05Провайдер — это DNS, DKIM и SPF

В загадочной панели всё было зелёное, но письмо всё равно не приходило.

Потом письмо пришло.

Мы обрадовались ровно до момента, когда нажали на кнопку внутри него.

Кнопка не работала. Зато работала неприметная ссылка под ней.

Мы починили кнопку. После этого она бодро сообщила участнику, что доступ будет открыт «на этом устройстве».

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

Пришлось объяснить ему, что он не служба пограничного контроля.

Существовал ли заказ, если ссылка уже умерла

Параллельно выяснилось, что ссылка живёт 30 минут.

А что потом?

Через день человек открывает письмо и попадает не в игру, а в философский вопрос: существовал ли мой заказ, если magic link уже умер?

Поэтому появилась страница восстановления.

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

Убрали.

Слово получило жизненный цикл стартапа

Дальше потребовался промокод. Казалось бы, слово. Иногда — пара слов, что ещё смешнее.

Но это слово должно:

  • существовать, но не существовать дважды;
  • погашаться атомарно;
  • создавать ровно один заказ и ровно одну лицензию;
  • иметь срок действия;
  • иногда быть многоразовым и считать активации;
  • отзываться;
  • заказываться через Башню;
  • работать через Worker и доходить до Узла;
  • не превращать бесплатную регистрацию в бесконечную раздачу лицензий.

Таким образом, одно слово получило базу данных, административный API, CLI, дашборд, статистику, revoke и жизненный цикл сложнее, чем у некоторых стартапов.

Регистрация встретилась с Узлом

Сайт мог создать заказ, но игра об этом не знала. Игра могла создать лицензию, но сайт не умел её забрать.

Мы соединили их закрытым контрактом и прошли настоящий круг:

generate → redeem → Worker → Узел → license_id → ключ → revoke

Круг замкнулся. Тестовую лицензию отозвали. Продакшен чистый.

Мы решили, что самое сложное позади.

Тогда появился Cloudflare.

Секрет Шрёдингера

Сначала зарегистрировались. Потом подключили Worker. Потом OAuth сообщил, что CSRF не совпадает сам с собой.

Повторили. Создали D1. Создали R2. Создали токен. Вставили токен. Не нашли кнопку деплоя. Нашли кнопку деплоя. Задеплоили.

После успешного бэкапа решили, что токен скомпрометирован. Потом решили, что он всё-таки нормальный и надо уже заниматься другими делами.

Это был редкий случай, когда секрет одновременно считался:

  • секретным;
  • раскрытым;
  • рабочим;
  • безопасным;
  • и «давайте больше никогда к нему не возвращаться».

Параллельно мы обсуждали, зачем нам вообще Cloudflare, если есть Backblaze.

Оказалось, Backblaze прекрасно хранит бэкапы, но почему-то не хочет становиться одновременно лендингом, транзакционным сервером, базой заказов, защитным контуром, API-шлюзом и почтовым диспетчером.

Непредусмотрительно с его стороны.

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

Денег нет, юридический контур есть

Потом мы почти дошли до оплаты.

Доллары, лари, USDT, USDC, Credo, европейский эквайринг, open banking, криптопроцессинг, Stripe, которого хочется, но непонятно, с какой стороны к нему подходить.

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

— Начинаем бесплатно с промокодами.

Бесплатная версия немедленно потребовала privacy policy, лицензионные условия, правила обработки email, подтверждение 18+, срок лицензии и понимание будущего 14-дневного возврата.

То есть денег пока нет, но юридическая инфраструктура для денег уже должна быть.

Честный ответ системы

Потом мы открыли публичную регистрацию.

Первый запрос вернул:

{"error":"forbidden"}

Это был честный ответ системы на наше желание выпустить продукт в мир.

Мы открыли правильную страницу. Появились ключ и архив. Архив скачался.

И тут возник вопрос:

— Зачем мы показываем человеку SHA архива?
SHA-256 / зачем-то на экране участникаe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

Ответ был примерно таким: потому что можем.

SHA убрали. Пользователю нужен архив, а не внеплановый экзамен по контролю целостности.

Осталось только навести красоту

Наконец весь сценарий заработал: промокод → заказ → лицензия → ключ → архив → письмо → возврат к заказу.

Осталось «только навести красоту».

Эта фраза открыла следующую главу.

Страница регистрации выглядела как налоговая форма, случайно попавшая в мир RELAY.

Пришлось перенести палитру, подключить шрифты, встроить их в Worker, разрешить в CSP, проверить кириллицу, переписать каждый экран, согласовать письмо со страницей и расставить неразрывные пробелы, чтобы короткие предлоги не убегали в одиночестве на следующую строку.

После этого мы вернулись на лендинг, чтобы сделать то, с чего всё начиналось: добавить кнопку «Начать».

Кнопка заняла примерно одну строку кода.

Всё, что требовалось, чтобы она имела право существовать, заняло несколько инфраструктур, три сервера, базу данных, объектное хранилище, почтового провайдера, юридический контур, систему промокодов, мост лицензирования, механику восстановления и половину нашей нервной системы.

Мораль простая

Игру писать было легче, потому что внутри игры мы придумывали мир и определяли его правила.

А лендинг пришлось соединять с миром реальным.

А в настоящем мире у каждого клика есть email, срок действия, согласие, база данных, резервная копия, механизм отзыва и пользователь, который совершенно справедливо спрашивает:

— А это что за самодеятельность?

И обычно оказывается прав.