-
Notifications
You must be signed in to change notification settings - Fork 0
Architecture
dripips edited this page Jun 24, 2026
·
2 revisions
-
Фронтенд: Vite + React 19 + TypeScript + Tailwind v4. PWA через
vite-plugin-pwa(injectManifest, собственный service worker для push). Единый бандл отдаётся API. -
Бэкенд: Fastify 5 на Node 24, со встроенным
node:sqlite— без внешней БД и без ORM. - Авторизация: подписанный JWT в httpOnly-cookie; сессии на 10 лет (переживают деплои). Роль читается из БД на каждый запрос, поэтому повышение/понижение прав применяется без перелогина.
Весь учебный материал — обычные файлы в content/, разбираются при старте сервера (и подхватываются на лету при изменении):
-
lessons/*.md— фронтматтер gray-matter (id, order, level, phase, exercises, reading, …) + теория в Markdown. Урок сkind: reading— это текст для чтения (исключается из списка грамматики, плана и очереди практики); тегlisteningпомечает диктанты. -
grammar/*.md— карточки-справочник. -
vocab/*.json— тематические наборы слов.idслова = slug, поэтому одно и то же слово в разных наборах дедуплицируется при загрузке. -
books/*.json— книги-картинки:{ id, title, level, character, style, pages:[{en, ru, scene}] }. Картинки страниц лежат вweb/public/books/<id>/<n>.webp.
Добавление контента не требует кода и пересборки фронтенда — просто положи файл и перезапусти сервер (изменения картинок/кода всё же требуют npm run build:web).
-
users(role, xp, longest_streak) ·settings(key/value на пользователя) -
lesson_attempts(по упражнению, upsert) ·activity(повторы/упражнения за день → стрики) -
srs_cards(SM-2: ease, interval, reps, due, state) ·custom_words(сохранённые из текстов) -
error_log·progress(освоение тем) ·push_subscriptions·translations_cache
Классический SM-2 (server/src/srs.js): оценки again/hard/good/easy подстраивают ease и интервал; лимит новых карточек в день настраивается на пользователя.
-
Перевод и разбор письма/речи: любой OpenAI-совместимый chat API (
LLM_TRANSLATE_*). Ответ принудительно в структурированном JSON и калибруется под уровень ученика. -
TTS:
POST /api/ttsпроксирует ElevenLabs, кэширует mp3 вserver/data/tts-cache/по ключуmodel|voice|speed|text; одновременные одинаковые запросы объединяются. На клиенте — откат на голос браузераspeechSynthesis. - Иллюстрации: генерируются отдельно через Gemini («Nano Banana») — см. Как добавлять контент.
- Навигация назад/вперёд восстанавливает позицию скролла (своя реализация в
Layout), переход вперёд сбрасывает наверх. -
useApiавтоматически ретраит временные сбои (например, рестарт при деплое), поэтому интерфейс самовосстанавливается. - POST с пустым телом не отправляют JSON content-type (иначе Fastify вернёт 400) — пофикшено в обёртке fetch.