Перейти к содержанию

Форма подписки

Модель SUB-01 отделила заявку от разрешённой подборки. Теперь форма должна объяснить это различие человеку до отправки адреса. В этом уроке подготовим FORM-01: поля, текст обещания, сообщения об ошибке и ожидаемое состояние после заявки. Результат — редакторский макет, который не создаёт реального подписчика автоматически.

Форма локальная и не имеет обработчика. Адрес reader001@professorweb.example вымышленный, контакт получает ID R001. Файлы lesson-02 в архиве описывают состояние интерфейса и данные, а не подключённую страницу сайта. Ни запрос, ни подтверждающее письмо не отправлялись.

Поле и обещание

Основное поле — адрес электронной почты. Подпись прямо называет его назначение. Под ним находится обещание PROMISE-v1: подборка новых уроков по выбранным темам, не чаще одного раза в неделю. Рядом человек выбирает темы веб-разработки и SEO. Не добавляем заранее отмеченное согласие и не скрываем цель в длинном нечитабельном тексте. Это требования учебного проекта, а не утверждение о любой правовой системе.

Кнопка называется «Запросить подписку». Такое название точнее «Подписаться мгновенно», потому что следующий шаг — подтверждение адреса. После допустимой заявки человек видит, что нужно сделать дальше, и не ожидает уже начавшуюся рассылку. Внутренняя запись имеет pending. Форма не превращает введённую строку в confirmed, даже если браузер считает её синтаксически похожей на email.

Элемент Учебное значение Назначение
Адрес reader001@professorweb.example Доставка по выбранной цели
Темы web Предпочтение содержания
Частота weekly Верхняя частота модели
Выбор обещания PROMISE-v1 Основание заявки
Состояние pending Подтверждение ещё требуется

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

Ошибка и восстановление

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

Синтаксическая проверка не доказывает существование ящика или владение им. Поэтому успешная форма говорит «заявка принята к подтверждению», а не «адрес проверен». Даже подтверждение в следующем уроке будет относиться к конкретному адресу и действию. Оно не позволит выводить личность, возраст и любые интересы человека по одному факту открытия ссылки.

Если выбрана тема, не предусмотренная моделью, серверная часть будущего проекта должна отклонить или нормализовать значение по известному набору. Интерфейсное ограничение само по себе недостаточно. В этой серии сервер отсутствует: мы описываем требование и ожидаемый результат, не предъявляем готовую безопасную реализацию. Автору важно обозначить границу редакторского макета и функционального обработчика.

После допустимой заявки сохраняются ID, адрес, темы, частота, версия обещания и сценарное время. Статус pending не включает контакт в подборку. В приложении нет настоящего IP-адреса или браузерного отпечатка. Если будущему проекту понадобятся дополнительные записи основания, их назначение и срок хранения определяются отдельно. Мы не добавляем данные «на всякий случай».

Повторная заявка

Рассмотрим двойное нажатие кнопки. Пользователь не должен получить две самостоятельные подписки и две одинаковые приветственные серии. В модели адрес связан с одной актуальной заявкой цели lesson_updates. Повтор обновляет допустимое состояние по правилам, а не создаёт бесконечные записи. При этом нельзя молча отменить прежнюю отписку: для остановленного контакта нужен новый явный выбор и подтверждение.

Публичное сообщение после заявки не должно раскрывать, числится ли чужой адрес в базе. Подходящий текст: «Если адрес можно использовать для этого запроса, получите инструкцию подтверждения». В нашей форме эта фраза является проектным решением для уменьшения раскрытия состояния. Она не утверждает, что письмо действительно отправлено, потому что почтовый канал в лаборатории отсутствует.

Для локального ожидаемого состояния R001 сохраняется confirmation_message_state: prepared_local. Это означает, что текст можно подготовить в следующей главе. Нельзя записать sent, получить выдуманный ID провайдера или придумать время доставки. Такие поля остаются неизвестными. Даже хорошая форма не доказывает работу почтовой инфраструктуры.

Отдельно опишите поведение при ошибке обработки. Если будущий обработчик недоступен, интерфейс должен сообщить о незавершённой заявке и возможности повторить действие. Не показывайте успешное подтверждение только потому, что кнопка нажата. Для модели достаточно двух состояний: допустимая заявка сохранена и операция не завершена. Это различие поможет при будущей технической реализации.

Передача макета

Редакторская рецензия проверяет совпадение обещания с первой главой. Если на форме написано «новости каждый день», а модель ограничена еженедельной подборкой уроков, нужно исправить текст или пересмотреть условия. Поля не должны жить независимо от процесса. Версия PROMISE-v1 связывает интерфейс, запись заявки и будущие письма в один понятный смысл.

В artifact.md есть все тексты интерфейса: подписи, кнопка, ошибки и сообщение после заявки. after.json добавляет FORM-01 и синтетический контакт R001 в состоянии pending. Предыдущая модель подписки сохранена. Ожидаемый результат — запись, которую нельзя включить в подборку до дальнейшего действия, и понятная человеку инструкция следующего шага.

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

Измените пример: адрес введён правильно, но тема не выбрана. Редактор решает, допускает ли модель общую подборку или требует хотя бы одну тему. В нашем варианте тема обязательна, поэтому заявка не принимается до выбора. Не подставляйте интерес «web» скрыто ради заполнения базы. Следующая глава добавит подтверждение и покажет, какие условия делают переход допустимым.