No description
Find a file
Simon Kuehn d26c534c34 feat: eBay aspect import — match/create attributes from eBay taxonomy
ArticleType gains ebayCategoryId (migration 20260520080000).

New admin action "Import eBay Aspects" on ArticleType list and detail:
  - Fetches aspects via EbayTaxonomyService (cached 7d)
  - Sorts: Required → Recommended → Optional
  - Auto-matches by case-insensitive name to existing AttributeDefinitions
  - Pre-selects "Create new" for required/recommended with no match
  - Pre-selects "Skip" for optional with no match
  - Already-assigned definitions highlighted green
  - Per-row: override to Skip / Match existing / Create new
  - Type auto-detected: Select (≤30 eBay values) or String (freetext)
  - User can override type in create form
  - Required checkbox pre-checked for eBay-required aspects
  - "All → Create" / "All → Skip" bulk buttons
  - On submit: creates new AttributeDefinitions, links all to ArticleType,
    deduplicates, calls applyAttributeAssignments(), flushes

PHPStan level 9 clean throughout.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 18:30:45 +00:00
.gitea/workflows feat: add Gitea Actions CI (CS Fixer, PHPStan, Pest + migrations) 2026-05-14 04:25:50 +00:00
bin feat: eBay sandbox integration — env config + taxonomy/adapter tests 2026-05-18 18:02:49 +00:00
config feat: Frappe ERP matching, pipeline model cache, ACL, stock field, specs by type 2026-05-18 16:42:15 +00:00
docker feat: add erpstaging.schaunwama.de reverse proxy to frappe docker 2026-05-18 11:39:14 +00:00
docs/superpowers docs: add README and update design doc for post-plan features 2026-05-18 17:41:33 +00:00
migrations feat: eBay aspect import — match/create attributes from eBay taxonomy 2026-05-18 18:30:45 +00:00
public feat: Frappe ERP matching, pipeline model cache, ACL, stock field, specs by type 2026-05-18 16:42:15 +00:00
src feat: eBay aspect import — match/create attributes from eBay taxonomy 2026-05-18 18:30:45 +00:00
templates feat: eBay aspect import — match/create attributes from eBay taxonomy 2026-05-18 18:30:45 +00:00
tests feat: expose eBay aspect usage tier (RECOMMENDED vs OPTIONAL) 2026-05-18 18:21:31 +00:00
translations feat: Frappe ERP matching, pipeline model cache, ACL, stock field, specs by type 2026-05-18 16:42:15 +00:00
.editorconfig chore: add tooling config, test bootstrap, env templates and docs 2026-05-17 22:44:16 +00:00
.env feat: replace Mistral web_search with Tavily for specs research 2026-05-18 08:35:52 +00:00
.env.dev chore: add tooling config, test bootstrap, env templates and docs 2026-05-17 22:44:16 +00:00
.env.test feat: eBay sandbox integration — env config + taxonomy/adapter tests 2026-05-18 18:02:49 +00:00
.gitignore feat: add PHPStan level 9, PHP CS Fixer, Pest; fix docker user=1000 to avoid root-owned files 2026-05-14 04:25:30 +00:00
.php-cs-fixer.dist.php chore: add tooling config, test bootstrap, env templates and docs 2026-05-17 22:44:16 +00:00
.php-cs-fixer.php feat: implement Plan 2 — Article Management API 2026-05-14 05:19:20 +00:00
composer.json feat: admin panel, Mistral client, attribute management, API key command 2026-05-17 20:15:13 +00:00
composer.lock feat: admin panel, Mistral client, attribute management, API key command 2026-05-17 20:15:13 +00:00
docker-compose.override.yml feat: add Docker Compose environment with Caddy, PostgreSQL 17, Redis, PHP-FPM workers 2026-05-14 04:14:55 +00:00
docker-compose.yml fix: raise PHP-FPM pool to 30 workers to prevent SSE starvation 2026-05-18 09:02:34 +00:00
phpstan.neon feat: implement Plan 2 — Article Management API 2026-05-14 05:19:20 +00:00
phpunit.dist.xml chore: add tooling config, test bootstrap, env templates and docs 2026-05-17 22:44:16 +00:00
phpunit.xml.dist feat: add PHPStan level 9, PHP CS Fixer, Pest; fix docker user=1000 to avoid root-owned files 2026-05-14 04:25:30 +00:00
README.md docs: add README and update design doc for post-plan features 2026-05-18 17:41:33 +00:00
symfony.lock feat: admin panel, Mistral client, attribute management, API key command 2026-05-17 20:15:13 +00:00

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.

Live: https://ss3k.schaunwama.de/admin
Full design doc: docs/superpowers/specs/2026-05-13-superseller3000-design.md


Quick Start

cp .env .env.local          # fill in secrets (DB, Redis, AI keys, eBay, Frappe)
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

Workers start automatically via Docker Compose (worker-ai, worker-orders, worker-channel).


Tech Stack

Layer Technology
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)
Admin EasyAdmin 5
Auth Symfony Security + TOTP 2FA (scheb/2fa-totp)
Proxy Caddy 2 (Auto-HTTPS)

Running Tests

# Unit tests (fast, no external deps)
docker compose exec app php vendor/bin/phpunit tests/Unit/ --testdox

# Integration tests (requires staging credentials in .env.local)
bin/test-integration

# Single integration file
bin/test-integration tests/Integration/path/to/Test.php

# Static analysis + code style
docker compose exec app composer phpstan
docker compose exec app composer cs-check

AI Backend

Switch between Ollama and Mistral in config/services.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.)
  • Orders / Customers / Invoices — full read/manage view
  • Prompt Templates — editable via admin (DB-backed, {{variable}} substitution)

Manual Article Ingest

Admin → New Article (or via API):

curl -X POST https://ss3k.schaunwama.de/api/pipeline/photo-upload \
  -H "X-Api-Key: <key>" \
  -F "articleTypeId=<uuid>" \
  -F "condition=good" \
  -F "stock=1" \
  -F "photo=@/path/to/photo.jpg"

Pipeline: Photo → OllamaVision (model number) → DB model cache check(cache hit: copy + done) / (cache miss: Tavily search → JsonCoding → Validation → Draft → eBay text)


API Keys

Generated via console only (raw key shown once):

docker compose exec app php bin/console app:api-keys:create --env=prod

Use as X-Api-Key: <rawKey> header.


Architecture

Hexagonal (Domain / Application / Infrastructure). See design doc for full details.

src/
  Domain/          # Pure PHP — Article, ArticleType, Order, Customer, AIPipelineJob …
  Application/     # Use cases, orchestration via interfaces
  Infrastructure/
    AI/            # OllamaClient, MistralClient, 4 AI agents
    Channel/       # EbayAdapter, FrappeErpAdapter
    Search/        # TavilyWebSearch
    Persistence/   # Doctrine repositories (PostgreSQL)
    Messenger/     # Message classes + handlers (3 queues: ai_pipeline, orders, channel_sync)
    Http/          # Symfony controllers, EasyAdmin CRUD, webhooks

All plans (16) complete. Active development tracked via Claude Code sessions.