diff --git a/.roo/memory-bank/activeContext.md b/.roo/memory-bank/activeContext.md
index 070a880..69e40cf 100644
--- a/.roo/memory-bank/activeContext.md
+++ b/.roo/memory-bank/activeContext.md
@@ -2,93 +2,77 @@
## Task State
-- task_id: TASK-SSR-DETAIL
+- task_id: TASK-MCP-SETUP
- status: success
-- parent_task: TASK-SSR-2
-- summary: **SSR /public/workouts/:id — HTML-контент переписан под DOM-структуру WorkoutItem.vue (вёрстка + фото + OG:image + noscript).**
-- next task: — (no active tasks)
+- parent_task: —
+- summary: **Настроить Playwright MCP для UI-верификации через браузер. Конфиг Zoo Code обновлён (Node 22), Chromium установлен.**
+- next task: —
-### TASK-F12/F13/F14 — фиксы карты тренировки (WorkoutItem.vue)
+## TASK-MCP-SETUP: Playwright MCP configuration
-- Ф12: `position="top-center left-center"` (центрирование маркера на координате); `findNearestTrackIndex` (радиус 40 м) вместо точного lookup `getKey`/`coordWithIndex`.
-- Ф13: стабильные `:settings` фото-маркеров через Map-кэш (`getPhotoMarkerSettings`) — одного этого оказалось НЕДОСТАТОЧНО (Vue патчит VNode-ы и при неизменённых пропсах).
-- Ф14: `v-memo="[photo.id]"` на фото-маркерах — жёсткий пропуск патча, `onUpdated`/`clearElement()` больше не срабатывают. Методология и причины записаны в `systemPatterns.md` (секция «Charts & maps»).
+**Что сделано:**
+- MCP-конфиг Zoo Code (`mcp_settings.json`): server `web-browser` → `@playwright/mcp@latest`, Node 22 via nvm absolute path, `--headless`
+- Chromium `1234` уже установлен в `~/.cache/ms-playwright/`
+- `.mcp.json` создан в проекте (project-level, для совместимости)
+- `techContext.md` обновлён: секция "UI Verification (MCP Browser)"
-## TASK-404: HTTP 404 для несуществующих страниц (SEO)
+**Как использовать (workflow):**
+1. `yarn dev` — запустить dev server (порт 5173)
+2. `browser_navigate` → `http://localhost:5173/explore` — проверить публичную страницу
+3. `browser_evaluate` → `() => { localStorage.setItem('token', 'test'); localStorage.setItem('user', JSON.stringify({id:1,name:'Test'})); location.reload(); }` — сымитировать auth
+4. `browser_navigate` → проверить auth-страницы (`/workouts`, `/workouts/:id`)
+5. `browser_snapshot` — проверить DOM-структуру
+6. `browser_take_screenshot` — визуальная проверка
+7. `browser_network_requests` — проверить API-запросы
-### Проблема
+### Баг (контекст)
-Любой неизвестный URL (например `/random-page`) отдаёт `200` + redirect на `/explore`. Поисковик путается.
+Сайдбар показывает `publicRoutes` (Лента + Маршрут) после логина до F5. Корень: [`NavigationRoutes.ts:70`](src/components/sidebar/NavigationRoutes.ts:70) — `routes` вычисляется один раз при module evaluation и кэшируется. TASK-AUTH-NAV-1 уже добавил реактивный `isAuthenticated` в `useGlobalStore` (инициализация из localStorage + `setAuthenticated` в Login/Logout). Эта задача переключает UI на computed.
-### Решение
+### TASK-AUTH-NAV-2: реактивные маршруты (3 файла)
-1. `server/index.ts` — catch-all 404 handler: `app.use((req, res) => { if (req.method === "GET") res.status(404).send(renderTemplate(...)) })` с SEO-мета (title: "404 — страница не найдена — Cycle Rider", noindex meta).
-2. `nginx.conf` — whitelist SPA-роутов (`/workouts`, `/auth`, `/preferences`, `/404`) → `try_files $uri /index.html`; всё остальное (кроме SSR-локаций) → `proxy_pass http://127.0.0.1:3001`.
-3. `src/router/index.ts` — catch-all `/:pathMatch(.*)*` → redirect на `{ name: "404" }` (вместо `explore`).
-4. `src/router/seo.ts` — запись `404: { title: "404 — страница не найдена — Cycle Rider", description: "..." }` в SEO_MAP.
+**1. `src/components/sidebar/NavigationRoutes.ts`**
-### Acceptance Criteria
+- Сделать named exports: `export const authRoutes: INavigationRoute[]` и `export const publicRoutes: INavigationRoute[]` (сейчас это локальные `const`, не экспортированные).
+- Убрать статическое поле `routes` из default export (или оставить default без `routes`, т.к. оба потребителя перейдут на computed). `INavigationRoute` интерфейс — не трогать.
+- Важно: массивы `authRoutes`/`publicRoutes` остаются теми же по структуре/содержимому — только экспортируются.
-- `curl -s -o /dev/null -w "%{http_code}" http://localhost:80/random-path` → `404`
-- `curl -s http://localhost:80/random-path | grep -c '404'` → > 0
-- `curl -s -o /dev/null -w "%{http_code}" http://localhost:80/workouts` → `200`
-- `curl -s -o /dev/null -w "%{http_code}" http://localhost:80/auth/login` → `200`
-- `curl -s -o /dev/null -w "%{http_code}" http://localhost:80/explore` → `200`
-- `yarn lint` → 0, `yarn build` → 0
+**2. `src/components/sidebar/AppSidebar.vue`** (Options API, `setup()`)
-## ✅ CODER SUCCESS REPORT — TASK-404
+- `import { useGlobalStore } from "../../stores/global-store";` + `import { authRoutes, publicRoutes } from "./NavigationRoutes";` (импорт `navigationRoutes` по default можно оставить/убрать — но все обращения `navigationRoutes.routes` заменить).
+- В `setup()`: `const globalStore = useGlobalStore();`
+- computed: `const routes = computed(() => globalStore.isAuthenticated ? authRoutes : publicRoutes);`
+- В `return` заменить `navigationRoutes` на `routes` (тепловой шаблон уже использует `navigationRoutes.routes` → поправить на `routes.value`? НЕТ — в Options API computed из setup доступно в шаблоне как `routes` без `.value`, т.е. в шаблоне `navigationRoutes.routes` → `routes`).
+- `setActiveExpand`: `navigationRoutes.routes.map(...)` → `routes.value.map(...)` (в setup `.value` нужен).
+- Шаблоны: `v-for="(route, index) in navigationRoutes.routes"` → `in routes`.
-- `server/index.ts` — добавлен catch-all 404 handler (`app.use(...)` без path) перед `app.listen`: для GET — `renderTemplate` с SEO-мета (title: "404 — Страница не найдена — Cycle Rider", canonical `/404`), для остальных методов — `res.status(404).send("Not Found")`.
-- `nginx.conf` — реорганизация: добавлен SPA whitelist `~ ^/(workouts|auth|preferences|404)(/|$)` → `try_files $uri /index.html`; старое `location /` (SPA fallback) заменено на catch-all → `proxy_pass http://127.0.0.1:3001` (SSR вернёт 404 для неизвестных путей).
-- `src/router/index.ts` — catch-all `/:pathMatch(.*)*` redirect: `{ name: "explore" }` → `{ name: "404" }`.
-- `src/router/seo.ts` — добавлена запись `"404"` в `SEO_MAP` (title + description).
-- Verified: `yarn lint` exit 0, `yarn build` exit 0 (vue-tsc 0 errors, vite build ✓ 7.02s).
+**3. `src/components/app-layout-navigation/AppLayoutNavigation.vue`** (script setup)
-## ✅ CODER SUCCESS REPORT — TASK-F11
+- `import { authRoutes, publicRoutes } from "../sidebar/NavigationRoutes";` + `import { useGlobalStore } from "../../stores/global-store";`
+- `const globalStore = useGlobalStore();`
+- `findRouteName` (строка ~64): `traverse(NavigationRoutes.routes)` → `traverse(globalStore.isAuthenticated ? authRoutes : publicRoutes)`.
+- Убедиться, что `items` computed (зависит от `route.matched` и `findRouteName`) остаётся реактивным — т.к. `findRouteName` читает `globalStore.isAuthenticated` внутри `items` computed, реactivity сохранится.
-- `package.json` — `@unhead/vue` ^3.4.1 в dependencies (установлено через `npm install @unhead/vue --legacy-peer-deps`; peer-конфликт vite 4 vs vite 5 разрешён legacy-flag'ом; vite в project поднят до 5.4.21 транзитивно).
-- Создан `src/router/seo.ts` — `setupSeo(router, head: Unhead)`: SEO_MAP по name роута + DEFAULT_SEO, `head.push({title, meta:[description]})` + `router.afterEach(() => update())`.
-- `src/main.ts` — `import { createHead } from "unhead/client"` + `import { headSymbol } from "@unhead/vue"`; `const head = createHead(); app.provide(headSymbol, head); setupSeo(router, head);` (после `app.use(router)`).
-- `index.html` — `
` заменён на «Cycle Rider — платформа для анализа велотренировок: ...»; добавлен `` в `` как fallback; блок Yandex.Metrika перенесён из `` в начало `` (Vite 5 parse5 запрещает `