diff --git a/README.md b/README.md index e2222bc..b907cd9 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ # SuperSeller3000 -Admin middleware for managing and selling refurbished IT hardware. Handles article ingestion via AI pipeline (photo → vision → specs → eBay text), multi-channel publishing (eBay), and order processing with Frappe ERP invoicing. +Admin middleware for managing and selling refurbished IT hardware. Handles article ingestion via AI pipeline (photo → vision → specs → eBay texts), multi-channel publishing (eBay), and order processing with Frappe ERP invoicing. **Live:** `https://ss3k.schaunwama.de/admin` +**Architecture reference:** `docs/architecture.md` **Full design doc:** `docs/superpowers/specs/2026-05-13-superseller3000-design.md` --- @@ -10,10 +11,11 @@ Admin middleware for managing and selling refurbished IT hardware. Handles artic ## Quick Start ```bash -cp .env .env.local # fill in secrets (DB, Redis, AI keys, eBay, Frappe) +cp .env .env.local # fill in secrets — see .env for all required vars docker compose up -d docker compose exec app php bin/console doctrine:migrations:migrate --env=prod docker compose exec app php bin/console app:users:create --env=prod +docker compose exec app php bin/console app:api-keys:create --env=prod ``` Workers start automatically via Docker Compose (`worker-ai`, `worker-orders`, `worker-channel`). @@ -27,11 +29,13 @@ Workers start automatically via Docker Compose (`worker-ai`, `worker-orders`, `w | Language / Framework | PHP 8.4 · Symfony 8.4 | | ORM | Doctrine ORM | | Database | PostgreSQL 17 — schemas: `app`, `logs`, `logs_archive` | -| Queue | Symfony Messenger + Redis Streams | -| AI | Ollama (local, SSH-tunnel) **or** Mistral Cloud API — alias-switchable in `services.yaml` | -| Web Search | Tavily API (`TAVILY_API_KEY`) | +| Queue | Symfony Messenger + Redis 7 Streams | +| AI | Mistral Cloud API — Vision: `pixtral-12b-2409`, Text: `mistral-large-latest` | +| Web Search | Tavily API | +| Channel | eBay Inventory / Account / Fulfillment / Taxonomy APIs | +| ERP | Frappe ERPNext (sales invoices, customer sync) | | Admin | EasyAdmin 5 | -| Auth | Symfony Security + TOTP 2FA (scheb/2fa-totp) | +| Auth | Symfony Security + TOTP 2FA · API keys via `X-Api-Key` header | | Proxy | Caddy 2 (Auto-HTTPS) | --- @@ -40,53 +44,47 @@ Workers start automatically via Docker Compose (`worker-ai`, `worker-orders`, `w ```bash # Unit tests (fast, no external deps) -docker compose exec app php vendor/bin/phpunit tests/Unit/ --testdox +docker compose exec app php vendor/bin/phpunit tests/Unit/ -# Integration tests (requires staging credentials in .env.local) +# Single test file or method +docker compose exec app php vendor/bin/phpunit tests/Unit/Domain/Article/ArticleTest.php +docker compose exec app php vendor/bin/phpunit --filter testSomeMethod + +# Integration tests (requires credentials in .env.local) bin/test-integration +bin/test-integration tests/Integration/Infrastructure/Channel/Ebay/ -# Single integration file -bin/test-integration tests/Integration/path/to/Test.php +# Static analysis (level 9, must be clean) +docker compose exec app php vendor/bin/phpstan analyse -# Static analysis + code style -docker compose exec app composer phpstan -docker compose exec app composer cs-check +# Code style +docker compose exec app php vendor/bin/php-cs-fixer fix --dry-run --diff +docker compose exec app php vendor/bin/php-cs-fixer fix ``` --- -## AI Backend - -Switch between Ollama and Mistral in `config/services.yaml`: - -```yaml -# Ollama (default — local via SSH tunnel) -App\Infrastructure\AI\OllamaClientInterface: - alias: App\Infrastructure\AI\OllamaClient - -# Mistral Cloud -App\Infrastructure\AI\OllamaClientInterface: - alias: App\Infrastructure\AI\MistralClient -``` - -Set models via env vars: `AI_TEXT_MODEL`, `AI_VISION_MODEL`. After switching: `docker compose exec app php bin/console cache:clear`. - ---- - ## Admin Panel Features -- **Articles** — list (click row → detail view, Edit as action), ingest form with stock quantity, attribute validation with required-field highlighting -- **AI Pipeline** — per-job progress view with step tracking; failed jobs show the real error; re-run AI from article detail -- **Article Types** — configurable attribute schemas (name, type, unit, options, required flag); attributes drive specs-research field list -- **Users** — permission checkboxes per user (`ARTICLES_MANAGE`, `PIPELINE_RUN`, `ORDERS_MANAGE`, etc.) +- **Articles** — list with row click → detail, inline actions (activate, re-run AI, manage photos) +- **Photo Management** — per-article page: upload, delete, set main, drag-to-reorder +- **AI Pipeline** — per-job step tracking; re-run AI from article detail; failed jobs show real error +- **Article Types** — configurable attribute schemas (name, type, unit, options, required flag) +- **eBay** — category + business policy configuration per article type (fulfillment, payment, return, location pulled live from eBay account) +- **eBay Aspect Import** — typeahead category search, imports taxonomy aspects as attribute mappings - **Orders / Customers / Invoices** — full read/manage view -- **Prompt Templates** — editable via admin (DB-backed, `{{variable}}` substitution) +- **Prompt Templates** — DB-backed, editable in admin, `{{variable}}` substitution +- **Users** — permission checkboxes per user; API keys via console --- -## Manual Article Ingest +## Article Ingest -Admin → **New Article** (or via API): +### Via Admin UI + +Admin → **Artikel einlesen** — select article type, condition, stock quantity, take/upload photo. Pipeline starts automatically. + +### Via API ```bash curl -X POST https://ss3k.schaunwama.de/api/pipeline/photo-upload \ @@ -95,39 +93,57 @@ curl -X POST https://ss3k.schaunwama.de/api/pipeline/photo-upload \ -F "condition=good" \ -F "stock=1" \ -F "photo=@/path/to/photo.jpg" + +# Poll status +curl https://ss3k.schaunwama.de/api/pipeline/jobs/ \ + -H "X-Api-Key: " ``` -Pipeline: Photo → OllamaVision (model number) → **DB model cache check** → *(cache hit: copy + done)* / *(cache miss: Tavily search → JsonCoding → Validation → Draft → eBay text)* +**Pipeline A (photo):** Vision → DB model cache check → *(hit: copy texts, done)* / *(miss: Tavily search → JSON coding → Validation → Draft → eBay text)* + +**Pipeline B (PXE dump):** JSON coding → Validation → Draft → eBay text + +After pipeline: admin reviews draft, sets price, activates → eBay listing published automatically (with photos). --- -## API Keys +## eBay Setup -Generated via console only (raw key shown once): +For each article type, configure in Admin → **eBay → Kategorie-Konfigurationen**: -```bash -docker compose exec app php bin/console app:api-keys:create --env=prod +1. Assign article type and eBay category ID +2. Select business policies (fulfillment, payment, return) — loaded live from your eBay account +3. Select merchant location + +Import aspect mappings via Admin → **Artikeltypen** → aspect import action. + +Set the public URL for photo hosting in `.env.local`: + +```dotenv +APP_PUBLIC_URL=https://ss3k.schaunwama.de ``` -Use as `X-Api-Key: ` header. - --- ## Architecture -Hexagonal (Domain / Application / Infrastructure). See design doc for full details. +Hexagonal (Domain / Application / Infrastructure). See `docs/architecture.md` for the full reference including all flows, entity relationships, queue details, and gotchas. ``` src/ Domain/ # Pure PHP — Article, ArticleType, Order, Customer, AIPipelineJob … - Application/ # Use cases, orchestration via interfaces + Application/ # Use cases, port interfaces (ChannelAdapterInterface, ErpAdapterInterface …) Infrastructure/ - AI/ # OllamaClient, MistralClient, 4 AI agents - Channel/ # EbayAdapter, FrappeErpAdapter - Search/ # TavilyWebSearch + AI/ # MistralClient, 4 AI agents (Vision, SpecsResearch, JsonCoding, EbayText) + Channel/ # EbayAdapter + 5 API clients, FrappeErpAdapter Persistence/ # Doctrine repositories (PostgreSQL) - Messenger/ # Message classes + handlers (3 queues: ai_pipeline, orders, channel_sync) - Http/ # Symfony controllers, EasyAdmin CRUD, webhooks + Messenger/ # Message classes + handlers (3 transports: ai_pipeline, orders, channel_sync) + Http/ # Symfony controllers, EasyAdmin CRUD, webhooks, public photo endpoint ``` -All plans (1–6) complete. Active development tracked via Claude Code sessions. +| Transport | Retries | Used for | +|---|---|---| +| `ai_pipeline` | 3 × 2 s | All AI pipeline steps | +| `orders` | 5 × 1 s | Order processing, invoicing | +| `channel_sync` | 5 × 2 s ≤ 60 s | Publish, stock sync, deactivate, tracking | +| `failed` | — | Dead-letter; replay via `messenger:failed:retry` |