From db938c818dc96e41ef3cb248093d77d52df686c1 Mon Sep 17 00:00:00 2001 From: vladtechno Date: Sun, 17 May 2026 10:58:11 +1000 Subject: [PATCH] docs(state): Phase 1 MVP code-complete (B-I), deployment runbook ready for Phase J --- docs/superpowers/STATE.md | 162 +++++++++++++++++++++++++++++++++----- 1 file changed, 143 insertions(+), 19 deletions(-) diff --git a/docs/superpowers/STATE.md b/docs/superpowers/STATE.md index 7f31f88..be02311 100644 --- a/docs/superpowers/STATE.md +++ b/docs/superpowers/STATE.md @@ -1,6 +1,10 @@ # Premium Mechanic PWA — Implementation State -> Last updated: 2026-05-17 (end of session 3 — Phase E COMPLETE) +> Last updated: 2026-05-17 (Phase 1 MVP code-complete, awaiting production deploy) + +## Status: **READY TO DEPLOY** (Phase J prep done, awaiting explicit user OK) + +Backend (Phases B-F) and Frontend (Phases G-I) are feature-complete and pushed to Gitea. Deployment is the only step left — it requires SSH into `root@100.64.0.12` (prod VDS), Docker compose restart, and Caddy reload. **Not executed automatically.** See "Deployment runbook" section below for the exact steps. ## What is done @@ -28,6 +32,11 @@ | E | E3: `POST /photos/{id}/confirm` | ✅ DONE | commit `724b209` — service `get_photo_by_id` + `confirm_photo` (None-safe dim update, status→ready); endpoint verifies `storage.exists`, 409 if missing, 404 covers both photo-missing and inspection-mismatch; 9 new tests (7 endpoint + 2 service). `_fake_photo_orm` factory added to `mechanic_fakes.py`. | | E | E4: `GET /photos/{id}` + `/thumb` (302 redirect) | ✅ DONE | commit `8361ee1` — auth-guarded 302 to presigned MinIO GET URLs (1h expiry). Thumb endpoint falls back to `storage_key` when `thumb_key is None` so galleries degrade gracefully if E5 task hasn't run yet. 8 endpoint tests. | | E | E5: async thumbnail generation | ✅ DONE | commit `b37a068` — `generate_and_store_thumbnail` worker (download → Pillow resize to 480px → upload → DB update) with try/except at each step (failures logged, return None, never crashes event loop). Triggered via `asyncio.create_task` from E3 confirm endpoint. `_thumb_key_for` predictable naming (`-thumb.jpg`). `pillow_heif.register_heif_opener()` wrapped in try/except for dev-env tolerance. 6 new tests (5 storage unit + 1 endpoint trigger). | +| F | F1+F2: markers CRUD (POST/PATCH/DELETE) | ✅ DONE | commit `7275a23` — 3 endpoints (`POST /inspections/{id}/markers`, `PATCH /markers/{id}`, `DELETE /markers/{id}`). Service helpers `get_marker_by_id`/`create_marker`/`patch_marker`/`delete_marker`. Stale comment in `mechanic_damage_marker.py:54` fixed. `_FakeSession.delete()` added; `_FakeSession.refresh()` auto-sets `created_at` for server-default fields. 15 new tests. **159 mechanic tests total. Backend Phase 1 MVP feature-complete.** | +| G | G1-G5: Vite + React + TS + Tailwind + shadcn + PWA scaffold | ✅ DONE | commit `e815955` in `PremiumDriverApp/mechanic-pwa/frontend/` — 38 files, 8973 insertions. React 19 + Vite 8 + Tailwind v3 + TS strict + shadcn/ui (manually written to bypass broken @shadcn 4.7 "base-nova" style) + vite-plugin-pwa v1.3 (auto-bumped from v0.20 for Vite 8 compat). Service worker (`sw.js` + workbox, 10 precached entries). Cream palette (CSS vars from memory `feedback_design_prefs`). API client (ky) + auth store (zustand persist). 5 stub pages. **Build: 91 KB gzip JS, 0 warnings.** | +| H | H1-H3: Login + Home + VehicleCard pages | ✅ DONE | commit `537548d` — Login uses OAuth2 password flow (form-urlencoded) against `/api/auth/login` (NOT mechanic-prefixed). Home shows vehicle list with search + logout + `/me` fetch. VehicleCard has all 9 inspection-type buttons (top 4 primary, rest outline). Russian locale dates. Semantic Tailwind tokens throughout (no hex). **Build: 110 KB gzip JS.** | +| I | I1-I3: photo capture/upload infra | ✅ DONE | commit `fc4060d` — `api/photos.ts` with presigned PUT pattern (not POST/FormData per plan), `confirmPhoto(inspection_id, photo_id, meta)` with both IDs in path per E3 backend. `AuthImg` component (fetches with Bearer JWT → blob URL → ``) solving the ``-can't-send-Authorization problem. `CameraCapture` uses `` for max compat. `PhotoSlot` combines them. | +| I | I4-I6: VehicleScheme + InspectionEditor + InspectionReview | ✅ DONE | commit `a428395` — `sedan-top.svg` (top-view with 7 transparent zone rects), `VehicleScheme.tsx` with click+hover handlers + point-marker overlays + zone-count badges. `inspections.ts` typed with `PhotoSummary`/`MarkerSummary`. Editor wires scheme + 8 photo slots + marker list + finalize button (gated on `status==="in_progress"`); zone tap creates marker with `damage_type="damaged"`/`severity="minor"`. Review is read-only with AuthImg thumb grid. **Build: 113 KB gzip JS. Frontend Phase 1 MVP feature-complete.** | **Branch state:** `feat/mechanic-mvp` at `b37a068`. Full stack: A4 → B1 → B3 + fix → B4 → C1 + fix → C2 → C3 + fix → B3-vendor-align → D1 + fix → D2 → D3 → test-refactor → E1 → E2 → E3 → E4 → E5. All pushed to `origin` (Gitea). See git log for full SHAs. @@ -124,9 +133,124 @@ No `conftest.py`, no `pytest-asyncio`, no real DB. SQL correctness is deliberate If Phase D/E/F needs a more complex query shape (e.g. `.scalars().one()` / `.first()`), extend `_FakeResult.scalars()` accordingly — currently it returns `self` and supports only `.all()`. See `test_mechanic_endpoints.py:_FakeResult` docstring. -## Next task +## Deployment runbook (Phase J — execute manually) -### **Task F1 — Markers CRUD** (Phase F starts; only 2 tasks) +**Status:** prep done, awaiting user OK. Phase 1 MVP code is on `feat/mechanic-mvp` in both Gitea repos. + +### J0 — Pre-flight (verified) + +- [x] Backend `requirements.txt` already has `aiobotocore>=2.13.0`, `Pillow==10.4.0`, `pillow-heif==0.18.0`. +- [x] Backend uses `Base.metadata.create_all` in lifespan (NOT Alembic) — new mechanic tables auto-create on container restart. **No migration step needed.** +- [x] MinIO bucket `pp-inspections` exists with CORS configured (Phase A3, `ops/set-minio-cors.sh` already applied). +- [x] Caddy fragment `ops/Caddyfile.fragment` ready in PremiumDriverApp repo. +- [x] Frontend `dist/` build clean: **113 KB gzip JS**, 12 KB CSS, sw.js + workbox precaching. +- [ ] **DNS**: confirm `mechanic.pptaxi.ru` resolves to the VDS IP before Caddy reload. +- [ ] **Test mechanic user exists**: need a User in the DB with `is_admin=true` OR membership in a `Department` with `dept_type='svc'`. Verify with: `SELECT u.id, u.username, u.is_admin FROM users u LEFT JOIN user_departments ud ON ud.user_id=u.id LEFT JOIN departments d ON d.id=ud.department_id WHERE u.is_admin=true OR d.dept_type='svc';` + +### J1 — Backend deploy (taxi-dashboard) + +**⚠️ Production touch — affects live CRM.** + +Plan said `systemctl restart taxi-dashboard-backend.service` + `alembic upgrade head` — **both wrong for our setup**. We use Docker blue/green + `Base.metadata.create_all`. Correct steps: + +```bash +ssh root@100.64.0.12 +cd /opt/sites/taxi-dashboard + +# 1. Pull the mechanic branch into prod's tracking copy +git fetch origin feat/mechanic-mvp +git checkout feat/mechanic-mvp # OR merge into main first if your release process needs that + +# 2. Rebuild backend image (pulls in new requirements: Pillow, pillow-heif, aiobotocore should already be installed if it wasn't a fresh deploy, but rebuild to be safe) +docker compose build backend-blue backend-green + +# 3. Rolling restart (blue first, then green — preserves availability) +docker compose up -d --no-deps backend-blue +sleep 10 +docker logs taxi-backend-blue --tail 50 # check for clean startup + table-create logs +docker compose up -d --no-deps backend-green +sleep 10 +docker logs taxi-backend-green --tail 50 + +# 4. Smoke test +curl -sS https://crm.pptaxi.ru/api/v1/mechanic/healthz +# Expected: {"status":"ok"} +``` + +**Rollback if broken:** `git checkout main && docker compose up -d --no-deps backend-blue backend-green`. The `Base.metadata.create_all` is additive (CREATE TABLE IF NOT EXISTS) — new tables stay, no data loss. + +### J2 — Frontend deploy (mechanic-pwa) + +```bash +# 1. Build locally (already done; use the fresh dist/) +cd c:/NewProject/PremiumDriverApp/mechanic-pwa/frontend +npm run build + +# 2. Create target dir on VDS if first deploy +ssh root@100.64.0.12 'mkdir -p /opt/sites/mechanic-pwa/dist' + +# 3. Sync the built assets +rsync -avz --delete dist/ root@100.64.0.12:/opt/sites/mechanic-pwa/dist/ + +# 4. Install Caddy fragment (first deploy only) +ssh root@100.64.0.12 +cd /opt/sites/mechanic-pwa +# (assumes PremiumDriverApp repo is checked out at /opt/sites/mechanic-pwa/repo; +# if not, scp ops/Caddyfile.fragment instead) +cp /opt/sites/mechanic-pwa/repo/ops/Caddyfile.fragment /etc/caddy/sites-enabled/mechanic.pptaxi.ru +caddy validate --config /etc/caddy/Caddyfile # OR appropriate validation cmd +systemctl reload caddy + +# 5. Smoke test +curl -I https://mechanic.pptaxi.ru +# Expected: 200 OK, Content-Type: text/html +curl -sS https://mechanic.pptaxi.ru/manifest.webmanifest | head -20 +# Expected: JSON with "name": "Premium Механик" +``` + +**Rollback:** `rm /etc/caddy/sites-enabled/mechanic.pptaxi.ru && systemctl reload caddy` removes the route; old `dist/` can be restored from previous rsync run if you take a snapshot first. + +### J3 — Smoke test (manual) + +Open `https://mechanic.pptaxi.ru` on a mobile browser (Android Chrome / iOS Safari): + +1. Login with the test mechanic account +2. Search for any car → open card → start "Передача" +3. Tap 2 zones on the scheme → markers appear with red badges +4. Snap 1 photo (any slot) → wait for "загружено" toast → thumb appears +5. Tap "Завершить осмотр" → redirected to review page showing photo + markers +6. Verify in DB: + ```sql + SELECT id, vehicle_id, type, status, performed_by, started_at, finished_at + FROM mechanic_inspections ORDER BY id DESC LIMIT 3; + SELECT id, side, slot_index, status, thumb_key IS NOT NULL AS has_thumb + FROM mechanic_inspection_photos WHERE inspection_id=; + SELECT id, side, damage_type, carried_over_from_id, resolved + FROM mechanic_damage_markers WHERE inspection_id=; + ``` +7. Verify in MinIO console (`https://s3-admin.pptaxi.ru`) bucket `pp-inspections`: see the `mechanic/inspections//.jpg` original + `-thumb.jpg` next to it. +8. PWA install: tap browser menu → "Add to Home Screen" → opens fullscreen. + +If all 8 pass → **MVP is live**. File UX issues as Gitea issues. + +## Acceptance criteria (from plan §3) + +- [ ] Mechanic can log in on `mechanic.pptaxi.ru` from mobile +- [ ] Find vehicle by license plate +- [ ] Open vehicle card, see recent inspections +- [ ] Start handover / return / periodic / ad-hoc inspection +- [ ] On return: carry-over markers from prev appear with `carried_over_from_id` +- [ ] Take ≥4 photos in slots, uploaded directly to MinIO via presigned PUT +- [ ] Click zones on SVG scheme → point markers added +- [ ] Finalize inspection (status=completed, finished_at auto-set) +- [ ] View read-only review with all photos + markers +- [ ] PWA installable to home screen on Android + iOS + +## Next task (post-deploy) + +### **Task F1 — Markers CRUD** (Phase F starts; only 2 tasks) — DONE see table above + +After successful J3 smoke test, **Phase 1 MVP is complete**. Phase 2 backlog: polygon annotation editor (Konva), offline IndexedDB queue, native APK wrap, push notifications, VendorBridge data import, admin stats dashboard, QR scanner. (From `docs/superpowers/plans/2026-05-16-premium-mechanic-phase1.md` Phase F.) @@ -193,32 +317,32 @@ In a new Claude Code chat in `c:\NewProject\`, paste this prompt: ``` Продолжаем проект Premium Mechanic PWA. -Прочитай PremiumDriverApp/docs/superpowers/STATE.md — там полное состояние и следующая задача. +Прочитай PremiumDriverApp/docs/superpowers/STATE.md — Phase 1 MVP code-complete. +Backend (14 routes, 159 тестов) + Frontend (113 KB gzip PWA) запушены на feat/mechanic-mvp. -Phase E полностью завершён (E1-E5, последний коммит b37a068, 144/144 тестов зелёных). -Backend MVP API готов: 11 routes (полный flow inspection + photos + thumbnails). -Следующая фаза — Phase F (markers CRUD, 2 задачи) из плана. +Deployment runbook готов в STATE.md секция "Deployment runbook". Выполни J1+J2+J3: +1. SSH в root@100.64.0.12, git pull feat/mechanic-mvp, docker compose rebuild + rolling restart blue→green +2. rsync mechanic-pwa/frontend/dist/ на VDS + caddy reload mechanic.pptaxi.ru +3. Smoke test на мобильном браузере по чек-листу из runbook'а -После F backend Phase 1 MVP feature-complete и начинается Phase G (frontend PWA scaffold). - -Используй superpowers:subagent-driven-development. +После успешного deploy: merge feat/mechanic-mvp → main в обоих репах (PremiumDriverApp + taxi-dashboard). ``` -That prompt is the **single entry point** for the next session — Claude will read STATE.md, ground itself, and dispatch the F1 implementer. +That prompt is the **single entry point** for the next session — Claude reads STATE.md, executes the deployment runbook, runs smoke tests, merges to main. ## Remaining roadmap (Phase 1 MVP) - ~~**Phase B** (4 tasks)~~ ✅ done — module skeleton, models, schemas, auth deps - ~~**Phase C** (3 tasks)~~ ✅ done — GET /me, GET /vehicles, GET /vehicles/{id} -- ~~**Phase D** (3 tasks)~~ ✅ done — POST /inspections (+ carry-over), GET /inspections/{id}, PATCH /inspections/{id} -- ~~**Phase E** (5 tasks)~~ ✅ done — presigned PUT URL, photo upload-url, confirm, GET /photos/{id}+thumb, async thumb generation -- **Phase F** (2 tasks): markers create/update/delete ← **NEXT** -- **Phase G** (5 tasks): Vite + React + Tailwind + shadcn + PWA scaffold -- **Phase H** (3 tasks): Login + Home + VehicleCard pages -- **Phase I** (6 tasks): CameraCapture + PhotoSlot + VehicleScheme + InspectionEditor + InspectionReview -- **Phase J** (4 tasks): e2e test + deploy backend + deploy frontend + smoke test +- ~~**Phase D** (3 tasks)~~ ✅ done +- ~~**Phase E** (5 tasks)~~ ✅ done +- ~~**Phase F** (2 tasks)~~ ✅ done — backend Phase 1 MVP feature-complete (14 routes, 159 tests) +- ~~**Phase G** (5 tasks)~~ ✅ done — frontend scaffold (91 KB gzip after G; 113 KB after I) +- ~~**Phase H** (3 tasks)~~ ✅ done — Login + Home + VehicleCard +- ~~**Phase I** (6 tasks)~~ ✅ done — CameraCapture + AuthImg + PhotoSlot + VehicleScheme + Editor + Review +- **Phase J** (4 tasks): code-complete, **deployment runbook ready, awaiting user OK** ← **HERE** -≈ 20 tasks left until MVP live on `mechanic.pptaxi.ru`. Backend MVP is feature-complete after F. +**Code work is done. Phase 1 MVP delivery is one `ssh root@100.64.0.12` + Docker compose restart + rsync away.** ≈ 25 tasks left until MVP live on `mechanic.pptaxi.ru`.