Модуль 7.2. Дизайн форм и валидации
Темы: модели ввода, требования к полям, доступность. Артефакт: спецификация форм. Практика: описать правила валидации формы.
Форма — главный интерфейс обмена данными между пользователем и системой. Роль системного аналитика (SA): зафиксировать модель ввода, правила валидации (полевые, кросс-полевые, серверные), состояния (loading/empty/error/async), доступность (a11y), требования к безопасности/локалям, и связать всё это с AC/BDD/OpenAPI/RTM.
Модель ввода: что именно мы принимаем
Слои модели
- Доменная модель (UL): сущности/атрибуты (модули 3.1–3.2).
- Модель формы: поля и их представления (UI-типы, маски).
- Модель транспорта: JSON схему запроса/ответа (OpenAPI), коды ошибок.
- Модель хранения: нормализованные данные (ER), ограничения БД.
Виды полей и рекомендации
|
Поле |
Хранение |
UI-тип |
Ввод/клавиатура |
Примечания |
|---|---|---|---|---|
|
|
text (NFC) |
<input type="email"> |
inputmode= |
Локаль-независимый, lowercasing для сравнения, хранение в исходном регистре |
|
Телефон |
E.164 (+71234567890) |
<input type="tel"> |
inputmode= |
Нормализация, регион по стране адреса/сим-оператора |
|
Деньги |
DECIMAL(18,2) + currency CHAR(3) |
numeric+селектор валюты |
inputmode= |
Десятичный разделитель по локали, но хранение в стандартном формате |
|
Дата/время |
timestamptz |
date/time pickers |
локальная TZ |
В форме — локаль, в хранении — UTC |
|
Адрес |
структурно (улица/дом/кв/почтовый/страна) |
3–6 полей + подсказки |
— |
Подсказки (autocomplete), справочники, валидация по стране |
|
ИНН/идентификаторы |
text |
text |
inputmode= |
Контроль длины/чек-сумм, маска вывода |
Обязательность/необязательность
Для каждого поля фиксируем: required?, nullable?, дефолт, источник автозаполнения (autocomplete), основания для сбора (privacy).
Валидация: уровни и стратегия
Уровни
- Клиентская (быстрый UX): формат/диапазон/обязательность.
- Серверная (истина): сложные правила, авторизация, кросс-полевые проверки, интеграции.
- Кросс-полевые: «сумма ≤ списанной», «from ≤ to», «страна ↔ индекс».
- Асинхронные: проверка уникальности, лимиты ролей, внешние справочники.
Классы эквивалентности и границы
Используйте EP/BVA (модуль 6.1): мин−1, мин, мин+1 … макс+1; для строк — длина/набор символов; для дат — окна и TZ.
Поведение при ошибках
- Inline-ошибка у поля + суммарный баннер (если нескольких ошибок).
- Сообщение: человеческий текст + машинный код (code) для QA/логов.
- Поле с ошибкой получает фокус/описание (aria-describedby).
- Кнопка сабмита активна, если это не гарантированно неверные данные; двойной клик/повтор предотвращаем идемпотентностью.
Структура ответа об ошибке (REST)
{
"code": "VALIDATION_ERROR",
"message": "Исправьте отмеченные поля",
"errors": [
{"field": "amount", "code": "AMOUNT_BELOW_MIN", "message": "Минимальная сумма 0,01"},
{"field": "currency", "code": "CURRENCY_NOT_SUPPORTED", "message": "Валюта не поддерживается"}
],
"correlationId": "corr-123"
}
Правила по типам полей (готовые блоки)
Числа/деньги
- Диапазон: min/max, точность: scale (например, 2 знака).
- Локаль: ввод может содержать , как разделитель; нормализуем на клиенте.
- Нельзя автокорректировать «тихо»; если привели значение — показываем, что изменили.
Примеры ошибок: AMOUNT_BELOW_MIN, AMOUNT_ABOVE_MAX, AMOUNT_SCALE_INVALID.
Строки/имена
- Длина: min/max, допускаем диакритики, дефисы, апострофы.
- Тримминг пробелов, запрет невидимых символов (ZWSP).
- Юникод-нормализация (NFC) для сравнения/хранения.
- Формат базовой RFC-проверкой (не «идеальной»), запрет пробелов/невидимых.
- Верификация MX/SMTP — асинхронная/по событию, не блокируем сабмит.
Телефон
- Нормализация к E.164, проверка длины по стране, маска в UI — только для удобства.
- Храним чистый номер +7…, показываем форматированным.
Дата/время
- Ввод в локали пользователя; сервер принимает ISO-8601/TZ.
- Валидация окна (from ≤ to ≤ from+90д), переходы DST.
Адрес
- Поля зависят от страны (динамическая форма).
- Индекс/регион — по справочнику; предупреждения не блокируют, если справочник «не знает» новый индекс.
Идентификаторы/коды
- Контроль длины/алфавита/чек-суммы (например, Лuhn).
- Маскирование при отображении: **** 1234.
Доступность (a11y) и UX-состояния
Обязательные требования
- Лейбл связывается с полем (<label for="id">), плейсхолдер — не лейбл.
- Группы полей — <fieldset><legend>…</legend>.
- Ошибки озвучиваются: контейнер role="alert", поле с ошибкой — aria-invalid="true", описание — aria-describedby="error-id".
- Фокус-контур заметен; клавиатурная навигация полна.
- Контраст текста ≥ 4.5:1, размеры кликабельных зон ≥ 44×44 px.
- Атрибуты autocomplete (например, autocomplete="email", address-line1, postal-code, cc-name …), inputmode (numeric/tel/decimal), lang, dir при RTL.
Состояния формы
- loading (skeleton, disable primary);
- content;
- inline errors + error summary;
- partial failure (частичные ошибки списков);
- offline (кеш/сохранение черновика);
- 202/async (ожидание результата).
Безопасность, приватность, эксплуатация
- CSRF (если cookie-сессии), rate-limit, bot-защита для открытых форм.
- Маскируем PII в логах/трейсах; минимизация: собираем только нужное.
- Идемпотентность (заголовок Idempotency-Key), защита от двойной отправки, таймауты/ретраи с джиттером.
- Конфигурируемые лимиты (через feature flags/config).
- Локализация сообщений ошибок, единый словарь ошибок.
Примеры (кейсы)
Чекаут: «Адрес + оплата (создание платежа)»
Поля: email*, phone, country*, postalCode*, address1*, address2, amount*, currency*.
Правила:
- amount: 0.01…100000.00, scale=2.
- currency: RUB|USD|EUR; иначе CURRENCY_NOT_SUPPORTED.
- postalCode: по стране (RU: ^\d{6}$, DE: ^\d{5}$, …).
- Кросс-поле: currency соответствует выбранному каналу (если канал ограничивает).
- Сервер: orderId принадлежит tenant; идемпотентность по Idempotency-Key.
AC-фрагменты:
- AC-1: Сумма на границе 0.01/100000.00 — валидна; 0.00/100000.01 — 422.
- AC-2: Повтор с тем же Idempotency-Key → тот же paymentId.
- AC-3: 202 при недоступном PSP, экран ожидания ≤ 2 мин.
Возврат
amount ≤ capturedAmount, причина обязательна; роль/лимит оператора (ABAC), аудит-запись.
Артефакт: Спецификация форм (шаблон)
# Form Spec — <Название формы> vX.Y
Owner: <Команда> | SA: <ФИО> | Связи: AC-…, OpenAPI, RTM, UL
## 1. Назначение и сценарии
- Цель/персоны
- Состояния: loading/content/empty/error/offline/202
## 2. Поля
| name | label | type | required | constraints | examples | autocomplete/inputmode |
|------|-------|------|----------|-------------|----------|------------------------|
| email | E-mail | email | true | RFC base, max 254 | user@site.ru | email |
| amount | Сумма | money | true | 0.01..100000.00, scale=2 | 10.00 | decimal |
...
## 3. Кросс-валидация
- amount ≤ capturedAmount
- from ≤ to ≤ from+90d
- country ↔ postalCode (по справочнику)
## 4. Ошибки (словарь)
- AMOUNT_BELOW_MIN: "Минимальная сумма 0,01"
- CURRENCY_NOT_SUPPORTED: "Валюта не поддерживается: {code}"
- POSTAL_FORMAT_INVALID: "Индекс не распознан для страны {country}"
Структура ответа: см. JSON (модуль)
## 5. Доступность
- label/for, aria-* атрибуты, role="alert" для ошибок
- контраст, таб-порядок, focus visible
## 6. Транспорт
- OpenAPI: /v1/payments (schema v1.2)
- Заголовки: Idempotency-Key (1..128 ASCII)
- Ответы: 201/202/4xx (карта ошибок)
## 7. Безопасность/Приватность
- CSRF/rate limit, PII-маскирование в логах
- Основание обработки, срок хранения, маски вывода
## 8. Наблюдаемость
- Метрики: form_submit_total, validation_error_total{field,code}
- Логи: correlationId, error.code
- Трейсы: атрибуты http.route, validation.count
## 9. Тест-дизайн (ссылка)
- EP/BVA таблицы, негативы, e2e шаги
## 10. Локализация
- RU/EN строки ошибок, плейсхолдеры, форматы
Чек-лист формы (короткий)
- Поля, типы, обязательность, длины, допустимые символы.
- EP/BVA для чисел/дат/строк; кросс-валидация.
- Карта ошибок: коды/тексты/локализация; JSON-структура ответа.
- Идемпотентность/анти-double-submit; таймаут/ретраи.
- a11y: labels, aria-describedby, role=alert, фокус, контраст.
- autocomplete/inputmode/маски — включены; хранение в нормализованном виде.
- Наблюдаемость: метрики, логи без PII, correlationId.
- Связи: AC/BDD/OpenAPI/RTM/ER.
Риски и как их гасить
|
Риск |
Симптом |
Меры |
|---|---|---|
|
Формат-центричная валидация ломает UX |
Пользователь «бьётся» об маску |
Мягкая нормализация, понятные сообщения, примеры |
|
Дубли из-за повторов |
Два платежа |
Idempotency-Key, блокировка повторной отправки |
|
Локали «ломают» суммы/даты |
10,5 → 105 |
Нормализация на клиенте, явные правила, демо-примеры |
|
Невидимые символы в строках |
«Одинаковые» e-mail не совпадают |
Юникод NFC, очистка ZWSP |
|
Недоступные ошибки |
Пользователь «не слышит» ошибку |
role=alert, aria-invalid, перевод фокуса |
|
Слишком строгие справочники |
Новые индексы не проходят |
Переключение: предупреждение вместо блокировки, ревизия справочника nightly |
|
PII в логах |
Риски приватности |
Маскирование/allowlist, тесты-сканеры в CI |
Практика: описать правила валидации формы (60–90 мин)
Задание: подготовьте Form Spec для формы «Создание платежа» (или вашей).
Шаги:
- Заполните разделы 2–4 шаблона (поля, кросс-валидация, словарь ошибок).
- Пропишите EP/BVA для amount, Idempotency-Key, postalCode (по RU/DE).
- Опишите a11y-требования (labels, aria, focus).
- Укажите OpenAPI-схему ошибок и заголовков.
- Добавьте метрики и логи (observability).
Критерии зачёта:
- Поля/правила полные; есть кросс-валидация.
- Ошибки с кодами/текстами и структурой ответа.
- EP/BVA покрывает границы.
- a11y-требования выполнимы.
- Связи с AC/BDD/OpenAPI присутствуют.
Вопрос–Ответ
В: Нужно ли дублировать клиентскую и серверную валидацию?
О: Да. Клиент — для UX, сервер — источник правды. Сообщения должны быть согласованы.
В: Маски в поле телефона обязательны?
О: Не всегда. Лучше нормализовать ввод и отображать форматированно; хранить E.164.
В: Где хранить тексты ошибок?
О: В едином словаре (i18n) с ключами-кодами ошибок — консистентность UI/логов/ответов.
В: Что делать с «умными» автозаполнениями браузера?
О: Настроить autocomplete правильно; для критичных полей — проверка после автозаполнения (blur/change).
В: Как учитывать доступность для screen-reader?
О: Лейблы/описания, role=alert для ошибок, порядок табов, aria-live для динамики, фокус-контур.
В: Как тестировать валидацию?
О: EP/BVA + негативы (6.1) + BDD-сценарии (6.2). Проверяйте API-ошибки, логи без PII, SQL-инварианты.
Шпаргалка
- Валидация: клиент + сервер + кросс-поле.
- Сообщения: человек + код, единый словарь.
- Идемпотентность/анти-double-submit — всегда.
- Локаль: ввод свободный → хранение нормализованное (UTC, E.164, DECIMAL).
- a11y: labels, aria, контраст, фокус.
- Связи: UL/ER ↔ Form Spec ↔ OpenAPI ↔ AC/BDD ↔ RTM.



