diff --git a/tasks/enduro-trails/DEV_TASK_DARK_STYLE.md b/tasks/enduro-trails/DEV_TASK_DARK_STYLE.md new file mode 100644 index 0000000..0ad3344 --- /dev/null +++ b/tasks/enduro-trails/DEV_TASK_DARK_STYLE.md @@ -0,0 +1,285 @@ +# DEV TASK: Тёмная тема карты (F-18) + +**Статус:** Ready for dev +**Проект:** enduro-trails +**Фаза:** 5.1 +**BRD:** нет (простая фича) + +--- + +## Цель + +> Карта MapLibre переключается между светлым и тёмным стилем синхронно с темой UI (auto/light/dark + SunCalc). + +## Архитектура + +Сейчас `style.json` — это светлый стиль (фон `#f0ede6`, OSM raster desaturated). Нужно создать `style-dark.json` с тёмной палитрой и исправить логику в `switchMapStyle()`, которая сейчас инвертирована (считает `style.json` тёмным). + +Подход: тёмный стиль = тот же OSM raster, но с `brightness-max: 0.3`, `contrast: -0.2`, тёмный background. Цвета треков и POI адаптированы для тёмного фона. + +## Стек / Зависимости + +- MapLibre GL JS (уже подключён) +- Никаких новых зависимостей + +--- + +## Инфраструктура + +| Параметр | Значение | +|----------|----------| +| Сервер | `slin@82.22.50.71` (пароль: `motoZ@yaz2010`) | +| Рабочая директория | `/home/slin/enduro-trails/prototype/static/` | +| Workspace | `/home/node/.openclaw/workspace/tasks/enduro-trails/prototype/static/` | +| Деплой | SFTP + `docker cp` после рестарта | +| Контейнер | `prototype-enduro-trails-1` | +| URL | `https://openclaw.mva154.duckdns.org/enduro/` | + +--- + +## Файловая карта + +| Действие | Файл | Ответственность | +|----------|------|-----------------| +| Создать | `static/style-dark.json` | Тёмный стиль карты | +| Переименовать | `static/style.json` → оставить как есть | Светлый стиль (уже есть) | +| Изменить | `static/app.js` (строки 86-105) | Исправить логику switchMapStyle | + +--- + +## Задачи + +### Task 1: Создать style-dark.json + +**Файлы:** +- Создать: `static/style-dark.json` + +**Шаги:** + +- [ ] **1.1** Создать `style-dark.json` на основе `style.json` со следующими изменениями: + +```json +{ + "name": "Enduro Trails Dark", + "layers": [ + { + "id": "background", + "paint": { "background-color": "#1a1a2e" } + }, + { + "id": "osm-base", + "paint": { + "raster-opacity": 1.0, + "raster-saturation": -0.6, + "raster-contrast": -0.1, + "raster-brightness-min": 0, + "raster-brightness-max": 0.35 + } + }, + { + "id": "trails-track", + "paint": { + "line-color": "...", + "line-opacity": 0.95 + } + // Цвета треков: grade1/2 → #FFE066, grade3/4/5 → #FF6633, default → #FF6633 + }, + { + "id": "trails-path-bridleway", + "paint": { + "line-color": "#ff4444", + "line-opacity": 0.9 + } + }, + { + "id": "poi-circles", + "paint": { + "circle-stroke-color": "#333333" + // Остальные цвета POI — ярче на 10-15% для контраста на тёмном фоне + } + }, + { + "id": "poi-labels", + "paint": { + "text-color": "#e0e0e0", + "text-halo-color": "#1a1a2e", + "text-halo-width": 2 + } + } + ] +} +``` + +Полная спецификация изменений относительно `style.json`: + +| Слой | Свойство | Светлый | Тёмный | +|------|----------|---------|--------| +| background | background-color | `#f0ede6` | `#1a1a2e` | +| osm-base | raster-saturation | `-0.4` | `-0.6` | +| osm-base | raster-contrast | `0.25` | `-0.1` | +| osm-base | raster-brightness-max | `0.9` | `0.35` | +| trails-track | line-color grade1/2 | `#FFD700` | `#FFE066` | +| trails-track | line-color grade3/4/5/default | `#FF4400` | `#FF6633` | +| trails-path-bridleway | line-color | `#cc0000` | `#ff4444` | +| poi-circles | circle-stroke-color | `#ffffff` | `#333333` | +| poi-labels | text-color | `#333333` | `#e0e0e0` | +| poi-labels | text-halo-color | `#ffffff` | `#1a1a2e` | +| poi-labels | text-halo-width | `1.5` | `2` | + +Все остальные свойства (sources, glyphs, filters, zoom levels, line-width) — копировать из `style.json` без изменений. + +- [ ] **1.2** Проверить валидность JSON + +```bash +cat static/style-dark.json | python3 -m json.tool > /dev/null && echo "OK" +# Ожидаемый результат: OK +``` + +**Критерий готовности:** Файл `style-dark.json` существует, валидный JSON, содержит все слои из style.json с тёмной палитрой. + +--- + +### Task 2: Исправить switchMapStyle() в app.js + +**Файлы:** +- Изменить: `static/app.js` (строки 86-105) + +**Шаги:** + +- [ ] **2.1** Заменить функцию `switchMapStyle()` (строки 86-105): + +**Было:** +```javascript +function switchMapStyle() { + const map = window._map; + if (!map) return; + const dark = isDarkTheme(); + const basePath = window.location.pathname.replace(/\/[^/]*$/, '') || ''; + const styleUrl = dark ? basePath + '/style.json' : basePath + '/style-light.json'; + + // Check if style-light.json exists - if not, keep current + fetch(styleUrl, { method: 'HEAD' }).then(r => { + if (r.ok) { + map.setStyle(styleUrl); + } else { + // No light style available, keep dark + if (!dark) { + console.log('Light map style not available, keeping dark'); + } + } + }).catch(() => { + // Network error, don't switch + }); +} +``` + +**Стало:** +```javascript +function switchMapStyle() { + const map = window._map; + if (!map) return; + const dark = isDarkTheme(); + const basePath = window.location.pathname.replace(/\/[^/]*$/, '') || ''; + const styleUrl = dark ? basePath + '/style-dark.json' : basePath + '/style.json'; + + fetch(styleUrl, { method: 'HEAD' }).then(r => { + if (r.ok) { + map.setStyle(styleUrl); + } else { + console.log('Map style not available:', styleUrl); + } + }).catch(() => { + // Network error, don't switch + }); +} +``` + +Ключевое изменение: `dark → style-dark.json`, `light → style.json` (было инвертировано). + +- [ ] **2.2** Проверить что `switchMapStyle()` вызывается в `applyTheme()` (строка 26) — уже есть, не трогать. + +**Критерий готовности:** При `isDarkTheme() === true` загружается `style-dark.json`, при `false` — `style.json`. + +--- + +### Task 3: Деплой и проверка + +**Шаги:** + +- [ ] **3.1** Загрузить файлы на сервер + +```bash +# Через Node.js ssh2 (deploy_static.js) или напрямую: +scp static/style-dark.json slin@82.22.50.71:/home/slin/enduro-trails/prototype/static/ +scp static/app.js slin@82.22.50.71:/home/slin/enduro-trails/prototype/static/ +``` + +- [ ] **3.2** Docker cp в контейнер + +```bash +ssh slin@82.22.50.71 << 'EOF' +docker cp /home/slin/enduro-trails/prototype/static/style-dark.json prototype-enduro-trails-1:/app/static/style-dark.json +docker cp /home/slin/enduro-trails/prototype/static/app.js prototype-enduro-trails-1:/app/static/app.js +EOF +``` + +⚠️ НЕ рестартовать контейнер! Просто cp — иначе придётся копировать ВСЕ файлы заново. + +- [ ] **3.3** Проверить доступность стилей + +```bash +curl -s -o /dev/null -w "%{http_code}" https://openclaw.mva154.duckdns.org/enduro/style.json +# Ожидаемый результат: 200 + +curl -s -o /dev/null -w "%{http_code}" https://openclaw.mva154.duckdns.org/enduro/style-dark.json +# Ожидаемый результат: 200 +``` + +- [ ] **3.4** Проверить содержимое тёмного стиля + +```bash +curl -s https://openclaw.mva154.duckdns.org/enduro/style-dark.json | python3 -c "import json,sys; d=json.load(sys.stdin); print(d['name'], d['layers'][0]['paint'])" +# Ожидаемый результат: Enduro Trails Dark {'background-color': '#1a1a2e'} +``` + +**Критерий готовности:** Оба стиля доступны по URL, тёмный стиль содержит правильную палитру. + +--- + +## Проверка (Acceptance) + +| # | Проверка | Действие | Ожидаемый результат | +|---|----------|----------|---------------------| +| 1 | Светлая тема | Открыть сайт, выбрать ☀️ | Карта светлая (бежевый фон) | +| 2 | Тёмная тема | Переключить на 🌙 | Карта тёмная (тёмно-синий фон, приглушённый OSM) | +| 3 | Auto (день) | Режим auto днём | Карта светлая | +| 4 | Auto (ночь) | Режим auto ночью | Карта тёмная | +| 5 | Overlay сохраняется | Включить terrain → переключить тему | Terrain слой остаётся видимым | +| 6 | Маршрут сохраняется | Построить маршрут → переключить тему | Маршрут остаётся на карте | +| 7 | style-dark.json 200 | `curl` | HTTP 200 | + +--- + +## Ограничения и контекст + +- ⚠️ `docker cp` БЕЗ рестарта контейнера — рестарт перезапишет статику из образа +- ⚠️ SSH через Node.js ssh2 модуль (бинарный ssh в контейнере OpenClaw не работает — glibc mismatch). Альтернатива: `deploy_static.js` +- ⚠️ После `map.setStyle()` все кастомные слои (terrain, routes, markers) слетают — `onMapStyleLoad()` + `rebuildMapOverlays()` уже обрабатывают это через событие `style.load` +- 🚫 Не трогать `style.json` — это рабочий светлый стиль +- 🚫 Не менять логику SunCalc / applyAutoTheme — она работает корректно + +--- + +## Деплой-чеклист + +- [ ] `style-dark.json` создан и валиден +- [ ] `app.js` — логика `switchMapStyle` исправлена +- [ ] Файлы загружены на сервер (`/home/slin/enduro-trails/prototype/static/`) +- [ ] `docker cp` выполнен (без рестарта!) +- [ ] `style-dark.json` доступен по URL (HTTP 200) +- [ ] Переключение темы меняет стиль карты +- [ ] Overlays (terrain, routes) сохраняются при смене стиля + +--- + +*Создано: 2026-05-12 | Автор ТЗ: Стрим | Исполнитель: Dev-агент* diff --git a/templates/DEV_TASK_TEMPLATE.md b/templates/DEV_TASK_TEMPLATE.md new file mode 100644 index 0000000..5c96ad5 --- /dev/null +++ b/templates/DEV_TASK_TEMPLATE.md @@ -0,0 +1,134 @@ +# DEV TASK: [Название фичи/задачи] + +**Статус:** Ready for dev +**Проект:** [slug проекта] +**Фаза:** [номер] +**BRD:** [ссылка на BRD если есть] + +--- + +## Цель + +> Одно предложение: что должно работать после выполнения этой задачи. + +## Архитектура + +> 2-3 предложения: подход, ключевые решения, почему именно так. + +## Стек / Зависимости + +- [Язык/фреймворк] +- [Библиотеки] +- [Внешние сервисы] + +--- + +## Инфраструктура + +| Параметр | Значение | +|----------|----------| +| Сервер | `user@host` | +| Рабочая директория | `/path/to/project/` | +| Деплой | [команды / скрипт] | +| URL | [где проверять результат] | + +--- + +## Файловая карта + +> Какие файлы создаются/меняются и за что отвечают. + +| Действие | Файл | Ответственность | +|----------|------|-----------------| +| Создать | `path/to/new_file.py` | [что делает] | +| Изменить | `path/to/existing.js:50-80` | [что меняется] | +| Тест | `tests/test_feature.py` | [что проверяет] | + +--- + +## Задачи + +### Task 1: [Компонент / Шаг] + +**Файлы:** +- Создать: `exact/path/file.py` +- Изменить: `exact/path/existing.js` + +**Шаги:** + +- [ ] **1.1** Написать [что именно] + +```python +# Точный код или псевдокод с достаточной детализацией +def example(): + pass +``` + +- [ ] **1.2** Проверить + +```bash +# Точная команда проверки +curl -s http://localhost:5558/api/endpoint | jq .status +# Ожидаемый результат: "ok" +``` + +- [ ] **1.3** Задеплоить + +```bash +# Точные команды деплоя +docker cp /path/file.py container:/app/file.py +docker restart container +``` + +**Критерий готовности:** [Что должно быть true чтобы задача считалась выполненной] + +--- + +### Task 2: [Следующий компонент] + +**Файлы:** +- Создать: `...` + +**Шаги:** + +- [ ] **2.1** ... +- [ ] **2.2** ... + +**Критерий готовности:** ... + +--- + +## Проверка (Acceptance) + +> Финальные проверки после всех задач. Что Стрим проверит перед тем как закрыть задачу. + +| # | Проверка | Команда / Действие | Ожидаемый результат | +|---|----------|-------------------|---------------------| +| 1 | [что проверяем] | `curl ...` | HTTP 200, JSON с полем X | +| 2 | [визуальная] | Открыть URL | Видно Y без ошибок | +| 3 | [edge case] | [действие] | [результат] | + +--- + +## Ограничения и контекст + +> Что Dev-агент ДОЛЖЕН знать, чтобы не наступить на грабли. + +- ⚠️ [Граблина 1 — например: docker cp ПОСЛЕ рестарта, не до] +- ⚠️ [Граблина 2 — например: SSH через ssh2 модуль, не бинарник] +- 🚫 [Чего НЕ делать — например: не трогать nginx конфиг] + +--- + +## Деплой-чеклист + +- [ ] Код написан и работает локально +- [ ] Файлы загружены на сервер +- [ ] Контейнер перезапущен (если нужно) +- [ ] docker cp выполнен (если статика) +- [ ] Проверка по URL — работает +- [ ] Нет ошибок в логах (`docker logs container --tail 50`) + +--- + +*Создано: YYYY-MM-DD | Автор ТЗ: Стрим | Исполнитель: Dev-агент* diff --git a/templates/DEV_WORKFLOW.md b/templates/DEV_WORKFLOW.md new file mode 100644 index 0000000..d5955ce --- /dev/null +++ b/templates/DEV_WORKFLOW.md @@ -0,0 +1,167 @@ +# Dev Workflow — Процесс разработки через OpenClaw + +> Адаптация методологии Superpowers под нашу архитектуру: Стрим (постановка) → Dev-агент (реализация) → Стрим (ревью) + +--- + +## Роли + +| Роль | Кто | Что делает | +|------|-----|-----------| +| **Product** | Слава | Идея, приоритеты, финальное ОК | +| **Architect** | Стрим | BRD, ТЗ по шаблону, ревью результата | +| **Implementer** | Dev-агент | Код, тесты, деплой | +| **Reviewer** | Стрим (+ опционально отдельный субагент) | Проверка соответствия ТЗ | + +--- + +## Пайплайн + +``` +Слава: идея/запрос + ↓ +Стрим: уточняющие вопросы (1-3 штуки, не больше) + ↓ +Стрим: BRD (если фича крупная) или сразу ТЗ + ↓ +Слава: ОК / правки + ↓ +Стрим: заполняет DEV_TASK по шаблону + ↓ +Dev-агент: реализация (sessions_spawn, agentId: "dev") + ↓ +Стрим: ревью результата (spec compliance) + ↓ +[если баги] → Dev-агент: фикс → Стрим: повторное ревью + ↓ +Стрим: обновляет PROJECT.md, онтологию + ↓ +Слава: финальная проверка +``` + +--- + +## Когда что использовать + +### Быстрая задача (< 30 мин Dev-работы) +- Один файл, понятная правка, нет архитектурных решений +- **Процесс:** Стрим пишет короткое ТЗ прямо в `task` параметре `sessions_spawn` +- **Шаблон не нужен** — достаточно: цель + файлы + команда проверки +- Пример: «поменять opacity слоя с 0.55 на 0.7 в app.js строка 450» + +### Средняя задача (30 мин — 2 часа) +- Несколько файлов, но понятная архитектура +- **Процесс:** Стрим заполняет DEV_TASK_TEMPLATE.md, передаёт Dev-агенту +- **Ревью:** Стрим проверяет по таблице Acceptance +- Пример: новая кнопка в UI + API endpoint + деплой + +### Крупная задача (> 2 часов, новая фича) +- Много файлов, архитектурные решения, несколько компонентов +- **Процесс:** BRD → ТЗ по шаблону → разбивка на Task 1..N → Dev-агент получает по одной задаче +- **Ревью:** после каждого Task (не в конце!) +- **Опционально:** отдельный субагент-ревьюер для spec compliance +- Пример: terrain layer, PWA, новый режим роутинга + +--- + +## Формат передачи задачи Dev-агенту + +### Вариант A: Файл (средние/крупные задачи) + +```python +sessions_spawn( + agentId="dev", + task="Реализуй задачу по ТЗ: /home/node/.openclaw/workspace/tasks/{project}/DEV_TASK_{feature}.md. Начни с Task 1. После каждого Task — отчитайся что сделано.", + mode="run" +) +``` + +### Вариант B: Inline (быстрые задачи) + +```python +sessions_spawn( + agentId="dev", + task=""" +Проект: enduro-trails +Сервер: slin@82.22.50.71 + +Задача: Поменять opacity гипсометрии с 0.55 на 0.7 + +Файл: /home/slin/enduro-trails/prototype/static/app.js +Строка: найти `'raster-opacity': 0.55` в source `terrain-hypso` +Заменить на: `'raster-opacity': 0.7` + +Деплой: +docker cp /home/slin/enduro-trails/prototype/static/app.js prototype-enduro-trails-1:/app/static/app.js + +Проверка: +curl -s https://openclaw.mva154.duckdns.org/enduro/static/app.js | grep "raster-opacity" +# Должно быть 0.7 +""", + mode="run" +) +``` + +--- + +## Ревью после реализации + +### Что проверяет Стрим: + +1. **Spec compliance** — всё ли из ТЗ реализовано? Ничего лишнего не добавлено? +2. **Деплой** — код на сервере, контейнер работает, URL отвечает? +3. **Edge cases** — что будет если [нет данных / таймаут / мобильный]? + +### Когда запускать отдельного ревьюера: + +- Задача > 3 Tasks +- Затрагивает > 5 файлов +- Есть сложная логика (роутинг, алгоритмы) + +```python +sessions_spawn( + task=""" +Ты — ревьюер. Проверь реализацию на соответствие ТЗ. + +ТЗ: [путь к DEV_TASK] +Реализация: [пути к изменённым файлам] + +Проверь: +1. Все задачи из ТЗ выполнены? +2. Нет лишнего кода, не описанного в ТЗ? +3. Команды проверки из ТЗ проходят? + +Формат ответа: +✅ Task N — ОК / ❌ Task N — [что не так] +""", + mode="run" +) +``` + +--- + +## Принципы (из Superpowers, адаптированные) + +| Superpowers | Наша адаптация | +|-------------|---------------| +| TDD обязателен | Тесты для бэкенда/логики. Для UI — acceptance checks | +| Git worktrees | Не используем. Деплой через docker cp / SSH | +| Fresh subagent per task | ✅ Уже делаем через sessions_spawn | +| No placeholders в плане | ✅ Точный код, точные пути, точные команды | +| Spec review + Code review | Spec review — всегда. Code review — для крупных задач | +| Continuous execution | Dev работает автономно внутри одного Task | +| YAGNI | Не добавлять фичи, которых нет в ТЗ | + +--- + +## Антипаттерны + +❌ **Стрим пишет код сама** — никогда, даже «быстрый фикс» +❌ **ТЗ без команды проверки** — Dev не знает когда он закончил +❌ **«Сделай как в прошлый раз»** — Dev не помнит прошлый раз, повтори контекст +❌ **Несколько крупных Tasks в одном spawn** — контекст переполнится +❌ **Ревью через неделю** — проверять сразу после выполнения + +--- + +*Создано: 2026-05-12 | Автор: Стрим*