Как я создал платформу для изучения иврита: от идеи до работающего сервиса
- пятница, 7 ноября 2025 г. в 00:00:07
Демо: 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):
✅ Словарь с поиском по русскому/ивриту
✅ Тренажёр для спряжений
✅ Объяснение биньянов с примерами
Хорошо бы добавить:
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 улучшается
Мне нужно было как-то окупать хостинг (~$15/мес) и мотивировать себя развивать проект.
Бесплатно (Forever Free):
✅ Базовый словарь (4000 самых частых слов)
✅ Первые 2 урока (алфавит, чтение, базовая грамматика)
✅ Ограниченный тренажёр (10 слов в день)
✅ Объяснение биньянов
Premium ($10/мес):
✨ Полный словарь (4000+ слов)
✨ Все 12 уроков
✨ Неограниченные тренажёры
✨ Статистика и прогресс
✨ Без рекламы
✨ Поддержка проекта
Почему $10? Это дешевле, чем:
Один урок с репетитором ($15-30)
Месяц Duolingo Plus ($13)
Подписка на любой учебник ($20+)
Шаг 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
}
Понял, что просто приложение без контента никто не найдет в поиске. Нужен органический трафик.
Написал 22 статьи на темы, которые люди ищут:
"10 причин начать учить иврит"
"Как выучить иврит с нуля онлайн"
"100 разговорных фраз на каждый день"
"Ошибки начинающих при изучении иврита"
"Как читать на иврите за неделю"
И т.д.
MDX = Markdown + React компоненты. Можно вставлять интерактивные элементы прямо в текст статьи.
---
title: "Ошибки начинающих при изучении иврита"
date: "2025-10-28"
description: "10 типичных ошибок и как их избежать"
keywords: ["ошибки иврит", "как учить иврит"]
---
## Ошибка 1: Игнорировать биньяны
**Не делайте так!** Биньяны — это основа всей системы.
**Попробуйте сами прямо сейчас:**
Что сделал для поисковиков:
✅ 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)
Процесс деплоя (автоматический):
# 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+
Честно о том, что пошло не так (и как исправлял).
Что сделал: Потратил месяц на полную поддержку английского с первого дня
Реальность: 70% пользователей русскоязычные, английской версией никто не пользовался первые 3 месяца
Урок: Делай локализацию по требованию, а не "на будущее". Принцип YAGNI (You Aren't Gonna Need It) работает.
Как исправил: Сделал русскую версию основной, английскую — второстепенной. Сэкономил бы месяц работы.
Что сделал: Сначала десктоп во всей красе, потом "адаптируем"
Правильно: Mobile-first подход с самого начала
Почему: 60% пользователей с телефонов, они видели плохой UX
Как исправил: Переделал весь UI с фокусом на мобильные экраны. Заняло еще 2 недели.
Что сделал: Установил $10/мес "на глаз", потому что "так у всех"
Правильно: Опросить потенциальных пользователей ДО запуска
Результат: Первые пользователи сказали "дорого для РФ", пришлось делать региональные цены
Как исправил: Добавил опрос, сделал $9 для всего мира.
Что сделал: Всё с нуля, включая правила спряжений
Правильно: Использовать существующие API или библиотеки (например, Pealim API)
Почему: "Изобретение колеса" заняло 3 недели
Но: Зато теперь у меня 100% контроль, никакой зависимости от внешних сервисов, и работает офлайн. Спорное решение.
Что сделал: Сделал крутую техническую платформу, написал 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 выше у качественного контента
[ ] Мобильное приложение (React Native + Expo)
[ ] AI помощник для составления предложений (OpenAI API)
[ ] Голосовой тренажер (Web Speech API)
[ ] Flashcards система (Spaced Repetition Algorithm)
[ ] Геймификация (достижения, рейтинги, соревнования)
Расширение на другие семитские языки (арабский, фарси — та же корневая система)
B2B версия для школ и ульпанов
Интеграция с существующими ульпанами (дополнительная домашка)
API для разработчиков (морфология как сервис)
Community features (форум, обмен опытом, языковые партнеры)
🌐 Демо: hebrewglot.com
Что можно попробовать бесплатно:
📚 Словарь — поиск по 500 словам + примеры
🎯 Тренажёры — 10 слов в день бесплатно
📖 Первые 2 урока — от алфавита до базовой грамматики
📝 Блог — все 22 статьи доступны
Для разработчиков:
Морфологический движок работает прямо в браузере
TypeScript для типобезопасности
Server Components для оптимизации
Что сработало отлично:
✅ Гибридная схема БД (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