Files
kvarta_project/README.md
T
nunuchek 523519fe40 docs: README и замер Lighthouse mobile с прода
Performance 99, Accessibility 100, Best Practices 100, SEO 100
(медиана трёх прогонов, LCP 1.7 с, CLS 0).
2026-10-17 17:37:21 +03:00

48 lines
8.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Кварта — лендинг обжарки с формой заявки
Тестовое задание [tz.vitai.world](https://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.md` (экспорт `/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](https://github.com/pbakaus/impeccable) (детектор AI-паттернов и audit), [slopotron](https://github.com/beaverbeard/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`.