Commit Graph

212 Commits

Author SHA1 Message Date
wasrusgen
c773adf05e fix: Content-Type: application/json во всех fetch-хелперах
measurements, assembly, request, me, inbox, proposals —
6 модулей, 6 хелперов (_fetchWithTimeout / apiFetch / _api).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 13:35:20 +03:00
wasrusgen
e934576e5c feat: клиентский кабинет #/c/cabinet
cabinet.js — дашборд клиента: профиль, менеджер, подборы, сборки.
Параллельная загрузка: /api/me + /api/proposal_list + /api/assembly_list.
Backend: assembly_list теперь поддерживает роль client (client_tg_id фильтр).
me.js: кнопка «Мой кабинет» → #/c/cabinet для роли client.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 13:25:49 +03:00
wasrusgen
f397747a34 ci: UI Playwright smoke после деплоя Pages (workflow_run)
Тригер: Deploy MiniApp to GitHub Pages → completed + success.
Скриншот сохраняется как артефакт при провале.
workflow_dispatch с опциональным SMOKE_URL для ручного запуска.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 12:33:35 +03:00
wasrusgen
f7a1c3e4c0 test: smoke-тест на локальном сервере (npx serve), убран chicken-and-egg
Сервер поднимается через spawn + HTTP polling.
SMOKE_URL=... для тестирования произвольного URL.
15 чеков: +inbox, +me, +titles.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 12:30:11 +03:00
wasrusgen
864e70f39b test: добавлены проверки #/inbox и #/me в ui_smoke.js
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 12:24:50 +03:00
wasrusgen
3741657fb6 feat: экран #/inbox — входящие задачи менеджера
InboxScreen.mount() — список замеров без решения по подбору.
Три действия: начать подбор / отложить / не нужен.
Роутинг #/inbox добавлен в routeByHash() и init().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 12:22:07 +03:00
wasrusgen
bdbdf4b259 feat: экран #/me — Мой профиль для всех ролей
manager: статус доступа, салон, быстрые переходы
staff: роли-чипы, кнопки на замеры/сборки
client: менеджер, кнопки подбора и сборок

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 12:17:52 +03:00
wasrusgen
be79f5447b docs: feature-status — #/master реализован 2026-05-18 12:08:33 +03:00
wasrusgen
b43087a4b4 feat: маршрут #/master — экран входящих задач замерщика/сборщика
- routeByHash: #/master → renderStaff(window.__zovMe)
- таймаут 15с на fetch в renderStaff и renderStaffAssemblies
- app.js v=20260518g

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 12:08:20 +03:00
wasrusgen
64292cef8e fix: права доступа по ролям — сборщик/клиент
- measurement_detail: любой мастер (measurer+assembler) видит фото замера
- assembly_list: клиент видит все свои сборки (по client_tg_id)
- assembly_detail: клиент видит детальную карточку сборки

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 11:59:16 +03:00
wasrusgen
4386779ea6 docs: структура ролей и взаимодействий (ROLES.md)
4 роли: manager / measurer / assembler / client
Цикл сделки, доступ по экранам, правило совместного подбора техники.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 11:42:38 +03:00
wasrusgen
542f96aaa0 docs: экономия токенов — правило краткости в CLAUDE.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 11:18:27 +03:00
wasrusgen
2d0246a5b5 feat: система идентификации агентов — бейдж в каждом ответе
Каждый агент обязан начинать ответ с бейджа роли:
🤖 КООРДИНАТОР / 🔧 DEV / ⚙️ DEVOPS / 🎨 DESIGN / 🧩 FEATURE / 🧪 TEST / 🔍 REVIEW

Правило прописано в CLAUDE.md и в каждом агент-файле.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 11:17:58 +03:00
wasrusgen
7b874e0195 feat: система активных агентов — ROADMAP, статусы, команда /project:review
- ROADMAP.md — единый роадмап продукта (реализовано / в работе / бэклог)
- agents/dev-status.md — состояние кода, долг, следующий шаг
- agents/devops-status.md — VPS, блокеры, инфра-бэклог
- agents/design-status.md — компоненты, нереализованные экраны
- agents/feature-status.md — таблица функционала, приоритизированный бэклог
- agents/test-status.md — покрытие, пробелы, следующий шаг
- .claude/commands/review.md — мастер-команда: сводный отчёт по всем агентам
- Все агенты обновлены: читают и пишут свой status.md в начале/конце работы

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 11:16:27 +03:00
wasrusgen
ff35dd769f ci: добавить pre-push hook (CSS-линтер + UI Playwright)
Блокирует push при JS-ошибках в интерфейсе или CSS-нарушениях.
API-тесты в хук не включены — зависят от VPS/Drive, запускать вручную.
Активируется через: git config core.hooksPath .githooks

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 09:30:36 +03:00
wasrusgen
0fb0597b8d fix: добавить 15-секундный таймаут fetch во все модули (measurements, assembly, proposals, request)
Кнопки больше не зависают бесконечно при медленном или недоступном бэкенде.
AbortController + дружелюбное сообщение «Сервер не отвечает — попробуйте ещё раз».

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 09:27:53 +03:00
wasrusgen
40e2275949 test: добавить Playwright UI smoke-тест (10 проверок JS-ошибок по экранам)
- tests/ui_smoke.js — headless Chromium с mock Telegram.WebApp, проверяет
  загрузку, список клиентов, форму нового клиента, замеры, сборки
- package.json — playwright devDependency
- .claude/commands/test.md — добавлен Шаг 4 (UI Playwright) в агент тестировщика

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 08:53:58 +03:00
wasrusgen
6f74d05184 fix: таймаут 15с на все fetch в clients.js — кнопки больше не висят
- _fetchWithTimeout() — единый fetch с AbortController
- saveClientNote, fetchClientNote, fetchClients, fetchMeasurements
  теперь через таймаут вместо бесконечного ожидания
- При таймауте показывает 'Сервер не отвечает — попробуйте ещё раз'
- Версия clients.js: 20260518e
2026-05-18 08:35:42 +03:00
wasrusgen
a9aa704950 fix: добавить escAttr — ReferenceError в карточке клиента
escAttr использовалась в 11 местах (карта, форма редактирования)
но не была объявлена в clients.js — отсюда пустая карточка.
Версия clients.js: 20260518d
2026-05-18 08:31:27 +03:00
wasrusgen
ad6c8b9205 feat: добавить команды агентов — dev, devops, design, feature, test
/project:dev     — разработчик (Python/JS/бот)
/project:devops  — деплой и обслуживание VPS
/project:design  — CSS, темы, WCAG, open-design
/project:feature — новый функционал, флоу, роутинг
/project:test    — тестировщик (все 3 теста + сводный отчёт)
2026-05-18 08:29:43 +03:00
wasrusgen
b6bf2eaf80 docs: добавить принципы работы Claude в CLAUDE.md 2026-05-18 08:25:50 +03:00
wasrusgen
057842b7e6 debug: показывать ошибку в карточке клиента вместо пустого экрана
- Обернуть renderClientHistory в try/catch — показывает текст ошибки
- Добавить .catch() в mount() для перехвата unhandled promise rejection
- Версия clients.js: 20260518c
2026-05-18 00:21:28 +03:00
wasrusgen
860c768572 fix: пустая карточка клиента — обработка ошибок и сравнение client_tg_id
- Добавить проверку data.error после fetchClients() в renderClientHistory
- Сравнивать client_tg_id как строки (String(c.client_tg_id) === String(clientKey))
  чтобы избежать 5937498515 !== '5937498515'
- Показывать явное сообщение если клиент не найден вместо пустой страницы
- Версия clients.js: 20260518b
2026-05-18 00:11:44 +03:00
wasrusgen
a4124c6b50 fix: открывать карточку клиента вместо списка подборов
- Заголовок 'История подборов' → 'Карточка клиента'
- Убрать инлайн-монтирование Proposals.mountManager в карточке клиента
- Оставить только кнопку 'Открыть →' для перехода к подборам
- Версия clients.js: 20260518a
2026-05-18 00:03:38 +03:00
wasrusgen
20665d73f3 fix: ARRIVALS_FILE_ID = SHIPMENTS_FILE_ID (один файл ОТГРУЗКИ)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 22:23:38 +03:00
wasrusgen
c7db038659 feat(lint): WCAG-контраст в CSS-линтере + fix shipments Drive ID
- lint_css.py: проверка контраста по WCAG 4.5:1 для HEX-цветов,
  разделение ошибок/предупреждений, проверка против всех тем
- config.py: SHIPMENTS_FILE_ID обновлён на актуальный из AI АНАЛИТИКА
  ARRIVALS_FILE_ID сброшен в пустой (ID пока не найден)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 18:19:35 +03:00
wasrusgen
87b8d0f3d6 feat(ci): автоматический тестировщик — CSS-линтер + smoke API + GitHub Actions CI
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 17:59:41 +03:00
wasrusgen
fe7d08ee39 ui(clients): все шрифты страницы клиентов #0E1621 — имя, телефон, счётчик, поиск, footer
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 15:14:17 +03:00
wasrusgen
fe79c832ec fix(privacy): client-name и client-phone цвет #F5F5F5
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 15:03:37 +03:00
wasrusgen
a1892f11a7 chore: добавить агент /project:ui-check — обязательная проверка перед UI-коммитами
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 15:00:45 +03:00
wasrusgen
dbcd2f37c5 fix(bot): меню-кнопка CRM открывает ?role=manager — пропуск выбора роли
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 14:59:13 +03:00
wasrusgen
7ff1b69663 fix(privacy): client-name и client-phone цвет #0E1621
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 12:46:59 +03:00
wasrusgen
4c629ed705 fix(privacy): color:var(--paper) для имён — совпадает с фоном страницы за карточками
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 12:35:52 +03:00
wasrusgen
a545df4005 fix(privacy): opacity:0 вместо transparent — без дырки-силуэта букв
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 12:30:38 +03:00
wasrusgen
16b52cdfe8 chore: добавить CLAUDE.md — pre-commit checklist для UI/CSS изменений
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 12:11:44 +03:00
wasrusgen
4c6cf3eedd fix(privacy): color:transparent для client-name и client-phone — гарантированно скрывает в любой TG-теме
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 12:01:22 +03:00
wasrusgen
844007f6ba ui: имена и телефоны клиентов — цвет совпадает с фоном карточки (приватность)
.client-name и .client-phone → color: var(--card), текст сливается
с фоном карточки во всех темах. Аватар и счётчики подборов остаются видимыми.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 11:15:14 +03:00
wasrusgen
eae5e61fcf ui: замена «Новый клиент» на «Заказы», стили карточек клиентов, Свободный день, splash −30%
- quickActions: «Новый клиент» → «Заказы» (clipboard → #/assembly),
  убрали дублирующую кнопку «Сборки» из быстрых действий
- «Свободный день»: текст теперь использует var(--ink)/var(--muted) вместо
  rgba белых значений, которые были невидимы на светлом фоне --card;
  заголовок — шрифт карточки ×1.3 (17.5px 600), описание — моно uppercase 9.5px
- styles.css: добавлены явные стили .client-card/.client-name/.client-phone/
  .client-avatar и др. — исправлен невидимый текст в карточках клиентов
  во всех темах (Foundry, Boardroom, Atelier)
- splash: minShow 1200 → 840 мс (−30%)
- index.html: версия ресурсов → 20260517c

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 09:47:06 +03:00
wasrusgen
2f50f6e920 fix(miniapp): remove location.reload() on back-to-home navigation (splash bug)
Every "Назад" / "На главную" button was calling location.reload() which
triggered a full page reload → splash screen appeared again. Fix: replace
reload() with routeByHash() call (global router function from app.js) which
re-renders the role-appropriate home screen from cached window.__zovMe
without any network round-trips.

Affected files: app.js, clients.js, measurements.js, request.js,
assembly.js, podbor.js. Bump asset versions to 20260517b to bust cache.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 00:39:12 +03:00
wasrusgen
cd587f846a fix(sheets): add TTL in-memory cache to prevent Sheets API 429 quota errors
Every /api/me call was reading the entire Users sheet via get_all_values(),
exhausting the 60 reads/minute quota under any load. Added a 90-second
TTL cache keyed by sheet name:
- _cached_get_all_values(): returns cached data or refreshes on miss/expiry
- _invalidate_cache(): called after every write (append_row, append_named_row,
  update_cell_by_key) so stale data is never served after mutations
- Patched: find_row, update_cell_by_key, list_users_with_role

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 00:33:52 +03:00
wasrusgen
a3b0ff511c fix: append_named_row uses RAW to preserve + in phones; fix seed script to use append_named_row 2026-05-16 13:09:34 +03:00
wasrusgen
632bce8f33 fix: wrap client_create/delete/update in try/except for proper error surfacing 2026-05-16 12:35:42 +03:00
wasrusgen
b3b62fa902 refine: per-theme personality from dashboard analysis
Extracted from reference dashboards (computed styles, class structure, color usage):

B Foundry:  r-card 0px, body lh 1.5, Archivo 800 display,
            dark #15140F header (palette + greeting full-width),
            wide 0.18em kicker tracking, heavy section labels
C Boardroom: r-card 0px, r-tag 999px (pills), body lh 1.12,
            Geist 400 display (restrained), dark petrol header,
            copper accent on greeting
D Atelier:  body lh 1.1, Manrope 700 display, white card header
            on dove bg, ink-bottom-border divider,
            prominent uppercase section labels

Also: role-card border-radius switched to var(--r-card) from hardcoded 16px

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 12:28:40 +03:00
wasrusgen
db6c4f3265 feat: theme switching system — 4 palettes (ZOV · Foundry · Boardroom · Atelier)
- styles.css v5: replaced old 3-variant system with 4 design-token themes
  extracted from reference dashboards:
  · brand (ЗОВ): #003E7E blue / #76BD22 green, Inter
  · b Foundry: #EFE9D8 cream / #B68A1A mustard, Archivo, sharp corners
  · c Boardroom: #F2E9D6 linen / #D08A55 copper, Geist, petrol tones
  · d Atelier: #E9EBEF dove / #2E5266 steel-blue, Manrope
  Each theme: --paper, --ink, --accent-*, --status-*, --r-*, --font-ui, --warm
- app.js: applyVariant() + savedVariant() helpers with localStorage persistence;
  renderPaletteSwitcher() component (color swatches + name label);
  injected in renderManagerHome + renderStaff; setupTelegram() restores saved variant
- index.html: added Archivo + Manrope to Google Fonts; cache-bust v20260517a
- podbor.css: .role-card .role-icon uses color: var(--accent-1) (was hardcoded walnut);
  SVG strokes switched to currentColor for theme-awareness

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 12:17:54 +03:00
wasrusgen
5fafdc35fb feat: replace hand-drawn role icons with Tabler Icons (MIT)
Manager: user-star (person + star badge)
Client: home-2 (house with square window)
Staff: tools (wrench + screwdriver crossed)
Source: tabler-icons.io, MIT license, stroke=#6B4A2B

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 11:53:19 +03:00
wasrusgen
35c3c3f440 feat: replace geometric role icons with pencil-sketch SVG illustrations
Manager: suit, lapels, tie, pocket square, face with hair/eyes/nose
Client: house with chimney+smoke, pane windows, paneled door, garden bush
Staff: dark hard hat, face with stubble+brows, work jacket, wrench in hand
All use feTurbulence displacement filter for hand-drawn line wobble
and diagonal hatching lines for shadow/volume.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 11:19:12 +03:00
wasrusgen
2479ac05cf chore: add Claude Code PostToolUse syntax-check hook
.claude/settings.json — hook fires after every Edit/Write:
- .js files  → node --check
- .py files  → py_compile.compile (doraise=True)
- exit 2 on failure → Claude sees the error immediately and fixes it

Scripts:
- .claude/hooks/syntax_check.ps1  (Windows, primary)
- .claude/hooks/syntax_check.sh   (bash fallback)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 11:01:34 +03:00
wasrusgen
f64a64e834 feat: canonicalize Measurements schema on startup + full column-order repair
_ensure_measurements_sheet() now:
1. Creates sheet with canonical headers if missing
2. Adds any missing columns
3. If column ORDER doesn't match _measurement_columns() — migrates all
   data rows in-place: reads by column name, rewrites in canonical order

@app.on_event("startup") calls _ensure_measurements_sheet() via
asyncio.to_thread so column order is always corrected on deploy,
not just on first client_create.

This guarantees append_named_row() always finds columns in expected
positions, eliminating the silent data-in-wrong-column bug.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 11:00:52 +03:00
wasrusgen
8318b25999 fix: write Measurements rows by column name, not by position
Root cause: _row_for_measurement() returned a positional list based on
_measurement_columns() order, but the actual Google Sheet may have
columns in a different order (if the sheet was created before new
columns were added and _ensure_measurements_sheet() appended them
at the end rather than in the middle). Values ended up in wrong
columns — client_name, manager_tg_id etc. were misaligned, so
_handle_clients couldn't match any rows and returned an empty list.

Fix:
- _row_for_measurement() now returns dict {col_name: value}
- sheets.append_named_row() reads real headers from the sheet and
  builds the positional row accordingly — safe regardless of column order
- All three Measurements append calls updated to use append_named_row

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 10:56:45 +03:00
wasrusgen
46812620eb fix: remove stray closing brace in zamer-picts.js that crashed MiniApp
Premature `};` at line 207 closed the ZAMER_PICTS object early,
leaving wall1/wall2/etc. as orphan code — syntax error on load.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 10:41:10 +03:00