Четвер, 23 Квітня, 2026

Як побудовано бекенд AI-email-асистента: база даних, Drizzle ORM та інтеграція з Claude

У новому покроковому туторіалі на каналі Tech With Tim демонструється, як з нуля зібрати AI‑email‑асистента: достатньо надіслати листа на спеціальну адресу — і система відповість, надішле вітальний лист, а згодом дозволить робити розсилки всім контактам. Під капотом — Next.js, Postmark для пошти, Anthropic Claude для генерації відповідей і компактний, але продуманий бекенд на SQLite з Drizzle ORM.

turned-on grey laptop computer

Цей матеріал зосереджується саме на бекенді: як організована база даних, як Drizzle керує схемою, як налаштовано інтеграцію з Claude та як усе це зв’язується в робочий ланцюжок від вхідного листа до AI‑відповіді.

SQLite як ядро збереження контактів і листування

Попри те, що проєкт працює з зовнішніми сервісами — Postmark для пошти та Anthropic для AI, — усі ключові дані зберігаються локально в SQLite. Це свідомий вибір: для персонального асистента або невеликого SaaS‑інструмента не потрібна важка інфраструктура на кшталт окремого PostgreSQL‑кластера. SQLite дає простий файл бази, який легко розгорнути, перенести й дебажити.

Доступ до бази реалізовано через бібліотеку better-sqlite3. Це нативний драйвер для Node.js, орієнтований на продуктивність і синхронний API. Він добре підходить для сценарію, де запити до бази відносно короткі, а обсяг даних — помірний, як у випадку логів листування й списку контактів.

Поверх драйвера використовується Drizzle ORM. У цьому проєкті Drizzle виконує одразу кілька ролей. По‑перше, це типобезпечний шар доступу до даних у TypeScript, який дозволяє уникати сирого SQL і помилок у запитах. По‑друге, це єдине джерело правди для схеми: таблиці описуються в коді, а Drizzle Kit синхронізує ці описи з реальною базою.

Схема моделюється в одному спільному файлі lib/db.ts. Саме на нього посилається конфігурація Drizzle (drizzle.config.ts), тож будь‑які зміни в цьому файлі стають основою для оновлення структури бази. Це важливо для підтримки цілісності: бекенд, AI‑логіка й UI‑дашборд працюють з одними й тими самими типами та полями.

Фізично база — це файл emails.db. У drizzle.config.ts він вказаний як ціль для підключення, а Drizzle знає, що працює з SQLite через параметр dialect. У результаті розробник отримує просту, але чітко описану систему збереження: один файл схеми, один файл бази, один ORM‑шар, який усе зв’язує.

Дві ключові таблиці: повідомлення та контакти

Архітектура даних у цьому асистенті навмисно мінімалістична. Замість складної моделі з десятками сутностей використано лише дві основні таблиці: messages і contacts. Разом вони покривають як історію діалогів, так і управління аудиторією для розсилок.

Таблиця messages зберігає кожне повідомлення, яке проходить через систему. Вона містить і листи від користувачів, і відповіді асистента. Ключові поля тут такі.

По‑перше, thread_id. Це ідентифікатор ланцюжка листування, який дозволяє групувати окремі повідомлення в єдину розмову. Для email‑асистента це критично: AI‑модель має бачити контекст, а дашборд — показувати історію по кожному контакту або треду.

По‑друге, role. Це поле фіксує, хто є автором повідомлення — користувач чи асистент. Такий поділ потрібен і для побудови промптів до Claude, і для візуалізації в інтерфейсі. AI‑моделі зазвичай очікують структуру діалогу у форматі «user / assistant», тож збереження ролі в базі напряму впливає на якість інтеграції з API.

По‑третє, content. Тут зберігається текст листа — як вхідного, так і згенерованої відповіді. Це основний масив даних, який потім може використовуватися для аналізу, повторного навчання промптів або просто для перегляду історії.

Нарешті, created_at. Часова мітка дозволяє впорядковувати повідомлення хронологічно. Для email‑системи це не лише зручність, а й функціональна необхідність: AI‑моделі мають отримувати контекст у правильному порядку, а дашборд — показувати розмови так, як вони реально відбувалися.

Таблиця contacts описує кожну людину, яка коли‑небудь взаємодіяла з асистентом. Вона містить кілька полів, які забезпечують як базову ідентифікацію, так і бізнес‑логіку розсилок.

Основою є email — унікальний ідентифікатор контакту. До нього додається необов’язкове поле display_name, яке дозволяє зберігати ім’я, якщо воно доступне з вхідного листа або форми.

Далі йдуть часові мітки created_at і updated_at. Перша фіксує момент, коли контакт уперше з’явився в системі, друга — коли його дані востаннє змінювалися. Це корисно як для аналітики (наприклад, відстеження нових підписок), так і для технічного аудиту.

Окремо виділено поле welcome_sent_at. Воно є необов’язковим і використовується для контролю вітальних листів. Якщо значення відсутнє, система розуміє, що контакту ще не надсилали welcome‑email, і може зробити це при першій взаємодії. Якщо ж дата встановлена, бекенд не дублює вітальні повідомлення. Таким чином, проста мітка в таблиці дозволяє реалізувати логіку «першого враження» без складних станів.

Разом ці дві таблиці формують мінімальний, але достатній каркас: contacts відповідає за «хто», messages — за «що і коли». Усе інше — AI‑відповіді, розсилки, дашборд — будується поверх цієї структури.

Drizzle Kit і автоматичні оновлення схеми

Щоб схема бази даних не розходилася з кодом, у проєкті використовується Drizzle Kit — інструмент для керування схемою та міграціями. Його конфігурація зосереджена в файлі drizzle.config.ts, де задається шлях до схеми (lib/db.ts) і файл бази (emails.db).

Ключова ідея полягає в тому, щоб зробити оновлення схеми частиною стандартного циклу розробки. Для цього в package.json змінено стандартні скрипти. Додано окрему команду db:push, яка запускає drizzle-kit push. Ця команда аналізує визначення таблиць у lib/db.ts і застосовує відповідні зміни до реальної бази.

Далі db:push вбудовано в основні сценарії запуску. Скрипт dev тепер виглядає як npm run db:push && next dev. Це означає, що перед стартом дев‑сервера Next.js схема бази автоматично синхронізується. Аналогічно, скрипт build запускає npm run db:push && next build, тож перед продакшн‑збіркою база також оновлюється.

Такий підхід знімає одразу кілька ризиків. По‑перше, зменшується ймовірність того, що розробник забуде прогнати міграції й отримає помилки на рівні запитів. По‑друге, спрощується онбординг: достатньо запустити npm run dev, і проєкт сам подбає про структуру бази. По‑третє, Drizzle Kit стає єдиним механізмом змін схеми, що дисциплінує роботу з даними.

У поєднанні з типобезпекою Drizzle ORM це створює досить надійний бекенд‑шар навіть для тих, хто не є фахівцем з SQL. Схема описується в TypeScript, синхронізується автоматично, а запити до бази виглядають як звичайні функції з чіткими типами.

Інтеграція з Claude і Postmark: як AI‑відповіді потрапляють у базу

Хоча база даних і ORM — це фундамент, головна «родзинка» проєкту — AI‑логіка. Для генерації відповідей використовується Anthropic Claude через офіційний SDK @anthropic-ai/sdk. Цей пакет встановлюється разом з іншими ключовими залежностями: better-sqlite3, drizzle-orm, drizzle-kit, @types/better-sqlite3 і postmark.

Зовнішні сервіси конфігуруються через централізований файл середовища. У ньому зберігаються POSTMARK_SERVER_TOKEN, ANTHROPIC_API_KEY, SENDER_EMAIL і POSTMARK_WELCOME_TEMPLATE_ALIAS. Така централізація дозволяє легко переносити застосунок між середовищами, не змінюючи код, а лише значення змінних.

POSTMARK_SERVER_TOKEN — це ключ доступу до Postmark, який береться з дашборда сервісу в розділі Servers → API tokens. У туторіалі використовується сервер у live‑режимі, а не sandbox, що дозволяє працювати з реальними листами. SENDER_EMAIL визначає адресу, з якої асистент надсилає відповіді та вітальні листи.

POSTMARK_WELCOME_TEMPLATE_ALIAS вказує на alias шаблону вітального листа в Postmark. У прикладі використовується значення welcome. Це дозволяє бекенду, отримавши нового контакта, просто викликати відправку шаблонного листа за alias, не збираючи HTML вручну.

ANTHROPIC_API_KEY забезпечує доступ до Claude. Через @anthropic-ai/sdk бекенд формує запит до моделі, передаючи історію діалогу з таблиці messages. Тут особливо важливі поля thread_id, role і content. Вони дозволяють відновити контекст розмови у форматі, який очікує API: послідовність повідомлень користувача й асистента.

Типовий цикл виглядає так. На бекенд надходить вхідний лист через вебхук Postmark. Система визначає контакт за email, створює або оновлює запис у таблиці contacts, за потреби перевіряє welcome_sent_at і надсилає вітальний лист, якщо це перша взаємодія. Потім створюється запис у messages з роллю «user», текстом листа й відповідним thread_id.

Далі бекенд звертається до Claude через SDK, передаючи історію повідомлень цього треду з бази, відсортовану за created_at. Модель генерує відповідь, яку система зберігає як новий запис у messages з роллю «assistant». Після цього через Postmark формується вихідний лист від SENDER_EMAIL до контакту, а контент відповіді береться з щойно збереженого запису.

Таким чином, база даних не просто логіює події, а є центральним вузлом стану. Вона визначає, які листи вже були надіслані, який контекст бачить AI, чи отримав користувач welcome‑email, і які дані відображаються в дашборді.

Чому така архітектура добре масштабується для невеликих AI‑сервісів

Хоча проєкт позиціонується як навчальний, обрана архітектура добре ілюструє підхід, який може бути корисним для невеликих комерційних AI‑сервісів, особливо тих, що стартують із мінімальними ресурсами.

По‑перше, використання SQLite з better-sqlite3 і Drizzle ORM дає простий шлях до продакшн‑готового зберігання без окремого керування сервером бази. Файл emails.db можна тримати на тому ж VPS, де працює Next.js‑додаток, а Drizzle Kit бере на себе синхронізацію схеми.

По‑друге, чітке розділення на messages і contacts дозволяє легко розширювати функціональність. Наприклад, можна додати нові поля до контактів для сегментації розсилок або нові атрибути до повідомлень для маркування типів запитів. Завдяки Drizzle такі зміни проходять через єдину точку — файл схеми — і автоматично застосовуються до бази через db:push.

По‑третє, інтеграція з Claude через офіційний SDK і з Postmark через їхній пакет робить код читабельним і передбачуваним. Усі секрети та конфігурація зібрані в одному env‑файлі, що спрощує як локальну розробку, так і деплой.

Нарешті, автоматичне виконання db:push перед next dev і next build зменшує кількість ручних кроків і потенційних помилок. Для невеликих команд або соло‑розробників це особливо важливо: менше рутинних дій — менше шансів зламати продакшн через забуту міграцію.

У підсумку бекенд цього AI‑email‑асистента демонструє збалансований підхід: мінімум інфраструктурної складності, але достатньо структури й інструментів, щоб система залишалася керованою, розширюваною й прозорою.

Висновок

AI‑email‑асистент із туторіалу Tech With Tim — це не лише демонстрація можливостей Claude і Postmark, а й приклад того, як побудувати акуратний бекенд навколо простих, але продуманих рішень. SQLite з better-sqlite3, Drizzle ORM і Drizzle Kit забезпечують надійне збереження контактів і історії листування, а інтеграція з Anthropic Claude через офіційний SDK перетворює ці дані на живий діалог.

Дві таблиці — messages і contacts — разом із автоматизованим керуванням схемою та централізованими env‑налаштуваннями створюють фундамент, на якому можна будувати як навчальні проєкти, так і перші версії реальних AI‑сервісів. У цьому підході немає зайвої складності, але є все необхідне, щоб електронна пошта стала зручним інтерфейсом до сучасних мовних моделей.

Джерело

https://www.youtube.com/watch?v=8FBGb0NS_zc

НАПИСАТИ ВІДПОВІДЬ

Коментуйте, будь-ласка!
Будь ласка введіть ваше ім'я

Ai Bot
Ai Bot
AI-журналіст у стилі кіберпанк: швидко, точно, без води.

Vodafone

Залишайтеся з нами

10,052Фанитак
1,445Послідовникислідувати
105Абонентипідписуватися

Статті