Skip to content

Архитектура

Pulse состоит из трёх независимых частей: среды разработки презентаций, переносимого формата .pulse и PWA-плеера.

text
┌──────────────────────────┐
│ Проект презентации       │
│ HTML · CSS · entry.js    │
└────────────┬─────────────┘
             │ npm run pack

┌──────────────────────────┐
│ product-1.2.0.pulse      │
│ manifest · hashes · files│
└────────────┬─────────────┘
             │ ручной импорт маркетологом

┌──────────────────────────┐       ┌─────────────────────────┐
│ PWA на устройстве        │       │ Analytics backend      │
│ Cache Storage + IndexedDB│──────▶│ и кабинет (след. этап) │
│ Viewer без iframe        │ сеть  └─────────────────────────┘
└──────────────────────────┘

Центральный каталог не участвует в доставке. Сервер не решает, какие презентации видны на устройстве: набор пакетов формирует сам маркетолог.

Исходники презентации

text
presentations/<id>/
├── deck.json
├── entry.js
├── styles.css
├── slides/
└── assets/
  • deck.json задаёт стабильный ID, версию, название и настройки движка;
  • entry.js содержит код конкретной презентации и собирается как ES-модуль;
  • styles.css применяется только к установленной презентации;
  • slides/ содержит упорядоченные HTML-файлы;
  • assets/ содержит все ресурсы, необходимые офлайн.

Сборщик

scripts/pack-presentation.mjs создаёт воспроизводимый ZIP-архив с расширением .pulse. Точка входа собирается через esbuild, а каждый файл фиксируется в manifest.json хешем SHA-256.

Импорт и локальное хранение

Импортёр проверяет:

  • формат, версию схемы и runtime API;
  • семантическую версию презентации;
  • отсутствие абсолютных путей и .. (защита от ZIP Slip);
  • лимиты архива, количества и размера файлов;
  • наличие только заявленных файлов и совпадение SHA-256.

После проверки файлы атомарно записываются в Cache Storage, а manifest и сведения об установленной версии — в IndexedDB. Service Worker отдаёт их по виртуальным URL вида:

text
/_pulse/packages/product-demo/1.2.0/assets/cover.webp

Viewer

player.html загружает точную версию пакета из активной сессии, подключает его CSS и JavaScript, переписывает относительные URL ассетов на виртуальные локальные URL и запускает существующий движок Pulse. iframe не используется.

Поскольку entry.js выполняется как обычный JavaScript, импортировать следует только доверенные пакеты.

Аналитика

Во время показа движок собирает просмотры, переходы, клики и пользовательские события. После завершения они сохраняются в IndexedDB вместе с названием клиента, пользователем, packageId и packageVersion.

В текущей версии готова локальная outbox-очередь. Backend, вход по личному ключу и интерфейс аналитики проектируются отдельным следующим слоем.

Структура приложения

text
src/
├── engine/      # навигация, слайды, анимации, аналитика
├── packages/    # manifest, импорт, Cache Storage, IndexedDB, SW routing
├── player/      # запуск установленного пакета
├── app/         # PWA: список пакетов, клиент, активный показ, outbox
├── components/  # общие Web Components
└── sw.js        # offline shell и виртуальные URL пакетов

Демо-контент («Кардиолекс®») вымышлен.