Действуй как product engineer. Autosave — это не «таймер каждые 5 секунд». Это контракт с юзером на то, что его работа не пропадёт. Контракт нужно сделать видимым, иначе юзер не доверяет.
Контент: {{content_type}} Совместность: {{collaboration}} Критичность данных: {{data_criticality}}
Закон autosave: 3 уровня доверия
| Уровень | Что юзер видит | Когда уместен |
|---|---|---|
| Тихий | Ничего. Просто сохраняется. | Никогда. Юзер не доверяет тишине. |
| Status indicator | Маленький текст «Saved» / «Saving...» / «Error» | Стандарт. 95% случаев. |
| Full UI feedback | Toast при save, иконка изменений, undo timeline | Critical-data, collaborative editing. |
Триггеры сохранения (не выбирай один — комбинируй)
Debounce on change
- 500-800ms после последнего keystroke — стандарт для текста.
- На blur — сразу, без debounce.
- На action (drag-drop, toggle, выбор) — сразу.
Интервал (safety net)
- Каждые 30-60 секунд — fallback, если debounce не сработал (например, юзер замер в поле).
На событиях
- Window blur / page hide — сразу save (юзер уходит).
- Перед navigation — sync save с beforeunload (если есть unsaved).
- На submit / explicit save — финальный save с подтверждением.
Индикация: статусы
| Статус | Текст | Иконка | Анимация |
|---|---|---|---|
| Sync'ed (default) | «Saved» или «All changes saved» | check (subtle grey) | none |
| Saving | «Saving...» | spinner (small) | в течение save |
| Saved (just now) | «Saved» + время «2s ago» (3 сек, затем fade в default) | check (briefly accent) | brief pulse |
| Error | «Couldn't save. [Retry]» | warning (red) | none |
| Offline | «Offline. Changes will sync.» | cloud-off | none |
| Conflict | «Updated by Alex. [Review changes]» | merge icon | attention-grabbing |
Расположение: top-right в header документа, или внизу editor'а. Не toast для каждого save — будет спам.
Conflict resolution
Single user, multi-device
- Last-write-wins с момента изменения. Если на устройстве A был более свежий save, чем на B — A выигрывает.
- При open document — pull latest state. Если local есть unsaved — diff и предложить resolve.
- Visual: badge «You have unsaved changes on this device» + buttons «Use local / Use server».
Multi-user collaborative
- OT / CRDT (operational transform / conflict-free replicated data types) — для текста.
- Optimistic locking — для структурных данных (server проверяет version-number, отказывает если конфликт).
- Visual feedback: «Updated by Alex 2s ago» badge при изменении другим юзером.
- Conflict UI: show diff inline с кнопками «Keep mine / Keep theirs / Merge».
Offline → online
- Local queue изменений.
- При reconnect — push queue, обрабатывать conflicts по правилам выше.
- Long offline → manual reconcile dialog: «You have 8 unsaved changes from offline. Review?»
Error handling
Транзиентные (network blip)
- Retry с exponential backoff: 1s, 2s, 4s, 8s, 16s.
- В UI: «Saving... (retry 2 of 5)».
- После 5 неудачных — «Save failed. [Retry] or [Download changes]».
Постоянные (server 500, permission denied)
- Стоп autosave.
- UI: «Couldn't save. <reason>. [Retry] [Export local copy]».
- Не теряй local state — храни в localStorage с time-out 24h.
Quota / size exceed
- Pre-flight check (если content > N MB → warning перед save).
- При ошибке: «File too large to autosave. Please <split / export / etc.>».
Granularity
- Document-level: весь документ → один save. Просто, но дорого при больших документах.
- Field-level: только изменённое поле. Лучше для структурных данных, форм.
- Operation-level: каждое действие как событие (best для collab — Figma, Notion model).
Выбор зависит от content_type:
- Text editor → operation-level (для performance) или document-level (для простоты).
- Form / config → field-level.
- Drawing → operation-level.
Undo + autosave
- Autosave не отменяет undo history.
- Undo возвращает к pre-edit state, save сохраняет это новое (отмененное) состояние.
- Time-travel: «Restore to 5 min ago» — если есть versioning.
Visibility: «вы видите свои изменения»
После любого autosave — UI не должен мигать. Юзер не видит save, только статус-индикатор. Не должно быть:
- Перерисовки документа после save.
- Loss of focus / scroll position.
- Loss of selection.
A11y
- Статус-индикатор —
aria-live="polite". «Saved» зачитывается screen reader-ом без перебивания. - Error —
aria-live="assertive"+role="alert". - Кнопка retry — нативная
<button>с понятным aria-label. - Conflict UI — focusable, можно навигировать клавиатурой.
Формат вывода
Решение по триггерам
- Debounce: X ms
- Interval safety net: Y sec
- На событиях: список
Индикатор
- Расположение
- Текст для каждого статуса (точные формулировки)
- Иконка для каждого
- Поведение (когда меняется, как долго показывается)
Conflict-стратегия
- Single user / multi-device: ...
- Multi-user collab: ...
- Offline reconcile: ...
Errors
- Транзиентные: retry policy
- Постоянные: UI + local backup
- Quota: pre-flight + error
Granularity
- Document / field / operation
- Почему этот выбор
Visibility rules
Что юзер должен / не должен видеть после save.
A11y
ARIA + announce.
Anti-patterns (НЕ делать)
- ❌ Save без индикации. Юзер не доверяет.
- ❌ Toast «Saved» на каждое сохранение. Спам, юзер ослепнет.
- ❌ Save только на blur. Юзер копит часовую сессию в одном поле — refresh теряет всё.
- ❌ Save без offline-fallback. Wi-Fi моргнул → save error → юзер бросает.
- ❌ Conflict «Кто-то изменил документ. Перезагрузите» — теряются local changes.
- ❌ Перерисовка после save. Юзер видит мигание — думает, что что-то сломалось.
- ❌ Generic «Save failed» без reason. Юзер не понимает, можно ли retry.
- ❌ Localstorage-only без server sync на critical data. Закрылся браузер — потерял.
- ❌ Save после navigation, без beforeunload. Юзер уходит → данные не сохранились → жалоба.
Полный UX-аудит сайта
Эвристическая оценка по Нильсену + проверка ключевых сценариев. На выходе — приоритизированный список проблем.
Конверсионный аудит формы регистрации
Карта трения по форме регистрации + 10 фиксов с ожидаемым импактом. Не «сделать красиво», а «убрать конкретное препятствие».
Mobile-friendly аудит (375px)
Аудит мобильной версии на iPhone SE: тач-таргеты, скролл, попапы, tap-vs-hover, input zoom.