Skip to content

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

  1. article_related (RelatedArticle):
  2. relation row id
  3. article_id (main article FK)
  4. related_article_id (related article FK)
  5. group_id (FK to group config)
  6. importance
  7. created_at, created_by_id
  8. uniqueness on (article_id, related_article_id)

  9. article_related_group (RelatedArticleGroup):

  10. group id
  11. behavior flags: required, mirrored, vehicleSpecific
  12. sorting: orderByFirst, orderBySecond
  13. optional externalId
  14. created_at, created_by_id

  15. Article aggregate integration:

  16. one-to-many relatedArticles mapping (indexed by related article id)
  17. 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

  1. Import creates one new group per import run and applies global settings, limiting mixed-group imports in one file.
  2. Group-sheet import path exists in code but is currently disabled/commented in the active importer flow.
  3. Full export triggers immediate browser output and exit, coupling export to controller lifecycle.
  4. Backup files are written directly to static downloads without explicit retention policy.
  5. Vehicle-specific filtering uses direct SQL table checks in service logic; contracts are implicit.
  6. Legacy sort comparator behavior is code-driven and should be explicitly specified in target contracts.
  7. 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

  1. Relations are group-based and carry group-level behavior flags.
  2. Required products and cross-sells remain distinct retrieval modes.
  3. Mirrored behavior remains supported for reverse lookup.
  4. Vehicle-specific groups only surface links compatible with active vehicle context.
  5. Duplicate (article, related_article) links are prevented.

Required Improvements

  1. Replace destructive migration assumptions with safe, incremental upsert migration for legacy data.
  2. Add explicit import dry-run/validation mode before applying writes.
  3. Define import contract for multi-group files (including external group IDs) and support it end-to-end.
  4. Move export and large import processing to async jobs with progress/audit records.
  5. Add retention policy and housekeeping for generated export backups.
  6. Document deterministic sorting semantics and ensure tests lock that behavior.

Suggested Target Components

  • RelatedArticleController (admin API)
  • RelatedArticleImportController / RelatedArticleExportController
  • RelatedArticleService
  • RelatedArticleVehicleMatcher
  • RelatedArticleImportService with dry-run report DTO
  • RelatedArticleExportService with 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

  1. Should mirrored links stay as group behavior or become explicit directional records in target schema.
  2. Should import support group creation from file metadata only, UI defaults only, or both.
  3. Should export backups move from web-accessible static storage to private object storage.
  4. Should vehicle-specific checks be generalized behind a shared fitment service for all merchandising modules.