Skip to content

Webshop - Legacy Edge Flows And Public Helpers

Overview

This document specifies legacy customer-facing edge flows and helper endpoints that exist in the current webshop but were not previously captured in migration specs.

Checklist coverage: - WF-036 Unsubscribe flow (instant opt-out + reason capture) - WF-037 Guarantee registration form (captcha + email dispatch) - WF-038 Pewag branded landing page - WF-039 Customer-only wheel/accessory pages with auth and brand gating - WF-040 Customer wheel/accessory search and detail route set - API-019 Postcode-to-city helper endpoint (postcode/getCitiesByPostcode)

Primary legacy evidence: - _core/config/pages.xml - _core/config/routing.php - _core/controller/classes/atx/customers/UnsubscribeController.php - _core/model/dbclasses/atx/customers/SubscriptionDAO.php - _core/view/classes/atx/customers/UnsubscribeView.php - _core/controller/classes/atx/customers/GuaranteeController.php - _core/model/classes/atx/customers/GuaranteeMail.php - _core/view/classes/atx/customers/GuaranteeView.php - _core/controller/classes/atx/pewag/PewagController.php - _core/controller/classes/atx/customers/articles/* - _core/view/classes/atx/customers/articles/* - _core/controller/classes/atx/system/PostcodeController.php - _core/view/classes/atx/system/PostcodeView.php - _static/js/atx/customers/guarantee.js

Legacy Capabilities (As-Is)

1. Unsubscribe Flow (WF-036)

Entry point: - Page route unsubscribe from _core/config/pages.xml.

Behavior: 1. Email is required as path param (param 1). 2. Opening the page already writes an unsubscribe record (without reason yet). 3. POST allows selecting predefined reasons; "other" requires free text. 4. On submit, unsubscribe reason is persisted.

Data model semantics (SubscriptionDAO): - Presence of a subscription row means "unsubscribed". - Absence of a row means "subscribed".

2. Guarantee Registration Flow (WF-037)

Entry point: - Page route guarantee from _core/config/pages.xml.

Behavior: 1. Public form captures dealer/customer identity, address, birth date, vehicle/tyre info, mounting date, and contact details. 2. Google reCAPTCHA token is mandatory and validated server-side (ReCaptchaAPI). 3. Mounting date must be a past date. 4. On success, no domain entity is created; the flow sends one email with form data to logs@atraxion.com.

Implementation notes: - Mail tag used: CUSTOMER_REQUEST. - Frontend helper uses postcode Ajax to suggest city names.

3. Pewag Landing Page (WF-038)

Entry point: - Page route pewag from _core/config/pages.xml.

Behavior: - Dedicated branded page/controller exists, but controller logic is intentionally empty. - Effective behavior is static CMS/page rendering.

4. Customer-Only Wheel/Accessory Flows (WF-039, WF-040)

Page-level entry points: - customer-wheels - customer-accessories

Custom route/controller aliases: - customer.wheelSearch - customer.wheel - customer.accSearch - customer.acc

Behavior differences versus public catalog: 1. customer-wheels and customer-accessories pages enforce authentication before rendering listings. 2. Brand visibility is constrained by Guard::canUserSeePageWithBrand(...). 3. Customer wheel view suppresses standard search-form rendering. 4. Customer accessory view disables tabs and uses dedicated sorting/filter defaults. 5. Customer accessory search enriches filters from Odoo spec values: - product_dedicated_car_model mapped to filter model (required) - product_materials mapped to filter material

Important legacy nuance: - The explicit auth/brand checks are implemented in the page controllers (WheelController, AccController) for list pages. - Customer detail controller classes are thin extensions of base detail controllers.

5. Postcode Helper Endpoint (API-019)

Route: - postcode/getCitiesByPostcode (legacy controller/action routing).

Request contract: - Method: GET - Params: postcode (required), country (required)

Response contract: - Buffered key cities containing a city-name list (used client-side as response.data.cities).

Runtime behavior: 1. Calls GeonamesAPI::getCitiesByPostcode(postcode, country). 2. On provider exception, returns empty city list. 3. Frontend usage in guarantee form triggers lookup once postcode length >= 3.

Current Gaps And Risks To Resolve In Migration

  1. Unsubscribe applies opt-out on initial page load (before explicit reason submit), which may need explicit consent handling in the new app.
  2. Guarantee flow is mail-only (no case/ticket persistence), limiting traceability and reporting.
  3. Guarantee recipient (logs@atraxion.com) is hardcoded in legacy implementation.
  4. Customer-only flows rely on route/controller conventions that are not explicitly documented in existing specs.
  5. Postcode endpoint has no explicit throttling/rate-limit/circuit-breaker contract.

Target Migration Specification (Symfony)

Scope

In-scope: - Unsubscribe experience and persistence semantics. - Guarantee form validation + secure submission pipeline. - Customer-only wheel/accessory listing/search behavior. - Postcode helper API contract. - Pewag page treatment as explicit static-content decision.

Out-of-scope: - Redesign of guarantee product/policy terms. - New external geolocation providers (unless decided separately).

Required Domain Rules

  1. Unsubscribe remains idempotent for repeated requests for the same email.
  2. Guarantee submit requires bot protection and strict server-side validation.
  3. Customer-only catalog pages require authenticated user context.
  4. Brand-based visibility constraints must be preserved.
  5. Postcode helper must fail safely (empty results, no hard failure in UI flow).

Suggested Target Components

  • UnsubscribeController + SubscriptionPreferenceService
  • GuaranteeRegistrationController + GuaranteeSubmissionService
  • CustomerCatalogController (or dedicated area/controllers) for protected wheel/accessory routes
  • PostcodeLookupController + PostcodeLookupService
  • Config-backed recipients for guarantee notifications

API Contract Notes

Suggested target endpoint: - GET /api/postcodes/{postcode}/cities?country=BE

Suggested response:

{
  "data": {
    "cities": ["Antwerpen", "Berchem"]
  },
  "meta": {
    "source": "geonames",
    "cache_hit": true
  }
}

Acceptance Scenarios (Gherkin)

Feature: Legacy edge flows and helper APIs

  Scenario: Unsubscribe with reason
    Given I open the unsubscribe page with a valid email tokenized URL
    When I submit reason "No interest"
    Then the email should be marked unsubscribed
    And the reason should be stored

  Scenario: Guarantee form requires captcha
    Given I fill all guarantee form fields
    When captcha token is missing or invalid
    Then submission should be rejected with validation errors

  Scenario: Guarantee form sends notification
    Given I submit a valid guarantee registration
    Then one customer-request notification should be created or sent to configured recipients

  Scenario: Customer wheel page requires authentication
    Given I am not authenticated
    When I open the customer wheel catalog page
    Then I should be redirected to home/login flow

  Scenario: Customer accessory search includes model and material filters
    Given I am authenticated on customer accessories
    When search data is loaded
    Then model and material filters should be available when spec values exist

  Scenario: Postcode helper returns city suggestions
    Given I request cities for postcode "2000" and country "BE"
    When provider lookup succeeds
    Then response should include a non-empty cities array

  Scenario: Postcode helper fails safely
    Given provider lookup throws an exception
    When I request cities by postcode
    Then response should contain an empty cities array
    And request should still return a successful API response

Open Decisions

  1. Should unsubscribe stay path-param based or move to signed-token links with explicit confirmation step.
  2. Should guarantee submissions become persisted records (ticket/case) instead of mail-only.
  3. Should customer detail routes enforce explicit auth guards independently from list-page entry.
  4. Should postcode lookups be cached per (postcode, country) with per-tenant limits.