DEPLOY_HOST, RELAY_HOST и TELEGRAM_BOT_ID обязательны и читаются из неотслеживаемого deploy/.env.local (образец — .env.local.example).
Кварта — лендинг обжарки с формой заявки
Тестовое задание tz.vitai.world. Клиент вымышленный.
- Сайт: https://kvarta.unuchak.com
- Lighthouse mobile (прод, медиана трёх прогонов): Performance 99 · Accessibility 100 · Best Practices 100 · SEO 100; LCP 1.7 с, CLS 0, TBT 10 мс — отчёт
docs/lighthouse/mobile.html - Лог работы с ИИ:
docs/ai-session.txt(экспорт/exportиз Claude Code); журнал ошибок ИИ —docs/ai-log.md
Что сделано
Лендинг «недельный календарь / штамп даты»: Кварта — «четвёртая», обжарка по четвергам; ассортимент свёрстан как этикетки пачек. Кнопки предзаполняют форму, на мобиле — липкая CTA. Форма уходит в отдельный сервис api: проверка белорусского телефона (любой ввод → +375XXXXXXXXX, одна функция на клиенте и сервере), повтор с того же номера в течение 10 минут дописывается к заявке как уточнение, сохраняются первое и последнее касание (utm, yclid, fbclid, referrer, страницы входа и отправки), rate-limit, honeypot, понятные ошибки с «позвоните». Заявки менеджер видит в теме Telegram-группы, сбои — в соседней теме «Система»; бэкапы базы каждый день уходят администратору в личку, восстановление — кнопкой в боте. 184 теста Vitest.
Стек: pnpm workspace — apps/landing (Next.js 16, Tailwind 4), apps/api (Hono, better-sqlite3), packages/shared (телефон и контракт заявки). Почему два сервиса — docs/adr/0001.
Почему SQLite. Один процесс и один файл в volume: проверка «есть ли заявка с этим номером за 10 минут» и запись идут в одной транзакции, и двойной клик не даёт дубля; бэкап — копия файла; база не зависит от Telegram — если он недоступен, заявка ждёт в очереди и уходит позже (так и случилось вживую при настройке). Внешняя БД для десятков заявок в день — лишняя движущаяся часть.
Кто что делал
Я — решения и контроль: план согласован в интервью (docs/plan.md, GLOSSARY.md, ADR), выбор референсов, шрифтов и фото, вычитка всех текстов, настройка Telegram-группы и Tailscale, приёмка каждого шага. ИИ (Claude Code) — весь код, тексты-черновики, дизайн и деплой, разделённые между агентами: оркестратор (план, shared, коммиты, всё на сервере), api, landing-функционал, deploy, исследователь референсов, копирайтер, дизайнер, независимый критик по скриншотам (3 итерации: 7 → 8 → 9 из 10), аудитор. Инструменты: impeccable (детектор AI-паттернов и audit), slopotron (чистка русских текстов).
Где ИИ ошибся и как заметили
Полный журнал — docs/ai-log.md (каждая запись: ошибка → чем поймали → исправление). Самое показательное:
- Не проверил окружение. План исходил из того, что VPS ходит в api.telegram.org, — с сервера в РФ Telegram недоступен; бот молчал после
/setup. Добавлен ретранслятор Bot API на домашнем сервере через Tailscale (deploy/tg-relay). - Rate-limit считал всех одним посетителем — дважды: сначала в плане не учли, что nginx приходит в контейнер со шлюза docker-сети, потом Node отдал этот адрес как
::ffff:172.31.120.1. Тесты проходили; поймал прогон на проде с двумя разнымиX-Real-IP. - Картинки не сжимались. Sharp подключён по устаревшей документации Next; Next 16 молча отдавал исходный JPEG 838 КБ. Поймал Lighthouse на проде.
- Самопроверка дизайнера по своим скриншотам пропустила полупрозрачную подложку штампа, запрещённые его же DESIGN.md «hero-метрики» и двойной повтор «ЧТ» на каждой этикетке — нашёл только независимый критик без доступа к коду.
- Оркестратор закоммитил чужую работу (
git add -Aв чекауте, где агент верстал) — шаг 12 уехал в коммит про Telegram; история переписана с моего согласия.
Допущения
- Хостинг — свой VPS, а не бесплатный: там уже есть nginx и certbot, и на нём работает SQLite с бэкапами.
- Стоимость доставки при заказе до 50 BYN в ТЗ не указана — «уточнит менеджер». Телефон +375 29 000-00-00 демонстрационный; Instagram и e-mail в ТЗ нет — на сайте их нет.
- «Кварта = четвёртая, обжарка по четвергам» — идея бренда, не факт из ТЗ. Штамп «дата обжарки» — визуальный приём, текст не утверждает, что дата стоит на пачке.
- Фото — Unsplash (авторы в подвале), остальное SVG.
Что не успел и что сделал бы иначе
- Без JS кнопки CTA не работают, а форма не сохраняет заявку (уходит POST на страницу — данные хотя бы не попадают в URL). Нужен серверный приём
application/x-www-form-urlencoded. - Нет skip-link; при увеличении текста до 200% на мобиле появляется горизонтальный скролл (фиксированные px-ширины ленты недели и этикеток).
- Нет браузерного e2e-теста формы (Playwright) — форма проверена вручную, логика — юнит- и интеграционными тестами.
- Telegram зависит от домашнего сервера с ретранслятором. Иначе: VPS не в РФ или собственный Bot API server.
- Rate-limit в памяти процесса — сбрасывается при рестарте api.
- Сделал бы иначе: сразу изолировать параллельных агентов в отдельных worktree и проверять окружение (сеть до Telegram, Tailscale, эмуляция amd64) до плана, а не по ходу.
Подробнее: деплой и эксплуатация — docs/deploy.md, шаблоны ссылок для Директа и Instagram — docs/links.md, дизайн-система — DESIGN.md.