06 — Технологический стек
Принятый стек продукта. Финальная валидация — с нанятым разработчиком; допустимое отклонение описано в разделе «Альтернативы».
Требования, которые определили выбор
- Три платформы одним небольшим коллективом: iOS + Android (тренер и клиент) + веб (конструктор тренера — в составе MVP, плюс админка).
- Local-first оффлайн с синхронизацией (NFR-3, CLI-3…CLI-5) — закладывается с первого дня, «прикрутить потом» нельзя.
- Drag-and-drop конструктор (CON-8), фоновый таймер с заблокированным экраном (TMR-3), загрузка/стриминг видео (VID, этап 2), пуш-уведомления (NTF), графики (PRO-6), HealthKit (INT-1, этап 3).
- РФ-специфика: хранение персональных данных в РФ (152-ФЗ), СМС-авторизация, платёжные провайдеры РФ.
Итоговый стек
Клиентская часть
| Слой | Технология | Обоснование |
|---|---|---|
| Мобильные приложения (тренер + клиент) | React Native + Expo (dev builds), TypeScript | Один язык со всем остальным стеком; зрелые библиотеки под все наши фичи; HealthKit/фоновые сервисы доступны через dev builds |
| Веб (конструктор тренера, админка) | React + Vite, TypeScript | Веб-конструктор — ядро продукта; React делит с mobile типы, бизнес-логику, парсер и API-клиент |
| Публичная страница тренера (BRD-2, этап 3) | Отдельный небольшой Next.js-сайт | Нужен SEO; не тащить SSR в основное SPA ради одной фичи |
| Монорепо | pnpm workspaces + Turborepo | Общие пакеты: domain-types, workout-parser, api-client, design-tokens |
Оффлайн и синхронизация — ключевое решение
PowerSync (self-hosted) + SQLite на клиенте + PostgreSQL на сервере.
- На устройстве — полноценная SQLite (op-sqlite в RN, wa-sqlite в браузере): приложение всегда читает и пишет локально, мгновенный UI и честный оффлайн (CLI-3, CLI-4).
- PowerSync Service реплицирует нужные данные из Postgres в клиентскую SQLite по декларативным sync-правилам (bucket'ы: клиент видит свои программы, тренер — своих клиентов).
- Записи идут через upload queue в наш backend API — критично для бизнес-правил: сервер, а не клиент, решает вопросы доступа (блокировка при неоплате PAY-1/PAY-5), валидации и прав. Ретраи и очередь оффлайн-записей SDK берёт на себя (CLI-5).
- Self-hosted редакция закрывает требование 152-ФЗ — весь контур в РФ.
- Медиа (GIF, видео) через PowerSync не синхронизируется — только структурированные данные; загрузкой медиа управляет отдельный кэш-слой по правилам из 07 — Оффлайн-режим.
Почему PowerSync, а не альтернативы:
| Вариант | Вердикт |
|---|---|
| PowerSync | ✅ Самый зрелый вариант для production-mobile; полноценные SDK для RN и веба; self-hosted; Postgres |
| ElectricSQL | Хорош для веба, но это read-path-движок общего назначения; RN — не основной фокус |
| WatermelonDB | Только локальная БД, серверный sync-протокол пишем сами — лишний объём работы |
| CRDT (Automerge/Yjs) | Для совместного редактирования документов; наша модель данных реляционная, конфликтов мало — overkill |
| Самописный sync | Классическая яма на месяцы; берём готовое |
Серверная часть
| Слой | Технология | Обоснование |
|---|---|---|
| API | Node.js + TypeScript, NestJS (или Fastify) | Один язык с клиентами; структура NestJS удобна при росте команды |
| Контракт API | tRPC внутри монорепо (или REST + OpenAPI — по вкусу команды, некритично) | End-to-end типы против целого класса багов |
| БД | PostgreSQL 16+ | Источник истины; требование PowerSync |
| Очереди | Redis + BullMQ | Уведомления (NTF-1), еженедельные анкеты (SUR-1), транскодинг видео |
| Файлы и видео | S3-совместимое хранилище РФ (Яндекс Object Storage / Selectel) + ffmpeg-воркеры + HLS | VID-1 (этап 2); стоимость хранения закладывается в тарифы |
| Auth | Телефонный OTP: СМС-провайдер РФ (SMS Aero / SMSC), дешёвые альтернативы — flash call, Telegram Gateway; JWT + refresh | REG-2; Firebase Auth в РФ не опора |
| Push | FCM + APNs через Expo Notifications | NTF |
| Платежи (этап 2) | Т-Банк (интернет-эквайринг / касса) | Уже используется в других продуктах основателя |
| Хостинг | Яндекс Cloud / Selectel (managed Postgres + Docker Compose на старте) | 152-ФЗ; Kubernetes на старте не нужен |
| Мониторинг | Sentry (crash + errors), простые метрики | Скорость конструктора — продуктовая метрика (NFR-4), меряем с первого дня |
Библиотеки под ключевые фичи
| Фича | Web | Mobile |
|---|---|---|
| Drag-and-drop (CON-8) | dnd-kit | react-native-gesture-handler + reanimated |
| Графики (PRO-6) | recharts | victory-native (Skia) |
| Таймер (TMR-1…4) | — | expo-audio background mode + local notifications; Android — foreground service |
| Парсер «EMOM 12» (TMR-1, CON-5) | Общий TS-пакет workout-parser, правила/грамматика (без LLM в MVP) |
тот же пакет |
Почему не Flutter и не нативная разработка
- Flutter: веб-конструктор — ядро продукта, а Flutter Web (canvas-рендеринг) слаб для текстонагруженных рабочих SPA: инпуты, буфер обмена, доступность, вес бандла. Пришлось бы писать веб отдельно на React → два стека и два набора компетенций.
- Нативная разработка / Kotlin Multiplatform: три UI-кодовые базы (SwiftUI, Compose, веб) — не по бюджету маленькой команды на скорости, которая нам нужна.
Обязательные спайки перед стартом (первая неделя разработки)
- PowerSync end-to-end: RN + веб-клиент, sync-правила «тренер видит своих клиентов», оффлайн-запись результата → синхронизация. Главный технический риск проекта.
- Drag-and-drop длинной тренировки в RN: 60fps на списке из 30+ упражнений.
- Парсер тренировочной нотации: «EMOM 12», «10 rounds / 30 sec work / 15 sec rest» — прототип грамматики.
Спайк таймера (звук и вибрация при заблокированном экране — TMR-2, TMR-3) проводится перед началом этапа 2.
Альтернативы
Если нанятый разработчик — сильный Flutter-специалист: мобильные на Flutter допустимы (PowerSync имеет зрелый Flutter SDK), но веб-конструктор всё равно пишется на React — это два стека, и решение надо принимать осознанно. Остальная серверная часть не меняется.