TextField rejects Collection values before formatValue runs. Switching to
the generic Field avoids the type check. ebayDescription now renders its
HTML tags in the detail view instead of showing raw markup.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
FK on attribute_values.attribute_definition_id now uses ON DELETE CASCADE
so deleting an AttributeDefinition also clears its values from all
articles. Admin delete action shows a confirmation warning.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove all hardcoded defaults from PromptTemplateService — the DB record
is now mandatory and render() throws if a key is missing. Admin UI
disables new/delete and makes the key field read-only so system prompts
cannot be renamed or removed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds model_name VARCHAR(255) column to app.articles, exposes it in the
admin CRUD form (optional, hidden on index), and adds translations for
both EN and DE.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Ingest page redesigned: camera modal (getUserMedia + capture fallback
for mobile), mandatory search photo with client-side validation,
optional extra photos grid with per-photo remove button
- Camera modal: live video preview, capture → preview → confirm/retake
flow; stops stream on modal close; falls back to native file picker
if getUserMedia is unavailable
- ManualIngestController: uploads extra photos via PhotoService::uploadRaw(),
stores [{storagePathId, filename}] in job inputData as extraPhotos
- PhotoService::attachExtra(): attach already-stored file to an article
by StoragePath ID + filename
- DraftArticleHandler: after creating the article, attaches extra photos
in sort order; errors are best-effort (pipeline not aborted)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add secured GET /admin/photos/{filename} to serve files from var/uploads/
- Add POST /api/articles/{id}/photos/sort for drag-and-drop reordering
- Add PhotoService::reorder() to persist new sort positions
- Add photo gallery field (onlyOnDetail) using custom Twig template:
- Drag-and-drop reorder via SortableJS CDN
- Click or drop to upload new photos
- Set main (★) and delete per photo
- Main photo highlighted with blue border + badge
- Add field.photos translation key (EN/DE)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add hasActiveJobForArticle() to check for queued/processing jobs.
The displayIf closure hides the action while a job is running.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add Translation entity (locale/domain/key/value, unique on all three)
- Add TranslationRepositoryInterface + DoctrineTranslationRepository
- Add DatabaseTranslator decorator (#[AsDecorator]) that checks DB first
and falls back to YAML files; clears per-request cache on setLocale()
- Add TranslationCrudController with locale/domain filters and read-only
key/locale/domain on edit to prevent accidental renames
- Add "Übersetzungen / Translations" menu entry in DashboardController
- Migration 20260520000000: create app.translations table
- Migration 20260520010000: seed from admin.en.yaml + admin.de.yaml (204 rows)
- Flatten admin.de.yaml to dot-notation; add new keys for translation CRUD
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add LocaleSubscriber: detects browser language, honours session override (priority 20)
- Add LocaleSwitchController: stores locale in session, linked from user menu
- Add admin.en.yaml / admin.de.yaml translation files (95 keys each)
- Wire translation fallback to EN in config/packages/translation.yaml
- Replace all hard-coded strings in CRUD controllers with TranslatableMessage
- Inject TranslatorInterface into DashboardController, ArticleCrudController,
AIPipelineJobCrudController and PipelineStreamController; add locale switcher
links (English / Deutsch) to the user menu
- Add confirmation dialog to "Re-run AI" and "Retry" pipeline actions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds real-time toast notifications to all admin pages for AI pipeline
job progress. The browser subscribes to an SSE endpoint
(GET /admin/pipeline/events) which polls the DB every 2 seconds and
emits events whenever a job's step or status changes.
- AIPipelineJob gains updatedAt (migration 20260519020000), bumped on
every state-change method, with an index for efficient polling
- AIPipelineJobRepositoryInterface/Doctrine get findUpdatedSince()
- PipelineStreamController streams SSE with per-connection dedup and
auto-reconnect (retry: 3000); streams for 90 s then signals reconnect
- pipeline-notifications.js handles EventSource, shows colour-coded
toasts (queued/processing/completed/failed/needs_review) and is loaded
globally via DashboardController::configureAssets()
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All agent prompts are now stored in app.prompt_templates (migration 20260519000000)
and editable by admins via the new AI Prompts CRUD page. If no DB entry exists
for a key the hardcoded default is used automatically as fallback.
PromptTemplateService renders templates with {{variable}} substitution.
All four agents (SpecsResearch, JsonCoding, EbayText, OllamaVision) use the service.
SpecsResearchAgent now receives the articleType name (e.g. "Laptop") so the
specs prompt is scoped to the correct device category instead of being generic.
SpecsResearchHandler loads the ArticleType from the repository for this purpose.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ManualIngestController: photo upload form that starts a new pipeline job
- AiStatusController: shows active backend config and runs live connectivity tests
- PipelineArchiveCrudController: read-only view of completed/failed jobs
- ManualIngestType / AttributeValueFormType: form types for ingest and attribute editing
- AiConfigService: encapsulates backend info and test methods for the status page
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Retry button on index and detail pages for failed/needs-review/processing jobs
- Shows inventory number, current step, attempt count, created-at on index
- Detail page renders full AI step output (vision, specs, attributes)
- Filters active jobs by non-completed status via custom query builder
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Console commands: CreateUser (interactive), BackupCommand, RotateLogsCommand.
Migrations 20260514: initial schema for app/logs schemas.
Config: register new bundles, Doctrine schema filter, Kernel micro-kernel
adjustments, deleted unused api.yaml route file and www.conf override.
Application service and API controller updates for the full article lifecycle.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
CRUD controllers for Article, ArticleType, AttributeDefinition,
ArticleTypeAttribute, AIPipelineJob, Order, Customer, Invoice, User
and LogEntry. SecurityController handles login/logout; TotpSetupController
manages 2FA enrollment. API controllers for pipeline and orders.
Admin dashboard template and Twig base layout included.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
eBay adapter covers OAuth, inventory API, fulfillment API, taxonomy
service and webhook signature verification. Frappe ERP adapter wraps
the Frappe HTTP client for order/invoice sync.
Includes CustomerResolver, InvoiceMailer, and the EbayWebhookController
for inbound eBay marketplace notifications.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Promote article_type_attributes join table to ArticleTypeAttribute entity
with a required boolean flag. ArticleType gains virtual form properties
(requiredAttributeDefs / optionalAttributeDefs) reconciled via
applyAttributeAssignments() on persist/update.
Admin form shows two Tom Select multi-selects; a small JS module
(article-type-attr-sync.js) listens for ea.autocomplete.connect events
and keeps the two lists mutually exclusive in real time.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Validates current password, enforces 8-char minimum, links from
EasyAdmin user menu. Also fixes route loader (attribute scan instead
of broken easyadmin.routes type).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>