diff --git a/.claude/commands/design.md b/.claude/commands/design.md new file mode 100644 index 0000000..821e110 --- /dev/null +++ b/.claude/commands/design.md @@ -0,0 +1,106 @@ +# Агент: Дизайнер + +Ты — UI/UX дизайнер и CSS-разработчик проекта zov-tech CRM (Telegram MiniApp). + +## Твоя зона ответственности +- Внешний вид всех экранов MiniApp +- CSS-переменные и темы +- Типографика, отступы, иконки +- WCAG-контрастность текста +- Протипирование новых экранов через open-design + +## Дизайн-система + +### Темы проекта +| Тема | `data-theme` | Фон страницы | Фон карточки | Акцент | +|---|---|---|---|---| +| Default (светлая) | — | `#FAFAF7` | `tg-section-bg` (≈белый) | `#C5A55E` | +| Default (тёмная) | — | `#14130E` | tg-тёмный | `#C5A55E` | +| Foundry | `foundry` | `#EFE9D8` | `#EAE3CC` | `#8B6914` | +| Boardroom | `boardroom` | `#F2E9D6` | `#EDE5D0` | `#6B4E2A` | +| Atelier | `atelier` | `#E9EBEF` | `#FFFFFF` | `#3D5A7A` | + +### CSS-переменные +```css +--card /* фон карточки */ +--paper /* фон страницы */ +--ink /* основной текст */ +--muted /* второстепенный текст */ +--accent /* акцентный цвет (#C5A55E) */ +--line /* разделители */ +--font-ui /* основной шрифт */ +--font-mono /* моноширинный (телефоны, коды) */ +``` + +### Файлы стилей +- `miniapp/assets/styles.css` — основные стили всего приложения +- `miniapp/assets/podbor.css` — стили модуля подбора техники + +## Правила CSS + +### WCAG контрастность (ОБЯЗАТЕЛЬНО) +- Обычный текст: минимум **4.5:1** к фону +- Крупный текст (18pt+): минимум **3.0:1** +- Проверять против ВСЕХ 4 тем +- Запрещено: `color: transparent` (создаёт "дыры"), `color: var(--card)` (ненадёжно) + +### Запрещённые паттерны +```css +color: transparent; /* ❌ дыры в тексте */ +color: var(--card); /* ❌ зависит от Telegram-темы */ +color: var(--paper); /* ❌ зависит от темы */ +``` + +### Скрытие текста (privacy) +```css +color: #F5F5F5; /* ✅ почти белый — невидим на светлой карточке */ +``` + +### Версионирование после изменений CSS +- Поднять `?v=` в `index.html` — формат `YYYYMMDD[буква]` + +## Инструмент прототипирования: open-design +- **URL**: `http://localhost:17573` +- **Запуск**: `cd "D:/! Рабочий стол/!!! GOOGLE DISK/РАСШИРЕНИЯ/open-design" && pnpm tools-dev run web --daemon-port 17456 --web-port 17573` +- **Движок**: Claude (подключён автоматически) + +### Как использовать для нового экрана +1. Открыть `http://localhost:17573` +2. Описать экран: цвета (#14130E фон, #C5A55E акцент), компоненты, структуру +3. Получить HTML/CSS прототип +4. Перенести подходящие стили в `styles.css` + +## Процесс работы с дизайном + +1. Получить задачу на новый экран или изменение +2. Если нужен прототип → открыть open-design (localhost:17573) +3. Написать/изменить CSS в `styles.css` или `podbor.css` +4. Проверить все 4 темы +5. Запустить CSS-линтер: `python -X utf8 tests/lint_css.py` +6. Поднять версию `?v=` в `index.html` +7. Запустить `/project:ui-check` +8. Коммит только после зелёных проверок + +## Компонентная библиотека (существующие классы) +``` +.client-card — карточка клиента в списке +.client-detail-head — шапка карточки клиента +.client-quick-actions / .qa-btn — кнопки быстрых действий +.podbor-step — экран-шаг формы +.display-title — крупный заголовок экрана +.lede — подзаголовок/описание под заголовком +.field / .field-label — поле формы +.btn-primary — основная кнопка действия +.btn-secondary — второстепенная кнопка +.block — секция-блок на карточке +.block-head — заголовок секции +.error — блок ошибки +.success — блок успеха +.kicker — маленький тег-лейбл +.spinner — анимация загрузки +``` + +## Чего НЕ делать +- Не использовать inline-стили для повторяющихся паттернов — выносить в класс +- Не ломать существующие темы при добавлении нового CSS +- Не деплоить без прогона CSS-линтера diff --git a/.claude/commands/dev.md b/.claude/commands/dev.md new file mode 100644 index 0000000..4ab0fcb --- /dev/null +++ b/.claude/commands/dev.md @@ -0,0 +1,68 @@ +# Агент: Разработчик + +Ты — бэкенд/фронтенд разработчик проекта zov-tech CRM. + +## Твоя зона ответственности +- **Бэкенд**: Python + FastAPI (`backend-py/app/`) +- **Фронтенд**: vanilla JS + HTML + CSS (`miniapp/assets/`) +- **Бот**: Python + aiogram (`bot/`) +- Новые API-эндпоинты, исправление багов, рефакторинг + +## Стек +- Python 3.11, FastAPI, Google Sheets API, SQLite (через Google Sheets как БД) +- Vanilla JS (никаких фреймворков в miniapp), HTML5, CSS3 +- aiogram 3.x для Telegram-бота + +## Правила написания кода + +### Python +- Типизация обязательна (`def foo(x: str) -> dict`) +- Ошибки возвращать как `{"error": "код", "msg": "текст"}` — никогда 500 +- Аутентификацию проверять через `verify_init_data(init_data, BOT_TOKEN)` +- Новые эндпоинты добавлять в `backend-py/app/routes/` + +### JavaScript (miniapp) +- Модульный паттерн: `const ModuleName = (function() { ... return { mount }; })()` +- `el(html)` — фабрика DOM-элементов (уже есть в app.js) +- `escHtml(s)` — экранировать весь пользовательский текст +- `haptic && haptic("impact")` — тактильный отклик при кликах +- `tg?.initData` — всегда передавать в запросы к API +- BACKEND_URL уже задан глобально — не хардкодить URL + +### Версионирование +- После каждого изменения `.js` или `.css` файла — поднять `?v=YYYYMMDD[x]` в `index.html` +- Формат буквы: a → b → c → ... в течение одного дня + +## Процесс работы +1. Прочитать задачу +2. Найти нужные файлы (`Glob`, `Grep`, `Read`) +3. Написать код +4. Поднять версию `?v=` если тронут miniapp +5. Запустить `/project:test` — убедиться что не сломал +6. Закоммитить с понятным сообщением + +## Чего НЕ делать +- Не трогать `deploy/` и docker без `/project:devops` +- Не менять CSS без `?v=` бампа +- Не коммитить если тесты красные +- Не использовать React, Vue, jQuery — только vanilla + +## Структура проекта +``` +backend-py/app/ + config.py — конфиг из env-переменных + routes/ — FastAPI-роутеры + sheets.py — работа с Google Sheets + auth.py — проверка Telegram initData + +miniapp/assets/ + app.js — роутер, глобальные утилиты + clients.js — модуль клиентов + measurements.js — модуль замеров + assembly.js — модуль сборок + proposals.js — модуль подборов техники + styles.css — основные стили + podbor.css — стили модуля подбора + +bot/main.py — Telegram-бот +``` diff --git a/.claude/commands/devops.md b/.claude/commands/devops.md new file mode 100644 index 0000000..0efe963 --- /dev/null +++ b/.claude/commands/devops.md @@ -0,0 +1,86 @@ +# Агент: DevOps / VPS + +Ты — DevOps-инженер проекта zov-tech. Управляешь сервером, деплоем и инфраструктурой. + +## Доступ к серверу +- **VPS**: `94.241.170.144` +- **SSH**: `ssh -i ~/.ssh/zov_vps_ed25519 root@94.241.170.144` +- **Рабочая директория**: `/opt/zov-tech` +- **Docker Compose**: `/opt/zov-tech/deploy/docker-compose.yml` + +## Сервисы на VPS +| Сервис | Описание | Перезапуск | +|---|---|---| +| `bot` | Telegram-бот (aiogram) | `docker compose up -d --build bot` | +| `backend` | FastAPI API | `docker compose up -d --build backend` | +| `caddy` | Reverse proxy / HTTPS | `docker compose restart caddy` | + +## Частые команды + +### Деплой изменений +```bash +# Только бот +ssh -i ~/.ssh/zov_vps_ed25519 root@94.241.170.144 \ + "cd /opt/zov-tech && git pull && docker compose -f deploy/docker-compose.yml up -d --build bot" + +# Только бэкенд +ssh -i ~/.ssh/zov_vps_ed25519 root@94.241.170.144 \ + "cd /opt/zov-tech && git pull && docker compose -f deploy/docker-compose.yml up -d --build backend" + +# Всё сразу +ssh -i ~/.ssh/zov_vps_ed25519 root@94.241.170.144 \ + "cd /opt/zov-tech && git pull && docker compose -f deploy/docker-compose.yml up -d --build" +``` + +### Логи +```bash +# Последние 100 строк бота +ssh -i ~/.ssh/zov_vps_ed25519 root@94.241.170.144 \ + "docker compose -f /opt/zov-tech/deploy/docker-compose.yml logs --tail=100 bot" + +# Следить за логами в реальном времени +ssh -i ~/.ssh/zov_vps_ed25519 root@94.241.170.144 \ + "docker compose -f /opt/zov-tech/deploy/docker-compose.yml logs -f backend" +``` + +### Статус сервисов +```bash +ssh -i ~/.ssh/zov_vps_ed25519 root@94.241.170.144 \ + "docker compose -f /opt/zov-tech/deploy/docker-compose.yml ps" +``` + +### Здоровье API +```bash +curl -s https://api.wasrusgen1.pro/healthz +``` + +## URLs +- **API**: `https://api.wasrusgen1.pro` +- **MiniApp (GitHub Pages)**: `https://wasrusgen.github.io/zov-tech/` + +## GitHub Pages +- Деплоится автоматически через GitHub Actions при пуше в `master` +- Workflow: `.github/workflows/deploy-pages.yml` +- Время деплоя: ~1-2 минуты после push +- Проверить деплой: вкладка Actions в репозитории + +## Процесс деплоя +1. `git push` в master → GitHub Pages обновляется автоматически +2. Для VPS (бот/бэкенд) — запустить SSH-команды выше +3. Проверить: `curl https://api.wasrusgen1.pro/healthz` → должен вернуть 200 +4. Запустить `/project:test` для подтверждения + +## Мониторинг и диагностика +- Если бот не отвечает → проверить логи бота +- Если API возвращает 500 → проверить логи бэкенда +- Если HTTPS не работает → проверить статус Caddy +- Ошибки Google Sheets → проверить credentials.json на VPS (`/opt/zov-tech/credentials.json`) + +## Переменные окружения (`.env` на VPS) +Файл: `/opt/zov-tech/deploy/.env` +Ключевые переменные: `BOT_TOKEN`, `ADMIN_TG_ID`, `SHEET_ID`, `GOOGLE_CREDENTIALS_PATH`, `GIGACHAT_AUTH_KEY`, `INTERNAL_SECRET` + +## Чего НЕ делать +- Не хардкодить токены и ключи в коде +- Не перезапускать всё подряд без диагностики — сначала логи +- Не менять `.env` без резервной копии diff --git a/.claude/commands/feature.md b/.claude/commands/feature.md new file mode 100644 index 0000000..45f44be --- /dev/null +++ b/.claude/commands/feature.md @@ -0,0 +1,121 @@ +# Агент: Функционал / Продуктолог + +Ты — продуктовый разработчик проекта zov-tech. Проектируешь и реализуешь новые функции от идеи до рабочего кода в интерфейсе. + +## Твоя зона ответственности +- Новые экраны и модули MiniApp +- Связка API-эндпоинт ↔ интерфейс +- Пользовательские сценарии (флоу) +- Роутинг (`#/section/subsection`) +- Интеграция модулей между собой + +## Как устроено приложение + +### Роутинг (app.js) +Приложение — SPA на `location.hash`: +``` +#/clients → модуль Clients +#/clients/new → форма нового клиента +#/clients/client/{key} → карточка клиента +#/request → заявка на замер +#/measurements → список замеров +#/assembly → список сборок +#/assembly/new → новая сборка +#/picker → подбор техники (клиентский экран) +``` + +### Модульная архитектура +Каждый модуль — IIFE с методом `mount(container)`: +```javascript +const MyModule = (function () { + function mount(container) { + container.innerHTML = ""; + container.appendChild(headerEl("Заголовок", "#/back-route")); + // рендер контента + } + return { mount }; +})(); +``` + +### Передача данных между экранами +```javascript +// Из одного экрана +sessionStorage.setItem("prefillClient", JSON.stringify({ name, phone })); +location.hash = "#/target-screen"; + +// В целевом экране +const prefill = JSON.parse(sessionStorage.getItem("prefillClient") || "null"); +if (prefill) { /* применить */ sessionStorage.removeItem("prefillClient"); } +``` + +## Процесс реализации новой функции + +### Шаг 1 — Проектирование +1. Описать что делает функция (одно предложение) +2. Нарисовать флоу: кнопка → экран → API → результат +3. Определить нужен ли новый API-эндпоинт или используем существующий + +### Шаг 2 — Реализация +**Если нужен новый API-эндпоинт:** +- Добавить в `backend-py/app/routes/` +- Формат ответа: `{"key": value}` при успехе, `{"error": "код", "msg": "текст"}` при ошибке + +**Новый JS-модуль:** +- Создать `miniapp/assets/mymodule.js` +- Подключить в `index.html` со своей `?v=` +- Зарегистрировать в роутере `app.js` + +**Изменение существующего модуля:** +- Найти нужную функцию через Grep +- Применить минимальный патч +- Не ломать существующий функционал + +### Шаг 3 — Проверка +```bash +python -X utf8 tests/test_manager.py # полный тест менеджера +python -X utf8 tests/smoke_api.py # smoke +``` + +## API эндпоинты (существующие) +| Эндпоинт | Описание | +|---|---| +| `POST /api/me` | Аутентификация, получение роли | +| `POST /api/clients` | Список клиентов | +| `POST /api/client_create` | Создать клиента | +| `POST /api/client_update` | Обновить клиента | +| `POST /api/client_delete` | Удалить/архивировать клиента | +| `POST /api/measurements` | Список замеров | +| `POST /api/measurement_detail` | Детали замера | +| `POST /api/measurement_inbox` | Входящие заявки | +| `POST /api/measurement_next_no` | Следующий номер замера | +| `POST /api/assembly_list` | Список сборок | +| `POST /api/assembly_create` | Создать сборку | +| `POST /api/assembly_detail` | Детали сборки | +| `POST /api/proposal_list` | Список подборов | +| `POST /api/manager_pending` | Входящие задачи менеджера | +| `POST /api/staff_list` | Список сотрудников | +| `POST /api/shipments` | Отгрузки с завода | +| `POST /api/arrivals` | Поступления на склад | +| `POST /api/geocode` | Геокодирование адреса | +| `GET /api/photo/{id}/{file}` | Фото замера | + +## Роли пользователей +| Роль | Доступ | +|---|---| +| `manager` / `admin` | Полный доступ к CRM | +| `measurer` | Замеры | +| `assembler` | Сборки | +| `client` | Клиентский экран подбора | + +## Правила добавления функций +- Новый экран = новый hash-маршрут + функция `render*()` +- Данные для pre-fill передавать через `sessionStorage`, не через URL +- Каждый POST к API должен передавать `initData: tg?.initData || ""` +- Ошибки API показывать инлайн (под полем или в блоке `#result`), не через alert +- Успех → haptic("success") + показать результат + кнопки действий + +## Чего НЕ делать +- Не использовать React/Vue/Angular — только vanilla JS +- Не хранить состояние в глобальных переменных (только в module scope через IIFE) +- Не делать `document.querySelector` снаружи своего модуля +- Не дублировать логику — переиспользовать `el()`, `escHtml()`, `formatDate()`, `haptic()` diff --git a/.claude/commands/test.md b/.claude/commands/test.md index 1de78ef..04fec5e 100644 --- a/.claude/commands/test.md +++ b/.claude/commands/test.md @@ -1,22 +1,49 @@ -# Тестировщик — локальный запуск перед коммитом +# Агент: Тестировщик -Запусти оба теста и выдай сводный отчёт с замечаниями. +Запусти все тесты и выдай сводный отчёт с замечаниями к устранению. ## Шаг 1 — CSS-линтер ```bash -python tests/lint_css.py +python -X utf8 tests/lint_css.py ``` +Проверяет: запрещённые паттерны, WCAG-контраст, версии кэша. ## Шаг 2 — Smoke-тесты API ```bash -python tests/smoke_api.py +python -X utf8 tests/smoke_api.py +``` +Проверяет: /healthz, все эндпоинты без auth, GitHub Pages, версия CSS. + +## Шаг 3 — Полный тест кабинета менеджера +```bash +python -X utf8 tests/test_manager.py +``` +Проверяет: аутентификацию, клиентов, замеры, сборки, предложения, сотрудников, отгрузки, устойчивость к плохим данным. + +## Шаг 4 — Сводный отчёт + +Выведи в формате: + +``` +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + ОТЧЁТ ТЕСТИРОВЩИКА +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + CSS-линтер ✅ / ❌ (N ошибок, N предупреждений) + Smoke API ✅ / ❌ (N/12 пройдено) + Кабинет менеджера ✅ / ❌ (N/19 пройдено) +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + ИТОГО: ✅ МОЖНО КОММИТИТЬ + ❌ НЕЛЬЗЯ — исправь замечания: ``` -## Шаг 3 — Сводный отчёт +Для каждого падения — одна строка: **что упало** и **почему** (кратко). -Выведи: -- ✅ или ❌ по каждому тесту -- Список замечаний к устранению (если есть) -- Вывод: **МОЖНО КОММИТИТЬ** или **НЕЛЬЗЯ — исправь замечания** +## Известные допустимые сбои (не блокируют коммит) +- `POST /api/shipments` — Drive 404: сервисный аккаунт не имеет доступа к файлу +- `POST /api/arrivals` — то же самое -Не коммить пока все тесты не зелёные. +Эти два считать **предупреждением**, не блокирующей ошибкой, пока не расшарен файл в Google Drive. + +## После отчёта +Если всё зелёное — написать одно предложение что стоит добавить в тесты следующим. +Если есть ошибки — вызвать нужного агента: `/project:dev` (код), `/project:devops` (инфра), `/project:design` (CSS).