fancai — AI-ридер художественной литературы с Entity Wiki и иллюстрациями
Собственный продукт · Чтение / EdTech / потребительское веб-приложение (PWA)
- Python
- FastAPI
- Celery
- PostgreSQL
- pgvector
- Redis
- SQLAlchemy
- Alembic
- TypeScript
- React
- Vite
- Tailwind CSS
- TanStack Query
- Zustand
- epub.js
- IndexedDB
- PWA
- Docker
- docker-compose
- Caddy/Nginx
- VPS
- REST API
- WebSocket
- OpenRouter/платежи
- Gemini
- Vertex AI
- FLUX.2
- pytest
- Playwright
- Vitest
- 1293 коммита, из них 853 с Co-Authored-By Claude (~66%)
- ~40 390 строк Python (backend/app)
- ~70 571 строка TS/TSX в 343 файлах (frontend/src)
- 28 router-файлов, 97 routes + 1 websocket
- 38 сервисов, 20 моделей, 54 Alembic-миграции, 84 backend-теста
- 5 кастомных субагентов, 6 слэш-команд, 30 скиллов, 7 rule-файлов
- 535 отчётов, 79 research-документов, 17 планов
- v1.0: 9 фаз, 23 плана, 52 требования, UAT 10/10, ~9 дней
Контекст и задача
fancai (изначально «BookReader AI», первый коммит — 23.08.2025) — личный продукт Эльдара: веб-приложение для чтения художественной литературы, в котором ИИ снимает две реальные боли читателя. Первая — «кто это вообще?»: в длинных книгах с десятками персонажей и локаций легко потерять нить, а обычные вики и фан-сайты спойлерят будущее. Вторая — отсутствие визуального ряда: текст не показывает, как выглядят сцены и герои.
Ответ продукта — две AI-функции поверх удобной мобильной читалки:
- Entity Wiki (главная фича) — ИИ строит интерактивный глоссарий персонажей, локаций и объектов прямо из текста книги, со спойлер-защитой по главам: карточка показывает только то, что уже встречалось в прочитанных главах.
- AI-иллюстрации — параллельно с чтением ИИ находит в тексте описания сцен и по клику генерирует к ним изображения.
Сознательно вне scope (зафиксировано в .planning/PROJECT.md): монетизация/подписки, соцфункции, встроенный магазин книг, нативное мобильное приложение, форматы помимо EPUB/FB2. Приоритет контента — русскоязычные книги.
Что я сделал
Эльдар — единственный разработчик и автор проекта: продуктовая идея, архитектура, весь backend и frontend, AI-пайплайн, инфраструктура, деплой и эксплуатация в проде. Это greenfield — с нуля, без legacy. По git: 1293 коммита за период 08.2025–06.2026, продукт доведён до работающего production на fancai.ru и продолжает развиваться.
Конкретные пласты работы (прослеживаются по CHANGELOG/STATE и коду):
- Backend на FastAPI/Python (~40K строк): парсинг книг, AI-извлечение сущностей и описаний, дедупликация и синтез биографий, спойлер-логика, ридер-сессии, заметки, аутентификация (JWT, token blacklist), Celery-воркеры и очереди.
- Frontend на React 19/TypeScript (~70K строк в
src, 343 файла): мобильная читалка на epub.js, жесты, оффлайн-кэш, Entity Wiki UI, генерация и кэширование изображений, PWA, i18n (RU/EN, 1000+ ключей по README). - Инфраструктура и DevOps: Docker Compose (dev/prod/monitoring), Caddy (auto-HTTPS, HTTP/3), мониторинг-стек, бэкапы БД, деплой на VPS через собственный
/deploy-скилл Claude Code. - Безопасность/харднинг (v1.0): DEBUG-enforcement, валидация SECRET_KEY, CSRF (double-submit cookie), rate limiting, политика паролей, CSP-хардненинг, circuit breaker для внешних AI-API. Хардненинг подтверждён живыми заголовками
fancai.ru.
Честная оговорка: часть наработок намеренно заброшена (self-hosted NLP, Modal-батч) — это зафиксированные стратегические развороты, а не «сделано и работает». См. раздел «Инженерные вызовы».
Решение и подход
Пайплайн «книга → текст → сущности/сцены → иллюстрации → читалка» (по docs/architecture/ai-pipeline.md и коду backend/app/services):
- Загрузка книги (EPUB/FB2) → парсинг в главы (
book_parser.py, ebooklib/lxml/BeautifulSoup). - Глава режется на чанки (~100K символов, ~15% overlap для устойчивости на границах).
- Чанк уходит в LLM через единый клиент-провайдер → извлекаются сущности (персонажи/локации/объекты), описания для картинок и связи между сущностями.
- Дедупликация (
entity_deduplication_service.py, fuzzy-matching для русских имён, порог 0.75; рекурсивный batched-reduce, BATCH_SIZE=50/MAX_DEPTH=2 для 500+ сущностей) и синтез биографий (entity_synthesis_service.py); консистентность —consistency_manager.py. - Спойлер-безопасность: сущность хранит
first_mention_chapter/first_mention_cfi(models/entity.py), UI показывает информацию только до текущей главы читателя; фильтрация покрыта property-based тестами (hypothesis). - Иллюстрации: описание → при необходимости перевод RU→EN → генерация изображения; Celery-задача
generate_image_task, отдельный circuit breaker, чтобы сбои LLM не блокировали генерацию картинок.
Архитектура сервисов (prod-compose, 8 сервисов): caddy (reverse proxy/TLS/HTTP-3) → frontend (статика) + backend (FastAPI/Gunicorn) → celery-worker + celery-beat (очереди book: soft-limit 3ч, image: 300с) → postgres (pgvector) + redis (кэш/pubsub/Celery-broker/JWT-blacklist) + pgbackup. Связь фронта с бэком — REST + WebSocket (прогресс обработки книг в реальном времени).
Читалка (нетривиальные места, из CHANGELOG): epub.js рендерит EPUB через CFI (не номера страниц), три системы подсветки (descriptions/entities/annotations) координируются через TreeWalker skip-фильтры; жесты — единый FSM-контроллер (заменил 3 параллельные системы), follow-finger свайпы со spring-физикой 60fps, полноэкранный iOS-overlay (обход бага: iOS Safari не доставляет touch-события в iframe); оффлайн — кэш глав в IndexedDB (Dexie) + PWA с graduated resume.
Результат
- Продукт в проде:
https://fancai.ruотвечает (HTTP/2 + HTTP/3), отдаёт приложение с задокументированным hardened-CSP, HSTS-preload, Hawk error-tracking и WebSocket — деплой и хардненинг подтверждены живыми заголовками (проверка 29.06.2026). - Отгруженные milestone'ы (CHANGELOG): v1.0 (готовность к проду, 52/52 требований, UAT 10/10), v1.1–v1.3 (mobile/PWA/iOS), все в продакшене в марте 2026; v1.4 (self-hosted NLP) и v1.5 (Modal) — частично/abandoned по итогам аудитов.
- Масштаб (прямой подсчёт): ~40K строк Python + ~70K строк TS/TSX; 28 routers / 38 сервисов / 20 моделей / 54 миграции / 84 backend-теста; 1293 коммита.
- Бизнес-метрики аудитории/нагрузки (DAU, число обработанных книг) в артефактах не зафиксированы — уточнить у автора.
Стек и обоснование
- Backend: Python 3.12 + FastAPI (Pydantic v2, строгие типы), SQLAlchemy 2 + PostgreSQL 17/pgvector (векторные эмбеддинги глав в наработках), Redis 7.4 + Celery 5.6 (тяжёлая обработка книг асинхронно), Alembic, пакет-менеджер uv. Resilience — tenacity (экспоненциальный backoff) + circuitbreaker для внешних AI-API.
- Frontend: React 19 + TypeScript 5.7 + Vite 8, Tailwind 4 + Radix + Vaul, TanStack Query (серверное состояние) + Zustand (клиентское), epub.js (CFI-рендеринг), Dexie/IndexedDB (оффлайн), vite-plugin-pwa/Workbox. Тесты — Vitest + Playwright.
- Инфраструктура: Caddy 2.11 (выбран вместо nginx — 748 строк конфига → ~80, auto-HTTPS, HTTP/3), Docker Compose (dev/prod/monitoring профили), бэкап-контейнер БД.
- AI (продукт): единый клиент через OpenRouter (LLM —
google/gemini-2.5-flashprimary +-flash-litefallback; изображения —black-forest-labs/flux.2-klein-4b). Обоснование (Key Decisions): один провайдер с fallback-цепочкой проще и дешевле, чем зоопарк SDK. - Мониторинг (активный compose): Netdata + VictoriaMetrics + Uptime-Kuma + Dozzle + Flower, error-tracking — Hawk. (В
monitoring/остались артефакты Grafana/Prometheus от ранних экспериментов — в активный compose не подключены.)
Роль ИИ в проекте
ИИ задействован двояко — в самом продукте и в процессе разработки.
1. ИИ внутри продукта. AI — ядро ценности: извлечение сущностей/описаний и генерация иллюстраций. Эволюция провайдеров (честно, по CHANGELOG/STATE/коду):
- Декабрь 2025: удалён self-hosted NLP, извлечение переведено на LLM API.
- v1.0 (март 2026): унификация на OpenRouter (Gemini Flash + fallback-цепочка, включавшая Claude Haiku 4.5; изображения — FLUX.2 Klein).
- v1.4–v1.5: эксперименты с self-hosted NLP (GLiNER2) и Modal (vLLM Qwen3.5 на GPU L40S) — заброшены.
- Stage A (последние коммиты, 16.06.2026, в работе): за фиче-флагом
AI_PROVIDERдобавлен прямой Gemini API (google-genai) с выбором backend'а Developer | Vertex AI (GEMINI_BACKEND, ADC-аутентификация для Vertex), а генерация картинок — через «Nano Banana» (gemini-3.1-flash-image) вnano_banana_generator.py. Фабрикаai_provider_factory.pyдаёт мгновенный rollback на OpenRouter. Это позволяет управлять провайдером без передеплоя.
Архитектурно AI спрятан за абстракцией AIProvider (Protocol) + фабрика по флагу — провайдеры взаимозаменяемы. Ключи API провайдеров (OpenRouter/Gemini/GCP) в портфолио не извлекались, констатируется лишь факт интеграции.
2. ИИ в разработке (Claude Code, agentic). Репозиторий — образец AI-augmented процесса:
CLAUDE.mdс конвенциями, «architecture gotchas», профилем разработчика и даже разделом «Known Claude Code Bugs» и правилами/compact.- 5 кастомных субагентов (
.claude/agents/):fancai-orchestrator(делегирование, «never implement directly»),ai-pipeline,entity-system,epub-reader,security-reviewer— с заданными tools/model/maxTurns. - 6 слэш-команд (
build,db,go,logs,status,test) и 30 скиллов (deploy,db-migrate,celery-debug,openrouter-monitor,entity-pipeline,perf-audit,harden,incident,research-and-analysis, кластер дизайн-скиллов и др.). - 7 rule-файлов (
ai-pipeline,backend,frontend,reader,docker,tests). - Кастомные MCP (
.mcp.json): доступ к прод-postgresчерез туннель иssh-manager— Claude Code работает с реальной БД и деплоем. - Doc-driven / SDD-процесс: огромный
docs/(535 отчётов, 79 research-документов, 17 планов) и архив планирования.planning/(PROJECT/STATE/ROADMAP/MILESTONES/RETROSPECTIVE, фазы и milestone'ы). Исторически использовался toolchain GSD (get-shit-done) + SuperPowers, затем GSD полностью вырезан (13.06.2026). - Цикл research → audit → implement: решения о разворотах (Modal, провайдеры) принимались по консолидированным аудитам, в т.ч. с кросс-проверкой другими моделями.
- Количественно: 853 из 1293 коммитов содержат
Co-Authored-By: Claude(~66%).
Инженерные вызовы
- Спойлер-безопасность как корректность, а не UI-фильтр. Нужно гарантировать, что ни одна карточка не «протечёт» в будущее сюжета. Решение — модель данных с первым упоминанием (глава/CFI) + property-based тесты (hypothesis) на инварианты фильтрации.
- Качество извлечения на русском. Дедупликация имён («Гарри» → «Гарри Поттер»), синтез биографий без противоречий, устойчивость к границам чанков: fuzzy-matching с порогом 0.75, token-overlap-эвристики, рекурсивный batched-reduce для книг с 500+ сущностями.
- Стоимость/надёжность LLM. Дорогой и нестабильный внешний AI потребовал circuit breaker'ов (раздельные для LLM и изображений), tenacity-ретраев, литерального кэша ответов в Redis, классификатора ошибок (5 типов) и структурированного per-chapter логирования.
- Серия дорогих разворотов с дисциплиной отказа. Self-hosted NLP → Modal (vLLM Qwen3.5): на staging реальный батч занял 40+ минут вместо ожидаемых 7–8 — Modal отменён, наработки списаны; курс возвращён на оптимизацию OpenRouter, затем — на флаговую миграцию к Gemini Direct/Vertex. Зрелое решение «не тащить sunk cost».
- Мобильный ридер на iOS. Корневая причина (STATE.md): iOS Safari не доставляет touch-события в iframe
contentDocument— потребовался полноэкранный overlay с FSM-жестами, shared-FSM через dependency injection (дедупликация ~454 строк), координация трёх систем подсветки через TreeWalker, follow-finger физика 60fps. UAT на физическом iPhone 15 Pro (8/8 проверок). - Production-инцидент-готовность. Token blacklist для безопасного logout, бэкапы БД, пакет аварийной миграции сервера (recon/план/runbook, RTO ≤ 4ч) как страховка.
Услуги в проекте
- разработка
- деплой
- devops
- мониторинг
- AI-интеграция
- аудит
- 152-ФЗ/ПДн