Аудит логической согласованности: единые правила через все фичи
Находит противоречия и асимметрии МЕЖДУ фичами: одно действие → разный результат в разных местах, роли работают по-разному в зависимости от раздела, термины меняются. Не per-feature testing — это поиск нарушений продуктовой логики.
functional-regression-matrix проверяет работает ли фича. Этот аудит проверяет другое: не противоречит ли одна фича другой. Это разница между «кнопка Delete работает» и «Delete в /projects требует подтверждения, а Delete в /drafts — нет, и обе операции необратимы».
Противоречия между фичами особенно опасны: каждая функция по отдельности проходит тест, но вместе они разрушают mental model пользователя. Такие баги живут месяцами — они незаметны для разработчика отдельной фичи и невидимы в изолированных тестах.
Product: {{product_url}} Scope: {{scope}}
1. Метод: обратный вывод правил продукта
Прежде чем искать нарушения — нужно сформулировать implicit rules продукта. Это правила, которые никто не записал, но которые пользователь ожидает после первого взаимодействия.
Как формулировать правило:
"Если пользователь делает X, продукт делает Y — везде, всегда."
Примеры implicit rules, которые нужно вывести для {{product_url}}:
- "Удаление необратимого объекта всегда требует явного подтверждения"
- "Неверифицированный пользователь не видит данные других пользователей"
- "Сортировка и фильтр сбрасываются при переходе на другую страницу"
- "Число в badge обновляется немедленно после действия"
- "Даты отображаются в timezone пользователя"
- "Disabled кнопка объясняет почему она disabled"
Для каждой implicit rule: запиши формулировку → затем проверь на каждой surface из {{scope}}.
2. Категории conformance: что проверять
2.1 Одно действие → один результат
Каждое действие должно давать предсказуемый результат независимо от того, где пользователь его выполняет.
Inventory действий:
Delete / Remove
- Где есть: перечисли все места в {{scope}} где можно удалить что-либо
- Проверить по каждому: есть ли confirm-диалог? Если нет — почему? Есть ли undo? Если есть undo в одном месте и нет в другом — это нарушение
- Именование: «Удалить» vs «Удалить навсегда» vs «Архивировать» — единообразно ли?
Save / Submit
- Автосохранение: в некоторых формах есть, в других нет — пользователь знает об этом?
- Explicit save: success-сообщение одинаковое везде? Toast, inline message, redirect — один паттерн?
- Unsaved changes warning: при навигации прочь — везде ли предупреждает?
Share / Export / Copy link
- Одинаков ли permission check перед share?
- Копирует ли ссылку в clipboard везде или где-то открывает диалог, а где-то просто копирует?
Bulk actions
- Если есть bulk-select: одинаково ли ведут себя bulk actions (delete, archive, export) как одиночные?
- Подтверждение при bulk delete: есть везде или только иногда?
Таблица conformance для действий:
| Action | Surface A | Surface B | Surface C | Consistent? | Нарушение |
|---|---|---|---|---|---|
| Delete item | /projects: confirm modal | /drafts: no confirm | /trash: no confirm | ✗ | /drafts: необратимо, нет confirm |
| Save form | /settings: toast + stay | /profile: redirect + toast | /billing: redirect, no toast | ✗ | inconsistent feedback |
| Copy link | /share dialog: clipboard | /post header: new tab | — | ✗ | разное поведение, одна иконка |
2.2 Permissions и роли: равномерное применение
Нарушение: действие разрешено на одной странице и неочевидно запрещено на другой для той же роли.
Метод:
- Перечисли все роли в {{scope}}: anonymous, user, admin, owner, editor, viewer, suspended, trial, etc.
- Для каждой роли — составь список: «что эта роль НЕ должна уметь»
- Проверь каждый запрет на каждой surface
Что искать:
- ✗ Admin может удалять в /dashboard, но не видит кнопку Delete на /reports — фича есть, UI скрывает
- ✗ Editor может редактировать через прямой URL /item/123/edit, но не через UI (скрытая кнопка, но endpoint открыт)
- ✗ Viewer видит «Export» кнопку, кликает — получает 403 без объяснений вместо disabled с tooltip
- ✗ Trial пользователь может создать 3 объекта в /dashboard и неограниченно через API /create
- ✗ Suspended пользователь: в одном разделе видит данные, в другом — нет
Permission conformance matrix:
| Action | Role | Surface A | Surface B | Surface C | Consistent? |
|---|---|---|---|---|---|
| Delete | admin | ✓ visible + works | ✓ visible + works | ✗ hidden | ✗ |
| Export | viewer | disabled + tooltip | enabled → 403 | hidden | ✗ |
| Create | trial | limited (3) | unlimited via API | — | ✗ |
2.3 State-model coherence: жизненный цикл объектов
Каждый объект в продукте имеет lifecycle states (draft → published → archived → deleted). Эти состояния должны вести себя одинаково в каждом представлении объекта.
Метод:
- Выдели все типы объектов в {{scope}} (Post, Project, User, Order, etc.)
- Для каждого типа — нарисуй state machine: какие states есть, какие transitions возможны
- Проверь: одинаково ли поведение объекта в каждом из состояний во всех представлениях
Что проверить:
- Draft post: в /dashboard виден, в /profile не виден, в /admin виден — ожидаемо ли?
- Archived project: можно ли его редактировать? Ответ должен быть одинаков в /projects, /project/123, и через «Recent» в sidebar
- Deleted item: немедленно исчезает из списка, или сначала «помечается», или попадает в trash — паттерн одинаков?
- «Pending» payment: какие действия доступны пока pending? Одинаковы ли они на /orders и /order/123?
State conformance table:
| Object | State | /list view | /detail view | /admin | Consistent? | Нарушение |
|---|---|---|---|---|---|---|
| Post | draft | виден | виден | виден | ✓ | — |
| Post | deleted | исчезает | 404 | виден | ✗ | admin видит, но нет CTA restore |
| Project | archived | hidden | read-only | edit available | ✗ | /admin нарушает read-only rule |
2.4 Терминология: один концепт = одно слово
Inventory терминов:
Составь список концептов продукта → для каждого проверь как он называется в разных местах.
| Концепт | Встречается как | Кол-во вариантов | Canonical | Где исправить |
|---|---|---|---|---|
| Сохранённый элемент | «Закладки», «Избранное», «Saved», «Сохранённые» | 4 | «Saved» | /profile header, sidebar, empty state, notification copy |
| Рабочее пространство | «Workspace», «Организация», «Team», «Аккаунт» | 4 | «Workspace» | /settings, onboarding, billing, invitation email |
| Бесплатный тариф | «Free», «Basic», «Starter», «Бесплатно» | 4 | «Free» | /pricing, upgrade modal, invoice, settings/billing |
Где искать: UI labels, page titles, empty state copy, toast messages, email notifications, API error messages, URL slugs, onboarding flow.
2.5 Форматирование дат, чисел, валют
Parity rule: одно поле отображается одинаково в каждом месте где встречается.
Date formats — инвентаризовать все представления дат в {{scope}}:
- «2 минуты назад» / «сегодня в 14:30» / «27 мая» / «27.05.2026» / «May 27, 2026»
- Ожидаемые правила: relative for <24h, absolute for older — но применяется ли везде?
- Timezone: показывается ли в UTC или user timezone — везде ли одинаково?
- Created date vs Updated date vs Deleted date: одинаковый формат?
Number formats:
- 1000 vs 1,000 vs 1 000 — разделитель тысяч единый?
- 0 vs пусто vs «—» для нулевых значений — единый паттерн?
- Percentage: 42% vs 42.0% vs 0.42 — единый?
Currency:
- $10 vs $10.00 vs 10 USD vs USD 10 — единый паттерн на invoice / dashboard / checkout?
- Отрицательные значения: -$10 vs ($10) vs $-10
| Field | Location A | Location B | Location C | Consistent? |
|---|---|---|---|---|
| Created date | «3 дня назад» (/dashboard) | «27.05.2026» (/detail) | «May 27» (/export) | ✗ |
| Price | «$9.99» (/pricing) | «9.99 USD» (/invoice) | «$10» (/checkout rounded) | ✗ |
2.6 Empty / error / loading состояния
Parity rule: одинаковые ситуации → одинаковый тип UX-ответа.
Empty states:
- Список без элементов: иллюстрация + заголовок + CTA — везде ли? Или где-то просто белый блок?
- Search без результатов: «Ничего не найдено» — везде одинаково или иногда пусто?
- Фильтр дал 0 результатов: предлагается ли сбросить фильтр везде?
Error states:
- Network error: retry button — везде ли?
- 404 resource: redirect или inline error — единый паттерн?
- Server 500: generic «something went wrong» или developer-message в продакшне (security issue)?
- Validation: inline vs toast vs page-level — единый паттерн для форм одного типа?
Loading states:
- Skeleton vs spinner vs none: единый паттерн для одинаковых данных?
- Кнопка Submit во время запроса: disabled + spinner везде? Или где-то кликабельна (double-submit)?
2.7 Destructive action policy
Собери все destructive actions в {{scope}} (delete, remove, revoke, cancel, clear, reset) → проверь единство политики:
| Action | Destructive? | Reversible? | Confirm required? | Surface A | Surface B | Consistent? |
|---|---|---|---|---|---|---|
| Delete post | yes | no (trash) | yes | /posts: ✓ | /dashboard widget: ✗ no confirm | ✗ |
| Revoke API key | yes | no | yes | /settings/api: ✓ | /admin/users: ✓ | ✓ |
| Cancel subscription | yes | no | yes | /billing: ✓ | /mobile: ✗ no confirm | ✗ |
| Clear search history | yes | no | no | /search: ✗ no confirm | — | needs rule |
Правило выводится так: если операция необратима → confirm всегда. Исключения документируются (например: «Unsave item — обратима через re-save, confirm не нужен»).
2.8 Optimistic vs pessimistic update: единый паттерн
Смешение — источник confusion. Выбери стратегию для каждого класса мутаций:
- Optimistic: UI обновляется немедленно, откатывается при ошибке. Хорошо для: toggle (like, bookmark, follow), sort/reorder, inline edit low-stakes полей.
- Pessimistic: UI ждёт подтверждения сервера. Хорошо для: delete, payment, permission change, publish.
Проверить: в продукте есть ли места где одна и та же операция иногда optimistic, иногда pessimistic? Или где optimistic применён к dangerous action (delete с optimistic removal → rollback на ошибке) без rollback-animation?
2.9 Что сохраняется при навигации, logout, refresh
Inventory persistence expectations:
| State | On navigation | On logout | On refresh | Actual behavior | Consistent? |
|---|---|---|---|---|---|
| Scroll position | сбрасывается | — | сохраняется (browser) | ✓ | — |
| Фильтры | сбрасываются | — | зависит от URL | ✓ если в URL params | — |
| Draft form | теряется | теряется | теряется | ✗ / предупреждение? | — |
| Search query | сохраняется (URL) | — | сохраняется | ✓ | — |
| Modal open state | закрывается | — | закрывается | ✓ | — |
| Pagination page | сбрасывается | — | сохраняется (URL) | зависит | нужно проверить |
| Sort order | сохраняется (URL) | — | сохраняется | ✓ если в URL | — |
Нарушение: фильтры сохраняются в URL на одной странице, теряются на другой — потому что один компонент использует URL params, другой — local state.
2.10 Pagination, sort, filter defaults
- Default sort: одинаков ли на всех list views? (new first? alphabetical? relevance?)
- Default page size: 10 / 20 / 25 / 50 — единый?
- После reset filters: возвращаются ли к defaults единообразно?
- Empty search vs all items: одинаковый ли view?
3. Conformance matrix: финальная таблица
После прохода по всем категориям — заполни conformance matrix:
| Rule | Feature/Surface 1 | Feature/Surface 2 | Feature/Surface 3 | Violation | Canonical | Severity |
|---|---|---|---|---|---|---|
| Destructive action → confirm | /posts delete: ✓ | /drafts delete: ✗ | /comments delete: ✓ | /drafts: нет confirm | всегда confirm | High |
| Admin can delete | /projects: ✓ | /reports: ✗ hidden | /admin: ✓ | /reports: скрыто | везде visible | Medium |
| Date: relative <24h | /feed: ✓ | /notifications: ✓ | /detail: ✗ absolute | /detail: нарушает правило | relative <24h | Low |
| "Workspace" term | /settings: ✓ | /billing: «Team» | /onboarding: «Organization» | 2 поверхности | «Workspace» | Medium |
Для каждого нарушения:
- Две конфликтующие локации
- Какая canonical (и почему)
- Severity: Critical (security/data loss) / High (user confusion) / Medium (inconsistency) / Low (cosmetic)
Anti-patterns
- ❌ Тестировать фичи изолированно — это выявляет per-feature bugs, не cross-feature contradictions
- ❌ Строить conformance matrix без предварительного формулирования implicit rules — тогда нечему conforming
- ❌ Считать «работает по-другому» нарушением без проверки: иногда разница намеренна и задокументирована
- ❌ Игнорировать мобильные/touch surfaces — часто отдельно реализованы и дрейфуют от desktop behavior
- ❌ Пропускать email- и push-уведомления — они часть продукта и нарушают терминологию и форматы
- ❌ Audit без role-switching — permission bugs invisible если тестировать только под admin
- ❌ Фиксировать только «что сломано», не «что canonical» — без canonical невозможно принять решение о фиксе
- ❌ Проверять только UI, не проверяя API endpoints — permission checks на UI могут отсутствовать на API
- ❌ Пропускать async flows (email, webhooks, cron) — они нарушают state-model чаще всего
Output
- Implicit rules doc — список сформулированных правил продукта из {{scope}} (10-30 правил)
- Conformance matrix — rule × surface × pass/fail/N.A., с нарушениями выделены
- Violation list — каждое нарушение: два конфликтующих места, canonical, severity, fix
- Terminology audit — таблица концепт → варианты → canonical → где исправить
- Format audit — дата/число/валюта: distinct formats per field + canonical
- Permission gap report — где роль имеет доступ в UI но не в API или наоборот
- Priority fix list — топ-10 нарушений по severity для первого PR
Полный UX-аудит сайта
Эвристическая оценка по Нильсену + проверка ключевых сценариев. На выходе — приоритизированный список проблем.
Аудит производительности (Core Web Vitals)
Глубокая проверка LCP, INP, CLS с привязкой к коду и приоритизированным планом исправлений.
Аудит доступности по WCAG 2.2 AA
Проверка контраста, клавиатурной навигации, скринридеров, фокус-индикаторов и ARIA.