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.
This commit is contained in:
2026-08-09 22:47:43 +02:00
commit 8580c996c3
1285 changed files with 325780 additions and 0 deletions
+141
View File
@@ -0,0 +1,141 @@
# 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`.
```http
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
```powershell
$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 `unmapped` → `mapped`, sets `options.item_path`)
Body uses the dashboard shape `{ key, mapping: { fieldName, xpath } }`:
```powershell
$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
```powershell
$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
```powershell
# 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/.../mapping`**200**.
## 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 `unmapped``mapped` 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
```powershell
cd apps/api
go test ./internal/feeds ./internal/httpapi -count=1
go build -o bin/api.exe ./cmd/api
cd ../web
npm run check
```
## Related
- [demo-user.md](demo-user.md) — credentials / API key
- [qa-local-demo.md](qa-local-demo.md) — broader Local Demo Co checklist
- [local-smoke-results.md](local-smoke-results.md) — prior smoke matrix