Files
kvarta_project/README.md
T

8.5 KiB
Raw Blame History

Кварта — лендинг обжарки с формой заявки

Тестовое задание 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.

Так заявки выглядят у менеджера в теме «Kvarta Cafe: Заявки»: интерес, телефон в едином формате, источник и путь по странице; повтор с того же номера приходит уточнением к заявке (#2), а не новой заявкой.

Заявки и уточнение в Telegram-теме «Kvarta Cafe: Заявки»

Стек: 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.