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:
@@ -0,0 +1,92 @@
|
||||
# Live public API verify — legacy-compatible contract
|
||||
|
||||
**When:** 2026-08-04 21:10 +02:00
|
||||
**Verdict:** **PASS** (process E2E + dual-mode OK; minor shape notes below)
|
||||
**API:** `http://localhost:8080`
|
||||
**Web:** `http://localhost:5174`
|
||||
**Postgres:** `localhost:5433` (`descrybe-v2-postgres`)
|
||||
**Auth:** Demo API key prefix `dk_demo_lo…` (redacted; full value in [demo-user.md](demo-user.md))
|
||||
**Worker:** `worker.exe` running (PID observed during run)
|
||||
|
||||
No API restart required — responses matched the current OpenAPI / handlers.
|
||||
|
||||
## PASS / FAIL by area
|
||||
|
||||
| Area | Result | Notes |
|
||||
|------|--------|-------|
|
||||
| Auth (missing key) | **PASS** | `401` `{ error: { code: "unauthorized", message: "Unauthorized" } }` |
|
||||
| Auth (Bearer) | **PASS** | `200` products list |
|
||||
| Auth (X-API-Key) | **PASS** | `200` products list |
|
||||
| GET `/products` | **PASS** | `{ data, meta }` — presentProduct fields (`id`, `product_id`, `name`, `category`, `status`, `feed_id`, `quality_score`, `quality_grade`, `created_at`, `updated_at`) |
|
||||
| GET `/products/quality` | **PASS** | `{ data, meta }` with `quality_checks`; meta has `page/limit/total` (no `totalPages`) |
|
||||
| POST `/products/process` (items/EAN) | **PASS** | `200` `{ data: { process_id, total_items, processed_items, message } }` |
|
||||
| GET poll → COMPLETED + `items` | **PASS** | `full` completed in ~4s with 2 items |
|
||||
| Process variants | **PASS** | `normalize_only`, `title`, `category` all `200` → `COMPLETED` + `items` |
|
||||
| Dual-mode `raw_product_ids` | **PASS** | On same path; must be **raw** UUIDs (not processed product list `id`) |
|
||||
| GET categories / attributes | **PASS** | `{ data, meta }` with page/limit |
|
||||
| GET feeds (+ one by id) | **PASS** | List `{ data, meta }`; GET one `{ data: {…} }`; sync **not** run |
|
||||
| GET export-feeds | **PASS** | `{ data, meta }` |
|
||||
| GET campaigns | **PASS** | `{ data: { year, presets, prepared } }` (no `meta`; matches OpenAPI) |
|
||||
| OpenAPI process docs | **PASS** | Documents `items` / `process_id`, dual-mode, legacy vs flat `/process` |
|
||||
|
||||
## Process outcome (critical)
|
||||
|
||||
### Start (`full`, real demo GTINs)
|
||||
|
||||
```http
|
||||
POST /api/v1/products/process
|
||||
{ "processing_type": "full", "items": [
|
||||
{ "ean": "8806088803005" },
|
||||
{ "ean": "8700000000002" }
|
||||
]}
|
||||
```
|
||||
|
||||
- **HTTP 200**
|
||||
- `process_id`: `d8f6d996-c0b8-43e7-9372-032fc725a523`
|
||||
- `total_items`: 2
|
||||
|
||||
### Poll
|
||||
|
||||
- Status **COMPLETED** on first poll (~4s)
|
||||
- `data.items` length **2** (Samsung dishwasher + Sample Gadget), with title/description/meta/eprel where applicable
|
||||
|
||||
### Variants (quick)
|
||||
|
||||
| `processing_type` | Start | Final | `items` |
|
||||
|-------------------|-------|-------|---------|
|
||||
| `full` | 200 | COMPLETED | yes |
|
||||
| `normalize_only` | 200 | COMPLETED | yes |
|
||||
| `title` | 200 | COMPLETED | yes |
|
||||
| `category` | 200 | COMPLETED | yes (title may be null) |
|
||||
|
||||
### Dual-mode
|
||||
|
||||
- Body `{ "processing_type": "normalize_only", "raw_product_ids": ["<raw UUID>"] }` → **200** envelope + COMPLETED with `items`.
|
||||
- Using a **processed** product list `id` → `400 validation_error` / `no matching products for company` (expected: IDs must be `raw_products.id`).
|
||||
- Flat surface `POST /api/v1/process` with same `raw_product_ids` → **202** flat `ProcessingJob` (documented separate contract).
|
||||
|
||||
## OpenAPI spot-check
|
||||
|
||||
- `/api/v1/openapi.yaml` **200**, documents:
|
||||
- Legacy: `POST /products/process` + `items[].ean` → `200` `{ data: { process_id, … } }`
|
||||
- Poll: `GET /products/process/{id}` with `items` when COMPLETED
|
||||
- Alternate body `raw_product_ids` on the same handler
|
||||
- Flat `/process` surface called out as separate (not legacy envelope)
|
||||
|
||||
## Remaining gaps / notes
|
||||
|
||||
1. **ID confusion:** ~~OpenAPI under-documented~~ **Closed (docs):** OpenAPI now documents dual IDs explicitly — `GET /products` `id` = processed, `raw_product_id` = raw; `raw_product_ids` must use raw UUIDs; COMPLETED poll items expose `processed_product_id` + `raw_product_id`. Plan gates (402) + gates-before-EnsureRaw on `items[].ean` documented.
|
||||
2. **Envelope inconsistency (intentional dual contract):** List endpoints use `{ data, meta }`; `GET /products/{id}` and flat `/process*` return **flat** objects (OpenAPI agrees). Not a regression vs docs.
|
||||
3. **Quality meta:** `totalPages` omitted (products list includes it).
|
||||
4. **Feed sync:** Skipped (avoid heavy sync spam). Single GET by UUID verified.
|
||||
5. **DELETE / create:** Skipped (no throwaway unique_ids created).
|
||||
6. **Export generate:** Not run (avoid large exports).
|
||||
|
||||
## Stack check
|
||||
|
||||
| Service | Port | Status |
|
||||
|---------|------|--------|
|
||||
| Go API | 8080 | Up (`/healthz` ok) |
|
||||
| Web (Vite) | 5174 | Listening |
|
||||
| Postgres | 5433 | Healthy |
|
||||
| Worker | — | Running |
|
||||
Reference in New Issue
Block a user