behaviour-logs

Логи и замеры поведения киоска — журнал операций, лог бэкенда, временный журнал касаний, приёмы измерения в браузере и ловушки фоновой вкладки. Использовать, когда «на приборе не работает», нужно дока

SKILL.md

GitHub

Логи поведения

Киоск стоит в зале, и жалобы приходят словами покупателя: «срабатывает со второго раза», «свайп не работает», «этикетка не печатается». Угадывать по описанию дорого — в этом проекте три подряд правильно звучавшие догадки оказались мимо. Здесь собрано, что прибор записывает сам, что можно включить на время и как получить доказательство.

Что записывается постоянно

  • Журнал операций — таблица transactions, видна в админке и через GET /api/transactions. Одна строка на напечатанную этикетку: время (местное, чтобы совпадало с бумагой), товар, вес, цена, сумма, штрихкод, файл растра. Это единственный долгоживущий след поведения покупателя.
  • Чего в нём нет: касаний, выбранных и брошенных товаров, поисковых запросов, отказов печати. Если понадобится статистика «что смотрели, но не купили» — это новая сущность, а не расширение журнала операций: тот привязан к факту продажи и на него ссылается мягкое удаление товаров.
  • Лог бэкенда — вывод uvicorn. Там видны все запросы и трассировки. Проверять его стоит раньше, чем лезть в код: POST /api/print 500 с sqlite3.OperationalError: disk I/O error однажды выглядел как «печать сломалась во фронтенде», а на деле процесс держал битое подключение к базе после блокировки папки антивирусом.

Журнал касаний

Для разбора «срабатывает со второго раза» в киоск временно вводится журнал указателя: слушатели pointerdown, pointerup, pointercancel, click, touchstart, touchend, touchcancel на окне в фазе перехвата, вывод — поверх экрана, включается ?taps=1 в адресе.

Что из него удалось узнать и чего иначе не увидеть:

  • клик может не родиться вовсе: pointerdown и pointerup по карточке в журнале есть, click отсутствует — так проявляется подавление касания после броска;
  • клик может родиться и не дойти: пишите его дважды, на перехвате (click↓) и на всплытии (click↑), и станет видно, что его гасят по дороге;
  • touchstart с флагом «неотменяемое» означает, что жест забрал себе браузер, и дальше искать надо в его правилах, а не в нашем коде.

Журнал держат ровно до починки и убирают: он вешает семь слушателей на каждое касание и рисует поверх всего экрана. В истории он есть — git log -S "tapsDebug".

Ловушки измерения в браузере

Проверять киоск удобно через браузерную автоматизацию, но фоновая вкладка врёт, и врёт правдоподобно. document.visibilityState === 'hidden' — и тогда:

  • requestAnimationFrame не идёт: переходы Vue не доигрывают, уходящие элементы копятся в DOM. Насчитать «две ленты вместо одной» и пойти чинить утечку — потеря вечера;
  • таймеры зажимаются до секунды, а после пяти минут в фоне — до минуты: полуторасекундная выдержка «платформа освободилась» срабатывает с задержкой, и кажется, что не работает;
  • loading="lazy" не грузит ничего: пересечения с вьюпортом не вычисляются;
  • синтетический left_click_drag шлёт pointermove без pointerdown — жест не начинается, и любой свайп «не работает».

Отсюда правило: прежде чем поверить измерению, спросите document.visibilityState, а жесты проверяйте синтетическими PointerEvent — они честнее псевдо-мыши.

Приёмы замера

  • Экран прибора воспроизводится так: корню задаются 1920x1080 и transform: scale() для обзора, а --s2l-kb-height выставляется значением для 1080 (340 px) — это единственная величина в вёрстке, завязанная на vh.
  • Живая лента среди уходящих: [...document.querySelectorAll('.track')] .find(t => !/leave/.test(t.className)). Без этого замеры идут по уходящей копии, и клики попадают в мёртвые элементы.
  • Геометрию считайте в слоях: getBoundingClientRect() под scale() делится на масштаб, а getComputedStyle возвращает уже честные пиксели раскладки — для долей и порогов берите второе.
  • Весы гоняются через /api/sim/weight: положить груз, качнуть, снять. Симулятор качается затухающим колебанием, поэтому им проверяется и «зачекайте на стабілізацію», и конец сессии по освобождению платформы (см. скилл hardware-hal).

Правило, которое эти логи выявили

Пока касание не завершилось, на экране не двигается ничего. Между pointerdown и click браузер решает, по какому элементу отдать клик; если раскладка успела съехать, клик уходит соседу или растворяется в общем предке. Так ломались пейджер при открытой клавиатуре и печать по карточке (сетка уезжала на 123 px, когда закрытие клавиатуры возвращало шапку). Оба раза лечилось одинаково: отложить перестройку экрана до конца касания. Ищите это первым, когда «нажимается со второго раза» или «нажал одно, получил другое».