форматирование
Gitea Actions Demo / build_and_push (push) Successful in 1m16s Details

This commit is contained in:
artem 2026-09-25 23:11:47 +03:00
parent 72b786994d
commit 37c92b1e25
3 changed files with 74 additions and 5 deletions

View File

@ -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`:

View File

@ -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) «Добавить фото» → `<img>` в `.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)**

View File

@ -177,7 +177,9 @@
/>
</div>
<div class="workout-item-params" v-if="isPrivate">
<div class="workout-item-params-name">{{ t("workout.hide_start_end") }}:&nbsp;</div>
<div class="workout-item-params-name">
{{ t("workout.hide_start_end") }}:&nbsp;
</div>
<input
type="checkbox"
v-model="workoutItem.hide_start_end"