Я построил полноценную образовательную платформу для изучения иврита — с интерактивными тренажерами, умным словарем на 4000+ слов и системой подписок. В статье рассказываю о нетривиальных технических решениях, архитектурных выборах и ошибках, которые пришлось исправлять по ходу.
Демо: hebrewglot.com
Стек: Next.js 15, TypeScript, PostgreSQL + SQLite, Stripe, NextAuth
🎯 Предыстория: почему вообще это началось
Я начал учить иврит и быстро столкнулся с проблемой: хороших онлайн-ресурсов на русском языке почти нет.
Что есть:
Duolingo — поверхностный, не объясняет грамматику
Pealim — отличный сайт для спряже��ий, но только для спряжений
Ульпаны — дорого ($300-500/месяц) и нужно ездить
Чего не хватало:
Интерактивных упражнений с мгновенной обратной связью
Нормального объяснения системы биньянов (это как виды глаголов, но сложнее)
Словаря с примерами использования в контексте
Всего этого на русском языке без необходимости учить через английский
Я подумал: "А что если сделать самому?" И понеслось...

Прежде чем рассказывать про код, нужно понять специфику языка. Иврит — это не английский. Там все устроено по-другому, и это создает интересные технические челленджи.
Корневая система
В иврите слова строятся из корней (обычно 3 буквы). Представьте, что у вас есть конструктор LEGO, где 3 базовых кубика порождают сотни вариантов.
Корень כ-ת-ב (к-т-б) = "писание"
От него образуются:
כָּתַב (katav) — "писал"
כּוֹתֵב (kotev) — "пишет"
מִכְתָּב (michtav) — "письмо" (объект)
כְּתוֹבֶת (ktovet) — "адрес"
כְּתִיבָה (ktiva) — "письмо" (процесс)
Видите паттерн? К-Т-Б везде, но слова разные. Для программиста это звучит как "идеальная задача для шаблонизации".
Система биньянов
Это породы глаголов — всего их 7 штук. Как спряжения в русском, но намного строже и системнее.
Один и тот же корень в разных биньянах дает разные значения:
Корень ש-ב-ר (ш-б-р) = "ломать"
ПААЛ: שָׁבַר (shabar) — "сломал" (просто действие)
НИФЪАЛЬ: נִשְׁבַּר (nishbar) — "сломался" (пассив/рефлексив)
ПИЭЛЬ: שִׁבֵּר (shiber) — "разбил на куски" (интенсив)
hИФЪИЛЬ: הִשְׁבִּיר (hishbir) — "заставил сломать" (каузатив)
Задача для программиста: Как это всё структурировать и генерировать автоматически? Именно здесь начинается самое интересное.
💡 Идея и MVP
Что должно было быть в продукте
Минимум (MVP):
✅ Словарь с поиском по русскому/ивриту
✅ Тренажёр для спряжений
✅ Объяснение биньянов с примерами
Хорошо бы добавить:
4. ✅ Уроки для начинающих (от алфавита)
5. ✅ Статистика прогресса
6. ✅ Блог с полезными статьями (для SEO)
7. ✅ Монетизация (чтобы окупить хостинг)
Выбор технологий
Тут я исходил из простого принципа: "Используй то, что знаешь, но не бойся учить новое".
Next.js 15 — потому что:
Server-side rendering для SEO (важно для образовательного контента)
API routes (не нужен отдельный бэкенд)
App Router с Server Components (новая фишка, хотел попробовать в деле)
Большое комьюнити и быстрые решения проблем
TypeScript — потому что:
Иврит имеет жесткую грамматическую структуру
Типобезопасность = меньше багов в морфологии
Автодополнение = быстрее писать сложный код
Рефакторинг становится безопасным
PostgreSQL + SQLite — об этом подробнее ниже, это самое интересное архитектурное решение
Stripe — для подписок:
Простая интеграция
Надежный
Автоматическое управление подписками
🏗️ Архитектура: необычное решение с двумя базами
Проблема
У меня было два типа данных с совершенно разными характеристиками:
1. Пользовательские данные (меняются часто):
Учетные записи
Статистика прогресса
История ответов
Подписки
~100 записей на пользователя
2. Словарь иврита (статичные, read-only):
4000+ слов
Все формы спряжений (~200 форм на глагол)
Переводы на русский и английский
Примеры использования
Размер: 44 МБ
Проблема: Держать 44 МБ статичных данных в облачной PostgreSQL — это:
💸 Дорого (облачные БД берут за объем)
🐌 Медленно (network latency при каждом запросе)
🤷 Бессмысленно (данные не меняются)
🔄 Сложно обновлять (нужны миграции для контента)
Решение: гибридная схема

┌─────────────────────────────────────────┐ │ Next.js приложение │ ├─────────────────────────────────────────┤ │ │ │ ┌──────────────┐ ┌───────────────┐ │ │ │ PostgreSQL │ │ SQLite │ │ │ │ (Render) │ │ (локально) │ │ │ ├──────────────┤ ├───────────────┤ │ │ │ Users │ │ Words (4000+) │ │ │ │ Sessions │ │ Roots │ │ │ │ Stats │ │ Conjugations │ │ │ │ Subscriptions│ │ Examples │ │ │ └──────────────┘ └───────────────┘ │ │ ↕ ↕ │ │ Prisma better-sqlite3 │ └─────────────────────────────────────────┘

PostgreSQL (облако) — для всего, что меняется
SQLite (файл в проекте) — для словаря
Создал менеджер баз данных, который прозрачно работает с обеими:
// src/lib/database.ts export class DatabaseManager { private sqlite: Database private prisma: PrismaClient // Словарь → SQLite (быстро, локально) async searchWords(query: string, locale: string) { const stmt = this.sqlite.prepare(` SELECT * FROM words WHERE form LIKE ? OR translation LIKE ? LIMIT 50 `) return stmt.all(`%${query}%`, `%${query}%`) } // Статистика → PostgreSQL (облако) async saveUserStats(userId: string, stats: any) { return this.prisma.userStats.upsert({ where: { userId }, update: stats, create: { userId, ...stats } }) } }
Плюсы этого подхода:
⚡ SQLite очень быстрый (нет сети, всё локально, < 1ms)
💰 Экономия на хостинге (~$20/месяц)
📦 Деплой проще (SQLite файл в репозитории)
🔍 Prepared statements работают мгновенно
Минусы:
🔄 Нельзя обновлять словарь на лету (нужен редеплой)
Но для образовательного контента это не проблема (обновления редки)
🧠 Морфологический движок: самая сложная часть
Это сердце всей системы. Нужно было научить программу генерировать формы глаголов по правилам.
Задача
Пользователь вводит (или система генерирует):
Корень: כ-ת-ב
Биньян: ПААЛ
Время: прошедшее
Лицо: я (1-е лицо, единственное число)
Программа должна выдать: כָּתַבְתִּי (katavti — "я писал")
И так для всех комбинаций: 7 биньянов × 4 времени × 9 лиц = 252 формы для каждого корня!
Как это работает
Шаг 1: Шаблоны с плейсхолдерами
Для каждого биньяна создал шаблоны:
// src/lib/morph/verbRules.ts const PAAL_TEMPLATE = { past: { '1s': { // 1-е лицо единственное число template: '{r1}ַ{r2}ְ{r3}ְתִּי', transcription: '{r1}a{r2}{r3}ti' }, '3ms': { // 3-е лицо муж.род ед.число template: '{r1}ַ{r2}ַ{r3}', transcription: '{r1}a{r2}a{r3}' } // ... всего 9 форм для каждого времени }, present: { 'ms': { template: '{r1}וֹ{r2}ֵ{r3}', transcription: '{r1}o{r2}e{r3}' } // ... }, future: { /* ... */ }, imperative: { /* ... */ } }
Шаг 2: Подстановка корня
function realizeVerb( root: [string, string, string], template: string ): string { const [r1, r2, r3] = root return template .replace('{r1}', r1) .replace('{r2}', r2) .replace('{r3}', r3) } // Пример использования realizeVerb(['כ', 'ת', 'ב'], '{r1}ַ{r2}ְ{r3}ְתִּי') // → 'כַתְבְתִּי'
Шаг 3: Обработка особых случаев
Некоторые буквы ведут себя странно (гортанные буквы א, ה, ח, ע):
// Если первая буква корня — א (алеф), // она "проглатывает" некоторые гласные if (r1 === 'א' && binyan === 'PAAL') { // Специальная обработка для слабых корней template = adjustForWeakRoot(template, 'first') } // Если последняя буква — ה (хей), // она меняется в некоторых формах if (r3 === 'ה') { template = adjustForWeakRoot(template, 'last') }
Результат:
Теперь из одного корня можно сгенерировать все 200+ форм автоматически!
const forms = generateAllForms('כתב', 'PAAL') // → { // past: { // '1s': 'כתבתי', // '2ms': 'כתבת', // '3ms': 'כתב', // // ... всего 9 форм // }, // present: { // 'ms': 'כותב', // 'fs': 'כותבת', // 'mp': 'כותבים', // 'fp': 'כותבות' // }, // future: { /* ... */ }, // imperative: { /* ... */ } // }
Зачем это нужно
Тренажёр: генерирую вопросы на лету (не нужно хранить все формы)
Словарь: показываю все формы слова динамически
Проверка ответов: сравниваю с правильной формой
Масштабируемость: новый корень = автоматически 200+ слов
🌍 Интернационализация: русский И английский
Здесь я потратил слишком много времени, но узнал важный урок о приоритизации.
Проблема
Хотел поддержать два языка:
🇷🇺 Русский (основная аудитория)
🇬🇧 Английский (для масштабирования и международной аудитории)
Простая часть: UI переводы (кнопки, меню)
// src/hooks/useI18n.ts const translations = { ru: { 'search': 'Поиск', 'login': 'Войти', 'dictionary': 'Словарь' }, en: { 'search': 'Search', 'login': 'Login', 'dictionary': 'Dictionary' } }
Сложная часть: Контент из базы данных
Слова в БД на иврите и русском. Как их показать англоязычным пользователям?
Решение: многоуровневая система переводов
// src/lib/translationService.ts // Уровень 1: Кеш (500+ предзаполненных переводов) const translationCache = new Map([ ['учить', 'to learn'], ['писать', 'to write'], ['говорить', 'to speak'], // ... еще 500+ самых частых слов ]) // Уровень 2: Паттерн-анализ function translateText(text: string, targetLocale: string): string { // Проверяем кеш if (translationCache.has(text)) { return translationCache.get(text)! } // Анализируем паттерны (например, глагольные формы) if (text.endsWith('ть')) { // русский инфинитив const englishForm = convertToEnglishInfinitive(text) return 'to ' + englishForm } // Паттерны существительных if (text.endsWith('ие') || text.endsWith('ость')) { return handleAbstractNoun(text) } // Резервный вариант: показываем как есть return text }
Результат: ~100% покрытие переводов без внешних API
Что я узнал (важный урок!)
Ошибка: Потратил месяц на полную локализацию, хотя 70% пользователей русскоязычные.
Правильно было бы:
Запустить только на русском
Собрать аудиторию
Посмотреть метрики
Локализовать по требованию
Урок: Делай интернационализацию, когда она реально нужна, а не "на будущее". YAGNI принцип работает.
🎯 Интерактивные тренажёры
Это то, ради чего всё затевалось. Пассивное чтение учебников не работает — нужна практика.
Типы тренажёров
1. Лёгкий режим: выбор из вариантов (Multiple Choice)
Вопрос: Как будет "я писал" на иврите? A) כותב B) כתבתי ← правильный ответ C) אכתוב D) כתב
2. Сложный режим: ввод формы (Free Input)
Введите форму глагола כתב (писать) Время: прошедшее Лицо: мы Ваш ответ: [_______] Правильно: כתבנו
3. Спряжения: полная таблица
Настоящее время (הווה) он пишет → כותב она пишет → כותבת они писали → כתבו
Генерация вопросов
Вопросы генерируются на лету:
// Упрощенный пример генерации вопросов export async function generateQuestions(locale: string, difficulty: string) { // Берем случайные слова из БД const words = await getRandomWords(10) // Для каждого слова генерируем формы const questions = words.map(word => { const forms = generateAllForms(word.root, word.binyan) // Случайное время и лицо const tense = randomChoice(['past', 'present', 'future']) const person = randomChoice(['1s', '2ms', '3fs', '1p']) const correctAnswer = forms[tense][person] // Генерируем неправильные варианты const wrongAnswers = generateDistractors(word, tense, person) // Формируем вопрос на нужном языке const question = formatQuestion(word, person, tense, locale) return { question, correctAnswer, wrongAnswers, metadata: { tense, person, binyan: word.binyan } } }) return questions }
Статистика и геймификация
После каждого ответа сохраняю результат в двух местах:
Локально (localStorage) — для быстрого доступа:
const stats = { totalAnswers: 142, correctAnswers: 98, wrongAnswers: 44, accuracy: 69.0, streak: 5, // дней подряд lastActiveDate: '2025-11-04' }
В облаке (PostgreSQL) — для кросс-девайсности:
await prisma.userStats.update({ where: { userId }, data: { totalWords: { increment: 1 }, correctAnswers: { increment: isCorrect ? 1 : 0 }, wrongAnswers: { increment: isCorrect ? 0 : 1 }, lastActiveDate: new Date(), streak: calculateStreak(user.lastActiveDate) } })
Эффект: Пользователи видят прогресс → мотивация растет → retention улучшается
💰 Монетизация: Stripe и Premium контент
Мне нужно было как-то окупать хостинг (~$15/мес) и мотивировать себя развивать проект.
Модель: Freemium
Бесплатно (Forever Free):
✅ Базовый словарь (4000 самых частых слов)
✅ Первые 2 урока (алфавит, чтение, базовая грамматика)
✅ Ограниченный тренажёр (10 слов в день)
✅ Объяснение биньянов
Premium ($10/мес):
✨ Полный словарь (4000+ слов)
✨ Все 12 уроков
✨ Неограниченные тренажёры
✨ Статистика и прогресс
✨ Без рекламы
✨ Поддержка проекта
Почему $10? Это дешевле, чем:
Один урок с репетитором ($15-30)
Месяц Duolingo Plus ($13)
Подписка на любой учебник ($20+)
Интеграция Stripe
Шаг 1: Создание Checkout Session
// Пример создания сессии оплаты import Stripe from 'stripe' const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!) export async function POST(req: Request) { const { priceId } = await req.json() const session = await getCurrentSession() if (!session?.user) { return Response.json({ error: 'Unauthorized' }, { status: 401 }) } // Создаём сессию оплаты const checkoutSession = await stripe.checkout.sessions.create({ customer_email: session.user.email, line_items: [{ price: priceId, quantity: 1 }], mode: 'subscription', success_url: `${YOUR_DOMAIN}/success`, cancel_url: `${YOUR_DOMAIN}/pricing`, metadata: { userId: session.user.id } }) return Response.json({ url: checkoutSession.url }) }
Шаг 2: Обработка Webhook (критично!)
// Упрощенный пример обработки webhook export async function POST(req: Request) { // Проверяем подпись Stripe const event = await verifyWebhookSignature(req) if (!event) { return Response.json({ error: 'Invalid signature' }, { status: 400 }) } // Обрабатываем события switch (event.type) { case 'checkout.session.completed': await handleSuccessfulPayment(event.data) break case 'customer.subscription.updated': await updateSubscriptionStatus(event.data) break case 'customer.subscription.deleted': await handleCancellation(event.data) break } return Response.json({ received: true }) }
Важно: Всегда проверяйте подписи webhook для защиты от подделки запросов.
Шаг 3: Защита контента (PremiumGate)
// components/PremiumGate.tsx export async function PremiumGate({ children }: { children: ReactNode }) { const session = await getServerSession(authOptions) if (!session) { return } // Проверяем подписку const subscription = await prisma.subscription.findUnique({ where: { userId: session.user.id } }) const hasPremium = subscription?.status === 'active' && subscription.currentPeriodEnd > new Date() if (!hasPremium) { return ( <div> <h3>🔒 Premium контент</h3> <p>Этот урок доступен только в Premium подписке</p> <button>Получить Premium за $10/мес</button> </div> ) } return <>{children} }
Использование:
// app/[locale]/lessons/[id]/page.tsx export default async function LessonPage({ params }) { const lesson = await getLesson(params.id) if (lesson.isPremium) { return ( ) } return }
📝 Блог для SEO: контент-маркетинг
Понял, что просто приложение без контента никто не найдет в поиске. Нужен органический трафик.
Что сделал
Написал 22 статьи на темы, которые люди ищут:
"10 причин начать учить иврит"
"Как выучить иврит с нуля онлайн"
"100 разговорных фраз на каждый день"
"Ошибки начинающих при изучении иврита"
"Как читать на иврите за неделю"
И т.д.
Технология: MDX
MDX = Markdown + React компоненты. Можно вставлять интерактивные элементы прямо в текст статьи.
--- title: "Ошибки начинающих при изучении иврита" date: "2025-10-28" description: "10 типичных ошибок и как их избежать" keywords: ["ошибки иврит", "как учить иврит"] --- ## Ошибка 1: Игнорировать биньяны **Не делайте так!** Биньяны — это основа всей системы. **Попробуйте сами прямо сейчас:**
SEO оптимизация
Что сделал для поисковиков:
✅ Semantic HTML (
<article>,<header>,<section>)✅ Meta tags (title, description, keywords)
✅ OpenGraph изображения (автогенерация через DeepAI API)
✅ Structured data (JSON-LD для Google)
✅ Sitemap.xml (автоматический)
✅ robots.txt (правильная индексация)
✅ Быстрая загрузка (Server Components + Image optimization)
Результат:
// Lighthouse Score { performance: 94, accessibility: 98, bestPractices: 100, seo: 100 }
🚀 Деплой и продакшен
Для хостинга выбрал облачную платформу с:
Недорогим PostgreSQL tier
Простым деплоем (git push = deploy)
Поддержкой Next.js из коробки
Автоматическими SSL сертификатами
Европейским регионом (ближе к целевой аудитории)
Конфигурация
# config.yaml services: - type: web name: hebrewglot env: node region: frankfurt # ближе к целевой аудитории plan: starter # $7/мес buildCommand: | npx prisma generate && npx prisma migrate deploy && next build startCommand: npm start envVars: - key: DATABASE_URL fromDatabase: name: hebrewglot-db property: connectionString - key: NEXTAUTH_SECRET generateValue: true - key: NEXTAUTH_URL value: https://hebrewglot.com databases: - name: hebrewglot-db databaseName: hebrewglot plan: starter # бесплатно (1GB)
CI/CD Pipeline
Процесс деплоя (автоматический):
# 1. Push в репозиторий git add . git commit -m "Add new feature" git push origin main # 2. Платформа автоматически: # → Скачивает код # → Устанавливает зависимости # → Запускает миграции БД # → Собирает проект # → Деплоит новую версию # → Делает zero-downtime restart # Время деплоя: ~4-5 минут
📊 Метрики и результаты
Производительность
Web Vitals:
LCP (Largest Contentful Paint): 1.2s ✅
FID (First Input Delay): 45ms ✅
CLS (Cumulative Layout Shift): 0.02 ✅
Размеры бандлов:
JavaScript: 180KB (gzip) — основной бандл
CSS: 12KB (gzip) — Tailwind
Первая загрузка: < 2s на 3G
Lighthouse Score:
{ "performance": 94, "accessibility": 98, "bestPractices": 100, "seo": 100 }
Технические метрики
Слов в словаре: 4,000+
Корней глаголов: 1,266
Статей в блоге: 22 (RU), 2 (EN)
Уроков: 16
Строк кода: ~15,000
Тестов: 47 (unit + integration)
Типов TypeScript: 150+
🤦 Ошибки, которые я совершил
Честно о том, что пошло не так (и как исправлял).
1. Переусложнил интернационализацию
Что сделал: Потратил месяц на полную поддержку английского с первого дня
Реальность: 70% пользователей русскоязычные, английской версией никто не пользовался первые 3 месяца
Урок: Делай локализацию по требованию, а не "на будущее". Принцип YAGNI (You Aren't Gonna Need It) работает.
Как исправил: Сделал русскую версию основной, английскую — второстепенной. Сэкономил бы месяц работы.
2. Игнорировал мобильную версию в начале
Что сделал: Сначала десктоп во всей красе, потом "адаптируем"
Правильно: Mobile-first подход с самого начала
Почему: 60% пользователей с телефонов, они видели плохой UX
Как исправил: Переделал весь UI с фокусом на мобильные экраны. Заняло еще 2 недели.
3. Не валидировал цену подписки
Что сделал: Установил $10/мес "на глаз", потому что "так у всех"
Правильно: Опросить потенциальных пользователей ДО запуска
Результат: Первые пользователи сказали "дорого для РФ", пришлось делать региональные цены
Как исправил: Добавил опрос, сделал $9 для всего мира.
4. Написал весь код сам (включая морфологию)
Что сделал: Всё с нуля, включая правила спряжений
Правильно: Использовать существующие API или библиотеки (например, Pealim API)
Почему: "Изобретение колеса" заняло 3 недели
Но: Зато теперь у меня 100% контроль, никакой зависимости от внешних сервисов, и работает офлайн. Спорное решение.
5. Недооценил важность контента
Что сделал: Сделал крутую техническую платформу, написал 3 статьи для блога
Правильно: Content is king. Писать статьи параллельно с разработкой
Результат: Первые 2 месяца — 0 органического трафика
Как исправил: Нанял копирайтера, написали 20 статей за месяц. Трафик вырос в 10 раз.
💡 Что я узнал (главные инсайты)
Технические инсайты
1. SQLite в продакшене — это нормально
Для read-only данных — идеальное решение
Быстрее PostgreSQL для статичного контента (нет network latency)
Проще деплоить (файл в репе)
Меньше точек отказа
2. Next.js App Router готов к продакшену
Server Components реально ускоряют (меньше JS в браузере)
Но документация местами сырая (много trial & error)
Community большое, ответы находятся быстро
3. TypeScript окупается на сложной логике
Морфология без типов = ад и боль
Рефакторинг с типами = ��езопасно и легко
Обучение команды занимает +2 недели, но оно того стоит
4. Монорепозиторий удобен для малых проектов
Всё в одном месте
Нет проблем с версионированием между фронтом и бэком
Но становится медленным на >50k LOC
5. Prepared statements в SQLite — must have
Защита от SQL injection
В разы быстрее обычных запросов
Кэширование плана выполнения
Бизнес-инсайты
1. SEO > платная реклама (для образовательных проектов)
Одна хорошая статья = 100+ визитов в месяц
Контент живет годами
Google Ads для ниши "иврит" стоит $3+ за клик
2. Freemium работает, если бесплатная часть реально полезна
Дай попробовать продукт
Покажи ценность
5-10% конвертируются в платящих
3. Community > маркетинг
Сообщества в соцсетях дали больше пользователей, чем реклама
Форумы и тематические площадки — бесплатный охват
Главное — не спамить, а помогать
4. Качество > количество
Лучше 12 крутых уроков, чем 50 средненьких
Пользователи ценят глубину
Retention выше у качественного контента
🎯 Что дальше: планы на будущее
Ближайшие месяцы (Q1 2025)
[ ] Мобильное приложение (React Native + Expo)
[ ] AI помощник для составления предложений (OpenAI API)
[ ] Голосовой тренажер (Web Speech API)
[ ] Flashcards система (Spaced Repetition Algorithm)
[ ] Геймификация (достижения, рейтинги, соревнования)
Мечты на будущее (2025-2026)
Расширение на другие семитские языки (арабский, фарси — та же корневая система)
B2B версия для школ и ульпанов
Интеграция с существующими ульпанами (дополнительная домашка)
API для разработчиков (морфология как сервис)
Community features (форум, обмен опытом, языковые партнеры)
🔗 Попробуйте сами
🌐 Демо: hebrewglot.com
Что можно попробовать бесплатно:
📚 Словарь — поиск по 500 словам + примеры
🎯 Тренажёры — 10 слов в день бесплатно
📖 Первые 2 урока — от алфавита до базовой грамматики
📝 Блог — все 22 статьи доступны
Для разработчиков:
Морфологический движок работает прямо в браузере
TypeScript для типобезопасности
Server Components для оптимизации
🤝 Выводы и takeaways
Что сработало отлично:
✅ Гибридная схема БД (PostgreSQL + SQLite) — быстро и дешево
✅ Морфологический движок с шаблонами — генерация форм в runtime
✅ SEO через блог — основной источник трафика
✅ Freemium модель — люди пробуют, потом платят
✅ TypeScript для сложной логики — меньше багов, проще рефакторинг
Что не сработало или было ошибкой:
❌ Слишком ранняя интернационализация — потратил месяц впустую
❌ Desktop-first подход — большинство с моб��льных
❌ Игнорирование маркетинга на старте — долго не было пользователей
❌ Изобретение колеса везде — где-то можно было использовать готовые решения
Главный урок для других разработчиков:
> "Делай, ошибайся, учись, итерируй. Идеальный код в вакууме никому не нужен — важен работающий продукт в руках реальных пользователей. Ship early, ship often."
Второй важный урок:
> "Сложная техническая часть (морфология) — это круто и интересно, но без контента, маркетинга и понимания аудитории это просто хобби-проект. Нужен баланс между технологиями и бизнесом."
📚 Полезные ресурсы
Если хотите повторить похожий проект:
Технологии:
Next.js 15 App Router — официальная документация
Prisma ORM — работа с PostgreSQL
better-sqlite3 — самый быстрый SQLite для Node.js
NextAuth.js — аутентификация
Stripe Docs — подписки и платежи
EdTech:
How to Build an EdTech Platform — Y Combinator
Spaced Repetition Algorithm — для запоминания
Если изучаете иврит:
HebrewGlot — моя платформа (можете попробовать)
Pealim — отличный справочник по спряжениям
Reverso Context — примеры использования слов
💬 Вопросы и обратная связь
Буду рад ответить на вопросы в комментариях!
Интересные темы для обсуждения:
Как вы решаете проблему хранения больших статичных данных?
Кто-нибудь еще использует SQLite в продакшене?
Делали ли вы морфологические движки для других языков?
Какие у вас опыт с монетизацией EdTech проектов?
Контакты:
Демо: hebrewglot.com
Статья написана: 4 ноября 2025
