Главная/React и Next.js/Блупринты/Стейт & Real-time/Offline-First PWA с синхронизацией фоновых мутаций и IndexedDB
К карточкам раздела «Стейт & Real-time»
Стейт & Real-time(ТЗ 8 из 10)
ТЗ: Offline-First PWA с синхронизацией фоновых мутаций и IndexedDB
Стейт & Real-time1 шагов • +5 XP

ТЗ: Offline-First PWA с синхронизацией фоновых мутаций и IndexedDB

Спецификация для приложений полевых инженеров: кэширование статики через Service Worker, локальная БД в IndexedDB и автоматическая фоновая синхронизация очередей при появлении сети.

~12 ч работыService WorkerIndexedDB (idb)Background Sync APISerwist / WorkboxIdempotency Keys
+5 XP за шаг
Выполнено 0 из 1 шагов (0%)
Трудозатраты~12 рабочих часов
Фриланс вилка~$540 – $900 (€480 – €840)
Оценка веб-студии~$1,140 – $1,920 (€1080 – €1800)

ТЗ заказчика (исходный бриф):

Инженер не должен думать о наличии интернета. Нажал "Сохранить акт" — данные мгновенно записаны в локальную память. Как только машина выехала из подвала и поймала 3G/LTE — все данные ушли в базу.
Ключевые требования:
  • •Надежное локальное хранилище черновиков и бинарных фото в IndexedDB
  • •Очередь отложенных запросов (Offline Mutation Queue) с автоматическими повторами
  • •Идемпотентные ключи запросов для предотвращения дублирования актов
  • •Индикатор статуса сети (Online / Offline / Syncing) в интерфейсе
Ограничения проекта:
  • •Потеря данных при закрытии приложения недопустима
  • •Синхронизация должна возобновляться даже при свернутом браузере
Критерии приёмки (KPI):
  • Время сохранения оффлайн-записи в IndexedDB < 10ms
  • 100% доставка накопленных мутаций при восстановлении сети

Пошаговое практическое руководство по ТЗ

Подробный разбор архитектуры, код реализации и советы эксперта по каждому этапу:

1
Этап 1 из 1

Менеджер очереди мутаций на базе библиотеки idb

~60 минСложный

Практическое руководство:

Создать модуль offlineQueue.ts с открытием базы IndexedDB, записью запросов в хранилище outbox и функцией flushQueue при онлайн-событии.

Важные технические нюансы и подводные камни:

Сериализуйте FormData в плоский JSON с base64 для бинарных вложений перед сохранением в IndexedDB.

Архитектурная база (Почему выбрано такое решение):

IndexedDB не имеет ограничений в 5 МБ как localStorage и поддерживает асинхронные транзакции без блокировки UI потока.

Совет эксперта (Best Practice):

Слушайте событие window.addEventListener("online", flushMutationQueue) для автоматической отправки.

Ожидаемый артефакт этапа:

Модуль очереди оффлайн-мутаций с персистентным хранением в IndexedDB.

TYPESCRIPT
// lib/offline/queue.ts
import { openDB, DBSchema } from 'idb'

interface OfflineMutation {
  id: string
  url: string
  method: 'POST' | 'PUT' | 'PATCH'
  payload: unknown
  createdAt: number
}

interface AppDB extends DBSchema {
  outbox: {
    key: string
    value: OfflineMutation
  }
}

const dbPromise = openDB<AppDB>('fullstacklab-offline', 1, {
  upgrade(db) {
    db.createObjectStore('outbox', { keyPath: 'id' })
  }
})

export async function enqueueMutation(url: string, method: 'POST' | 'PUT' | 'PATCH', payload: unknown) {
  const db = await dbPromise
  const mutation: OfflineMutation = {
    id: crypto.randomUUID(),
    url,
    method,
    payload,
    createdAt: Date.now()
  }
  await db.put('outbox', mutation)
}

export async function flushMutationQueue(): Promise<number> {
  const db = await dbPromise
  const mutations = await db.getAll('outbox')
  let synced = 0

  for (const m of mutations) {
    try {
      const res = await fetch(m.url, {
        method: m.method,
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(m.payload)
      })

      if (res.ok) {
        await db.delete('outbox', m.id)
        synced++
      }
    } catch {
      // При сетевой ошибке прерываем цикл до следующего подключения
      break
    }
  }

  return synced
}

Типичные грабли на этом ТЗ

1 антипаттерна

Что сдаём клиенту (Deliverables)

Чек-лист сдачи
Очередь мутаций на IndexedDB
Service Worker кэширование статики
Автоматический фоновый синк