# Live E2E — local Descrybe v2 (real HTTP, not seed-only) **Verdict: PASS (21/21)** **Window (UTC):** `2026-08-04T01:15:00.966Z` → `2026-08-04T01:16:02.300Z` (~61s) **Tenant:** `demo@descrybe.local` → **Local Demo Co** (`ee246275-dec0-4446-9e83-58d0c16c258a`) **API:** `http://127.0.0.1:8080` (process `api.exe`, healthz/readyz 200) **Worker:** `worker.exe` running (required for process job completion) **Web:** `http://127.0.0.1:5174` (primary) and `:5173` (also 200; prefer **5174**) **Build checks after run:** `go build ./...` exit 0 · `go vet ./...` exit 0 · `npm run check` (web) 0 errors Raw machine log: `artifacts/live-e2e-summary.json`, `artifacts/live-e2e-run.jsonl`. This run **executed** login, list, mapping PUT, process queue+poll, export generate, public download, campaign create+generate, and SEO apply. Counts and bytes below come from live responses, not from assuming seed state. ## Services (fail-closed) | Probe | HTTP | UTC | Body / note | |-------|-----:|-----|-------------| | `GET /healthz` | **200** | 01:15:01.013Z | `{"status":"ok","maintenance":false,...}` | | `GET /readyz` | **200** | 01:15:01.056Z | `{"status":"ready",...}` | | `GET http://127.0.0.1:5174/` | **200** | 01:15:01.562Z | SvelteKit HTML | | `GET http://127.0.0.1:5173/` | **200** | 01:15:01.580Z | HTML (secondary Vite; do not confuse with v2 app) | If healthz had failed, the suite exits before auth. ## Auth | Step | HTTP | UTC | Evidence | |------|-----:|-----|----------| | Session CSRF + `POST /api/auth/login` | **200** | 01:15:01.722Z | `demo@descrybe.local`, company **Local Demo Co** | | `GET /api/auth/me` (same session) | **200** | (with login) | `company_id=ee246275-dec0-4446-9e83-58d0c16c258a`, `remaining_credits=999996` | | Vite proxy login `POST http://127.0.0.1:5174/api/auth/login` | **200** | post-suite check | `GET .../api/auth/me` → Local Demo Co | API key used for v1 product/feed/process/export calls: `Authorization: Bearer dk_demo_local_descrybe_test_key_v1`. ## Products & feeds | Step | HTTP | UTC | Evidence | |------|-----:|-----|----------| | `GET /api/v1/products?limit=5` | **200** | 01:15:01.764Z | **total=4330**; sample `d2c309ed-fa99-4785-aa72-4f7d180f1f85` | | `GET /api/v1/products?kind=raw&limit=5` | **200** | 01:15:01.918Z | 5 IDs returned (e.g. `fa4d70c7-938a-405e-ada7-f7341eb64b53`, …) | | `GET /api/v1/feeds` | **200** | 01:15:01.964Z | **13** feeds; target **Vama Trade** `b5fc7c4c-830b-4d6e-a90c-9b72800a89a1` status=`active` | | `GET .../feeds/{id}/mappings` | **200** | 01:15:01.990Z | **13** mappings | | `PUT .../feeds/{id}/mappings` | **200** | 01:15:02.038Z | Re-saved 13 mappings; mapping row id `26951cb8-704d-423f-8357-4c8ff5a43720` | ## Process job (queued + polled to completion) | Step | HTTP | UTC | Evidence | |------|-----:|-----|----------| | `POST /api/v1/process` | **202** | 01:15:02.081Z | **job_id=`a84b26db-c39f-4491-9623-90e68e411144`**, `status=pending`, `total_products=3`, `processing_type=normalize` | | Poll `GET /api/v1/process/{id}` | **200** | running → **completed** at 01:15:10.214Z | `processed_products=3/3`, `current_step=done` | Step progress (live GET after complete): | Step | Status | |------|--------| | normalize | done | | parse_specs | done | | fill_fields | done | | eprel | skipped (`no_id`) | | ai_enhance | done | Worker must be running; a stuck `pending`/`running` past the 3-minute poll window would be **FAIL**. ## Export generate + public URLs | Step | HTTP | UTC | Evidence | |------|-----:|-----|----------| | `GET /api/v1/export-feeds` | **200** | 01:15:10.239Z | **3** export feeds | | `POST .../export-feeds/d52bc02c-…/generate` (XML - Example) | **200** | 01:15:10.598Z | `status=completed`, **products_exported=4322**, `last_generated_at=2026-08-04T01:15:10Z` | | `GET /api/public/export-feeds/f2321bf2d18609b7abf5ea0f0f9fbb86.xml` | **200** | 01:15:41.570Z | **10,171,817** bytes; starts with `` | | `POST .../export-feeds/df6073cf-…/generate` (Black Friday 2026 CSV) | **200** | 01:15:42.141Z | `status=completed`, **products_exported=4316**, `last_generated_at=2026-08-04T01:15:42Z` | | `GET /api/public/export-feeds/1d00586848b0cded58b49dfb0f615d64.csv` | **200** | 01:15:55.072Z | **8,908,695** bytes; CSV header `availability,brand,condition,...` | Public downloads prove generate wrote real artifacts (multi‑MB bodies), not empty placeholders. ## Campaign generate | Step | HTTP | UTC | Evidence | |------|-----:|-----|----------| | `POST /api/campaigns` | **201** | 01:15:55.114Z | **id=`a5a1759e-c729-4409-9f50-9fbb81658ea9`**, name `Live E2E 20260804-031555`, `template_key=spring`, `status=draft` | | `POST /api/campaigns/{id}/generate` `mode=ai` | **200** | 01:16:00.678Z | `status=ready` (~5.5s) | | Follow-up `GET /api/campaigns/{id}` | **200** | post-suite | `status=ready`, subject **Upgrade your home essentials** | ## SEO apply | Step | HTTP | UTC | Evidence | |------|-----:|-----|----------| | `POST /api/seo/apply` `{product_id, mode:ai}` | **200** | 01:16:01.913Z | product `d2c309ed-…`; `mode=ai`; **credits_charged=2**; `meta_title=Sample Gadget \| Premium Wireless Connectivity` | | `GET /api/seo/recommendations` | **200** | 01:16:02.298Z | response **83,536** bytes | ## Step matrix | # | Step | HTTP | Result | UTC | |--:|------|-----:|--------|-----| | 1 | healthz | 200 | PASS | 01:15:01.013Z | | 2 | readyz | 200 | PASS | 01:15:01.056Z | | 3 | web_5174 | 200 | PASS | 01:15:01.562Z | | 4 | web_5173 | 200 | PASS | 01:15:01.580Z | | 5 | login | 200 | PASS | 01:15:01.722Z | | 6 | list_products | 200 | PASS | 01:15:01.764Z | | 7 | list_raw_products | 200 | PASS | 01:15:01.918Z | | 8 | list_feeds | 200 | PASS | 01:15:01.964Z | | 9 | get_mappings | 200 | PASS | 01:15:01.990Z | | 10 | put_mappings | 200 | PASS | 01:15:02.038Z | | 11 | queue_process | 202 | PASS | 01:15:02.081Z | | 12 | poll_process | 200 | PASS | 01:15:10.214Z | | 13 | list_export_feeds | 200 | PASS | 01:15:10.239Z | | 14 | export_generate_xml | 200 | PASS | 01:15:10.598Z | | 15 | public_export_xml | 200 | PASS | 01:15:41.570Z | | 16 | export_generate_csv | 200 | PASS | 01:15:42.141Z | | 17 | public_export_csv | 200 | PASS | 01:15:55.072Z | | 18 | campaign_create | 201 | PASS | 01:15:55.114Z | | 19 | campaign_generate | 200 | PASS | 01:16:00.678Z | | 20 | seo_apply | 200 | PASS | 01:16:01.913Z | | 21 | seo_recommendations | 200 | PASS | 01:16:02.298Z | ## Failures / fixes this run **None.** No application code changes required; all exercised paths returned success codes and completed job/export/campaign/SEO side effects. ## How to re-run Prerequisites: Postgres (`docker compose` on `:5433`), API `:8080`, worker, web `:5174`, demo user (`seed-demo`). ```powershell # Fail closed if API down curl.exe -sf http://127.0.0.1:8080/healthz curl.exe -sf http://127.0.0.1:8080/readyz # Session login needs CSRF cookie then X-CSRF-Token on POST /api/auth/login # v1 calls: Authorization: Bearer dk_demo_local_descrybe_test_key_v1 # Process: POST /api/v1/process → poll GET /api/v1/process/{id} until completed # Export: POST /api/v1/export-feeds/{id}/generate → GET /api/public/export-feeds/{token}.{xml|csv} # Campaign: POST /api/campaigns → POST /api/campaigns/{id}/generate {mode:ai} # SEO: POST /api/seo/apply {product_id, mode:ai} ``` Related: [e2e-feeds-process-export.md](e2e-feeds-process-export.md), [e2e-marketing.md](e2e-marketing.md), [demo-user.md](demo-user.md), [qa-local-demo.md](qa-local-demo.md).