Files
descrybe/docs/e2e-feeds-process-export.md
T
greeneclipse 8580c996c3 Initial commit of Descrybe v2 without local scratch artifacts.
Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
2026-08-09 22:47:43 +02:00

5.6 KiB

E2E: Feeds → Map → Process → Export (Local Demo Co)

When: 2026-08-04
Tenant: Local Demo Co (ee246275-dec0-4446-9e83-58d0c16c258a)
Web: http://127.0.0.1:5174 (not 5173 — that port may be another Vite app)
API: http://127.0.0.1:8080
DB: postgres://descrybe:***@localhost:5433/descrybe

Credentials

Email demo@descrybe.local
Password DemoPass123!
API key dk_demo_local_descrybe_test_key_v1

Session login needs CSRF: GET any /api/* route to set descrybe_csrf, then POST /api/auth/login with header X-CSRF-Token.

Authorization: Bearer dk_demo_local_descrybe_test_key_v1

Pipeline (what “done” looks like)

input feeds → PUT mappings → (sync*) → POST process → export generate → public XML/CSV

* Live FTP/FTPS supplier URLs return 400 ftp/ftps feed sync is not supported yet. Local Demo Co already has migrated raw/processed rows, so process + export work without re-sync.

Verified counts (after this E2E)

Surface Result
Input feeds 12 (active / mapped)
Feed mappings Present (e.g. Vama Trade 13 fields)
Processed products ~4330 (GET /api/v1/products)
Raw / unprocessed 23744 (kind=raw or kind=unprocessed)
Export generate XML 4322 products, status=completed
Export generate CSV 4322 products, status=completed
Process job 5/5 completed (normalize → specs → fill → eprel skipped → ai)

API path (copy/paste)

1. List feeds + mappings

$H = @{ Authorization = "Bearer dk_demo_local_descrybe_test_key_v1"; "Content-Type" = "application/json" }
Invoke-RestMethod http://127.0.0.1:8080/api/v1/feeds -Headers $H
Invoke-RestMethod http://127.0.0.1:8080/api/v1/feeds/b5fc7c4c-830b-4d6e-a90c-9b72800a89a1/mappings -Headers $H

2. Save mappings (flips unmappedmapped, sets options.item_path)

Body uses the dashboard shape { key, mapping: { fieldName, xpath } }:

$body = @{
  mappings = @(
    @{ key = "Export/Item/name"; mapping = @{ fieldName = "name"; xpath = "Export/Item/name" } }
    @{ key = "Export/Item/EAN";  mapping = @{ fieldName = "gtin"; xpath = "Export/Item/EAN" } }
  )
} | ConvertTo-Json -Depth 6
Invoke-RestMethod -Method PUT -Uri http://127.0.0.1:8080/api/v1/feeds/<feedId>/mappings -Headers $H -Body $body

3. Process sample raw products

$raw = Invoke-RestMethod "http://127.0.0.1:8080/api/v1/products?kind=raw&limit=5" -Headers $H
$ids = @($raw.products | ForEach-Object { $_.id })
$jobBody = @{ raw_product_ids = $ids; processing_type = "normalize" } | ConvertTo-Json
$job = Invoke-RestMethod -Method POST -Uri http://127.0.0.1:8080/api/v1/process -Headers $H -Body $jobBody
# poll GET /api/v1/process/{id} until status=completed (worker must be running)

Dashboard alias: POST /api/processing/jobs (same body).

4. Export XML + CSV

# Example feed IDs on Local Demo Co
$xmlId = "d52bc02c-77ee-4cd5-bcd9-fde652133f38"   # XML - Example
$csvId = "d6ccb83e-7c76-4328-8b60-820503bd24d0"   # CSV - Example
Invoke-RestMethod -Method POST -Uri "http://127.0.0.1:8080/api/v1/export-feeds/$xmlId/generate" -Headers $H -Body "{}"
Invoke-RestMethod -Method POST -Uri "http://127.0.0.1:8080/api/v1/export-feeds/$csvId/generate" -Headers $H -Body "{}"

# Public downloads (token from export feed)
# GET /api/public/export-feeds/{public_token}.xml
# GET /api/public/export-feeds/{public_token}.csv

Example tokens after seed/migrate: XML f2321bf2d18609b7abf5ea0f0f9fbb86, CSV 7fdea27d7bc9e21aec6403e24ccb3c8a.

UI path

Step URL
Login http://127.0.0.1:5174/login
Feeds http://127.0.0.1:5174/feeds
Mapping http://127.0.0.1:5174/feeds/{feedId}/mapping
Products http://127.0.0.1:5174/products (Processed / Unprocessed tabs)
Processing http://127.0.0.1:5174/processing
Export feeds http://127.0.0.1:5174/export-feeds

Session-cookie calls go through the Vite proxy (/api/...:8080). Same CSRF rules as direct API.

SSR smoke (logged in): /dashboard, /feeds, /products, /export-feeds, /processing, /feeds/.../mapping200.

Blockers fixed in this pass

Issue Fix
parseMappings ignored UI {key,mapping} rows → sync would apply zero fields Unwrap nested mapping + key as xpath/source in internal/feeds/mapping.go
PUT mappings left feed status=unmapped Derive item_path from xpath parents; always set unmappedmapped when fields saved (service.go / extract_schema.go)
kind=unprocessed ignored (returned processed) Alias to raw list in catalog_handlers.go
Empty-looking processed tab Data was present (~4.3k); use Unprocessed/kind=raw for inventory; API totals verified

Known limits

  • FTP/FTPS sync not supported: POST .../sync and .../sync-process-sample return 400 for supplier FTP URLs (Vama, ComTrade, …).
  • Worker required for process jobs (scripts/run-api.ps1 worker or go run ./cmd/worker).
  • Public export HEAD may 405; use GET.
  • Web port is 5174 in local docs/smoke; confirm with the Descrybe title before testing.

Verification commands

cd apps/api
go test ./internal/feeds ./internal/httpapi -count=1
go build -o bin/api.exe ./cmd/api

cd ../web
npm run check