Технічний опис

Як влаштований Groundhog Board

AI-конвеєр, архітектура, що вже реалізовано в MVP і як ми це покажемо на демо. Продуктова частина — на головній.

AI за інтерфейсом

П’ять коротких задач, а не один чат-бот

Кожна задача — окремий виклик із виходом за zod-схемою. Невалідна відповідь — одна повторна спроба, далі передбачувана резервна поведінка. Модель викликає лише воркер, жоден компонент UI.

moderatePostПост і фотоallow / needs_approval / reject + причина→ «Чекає схвалення»
structurePostВільний тексттип, заголовок ≤ 60, деталі, дата події→ перші 60 символів
captionPhotoФото + тема челенджужартівливий підпис ≤ 60 символів→ без підпису
weeklyRecapДані екрана за 7 днів≤ 5 пунктів, кожен з sourceId→ сцену не показуємо
pollFromTextОдна фраза адмінапитання, 2–5 варіантів, дедлайн→ ручна форма

Локальна Gemma 4

Ollama на машині команди: дані не їдуть у сторонні сервіси. Hosted Gemma — резерв змінною середовища.

Асинхронна черга

ai_jobs у Postgres, FOR UPDATE SKIP LOCKED, одна задача на GPU, до 2 повторів. Модель прогріта весь час демо.

Текст — це дані

Пост обгорнутий роздільниками з інструкцією не виконувати його. Збір коштів завжди йде на схвалення.

Технічний опис

Проста архітектура, яку видно наскрізь

Клієнти пишуть через Next.js, читають і отримують оновлення напряму з Supabase під RLS. Уся робота з моделлю — у воркері поруч із GPU: він не відкриває портів і сам ходить у базу.

TV

/tv/[slug]?key — короткий JWT лише на читання

Браузер

стрічка / та екран /s/[slug]

Телефон

/join → /p/[slug], анонімний вхід

запис

Next.js на Vercel

Route Handlers, zod на вході, rate limits

Supabase

Postgres + RLS, Realtime → клієнтам, Storage для фото й логотипів

черга

Воркер

черга ai_jobs, розклад: погода, свята, підсумок

Ollama · Gemma 4

локально, без вхідних портів

Пунктир — те, що працює на машині з GPU. Hosted-провайдер вмикається змінною LLM_PROVIDER=google.

Стек

  • TypeScript strict
  • Next.js 16 App Router
  • Tailwind + shadcn/ui
  • Supabase Postgres + RLS
  • Supabase Realtime
  • Supabase Storage & Auth
  • Vercel AI SDK + zod
  • Ollama · Gemma 4
  • Node.js worker + node-cron
  • Vitest + Playwright
  • pnpm workspaces
  • Vercel

Монорепозиторій

apps/
  web/      Next.js: /tv /p /join /s /me /admin /api
  worker/   черга ai_jobs, розклад, виклики llm
packages/core/
  llm/      провайдер, задачі, схеми, промпти
  widgets/  реєстр 8 віджетів, toCards()
  scenes/   генератор сцен для TV
  db/       типи Supabase, клієнти
supabase/   міграції з RLS, seed
MVP

Що вже працює

Усі сценарії зі специфікації — обов’язкові й бажані — реалізовані, задеплоєні й перевірені наскрізно з реальною моделлю.

  • US-1Публікація з телефона: QR → ім’я → пост, статус наживо, «Щойно додано» на TV
  • US-2Фото й челендж: стискання без EXIF, AI-підпис, один голос, лідер наживо
  • US-3Опитування і квіз, правильна відповідь після закриття, опитування з однієї фрази
  • US-4Той самий екран у браузері, від 360 до 1920 px
  • US-5Кілька екранів, підписки, спільна стрічка
  • US-6Адмінка: віджети, черга схвалення з телефона, ротація ключів
  • US-7AI-підсумок тижня з перевіркою джерел
  • US-8Хто в офісі на цей і наступний тиждень
  • US-9Збір коштів із прогресом і QR
  • +Брендинг екрана: логотип, колір акценту, світла або темна тема TV

85

юніт- та інтеграційних тестів + e2e «пост з телефона з’являється на TV»

< 8 с

від «Надіслати» до картки на TV з локальною Gemma 4 E4B

1 команда

pnpm setup:local — ідемпотентний скрипт розгортання для всієї команди

Прод

Vercel + Supabase, воркер із моделлю на машині команди

Демо за 5 хвилин

Як ми це покажемо

  1. 1На великому екрані — TV-режим компанії, сцени змінюються самі.
  2. 2Зал сканує QR і голосує — стовпчики ростуть наживо.
  3. 3Фото-челендж «Покажи своє домашнє робоче місце»: ігрові сетапи, старі ЕПТ-монітори й енергетики з AI-підписами, голос за фото дня.
  4. 4Недоречний пост не з’являється, а на телефоні видно причину.
  5. 5Браузер: стрічка компанії й команди разом, як її бачить людина вдома.
  6. 6Фінал: «Згенерувати підсумок тижня» — на TV те, що щойно відбулося.