Технічна специфікаціяЗакрити

ШІ-веброзробка для малого бізнесу — Технічна специфікація

Назва бренду — Factory (використовується всюди в UI: навбар, <title>, JSON-LD — більше не PLACEHOLDER). Продакшн-домен — ще не відомий: деплой на Railway, кожен сервіс отримує власний згенерований *.up.railway.app-домен (розділ 14); NEXT_PUBLIC_SITE_URLPLACEHOLDER доки цей домен не згенеровано. Логотип/фірмовий знак ще не визначено.

1. Overview

Багатосторінковий маркетинговий сайт для технологічної компанії, яка розробляє професійні вебсайти для малого бізнесу (масажисти, стоматологи, дитячі студії, тренери, локальні спеціалісти) за допомогою спеціалізованого ШІ-агента, побудованого на 10+ роках досвіду веброзробки. Сайт — премium/технологічний, українською мовою, і одночасно виконує три задачі: (1) генерує ліди через головний CTA «Отримати сайт», (2) пояснює методологію (людина-розробник + спеціалізований ШІ + перевірка) так, щоб не читатись як типовий «AI-білдер», (3) додає шар довіри через дослідницький (PhD) контекст, стек технологій і команду.

Сайт складається з чотирьох навігаційних маршрутів: головна (/, 11 активних секцій — розділ 7.1), /research, /technology, /team. Додатково є один утилітарний маршрут поза навігацією — /spec: рендерить актуальний текст цієї специфікації у спливаючому вікні, відкривається кнопкою в секції 8 «Це наш продукт» (розділ 7.1). Ціноутворення — секція на головній (#pricing), без окремого маршруту (обґрунтування — розділ 4). «Готово» означає: усі активні секції головної та три навігаційні під-сторінки реалізовані згідно копірайту нижче, форма ліда реально працює (надсилає повідомлення в Telegram через окремий Elysia-бекенд — нічого не персистується в базі даних), демо бронювання та демо інтерфейсу правок — статичні/клієнтські макети без бекенду, шейдер у hero працює і коректно деградує, сайт проходить перевірки продуктивності/доступності зі skill frontend.

Порівняно з початковою версією брифу: дві секції прибрані з головної повністю — AI development system flow та Technology тизер (компоненти й ексклюзивні контент-константи прибрані з кодової бази; повна сторінка /technology не постраждала). «Website examples» (портфоліо) з початкового брифу в продукті більше немає — не планується й не описується в цьому документі. Замість видалених секцій з'явилась нова секція 8 «Це наш продукт» — самореферентний доказ методології з кнопкою, що відкриває цю специфікацію. Див. розділ 15 «Assumptions».

2. Goals & Non-Goals

Goals

Non-Goals

3. Users & Key Flows

A. Власник малого бізнесу (нетехнічний), головний сценарій Заходить на / → бачить hero (обіцянка + CTA) → прокручує довіру/проблему/рішення → дивиться 6 кроків розробки та демо інтерфейсу правок → бачить демо онлайн-запису, впізнає свій випадок (масаж/групові заняття/тощо) → переглядає приклади сайтів для своєї ніші → бачить розділ ціноутворення (безкоштовно за акцією + хостинг) → читає FAQ → тисне «Отримати сайт» → заповнює форму ліда (ім'я, контакт, тип бізнесу, коментар) → бачить підтвердження.

B. Власник, який хоче спочатку поговорити з людиною У фінальному CTA або в контактному блоці бачить «Обговорити сайт з розробником» → клік відкриває зовнішнє посилання nedoshev.dev/meet в новій вкладці (жодної форми на самому сайті).

C. Технічний/академічний відвідувач (розробник, дослідник, потенційний партнер) Заходить через hero → зацікавлений формулюванням «перетворили досвід на ШІ-агента» → переходить у навбарі на «Технології» → дивиться повний стек по категоріях → переходить на «Дослідження» → читає обидва research-картки, розуміє гіпотези й методологію → переходить на «Команда» → бачить, хто стоїть за продуктом → або надсилає лід, або йде з довірою до бренду.

D. Повторний відвідувач, що порівнює пропозиції Отримує пряме посилання на /#pricing (наприклад, від розробника в переписці) → одразу бачить структуру ціни без проходження всієї сторінки заново → переходить до FAQ або форми ліда.

4. Scope

Тип застосунку: комбінація — багатосторінковий маркетинговий/лендинг-сайт (основний обсяг) + один реальний бекенд-ендпоінт для форми ліда (мінімальний, без бази даних узагалі — ендпоінт лише пересилає повідомлення в Telegram). Немає адмін-панелі, немає реального booking-бекенду.

Частина Skill(и)
Усі 4 сторінки, вся верстка/дизайн/секції frontend (обов'язково — SKILL.md, а перед кожною секцією відповідний references/*.md)
Hero-шейдер (фон) frontend/references/animated-backgrounds.md — за драбиною витрат зупинитись на OGL/WebGL, оскільки ефект — один шейдер (потік/спотворення), а не мультипрохідна сцена; ескалація до vgpu (WebGPU) — опційна, лише якщо піксель-шейдер OGL не тягне бажаний «інженерний» ефект (композиція кількох шарів, ping-pong буфери)
Демо онлайн-запису (секція 6) frontend/references/booking-section.md для дизайну секції; appointments skill НЕ використовується — це презентаційний макет із хардкод-даними, без слот-логіки, без БД
Демо інтерфейсу збору правок (частина секції 5) Немає окремого skill — простий клієнтський стан (React), лише вигляд
FAQ, Pricing, Testimonials-подібні секції frontend/references/sections.md, cards.md, testimonials-section.md (якщо колись з'являться реальні відгуки — зараз їх немає, розділ пропущено, див. Assumptions)
Форма ліда «Отримати сайт» / «Обговорити проєкт» (єдиний реальний бекенд) backend + elysiajs + bun skills (Elysia-сервіс) + Telegram Bot API (fetch напряму, без SDK/skill — немає бази даних узагалі) + captcha skill (honeypot + timing на формі)
Адмін-панель Не потрібна — немає бази даних, яку можна було б тріажити; кожен лід — окреме повідомлення в Telegram

Pricing: анchor чи окремий маршрут? Анкор #pricing на головній. Обґрунтування, узгоджене з конвенціями frontend skill: ціна — одна проста модель (одна «пропозиція», не порівняння тарифів), не потребує окремого маршруту чи SEO-цінності асинхронної сторінки; секція вже входить у наратив головної (sections.md — «Objection handling» перед FAQ). Інші сторінки (/research, /technology, /team) за потреби посилаються глибоким лінком на /#pricing, а не дублюють вміст.

5. Tech Stack

Шар Вибір Обґрунтування
Runtime Bun Фіксовано проєктом (CLAUDE.md/bun skill)
Структура репозиторію Bun workspaces monorepo — корінь із package.json (workspaces: ["frontend", "backend"]), один bun install на весь репозиторій, один bun run dev піднімає фронтенд і бекенд паралельно (bun run --filter '*' --parallel dev) Два незалежні пакети (frontend/, backend/) з окремими білдами, але спільним встановленням залежностей і єдиною dev-командою; build/lint/typecheck/test так само агреговані через --filter '*' --if-present
Фронтенд-фреймворк Next.js (App Router), TypeScript Фіксовано frontend skill; 4 навігаційні маршрути + утилітарний /spec природно лягають на App Router (маршрути /, /research, /technology, /team — у групі (site) зі спільним layout-ом навбару/футера; /spec — поза групою, без навбару/футера, див. розділ 7.1 секцію 8)
Рендеринг Static export (output: 'export') Увесь контент — статичний маркетинг; єдина динамічна дія (форма ліда) — це fetch() до окремого Elysia-сервісу, тож сервер Next.js не потрібен
Стилі Tailwind CSS v4 (@theme у globals.css) Фіксовано skill; усі токени кольору з розділу 10 живуть тут
Типографіка next/font — Geist Sans (display/body) + Geist Mono (числа, мітки кроків, технічні деталі) Геометричний, техно-нейтральний грощеск, що читається як «інженерний продукт», без ліцензійних ризиків; моно-шрифт підсилює «технічні деталі UI», яких просить бриф
Анімація/хореографія скролу GSAP + ScrollTrigger Стандарт skill для reveal/pin
Компонентна анімація Звичайні CSS-переходи (Tailwind transition-*) motion/react не додавали — усі ховери/демо-стани (booking, change-request, nav CTA) покриваються CSS-переходами; зайва залежність прибрана під час аудиту JS-бюджету (розділ 12)
Плавний скрол Lenis Стандарт skill, вимикається на prefers-reduced-motion і <768px
Hero-фон OGL (WebGL, ~12kb) Один шейдер-ефект (потік/шум/спотворення на курсор), чорно-золота палітра з токенів; статичний постер до готовності контексту; graceful fallback, якщо WebGL недоступний
Markdown → HTML (лише для /spec) marked Рендерить цю специфікацію в HTML на етапі білду (Server Component, fs.readFileSync + marked.parse) — нуль байтів у клієнтському бандлі; використовується виключно на утилітарній сторінці /spec, не на маркетингових сторінках
Форми react-hook-form + zod Валідація форми ліда на клієнті; та ж zod-схема повторюється на бекенді
Бот-захист форми captcha skill (honeypot + timing, Turnstile — лише якщо з'явиться спам) Форма ліда — єдина публічна форма запису в БД на сайті
Бекенд (лише для форми ліда) Bun + ElysiaJS, окремий процес/контейнер Фіксовано backend skill — статичний фронтенд не має власного сервера
База даних Немає жодної. Ліди нічого не персистують — POST /leads лише пересилає повідомлення в Telegram і повертає успіх/помилку; замінило Firestore, щоб не тримати окрему БД + сервіс-акаунт заради єдиної форми на сайті
Сповіщення про ліди Telegram Bot API, прямий fetch (Bun-нативний, без SDK) POST https://api.telegram.org/bot<token>/sendMessage з chat_id+text; src/lib/telegram.ts
Іконки Lucide React, stroke-width={1.5}, лише де іконка — афорданс (гамбургер, зовнішнє посилання, соцмережі у футері) rules/icons.md — за замовчуванням без іконок
Хостинг Власна керована інфраструктура компанії (Docker + Linux + reverse proxy + CDN) — див. розділ 14 Автентична деталь: власний сайт компанії розгорнутий на тій самій інфраструктурі, яку вона продає клієнтам (розділ «Технологія», категорія Infrastructure)

6. Information Architecture

Маршрут Призначення Ключові компоненти Дані
/ Головна — повна історія позиціювання, 11 активних секцій (розділ 7.1) Hero, TrustSection, ProblemSection, SolutionSection, HowItWorks (+ change-request demo), BookingDemo, ResearchTeaser, BuildProofSection, PricingSection, FaqSection, FinalCta (форма ліда) Хардкод-контент (типізовані константи, розділ 8) + один реальний POST до /leads
/research Повний опис дослідницької (PhD) методології + картки досліджень (наразі 7, не 2 — реальні публікації з реальними посиланнями, більше не TBD) ResearchIntro, ResearchCard × N (мапиться по масиву, не фіксована кількість) Хардкод-контент; посилання на публікації здебільшого реальні (див. розділ 16 щодо решти)
/technology Повний технологічний стек по категоріях TechCategoryBlock × 5 (Frontend/Backend/Database/Infrastructure/AI) Хардкод-контент
/team Картки ролей — наразі 5: Founder/Lead Developer, Founder/Backend Engineer, і троє під роллю «Consultants / Advisors» (безпека, UI/UX, юридичні питання) TeamMemberCard × N (мапиться по масиву) Хардкод-контент, усі імена реальні — жодного PLACEHOLDER не лишилось (розділ 16 оновлено)
/spec Утилітарний, поза навігацією. Рендерить цю специфікацію (Markdown → HTML на етапі білду) у мінімальному layout без навбару/футера — призначений для відкриття у спливаючому вікні (window.open) кнопкою в секції 8 головної, не для прямого переходу з меню Server Component, читає docs/specs/ai-web-development-studio.md через fs відносно кореня монорепо, конвертує marked-ом; SpecCloseButton (client, закриває вікно або веде на /) Немає — рендериться напряму з файлу специфікації, єдине джерело правди

Навігація (усі сторінки): Головна · Як це працює · Дослідження · Технології · Команда, CTA праворуч — «Отримати сайт». «Як це працює» з будь-якої під-сторінки веде на /#how-it-works; «Головна», «Дослідження», «Технології», «Команда» — прямі маршрути. /spec у навігації немає навмисно. CTA навбару на під-сторінках веде на /#get-site (форма ліда живе лише на головній).

Nav CTA — не дублювати CTA hero. Поки hero у в'юпорті, навбар не показує кнопку «Отримати сайт» (вона й так уже показана великою в hero) — IntersectionObserver на #herorootMargin, що дорівнює висоті навбару) перемикає видимість/aria-hidden/tabIndex кнопки, коли hero йде за навбар. На сторінках без hero (/research, /technology, /team, /spec) кнопка показана завжди. Деталі патерну і важливий hydration-нюанс (початковий стан не можна обчислювати з document у useState-ініціалізаторі — інакше SSR/клієнт розходяться і React не перемальовує невдалий hydration-мисматч) задокументовані в frontend/references/navbar.md → «Don't show the same CTA twice at once».

7. Sections & Content

7.1 Головна сторінка — 11 активних секцій по порядку

1. Hero

2. Trust / Expertise

3. Problem

4. Solution

5. How development works (критична секція) — 6 кроків Формат: великі легкі номери 01–06 (без іконок, cards.md/sections.md — «Steps»), з'єднувальна тонка лінія між кроками на десктопі, вертикальний стек на мобільному.

5a. Демо-макет інтерфейсу правок (вкладена частина кроку 05, лише візуальна, без реальної логіки)

6. Online booking (демо, ключова можливість продукту)

AI development system — видалена повністю Секція «Вимоги → Спеціалізовані skills → AI development agent → Code generation → Automated checks → Developer review → Production» та її ексклюзивна контент-константа видалені з кодової бази (компонент, імпорт, дані) — рішення власника продукту, не юридичне. Секція 8 нижче («Це наш продукт») тепер несе аналогічну функцію (довести, що методологія реальна), іншим способом — прямим доказом, а не діаграмою.

7. Research (тизер)

8. Це наш продукт (build proof) — НОВА секція

9. Pricing (id="pricing")

10. FAQ — точні пари питання/відповідь (не більше і не менше, порядок збережено; формат <details>/<summary>, максимум 6 зі sections.md тут навмисно перевищено, бо контент фіксований клієнтом):

  1. Сайт справді безкоштовний? — Розробка сайту зараз доступна без оплати за акцією. Ви сплачуєте хостинг та домен.
  2. Що входить у сайт? — Landing pages, послуги, ціни, галерея, контакти, форми, адаптивний дизайн, базове SEO та онлайн-запис — залежно від вимог проєкту.
  3. Чи можна додати онлайн-запис? — Так.
  4. Чи можна записуватися на групові заняття? — Так, система може працювати не лише з індивідуальними записами, а й з груповими заняттями та обмеженою кількістю місць.
  5. Чи можу я використовувати власний домен? — Так.
  6. Хто створює сайт? — Розробку прискорює спеціалізований AI-агент, але результат проходить перевірку розробником.
  7. Чи можу я попросити зміни? — Так. Для цього передбачений зручний процес формування документа зі змінами.
  8. Що відбувається після запуску? — Сайт розміщується на керованій інфраструктурі, а клієнт сплачує щомісячний хостинг.

11. Final CTA (id="get-site")

7.2 /research

7.3 /technology

Повна версія тизера з головної, по категоріях, кожна — окремий блок (не картка-з-іконкою, а текстовий блок + список технологій моно-шрифтом):

7.4 /team

Картки ролей, cards.md — plain grid (md:grid-cols-3), без stock-фото, без вигаданих досягнень. Наразі 5 карток, не 3 — команда додала «Consultants / Advisors» як третю категорію ролі, окрім засновників:

  1. Максим — Founder / Lead Developer. Фокус: web architecture, frontend engineering, UI/UX design, AI-assisted development, developer tooling, research.
  2. Олександр — Founder / Backend Engineer. Фокус: backend architecture, databases, distributed systems, monitoring and observability, secure development practices.
  3. Максим — Consultants / Advisors (кібербезпека). Фокус: cybersecurity, data protection, secure development practices.
  4. Ліза — Consultants / Advisors (UI/UX). Фокус: UI/UX design.
  5. Діана — Consultants / Advisors (юридичні питання). Фокус: legal aspects, intellectual property protection, legal compliance.

Усі 5 імен реальні — жодного PLACEHOLDER не лишилось (розділ 16 оновлено відповідно). При md:grid-cols-3 і 5 картках останній рядок — 2 картки, не 3; це прийнятно, спеціально сітку під непарну кількість не переробляли. Жодних біографій чи досягнень понад дані вище не вигадувати — якщо додається новий консультант/розробник, дотримуватись того самого мінімального формату (ім'я, роль, 1 речення опису, список фокус-областей).

7.5 /spec (утилітарний, поза навігацією)

8. Data Model

Сайт повністю статичний — немає жодної персистентності. Форма ліда не пише в жодну базу даних; POST /leads пересилає дані в Telegram і забуває про них. Лід «зберігається» рівно настільки, наскільки Telegram зберігає історію чату.

Lead (вхідні дані форми — тип LeadInput, спільний для zod-схеми фронтенду й бекенду, розділ 9)

Поле Тип Опис
name string Ім'я з форми
contact string Телефон або email (одне поле, вільний формат — валідація на непорожність)
businessType string (опційно) Тип бізнесу (опційний select/free text)
message string (опційно) Коментар (опційний)
source 'get-site' | 'discuss-project' Який CTA/форма ініціювали лід
page string Шлях сторінки, з якої надіслано (/, /technology, …)

Ці ж поля (крім пасток бот-захисту) форматуються в текст одного Telegram-повідомлення — formatLeadMessage() у backend/src/lib/telegram.ts. Немає ні id, ні status, ні createdAt — нічого з цього не потрібне, коли немає запису для ідентифікації/тріажу/датування.

Поля-пастки бот-захисту (captcha skill) подорожують у тому ж запиті, але ніколи нікуди не пересилаються: company_website (honeypot, має бути порожнім), renderedAt (timestamp рендеру форми).

Контентні типи (build-time константи, не персистуються, живуть у коді фронтенду)

type Service = { name: string; durationMinutes: number; priceUah: number }
type TimeSlot = { time: string; available: boolean }
type ClassSession = { name: string; day: string; time: string; seatsTaken: number; seatsTotal: number }
type ResearchPaper = { title: string; year: number | 'TBD'; description: string; researchQuestion: string; relevance: string; publicationUrl: string | null /* most entries now have a real URL — 'TBD'/null is the exception, not the default */ }
type TeamMember = { name: string | null /* null → render as visible PLACEHOLDER; no entry currently uses null */; role: string; focus: string[]; description?: string }
type TechCategory = { name: string; items: string[] }
type FaqItem = { question: string; answer: string }

Немає жодної бази даних, схеми міграцій чи ORM на всьому сайті.

9. API / Integrations

POST /leads (Elysia-бекенд, окремий origin від статичного сайту)

Request body (zod, спільна схема з react-hook-form):

{
  name: string,          // min 2
  contact: string,       // min 1 — телефон або email, вільний формат
  businessType?: string,
  message?: string,
  source: 'get-site' | 'discuss-project',
  page: string,
  company_website: string, // honeypot — має лишатись порожнім
  renderedAt: number,       // timestamp рендеру форми
}

Response: { id: "ok" } на успіх (буквально той самий літерал і для реального надсилання, і для фейкового успіху при спрацюванні honeypot/timing, за captcha skill — немає реального id, бо немає запису, який він міг би ідентифікувати), реальна помилка з кодом 4xx/5xx через onError Elysia лише при валідній, але невдалій операції.

Ендпоінт: валідація zod → перевірка honeypot/timing (captcha skill) → POST в Telegram Bot API (src/lib/telegram.ts, sendLeadNotification). Помилки: 500 якщо TELEGRAM_BOT_TOKEN/TELEGRAM_CHAT_ID не задані; 502 якщо сам HTTP-запит до Telegram впав (мережа) або Telegram відповів не-2xx (наприклад, бот не запущений отримувачем — «chat not found»).

Зовнішні інтеграції

Env vars (лише назви, без значень)

Frontend (.env статичного Next.js-застосунку):

Backend (Elysia-сервіс, .env, ніколи не в браузері):

Frontend, лише якщо буде додано Turnstile:

10. Design Direction

Токени кольору (точні значення з брифу, використовувати як є)

--text-50: #f5f3ef;  --text-100: #ebe7e0; --text-200: #d7cec1; --text-300: #c3b6a2; --text-400: #af9d83;
--text-500: #9c8563; --text-600: #7c6a50; --text-700: #5d503c; --text-800: #3e3528; --text-900: #1f1b14; --text-950: #100d0a;

--background-50: #f7f3ee;  --background-100: #eee8dd; --background-200: #ded1ba; --background-300: #cdba98; --background-400: #bda375;
--background-500: #ac8b53; --background-600: #8a7042; --background-700: #675432; --background-800: #453821; --background-900: #221c11; --background-950: #110e08;

--primary-50: #f8f4ec;  --primary-100: #f2e9d9; --primary-200: #e4d3b4; --primary-300: #d7be8e; --primary-400: #caa868;
--primary-500: #bd9242; --primary-600: #977535; --primary-700: #715828; --primary-800: #4b3a1b; --primary-900: #261d0d; --primary-950: #130f07;

--secondary-50: #faf5eb;  --secondary-100: #f5ead6; --secondary-200: #ebd5ad; --secondary-300: #e0c085; --secondary-400: #d6ab5c;
--secondary-500: #cc9633; --secondary-600: #a37829; --secondary-700: #7a5a1f; --secondary-800: #523c14; --secondary-900: #291e0a; --secondary-950: #140f05;

--accent-50: #fbf5e9;  --accent-100: #f8ebd3; --accent-200: #f1d7a7; --accent-300: #eac37b; --accent-400: #e2af50;
--accent-500: #db9b24; --accent-600: #af7c1d; --accent-700: #845d15; --accent-800: #583e0e; --accent-900: #2c1f07; --accent-950: #161004;

Ці значення йдуть у Tailwind v4 @theme як CSS custom properties один-в-один (не переводити в OKLCH — брифом задано саме ці hex-значення, зберегти дослівно).

Ролі використання (default):

Роль Токен
Фон за замовчуванням --background-950
Основний текст --text-50
Другорядний текст --text-300 / --text-400
Основний інтерактивний (кнопки, посилання за замовчуванням) --primary-500 (hover → --primary-400/--primary-600)
Акцент/підсвітка (одне слово в заголовку, glow навколо ключового UI, focus ring) --accent-500
Тонкі рамки --background-800 / --primary-900
--secondary-* Резервна, рідкісна тональна варіація (напр. м'який радіальний glow позаду hero, або дуже тонкий wash між секціями) — ніколи як другий конкуруючий акцент для CTA

Хоча в брифі задано п'ять іменованих шкал (text/background/primary/secondary/accent), primary/secondary/accent — один і той самий золотий відтінок на різних щаблях яскравості/насиченості, тож за формулою frontend/references/colors.md це рахується як один акцентний колір, розділений на семантичні ролі, а не «п'ять кольорів». Домен-калібрування — строгий кінець (dev-tools/premium software/research lab): один акцент, щільність <5% пікселів, золото зʼявляється вибірково (кнопки, фокус-кільце, підсвітка ключового слова, glow біля шейдера) — домінує темна мова, як і вимагає бриф.

Типографіка

Ритм і компонування

Візуальна мова

Тон голосу

Впевнений, технічний, розумний, сучасний, прямий, доступний. НЕ корпоративний, не зверхній, не надто академічний, не hype-driven, не «написаний ШІ-стартапом». Уникати фраз на кшталт «революційна технологія, яка змінить світ» — конкретні інженерні переваги замість хайпу. Кожен розділ копірайту вище написаний із цим орієнтиром; координатор/coder не повинен додавати маркетингові суперлативи понад задане.

11. Responsive & Accessibility Requirements

12. Performance & SEO

13. Build Plan

Кроки 1–20 нижче — початкова послідовність побудови «з нуля» і досі коректна для повторного білду. Кроки 21–24 додані пізніше й відображають те, чого початковий план не міг передбачити (монорепо, self-referential секція, видалення секцій, зміна плану деплою з subpath на Railway).

  1. Скелет проєкту. bunx create-next-app (TS, Tailwind, App Router, src/), next.config.ts з output: 'export'. Верифікація: bun run dev піднімається без помилок.
  2. Токени та шрифти. @theme-блок з усіма кольоровими шкалами розділу 10 дослівно, підключення Geist Sans/Mono через next/font. Верифікація: тестова сторінка показує коректні кольори/шрифти.
  3. Глобальний layout. Навбар (navbar.md) + футер (footer-section.md, sitemap-варіант — є куди йти: 4 маршрути + дослідження/технології/команда), 4 порожні маршрути (/, /research, /technology, /team). Верифікація: навігація між усіма 4 сторінками працює, мобільне меню відповідає a11y-вимогам розділу 11. (Оновлено кроком 23 — ці 4 маршрути тепер у групі (site) зі спільним layout-ом, а не в кореневому.)
  4. Скелет головної. Секції як плоский семантичний HTML без стилів/анімації (build order frontend/SKILL.md). Верифікація: контент читається згори вниз у правильному порядку.
  5. Hero + шейдер. Верстка hero (hero-section.md) + OGL-шейдер + DOM-оверлей wireframe-панелі. Верифікація: H1 видимий без JS, постер рендериться миттєво, шейдер degrades gracefully без WebGL, пауза поза viewport/на прихованій вкладці, prefers-reduced-motion → статика. id="hero" на секції — потрібен кроку 23 для nav CTA reveal.
  6. Trust / Problem / Solution. Стилізація трьох секцій. Верифікація: контраст, відсутність вигаданих цифр.
  7. How it works + change-request демо. 6 кроків + вкладений hotspot-демо. Верифікація: демо клікабельне з клавіатури, працює на тач (без hover-залежності), жодних мережевих викликів.
  8. Booking демо. Клієнтський степер (послуга → дата → час → дані → підтвердження) + блок про адаптивність + приклад групового заняття. Верифікація: повністю keyboard-operable, дані — лише в React state, нічого не надсилається нікуди.
  9. AI system flow + Research/Technology тизери. AI system flow видалено повністю кроком 21. Research/Technology тизери лишаються (див. кроки нижче) — Research тизер тепер мапиться по масиву довільної довжини, не фіксовано на «2».
  10. Pricing. Верифікація: закреслена стара ціна семантична (<s>), ієрархія «безкоштовно / 600 грн / домен окремо» читається за 3 секунди погляду. Ціна БЕЗКОШТОВНО має flex-wrap і whitespace-nowrap на закресленій сумі — без цього текст переповнює картку на вузьких в'юпортах (реальний баг, знайдений і виправлений після першого білду).
  11. FAQ. Усі 8 пар дослівно, <details>/<summary>. Верифікація: клавіатурна навігація по акордеону.
  12. Final CTA + форма ліда. Форма з honeypot+timing полями (captcha skill), клієнтська zod-валідація, fetch() на NEXT_PUBLIC_API_BASE_URL, вторинне посилання на nedoshev.dev/meet. Верифікація (поки бекенд-заглушка): форма валідовується, показує стан помилки/успіху, honeypot-поле поза tab-порядком.
  13. /research. Картки, що мапляться по масиву RESEARCH_PAPERS (не фіксована кількість). Верифікація: контент відповідає розділу 7.2.
  14. /technology. П'ять категорій повністю. Верифікація: усі перелічені технології присутні, без зайвого маркетингового опису.
  15. /team. Картки, що мапляться по масиву TEAM_MEMBERS (не фіксована кількість — зараз 5). Верифікація: жодних вигаданих досягнень.
  16. Анімаційний прохід. GSAP scroll-reveal на всіх секціях, Lenis, ховер-стани (звичайні CSS-переходи — motion/react не додавали, розділ 5), glow навколо ключового UI (animations.md defaults: 500–700ms, power3.out, стагер 60–80ms). Верифікація: prefers-reduced-motion вимикає все, контент лишається повністю видимим.
  17. Бекенд-сервіс. bun create elysia app (окремий пакет), POST /leads з zod-валідацією, honeypot/timing (captcha skill), CORS обмежений на CORS_ORIGIN. Верифікація: bun test на валідатори + ручний curl проти локального інстансу.
  18. Telegram-сповіщення. src/lib/telegram.ts — прямий fetch до Telegram Bot API (sendLeadNotification, formatLeadMessage), без SDK/бази даних; TELEGRAM_BOT_TOKEN/TELEGRAM_CHAT_ID задокументовані в .env.example. Верифікація: bun test на форматування повідомлення й на всі гілки помилок (не налаштовано → 500, Telegram відповів не-2xx → 502, мережа впала → 502) через мокнутий fetch; вручну — реальний бот, реальний чат, реальне повідомлення доходить.
  19. Адаптив + продуктивність + a11y + SEO прохід. 360px→1920px без горизонтального скролу, Lighthouse ≥90 по всіх метриках, meta/OG/favicon на всіх 4 сторінках, JSON-LD Organization на головній. Верифікація: чек-лист розділів 11–12 пройдений повністю.
  20. Наскрізна перевірка деплою. Статичний фронтенд збирається (bun run build, output: 'export'), бекенд розгорнутий окремо, NEXT_PUBLIC_API_BASE_URL вказує на реальний бекенд. Верифікація: end-to-end сабміт форми на staging-оточенні доставляє реальне повідомлення в Telegram-чат.
  21. Прибрати дві секції головної. AI system flow — повне видалення компонента (components/home/ai-system-flow.tsx) і контент-константи (AI_SYSTEM_FLOW з content.ts). Technology тизер — повне видалення компонента (components/home/technology-teaser.tsx); TECH_CATEGORIES/TECH_STACK_NOTE не видаляти — їх ще використовує повна сторінка /technology. Верифікація: bun run lint/build чисті (немає імпортів мертвих файлів), /technology як і раніше рендерить п'ять категорій.
  22. Build proof секція. Новий компонент BuildProofSection (components/home/build-proof-section.tsx) на місці видаленого AI system flow — headline «Цей сайт — живий приклад нашого процесу.», mono-число ~30 хв, кнопка, що відкриває /spec у попапі (розділ 7.1 секція 8). Верифікація: клік по кнопці в реальному браузері (не тільки next dev через статик-сервер зі сторонніми особливостями trailing slash) відкриває саме /spec, а не directory listing чи 404.
  23. /spec попап-сторінка + реструктуризація маршрутів. Існуючі 4 навігаційні маршрути перенесені в групу src/app/(site)/ зі своїм layout.tsx (навбар+футер+<main>); кореневий layout.tsx лишає тільки <html>/<body>, шрифти, JSON-LD, SmoothScroll. Новий src/app/spec/page.tsx (Server Component, читає файл специфікації через fs, конвертує marked-ом) — поза групою (site), без навбару/футера. На той момент планувався subpath-деплой (nedoshev.dev/factory) — додано basePath у next.config.ts через NEXT_PUBLIC_BASE_PATH, і src/lib/base-path.ts для єдиного raw window.open/<a>. Рішення пізніше змінено на розділ 24/14 (Railway, кожен сервіс — власний корінь-домен): basePath-плумбінг лишився в коді (нешкідливий, undefined за замовчуванням), але production-білд його більше не встановлює. Верифікація: bun run build генерує окрему статичну сторінку spec.html з коректним <h1> і таблицями; nav CTA reveal (розділ 6) далі коректно шукає #hero, знайдений лише на /.
  24. Деплой на Railway. .railway/railway.ts (Infrastructure as Code — розділ 14) визначає два сервіси (backend, frontend) через rootDirectory; фронтенд отримав serve-static.ts (Bun-нативний статичний сервер, bun run start:static) замість next start; SITE_URL/NEXT_PUBLIC_BASE_PATH централізовано в src/lib/site-url.ts, .env.production із захардкодженим субшляхом видалено. Верифікація: bun run build без NEXT_PUBLIC_BASE_PATH дає кореневі (не /factory-префіксовані) посилання; bun run start:static коректно віддає /, /team, /spec, /sitemap.xml, статичні асети (усі 200) і справжній 404 для неіснуючих шляхів; виміряний RSS процесу — ~23MB в стані спокою.

14. Deployment

Платформа — Railway, не власна reverse-proxy інфраструктура з розділу 5/13. Рішення змінилось: замість субшляху nedoshev.dev/factory за власним Nginx/Caddy, кожен сервіс отримує власний згенерований Railway-домен (*.up.railway.app) і живе як окремий Railway-сервіс. NEXT_PUBLIC_BASE_PATH/src/lib/base-path.ts лишаються в коді (не видалені — нешкідливі, якщо колись субшлях-деплой знадобиться десь ще), але production-білд для Railway їх не встановлює: frontend/.env.production видалено, basePath за замовчуванням undefined (корінь).

15. Assumptions

16. Open Questions

Шість пунктів, що були тут раніше, тепер вирішені: імена команди більше не PLACEHOLDER (5 реальних людей на /team, розділ 7.4); усі 7 публікацій дослідження мають реальні рік і publicationUrl (розділ 7.2); назва бренду (Factory) підтверджена (розділ 5/14); «Website examples» (портфоліо) більше не в продукті; TELEGRAM_BOT_TOKEN/TELEGRAM_CHAT_ID — реальні значення вже в backend/.env. Актуальний список того, що ще потребує реального рішення:

  1. Цей репозиторій ще не git init-нутий.railway/railway.ts's github()-джерело вимагає реального GitHub-репо; REPO там — плейсхолдер <github-owner>/<github-repo>. Блокує будь-який Railway-деплой, поки не виправлено.
  2. NEXT_PUBLIC_SITE_URL — залишиться PLACEHOLDER (https://example.com), доки Railway не згенерує домен фронтенд-сервісу; встановити й передеплоїти після (розділ 14).
  3. Ліміти ресурсів на Railway — не частина .railway/railway.ts (дашборд-only); виставити мінімум на обох сервісах вручну після першого деплою.
  4. Логотип/фірмовий знак — назва бренду (Factory) підтверджена, візуальний знак — ще ні.
  5. CI-провайдер і аналітика — окремий CI не потрібен (Railway деплоїть на push), але аналітика так і не обрана; жодних сторонніх скриптів не додано за замовчуванням (розділ 12).