Webshop - Related Articles Module And Import/Export¶
Overview¶
This document specifies the legacy related-articles capability used for cross-sell and required-product suggestions, including admin management and XLSX import/export flows.
Checklist coverage:
- AD-016 Related articles (wheels) import/export
- AD-019 Related articles (tyres) import/export
- AD-021 Related articles (accessories) import/export
- MK-008 Related articles module and import/export
- DM-011 Related articles entities
Primary legacy evidence:
- _admin/config/menu.php
- _admin/config/routing.php
- _admin/controller/classes/atx/articles/AdminRelatedArticlesController.php
- _admin/view/classes/atx/articles/AdminRelatedArticlesView.php
- src/Atraxion/Module/RelatedArticles/ServiceProvider/RelatedArticlesServiceProvider.php
- src/Atraxion/Module/RelatedArticles/Service/RelatedArticlesService.php
- src/Atraxion/Module/RelatedArticles/Service/ImportRelatedArticlesService.php
- src/Atraxion/Module/RelatedArticles/Service/ExportRelatedArticlesService.php
- src/Atraxion/Module/RelatedArticles/Service/MatchesVehicle.php
- src/Atraxion/Module/RelatedArticles/Service/RelatedArticlesSorter.php
- src/Atraxion/Module/RelatedArticles/Repository/RelatedArticleRepository.php
- src/Atraxion/Module/RelatedArticles/Repository/RelatedArticleGroupRepository.php
- src/Atraxion/Module/RelatedArticles/Resources/doctrine/RelatedArticle.orm.xml
- src/Atraxion/Module/RelatedArticles/Resources/doctrine/RelatedArticleGroup.orm.xml
- _core/model/classes/atx/articles/Article.php
- _core/config/doctrine/articles.Article.orm.xml
- src/namespaced_functions.php
- _core/view/classes/atx/articles/ArticleDetailView.php
- _core/view/classes/atx/customers/cart/CartView.php
- _core/config/doctrine/migrations/2024/11/Version20241105123552.php
- _core/config/doctrine/migrations/2024/11/Version20241125093540.php
Legacy Capabilities (As-Is)¶
1. Admin Entry Points Across Product Verticals (AD-016, AD-019, AD-021)¶
Legacy admin exposes related-article management under all three product domains:
- Wheels menu entry -> admin.relatedArticles_importExport
- Tyres menu entry -> admin.relatedArticles_importExport
- Accessories menu entry -> admin.relatedArticles_importExport
The same controller route key (admin.relatedArticles) is used for all actions.
From product detail pages, operators can open one dialog with three tabs:
1. Current related articles (browse)
2. Add related articles (add)
3. Import/export related articles (importExport)
2. Relationship Semantics (MK-008)¶
Related links are grouped and configured per group with these behaviors:
- required:
- true = required products shown in add-to-cart context
- false = cross-sell products shown in checkout/cart context
- mirrored:
- true = relation can work both ways (fallback from related article back to main article)
- false = one-way from main article only
- vehicleSpecific:
- if enabled, only suggest related wheels/accessories linked to the active vehicle model
- sorting strategy:
- orderByFirst and orderBySecond
- supported values: total_sold and importance
3. Storefront Consumption (MK-008)¶
Legacy helpers expose:
- product_get_related(...)
- cart_get_related_articles(...)
Observed storefront behavior:
1. Product-detail ordered state requests product_get_related(..., onlyRequired: true) and renders required products.
2. Cart page requests cart_get_related_articles(...) and renders cross-sell suggestions.
3. Vehicle-specific groups are filtered by vehicle fitment checks (article_wheel_vehicle, article_acc_vehicle).
4. Cart-related suggestion logic removes duplicates and removes items already in cart.
4. Admin Operations¶
AdminRelatedArticlesController and its view support:
- Browse current grouped links, update group settings, update per-link importance, remove selected links.
- Search catalog candidates with category/brand/ID/EAN/description and wheel/tyre/accessory-specific filters.
- Add selected links in bulk with group flags and sorting settings.
- Export one article’s links to XLSX.
- Export all related links to XLSX and also store a backup file.
- Import related links from XLSX with per-run group settings.
Validation and guard behavior visible in repository/services: - Duplicate article/related-article pairs are blocked by DB unique constraint. - Import records generate errors for: - missing target articles - non-purchasable targets - products with mounting hours (disallowed for linking)
Legacy Data Model (DM-011)¶
Core tables¶
article_related(RelatedArticle):- relation row id
article_id(main article FK)related_article_id(related article FK)group_id(FK to group config)importancecreated_at,created_by_id-
uniqueness on (
article_id,related_article_id) -
article_related_group(RelatedArticleGroup): - group id
- behavior flags:
required,mirrored,vehicleSpecific - sorting:
orderByFirst,orderBySecond - optional
externalId -
created_at,created_by_id -
Articleaggregate integration: - one-to-many
relatedArticlesmapping (indexed by related article id) - helper methods for add/find/has relation in domain object
Migration history nuance¶
Legacy migration sequence shows model evolution:
- links table introduced first
- flags initially stored directly on link rows
- later moved to dedicated group table
- migration Version20241125093540 includes a destructive reset (DELETE + TRUNCATE) before regrouping
This reset behavior is a migration-risk signal for historical data preservation in the Symfony target.
Current Gaps And Risks To Resolve In Migration¶
- Import creates one new group per import run and applies global settings, limiting mixed-group imports in one file.
- Group-sheet import path exists in code but is currently disabled/commented in the active importer flow.
- Full export triggers immediate browser output and
exit, coupling export to controller lifecycle. - Backup files are written directly to static downloads without explicit retention policy.
- Vehicle-specific filtering uses direct SQL table checks in service logic; contracts are implicit.
- Legacy sort comparator behavior is code-driven and should be explicitly specified in target contracts.
- Historical migration includes destructive reset semantics that should not be repeated unintentionally.
Target Migration Specification (Symfony)¶
Scope¶
In-scope: - Related-article domain model and retrieval logic. - Admin management UI/API for add/update/remove/search. - XLSX import/export operational workflows. - Vehicle-specific filtering parity.
Out-of-scope: - Redesign of merchandising strategy beyond current required/cross-sell semantics.
Domain Rules To Preserve¶
- Relations are group-based and carry group-level behavior flags.
- Required products and cross-sells remain distinct retrieval modes.
- Mirrored behavior remains supported for reverse lookup.
- Vehicle-specific groups only surface links compatible with active vehicle context.
- Duplicate
(article, related_article)links are prevented.
Required Improvements¶
- Replace destructive migration assumptions with safe, incremental upsert migration for legacy data.
- Add explicit import dry-run/validation mode before applying writes.
- Define import contract for multi-group files (including external group IDs) and support it end-to-end.
- Move export and large import processing to async jobs with progress/audit records.
- Add retention policy and housekeeping for generated export backups.
- Document deterministic sorting semantics and ensure tests lock that behavior.
Suggested Target Components¶
RelatedArticleController(admin API)RelatedArticleImportController/RelatedArticleExportControllerRelatedArticleServiceRelatedArticleVehicleMatcherRelatedArticleImportServicewith dry-run report DTORelatedArticleExportServicewith queued job option
Acceptance Scenarios (Gherkin)¶
Feature: Related articles module and import/export
Scenario: Add grouped related articles from admin search
Given an admin searches candidate articles for a main article
When the admin selects multiple candidates with group settings
Then related links should be created under one configured group
And duplicate links should be rejected
Scenario: Required products appear on product ordered state
Given a product has related links in a required group
When the product ordered panel is rendered
Then required related products should be returned by the related-articles service
Scenario: Cross-sell products appear in cart and exclude existing cart items
Given cart items have non-required related links
When cart cross-sell suggestions are loaded
Then returned articles should exclude already present cart items
Scenario: Vehicle-specific group filters incompatible wheels/accessories
Given a related group is marked vehicle specific
And a vehicle model context is provided
When related products are resolved
Then incompatible wheel/accessory links should be excluded
Scenario: Import reports invalid related rows without aborting valid rows
Given an XLSX contains valid and invalid related-article rows
When import runs
Then valid rows should be persisted
And importErrors should list invalid rows
Scenario: Export all related links creates operator-downloadable file and backup
Given related links exist in the system
When admin exports all related articles
Then an XLSX should be returned for download
And a backup file should be written to configured export storage
Open Decisions¶
- Should mirrored links stay as group behavior or become explicit directional records in target schema.
- Should import support group creation from file metadata only, UI defaults only, or both.
- Should export backups move from web-accessible static storage to private object storage.
- Should vehicle-specific checks be generalized behind a shared fitment service for all merchandising modules.