From 37c92b1e256ed5f3e74dec96430a63d1cda449d2 Mon Sep 17 00:00:00 2001 From: artem Date: Fri, 25 Sep 2026 23:11:47 +0300 Subject: [PATCH] =?UTF-8?q?=D1=84=D0=BE=D1=80=D0=BC=D0=B0=D1=82=D0=B8?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .roo/memory-bank/activeContext.md | 56 ++++++++++++++++++- .roo/memory-bank/progress.md | 19 ++++++- src/pages/workouts/components/WorkoutItem.vue | 4 +- 3 files changed, 74 insertions(+), 5 deletions(-) diff --git a/.roo/memory-bank/activeContext.md b/.roo/memory-bank/activeContext.md index 52fe91b..f4d3443 100644 --- a/.roo/memory-bank/activeContext.md +++ b/.roo/memory-bank/activeContext.md @@ -2,12 +2,62 @@ ## Task State -- task_id: TASK-HIDE-TRACK-3-FIX +- task_id: TASK-PROFILE-ULID-BUG - status: success -- parent_task: TASK-HIDE-TRACK -- summary: **Чекбокс `hide_start_end` + `changeHideStartEnd` + i18n ключ восстановлены в WorkoutItem.vue (потеряны в git stash при TASK-HIDE-TRACK-4).** +- summary: **PATCH /profiles/{id} возвращает 500 (смена имени не персистится). Root cause: `default=str(ULID())` в `profiles.py:32` и `users.py:20` — ULID считается один раз при импорте; `DBProfileRepository.update` включает `id` в SET → `IntegrityError`. Фикс: `default_factory=lambda: str(ULID())` + defensive `del new_dict["id"]` + новый API-тест (PATCH → 200 + персистентность имени).** - next task: — +## TASK-PROFILE-ULID-BUG: план делегирования + +**Scope:** `../backend/` (3 файла фикса + 1 новый тест). + +**Изменения:** + +1. `../backend/app/modules/users/domains/profiles.py:32` — `default=str(ULID())` → `default_factory=lambda: str(ULID())` (обязательный фикс). +2. `../backend/app/modules/users/domains/users.py:20` — та же замена (оборона в глубине). +3. `../backend/app/modules/users/repositories/profile.py` (`DBProfileRepository.update`, ~106-108) — после `del new_dict["created_at"]` добавить `new_dict.pop("id", None)` (PK не должен участвовать в UPDATE). +4. Новый тест `../backend/tests/test_api_profile.py` (паттерн `test_api_general.py`, фикстуры `client` + `signin_data` из `conftest.py`): + - signup → получить `profile_id` (из `data["profile"]["id"]`) + token; + - `PATCH /api/v0/profiles/{profile_id}` с `{"profile": {"first_name": "New", "surname": "Family"}}` → 200; + - `GET /api/v0/profiles/{profile_id}` → `profile.first_name == "New"` и `surname == "Family"`; + - второй PATCH (ещё раз) → 200 + персистится (ловит регрессию «один ULID на процесс»). + +**Acceptance criteria:** + +1. `./venv/bin/python -m pytest tests/test_api_profile.py -v` → passed. +2. `./venv/bin/python -m pytest tests/ -v` → green (зафиксировать diff, если есть пре-экзистинг failing). +3. `./venv/bin/python -m mypy app/modules/users/ --explicit-package-bases --no-error-summary` → 0 errors. +4. `ruff check` (по `ruff.toml`) → 0 errors. + +**Не в scope (follow-up):** обновление `../integration/tests/workout-upload-flow.spec.ts` (добавить assert персистентного имени, убрать comment KNOWN BACKEND BUG) и `../integration/README.md` — отдельная мини-задача после success. + +## ✅ CODER SUCCESS REPORT — TASK-PROFILE-ULID-BUG + +- `../backend/app/modules/users/domains/profiles.py:32` — `default=str(ULID())` → `default_factory=lambda: str(ULID())` (ULID теперь вычисляется на каждый `Profile()`, а не один раз при импорте). +- `../backend/app/modules/users/domains/users.py:20` — та же замена (оборона в глубине). +- `../backend/app/modules/users/repositories/profile.py` (`DBProfileRepository.update`) — добавлено `new_dict.pop("id", None)` после `del new_dict["created_at"]` (PK не участвует в UPDATE — defensive). +- `../backend/tests/test_api_profile.py` — 2 API-теста: (1) PATCH с `{"profile": {"first_name": "New", "surname": "Family"}}` → 200 + GET → персистентность имени/фамилии; (2) повторные PATCH → 200 + GET `first_name == "Second"` (ловит регрессию «один ULID на процесс»). +- Verified: `./venv/bin/python -m pytest tests/test_api_profile.py -v` → **2 passed**. +- Verified: `./venv/bin/python -m pytest tests/ -v` → **56 passed, 10 errors** — все 10 errors **пре-экзистинг** (проверено через `git stash`: `NotImplementedError: No support for ALTER of constraints in SQLite dialect` в fixture-setup `test_db_profile.py`/`test_db_workout.py`/`test_db_workout_photos.py` — миграции на SQLite, не связаны с фиксом; до/после идентично). +- Verified: `./venv/bin/python -m mypy app/modules/users/ --explicit-package-bases --no-error-summary` → **0 errors**. +- Verified: `./venv/bin/python -m ruff check app/modules/users/ tests/test_api_profile.py` → **All checks passed** (полный `ruff check` по репо: единственная находка F401 в `migration/versions/2025-09-25-0000-...-hide-start-end.py:8` — пре-экзистинг, коммит `ff5f468`, вне scope). +- Follow-up (отдельная задача): update `../integration/tests/workout-upload-flow.spec.ts` (assert персистентного имени вместо KNOWN BACKEND BUG comment) + `../integration/README.md`. + +## ✅ CODER SUCCESS REPORT — TASK-TEST-WORKOUT-UPLOAD + +- `../integration/tests/workout-upload-flow.spec.ts` создан: 5 последовательных тестов (signup UI+профиль, upload .fit + resolve id, make public→GET public=200, hide_start_end→authed GET body true, add photo→img в `.workout-photos-grid`). +- Ключевое решение: **стабильный owner** (`itest-workout-owner@example.com`, idempotent signup/signin) для Части 2 — dedup по content-hash ГЛОБАЛЕН, а `GET /api/v0/workouts` scoped по `created_by`, поэтому уникальный юзер на повторном прогоне всегда падал бы в dedup-ветку с пустым своим списком. Part 1 (профиль) — уникальный юзер через UI (genuine signup). +- Детальный URL `/workouts/workouts/:id` (сверено с `router/index.ts`: вложенный `workouts` → `workouts/:id`); навигация `domcontentloaded` (Yandex map держит соединения, `networkidle` не стабилизируется). +- `../integration/README.md` обновлён (секция + notes про dedup и про backend-баг имени). +- Verified: `npx playwright test tests/workout-upload-flow.spec.ts` → **5 passed**, стабильно ×3 (dedup-путь) + прогон на свежей DB (redirect-путь). `yarn build` (vue-tsc --noEmit) exit 0. +- Cleanup: диагностический `../integration/tests/_diag.spec.ts` удалён; `npx playwright test --list` → 16 tests в 5 файлах, `_diag` отсутствует. + +## ⚠️ Discovered (NOT fixed, out-of-scope test-only) + +- **Backend-баг сменy имени:** `PATCH /api/v0/profiles/{id}` (ветка `profile`) возвращает 500. Причина: `../backend/app/modules/users/domains/profiles.py:32` — `id: str = field(default=str(ULID()), ...)` вычисляет ULID ОДИН раз при импорте (не `default_factory`), ORM-UPDATE переписывает PK → `IntegrityError: duplicate key (profiles_pkey)`. SPA показывает toast синхронно (до чтения ответа), поэтому имя НЕ персистится. Spec асертит SPA-toast (реальное UI-поведение), персистентное имя задокументировано, но не asserted. +- **Стек должен быть свежим:** колонка `hide_start_end` появляется только после `alembic upgrade head`. Перед прогоном спе — свежий стек / `docker compose up -d --force-recreate backend`. +- **`yarn lint` сломан системно** — `tsutils.iterateComments is not a function` (пре-экзистинг, падает и на нетронутые `.ts`, дефект env eslint/typescript-estree). + ## ✅ CODER SUCCESS REPORT — TASK-HIDE-TRACK-3-FIX - `src/pages/workouts/components/WorkoutItem.vue`: diff --git a/.roo/memory-bank/progress.md b/.roo/memory-bank/progress.md index d3ab0eb..4001bb3 100644 --- a/.roo/memory-bank/progress.md +++ b/.roo/memory-bank/progress.md @@ -1,5 +1,23 @@ # Progress — Strava Frontend +## 2026-09-25 — TASK-PROFILE-ULID-BUG: фикс PATCH /profiles 500 (смена имени не персистится) + +- `../backend/app/modules/users/domains/profiles.py:32` — `default=str(ULID())` → `default_factory=lambda: str(ULID())`. +- `../backend/app/modules/users/domains/users.py:20` — та же замена. +- `../backend/app/modules/users/repositories/profile.py` — `DBProfileRepository.update`: `new_dict.pop("id", None)` (PK вне UPDATE). +- `../backend/tests/test_api_profile.py` — 2 теста (персистентность имени + повторные PATCH). +- Verified: `pytest tests/test_api_profile.py -v` → 2 passed; `pytest tests/ -v` → 56 passed, 10 errors (все 10 пре-экзистинг: SQLite alembic ALTER-constraints в db-fixture setup, подтверждено git stash); `mypy app/modules/users/ --explicit-package-bases --no-error-summary` → 0; `ruff check app/modules/users/ tests/test_api_profile.py` → 0. +- Фикс закрывает known issue из TASK-TEST-WORKOUT-UPLOAD (backend-баг имени). + +## 2026-09-25 — TASK-TEST-WORKOUT-UPLOAD: интеграционный тест загрузки тренировки (Playwright) + +- `../integration/tests/workout-upload-flow.spec.ts` — 5 последовательных тестов полного user-journey: (1) signup через UI + профиль (аватар-загрузка toast «Фото успешно загружено!», смена имени toast «Вы успешно изменили имя!»), (2) загрузка `.fit` на `/workouts/upload` + resolve id (redirect ИЛИ dedup-фолбэк через owner's `GET /api/v0/workouts`), (3) «Сделать публичной» → `GET /api/v0/public/workouts/{id}`=200, (4) «Скрыть начало и конец трека» → authed detail `workout.hide_start_end===true`, (5) «Добавить фото» → `` в `.workout-photos-grid`. +- Ключевое: **стабильный owner**-юзер для Части 2 (глобальный content-hash dedup vs scoped `GET /workouts`); unique-юзер через UI для Части 1. Detail URL `/workouts/workouts/:id`, nav `domcontentloaded`. +- `../integration/README.md` — секция про спек + notes (workout-dedup, backend-баг имени). +- Cleanup: `../integration/tests/_diag.spec.ts` (диагностический) удалён. +- Verified: `npx playwright test tests/workout-upload-flow.spec.ts` → **5 passed** (×3 dedup-путь + 1 свежая DB redirect-путь); `yarn build` exit 0; `npx playwright test --list` → 16 tests / 5 files (без `_diag`). +- Known issues (не фикс, out-of-scope): backend `PATCH /profiles` (имя) → 500 из-за `Profile.id = field(default=str(ULID()))` (не `default_factory`) → имя не персистится, SPA toast ложный; `yarn lint` системно сломан (`tsutils.iterateComments`); перед прогоном спе нужен свежий стек / force-recreate backend (миграция `hide_start_end`). + ## 2026-09-25 — TASK-HIDE-TRACK-3-FIX: восстановление чекбокса hide_start_end в WorkoutItem.vue - `src/pages/workouts/components/WorkoutItem.vue` — восстановлены (потеряны в git stash при TASK-HIDE-TRACK-4): @@ -248,4 +266,3 @@ - `../backend/tests/test_api_workout.py`: добавлен `test_workout_hide_start_end` (PATCH hide_start_end False→True→False + GET-верификация) - Результат: `python -m pytest tests/test_api_workout.py -v` → **4 passed (5.13s)** - diff --git a/src/pages/workouts/components/WorkoutItem.vue b/src/pages/workouts/components/WorkoutItem.vue index d70180f..3ed1a3c 100644 --- a/src/pages/workouts/components/WorkoutItem.vue +++ b/src/pages/workouts/components/WorkoutItem.vue @@ -177,7 +177,9 @@ />
-
{{ t("workout.hide_start_end") }}: 
+
+ {{ t("workout.hide_start_end") }}:  +