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¶
- Unsubscribe applies opt-out on initial page load (before explicit reason submit), which may need explicit consent handling in the new app.
- Guarantee flow is mail-only (no case/ticket persistence), limiting traceability and reporting.
- Guarantee recipient (
logs@atraxion.com) is hardcoded in legacy implementation. - Customer-only flows rely on route/controller conventions that are not explicitly documented in existing specs.
- 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¶
- Unsubscribe remains idempotent for repeated requests for the same email.
- Guarantee submit requires bot protection and strict server-side validation.
- Customer-only catalog pages require authenticated user context.
- Brand-based visibility constraints must be preserved.
- Postcode helper must fail safely (empty results, no hard failure in UI flow).
Suggested Target Components¶
UnsubscribeController+SubscriptionPreferenceServiceGuaranteeRegistrationController+GuaranteeSubmissionServiceCustomerCatalogController(or dedicated area/controllers) for protected wheel/accessory routesPostcodeLookupController+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¶
- Should unsubscribe stay path-param based or move to signed-token links with explicit confirmation step.
- Should guarantee submissions become persisted records (ticket/case) instead of mail-only.
- Should customer detail routes enforce explicit auth guards independently from list-page entry.
- Should postcode lookups be cached per
(postcode, country)with per-tenant limits.