feat: Track A frontend - analytics event pipeline core + real call sites
core/analytics (AnalyticsEvent model, gateway/token/mock, AnalyticsService wrapper) against docs/backend/TRACK-A-ANALYTICS-CONTRACT.md §1. isSynthetic is derived from the build environment at the service layer, never client-settable at a call site - matches the contract's §6 requirement that synthetic traffic be inseparable-by-accident from production data once a real backend exists. Wired into real, live interaction points (additive only, no existing logic touched): product_view + add_to_cart in product-details-container.component.ts, checkout_started + payment_started in pages/cart/cart.component.ts. This is the actual event-firing infrastructure the plan calls "the single largest remaining backend effort" (§3.1) - the frontend side (call sites) is real now; the mock gateway just doesn't persist anywhere yet. Not wired: search/category_view/seller_view/cart_view/payment_success/ payment_failed/order_created - follow-up call sites once this pattern is reviewed, to avoid a much larger unreviewed diff in one push. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -17,6 +17,7 @@ import { DEFAULT_PRODUCT_PAGE_CONFIG, DEFAULT_USER_EXPERIENCE_CONFIG, ProductPag
|
||||
import { getStockStatus, getTranslatedField } from '../../../../utils/item.utils';
|
||||
import { ProductShareService } from '../../user-experience/services/product-share.service';
|
||||
import { SeoService } from '../../../../services/seo.service';
|
||||
import { AnalyticsService } from '../../../../core/analytics/services/analytics.service';
|
||||
import { ApiService } from '../../../../services/api.service';
|
||||
import { LocalStorageService } from '../../../../core/storage/local-storage.service';
|
||||
import { UserNotificationService } from '../../user-experience/services/user-notification.service';
|
||||
@@ -78,6 +79,7 @@ export class ProductDetailsContainerComponent {
|
||||
private readonly translate = inject(TranslateService);
|
||||
private readonly shareService = inject(ProductShareService);
|
||||
private readonly seoService = inject(SeoService);
|
||||
private readonly analytics = inject(AnalyticsService);
|
||||
private readonly apiService = inject(ApiService);
|
||||
private readonly storage = inject(LocalStorageService);
|
||||
private readonly notifications = inject(UserNotificationService);
|
||||
@@ -276,6 +278,7 @@ export class ProductDetailsContainerComponent {
|
||||
|
||||
this.product.set(product);
|
||||
this.seoService.setItemMeta(product);
|
||||
this.analytics.track('product_view', { itemID: product.itemID });
|
||||
if (this.userExperienceConfig().recentlyViewed.enabled) {
|
||||
this.uxFacade.trackRecentlyViewed(product, this.userExperienceConfig().recentlyViewed.maxItems);
|
||||
}
|
||||
@@ -321,6 +324,7 @@ export class ProductDetailsContainerComponent {
|
||||
addToCart(): Promise<void> {
|
||||
const current = this.product();
|
||||
if (!current) return Promise.resolve();
|
||||
this.analytics.track('add_to_cart', { itemID: current.itemID, price: this.effectivePrice(), currency: this.effectiveCurrency() });
|
||||
return this.cartService.addItem(current.itemID, 1, {
|
||||
colour: this.selectedColour() ?? undefined,
|
||||
size: this.selectedSize() ?? undefined,
|
||||
|
||||
Reference in New Issue
Block a user