Подкастр

Хостинг подкастов, которым приятно пользоваться · podcastr.ru

Заметки

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

Захотел сделать кэширование файлов на локальной машине, чтобы не делать лишние запросы к Spaces (аналог S3 от DO), а то вдруг они дорогие. Два генсервера спустя догадался всё-таки посмотреть в документацию к Spaces — не-кросс-ДЦ-запросы уже включены в стоимость 😒 Пришлось оправдывать своё желание запилить генсерверы иначе!

Транзакционные письма

Продолжая тему скучных вещей, необходимых каждому веб-сервису, нельзя не упомянуть транзакционные письма. Это те самые «подтвердите свой аккаунт», «сбросить пароль», и так далее. В лихие девяностые такие письма можно было рассылать, подняв свой SMTP-сервер и обращаясь к нему напрямую. SMTP — simple mail transfer protocol — простой протокол в лучших программистских традициях: человекочитаемый, плейнтекстовый, придуман в эпоху, когда люди и компьютеры верили друг другу на слово. Чисто теоретически письмо через SMTP можно отправить через telnet, HELO.

Сейчас же так отправлять не стоит — вероятно, что GMail и прочие гиганты просто не примут письмо от вашего домашнего сервера, или отправят в спам, или просто будут долго заставлять. Транзакционные письма очень требовательны к надёжности и скорости доставки — никому не нравится ждать письмо сброса пароля. Поэтому проще воспользоваться специализирующимся на таких письмах сервисом, «одолжив репутации».

А раз уж всё равно придётся использовать сторонний сервис, то можно заменить SMTP на REST. Так делает Postmark. Их я выбрал по отзывам в разных подкастах, отдельно подкупило, что это небольшой сервис (инди-дух!)

В общем, код, который отправляет письма, выглядит так (над дизайном писем надо будет ещё поработать):

  # Podcastr.Accounts.UserEmail
def confirm_email(user, url) do
    new()
    |> to(user.email)
    |> from("tim@podcastr.ru")
    |> subject("Подтвердить почту на Подкастре")
    |> html_body("<h2>Привет!</h2><p>Чтобы подтвердить почту, нажми на ссылку: #{url}</p>")
    |> text_body("Привет!\n\nПодтвердить почту: #{url}\n")
end
# Podcastr.Accounts.UserNotifier
def deliver_confirmation_instructions(user, url) do
    UserEmail.confirm_email(user, url)
    |> deliver()
end
    

Тут используется библиотека Swoosh, она умеет работать с API Postmark.

Но оказалось, что просто так отправить письмо нельзя — см. выше про утраченную эпоху доверия — нужно настроить DKIM для своего домена. Postmark предлагают простые инструкции, надо было добавить одну TXT DNS-запись домену.

Дальше начались проблемы с подтверждением Sender Signature: я пытался отправить письмо как Tim Marinin <tim@podcastr.ru>, в то время как на Postmark я добавил Тим Маринин <tim@podcastr.ru> — в какой-то момент я долго смотрел в две эти строки, пытаясь найти разницу. 😅

Впрочем, отправить письмо на mt@marinintim.com я пока так и не смог — непроверенные клиенты Postmark могут отправлять письма только на свой же домен, чтобы избежать спама. А это означает, что пришлось бы настраивать в Fastmail приём писем для домена podcastr.ru — проще уж подать заявку на подтверждение и подождать 24 часа.

В целом, хочется, чтобы у Подкастра было хорошее покрытие тестами — тогда можно будет спокойнее спать. Генераторы Феникса идут вместе с тестами, но я на них забил на время прототипирования, то теперь есть 132 теста, из которых 58 падают 😅

Пожалуй, лучше пофиксить сейчас, а то так никогда и не приступлю.

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

Для веб-части Подкастра я выбрал использовать Elixir + Phoenix. Почему именно их я, если любопытно, расскажу отдельно, а сейчас хочу отметить одну приятную штуку: все эти скучные вещи сверху я получил, практически, бесплатно, при помощи phx_gen_auth. Это генератор, то есть, сам код контроллеров и шаблоны находятся внутри кода приложения, и их можно переделать как угодно.

первая версия лэндинга

Поэтому сейчас могу только поделиться скриншотом из превью в BB Edit. А ещё говорят, мол, HTML — не язык программирования 🧑‍💻

Привет! Здесь будет дневник разработки сервиса «Подкастр».

Сегодня я сверстал простяцкий лендинг, закинул его на сервер, настроил http через nginx, и завис на этапе «надо подождать, пока сбросится кэш DNS на NS записи, чтобы подхватились A записи Digital Ocean, чтобы настроить SSL через letsencrypt», и теперь придётся ждать не меньше двух часов.