diff --git a/.roo/memory-bank/activeContext.md b/.roo/memory-bank/activeContext.md
index a2c1df7..971138a 100644
--- a/.roo/memory-bank/activeContext.md
+++ b/.roo/memory-bank/activeContext.md
@@ -2,11 +2,32 @@
## Task State
-- task_id: TASK-MAP-DOTS-RESET
+- task_id: TASK-FVP-1..4 (Virtual Power Frontend)
- status: success
-- summary: **Фикс: серые точки на карте нельзя поставить повторно после reset. Корень: `resetChartZoom()` не очищает `mapX` и `clickCoordinates`. Фикс: добавить `mapX.value = []` + `clickCoordinates.value = []` в `resetChartZoom()`; inline onClick вынесен в `onMapClick` (строка 536). `yarn build` exit 0.**
+- summary: **Все 4 задачи VP-фронтенда завершены: вес в профиле, кнопка+modal+POST, график (merge/separate), avg в шапке. `yarn build` → 0 ошибок. Browser verification pending (requires `yarn up`).**
- next task: —
-- plan: `plans/TASK-MAP-DOTS-RESET.md`
+- plan: `plans/TASK-FRONTEND-VIRTUAL-POWER.md`
+
+## ✅ CODER SUCCESS REPORT — TASK-FVP-4
+
+- `src/pages/workouts/components/WorkoutItem.vue`: добавлена карточка `v-if="workoutItem.virtual_power != null"` после блока «Максимальная мощность» (линия 151), перед блоком «Сделать публичной».
+- `yarn build` (vue-tsc --noEmit + vite) → exit 0.
+- Lint: предсуществующая `tsutils.iterateComments` (не связана с изменением).
+
+## ✅ CODER SUCCESS REPORT — TASK-FVP-2
+
+- `components/WorkoutItem.vue`: кнопка VP (active state по `virtual_power_bike_type`), VaModal с 2 VaSelect, `calculateVP()` POST, emit `vpCalculated`, error handling (400/422).
+- `pages/WorkoutItem.vue`: `@vpCalculated="initWorkout(...)"`.
+- `Definitions.vue`: добавлено `virtual_power_bike_type?: string | null`.
+- 6 locale-файлов: 12 ключей `virtualPower*`.
+- `yarn build` → 0 ошибок.
+
+## ✅ CODER SUCCESS REPORT — TASK-FVP-1
+
+- `src/stores/user-store.ts`: `weight: null as number | null` в SSR + localStorage hydration, action `setWeight(w)`.
+- `src/pages/preferences/settings/Settings.vue`: 4-я строка с `VaInput type="number"` + save button, `PATCH /api/v0/profiles/{id}` с `{ profile: { weight } }`, toast success/error.
+- 6 locale-файлов: `"preferences": { "weight": "..." }`.
+- `yarn build` → 0 ошибок. Lint: предсуществующая `tsutils.iterateComments` (не связана).
## ✅ CODER SUCCESS REPORT — TASK-INTEG-SECTION (+TASK-SECTION-BUGS)
diff --git a/.roo/memory-bank/progress.md b/.roo/memory-bank/progress.md
index 5c96436..92f7a88 100644
--- a/.roo/memory-bank/progress.md
+++ b/.roo/memory-bank/progress.md
@@ -1,5 +1,10 @@
# Progress — Strava Frontend
+## 2026-10-02 — TASK-FVP-4: карточка «Вирт. мощность» в шапке тренировки
+
+- `src/pages/workouts/components/WorkoutItem.vue`: блок `v-if="workoutItem.virtual_power != null"` (label `t("workout.virtualPower")`, значение `Math.floor(workoutItem.virtual_power)` Вт), вставлен после «Максимальная мощность» (линия 151), перед «Сделать публичной».
+- Verified: `yarn build` (vue-tsc --noEmit + vite) → exit 0. Lint: только предсуществующая `tsutils.iterateComments` (не связана).
+
## 2026-09-26 — TASK-SECTION-REZOOM-LOOP: фикс бесконечного цикла re-render (CPU-шум)
- `src/pages/workouts/components/WorkoutItem.vue`:
diff --git a/src/i18n/locales/br.json b/src/i18n/locales/br.json
index 7b8f693..8d707b4 100644
--- a/src/i18n/locales/br.json
+++ b/src/i18n/locales/br.json
@@ -159,6 +159,21 @@
"fileDeleted": "Arquivo excluído"
},
"workout": {
- "hide_start_end": "Ocultar início e fim da trilha"
+ "hide_start_end": "Ocultar início e fim da trilha",
+ "virtualPower": "Potência virtual",
+ "virtualPowerBtn": "Calcular potência virtual",
+ "virtualPowerBikeType": "Tipo de bicicleta",
+ "virtualPowerRoad": "Estrada",
+ "virtualPowerOther": "Outro",
+ "virtualPowerSurface": "Superfície",
+ "virtualPowerAsphalt": "Asfalto",
+ "virtualPowerGravel": "Cascalho",
+ "virtualPowerDirt": "Terra",
+ "virtualPowerSnow": "Neve",
+ "virtualPowerCalculate": "Calcular",
+ "virtualPowerNeedWeight": "Defina seu peso nas configurações primeiro"
+ },
+ "preferences": {
+ "weight": "Peso (kg)"
}
}
diff --git a/src/i18n/locales/cn.json b/src/i18n/locales/cn.json
index b761a8b..b2707f7 100644
--- a/src/i18n/locales/cn.json
+++ b/src/i18n/locales/cn.json
@@ -192,6 +192,21 @@
"fileDeleted": "文件已删除"
},
"workout": {
- "hide_start_end": "隐藏轨迹起点和终点"
+ "hide_start_end": "隐藏轨迹起点和终点",
+ "virtualPower": "虚拟功率",
+ "virtualPowerBtn": "计算虚拟功率",
+ "virtualPowerBikeType": "自行车类型",
+ "virtualPowerRoad": "公路",
+ "virtualPowerOther": "其他",
+ "virtualPowerSurface": "路面",
+ "virtualPowerAsphalt": "柏油路",
+ "virtualPowerGravel": "碎石",
+ "virtualPowerDirt": "泥土",
+ "virtualPowerSnow": "雪",
+ "virtualPowerCalculate": "计算",
+ "virtualPowerNeedWeight": "请先在个人资料设置中设置体重"
+ },
+ "preferences": {
+ "weight": "体重 (kg)"
}
}
diff --git a/src/i18n/locales/es.json b/src/i18n/locales/es.json
index e3a321b..ac841a3 100644
--- a/src/i18n/locales/es.json
+++ b/src/i18n/locales/es.json
@@ -148,6 +148,21 @@
"fileDeleted": "Archivo eliminado"
},
"workout": {
- "hide_start_end": "Ocultar inicio y fin de la ruta"
+ "hide_start_end": "Ocultar inicio y fin de la ruta",
+ "virtualPower": "Potencia virtual",
+ "virtualPowerBtn": "Calcular potencia virtual",
+ "virtualPowerBikeType": "Tipo de bicicleta",
+ "virtualPowerRoad": "Carretera",
+ "virtualPowerOther": "Otro",
+ "virtualPowerSurface": "Superficie",
+ "virtualPowerAsphalt": "Asfalto",
+ "virtualPowerGravel": "Grava",
+ "virtualPowerDirt": "Tierra",
+ "virtualPowerSnow": "Nieve",
+ "virtualPowerCalculate": "Calcular",
+ "virtualPowerNeedWeight": "Establezca su peso en la configuración primero"
+ },
+ "preferences": {
+ "weight": "Peso (kg)"
}
}
diff --git a/src/i18n/locales/gb.json b/src/i18n/locales/gb.json
index 3458877..0b2c187 100644
--- a/src/i18n/locales/gb.json
+++ b/src/i18n/locales/gb.json
@@ -185,6 +185,21 @@
"fileDeleted": "File deleted"
},
"workout": {
- "hide_start_end": "Hide start and end of track"
+ "hide_start_end": "Hide start and end of track",
+ "virtualPower": "Virtual Power",
+ "virtualPowerBtn": "Calculate Virtual Power",
+ "virtualPowerBikeType": "Bike type",
+ "virtualPowerRoad": "Road",
+ "virtualPowerOther": "Other",
+ "virtualPowerSurface": "Surface",
+ "virtualPowerAsphalt": "Asphalt",
+ "virtualPowerGravel": "Gravel",
+ "virtualPowerDirt": "Dirt",
+ "virtualPowerSnow": "Snow",
+ "virtualPowerCalculate": "Calculate",
+ "virtualPowerNeedWeight": "Set your weight in profile settings first"
+ },
+ "preferences": {
+ "weight": "Weight (kg)"
}
}
diff --git a/src/i18n/locales/ir.json b/src/i18n/locales/ir.json
index 3a651ae..6751aa4 100644
--- a/src/i18n/locales/ir.json
+++ b/src/i18n/locales/ir.json
@@ -200,6 +200,21 @@
"fileDeleted": "فایل حذف شد"
},
"workout": {
- "hide_start_end": "پنهان کردن شروع و پایان مسیر"
+ "hide_start_end": "پنهان کردن شروع و پایان مسیر",
+ "virtualPower": "توان مجازی",
+ "virtualPowerBtn": "محاسبه توان مجازی",
+ "virtualPowerBikeType": "نوع دوچرخه",
+ "virtualPowerRoad": "جادهای",
+ "virtualPowerOther": "دیگر",
+ "virtualPowerSurface": "سطح",
+ "virtualPowerAsphalt": "آسفالت",
+ "virtualPowerGravel": "شن و ماسه",
+ "virtualPowerDirt": "گل",
+ "virtualPowerSnow": "برف",
+ "virtualPowerCalculate": "محاسبه",
+ "virtualPowerNeedWeight": "ابتدا وزن خود را در تنظیمات پروفایل وارد کنید"
+ },
+ "preferences": {
+ "weight": "وزن (کیلوگرم)"
}
}
diff --git a/src/i18n/locales/ru.json b/src/i18n/locales/ru.json
index 85d7cac..9b2102d 100644
--- a/src/i18n/locales/ru.json
+++ b/src/i18n/locales/ru.json
@@ -189,6 +189,21 @@
"fileDeleted": "Файл удалён"
},
"workout": {
- "hide_start_end": "Скрыть начало и конец трека"
+ "hide_start_end": "Скрыть начало и конец трека",
+ "virtualPower": "Вирт. мощность",
+ "virtualPowerBtn": "Рассчитать вирт. мощность",
+ "virtualPowerBikeType": "Тип велосипеда",
+ "virtualPowerRoad": "Шоссейный",
+ "virtualPowerOther": "Другой",
+ "virtualPowerSurface": "Покрытие",
+ "virtualPowerAsphalt": "Асфальт",
+ "virtualPowerGravel": "Гравий",
+ "virtualPowerDirt": "Грязь",
+ "virtualPowerSnow": "Снег",
+ "virtualPowerCalculate": "Рассчитать",
+ "virtualPowerNeedWeight": "Сначала укажите вес в настройках профиля"
+ },
+ "preferences": {
+ "weight": "Вес (кг)"
}
}
diff --git a/src/pages/preferences/settings/Settings.vue b/src/pages/preferences/settings/Settings.vue
index 76bd42b..923d266 100644
--- a/src/pages/preferences/settings/Settings.vue
+++ b/src/pages/preferences/settings/Settings.vue
@@ -45,13 +45,68 @@
{{ t("preferences.weight") }}
+{{ t("workout.virtualPowerBikeType") }}
+{{ t("workout.virtualPowerSurface") }}
+