Status: Target Architecture
Audience: Product, Engineering, Tagging Teams
Date: 2026-06-15
Multiple Tagging Teams
├── Team A: Uses satellite.track("event_name", data)
├── Team B: Uses window.digitaldata = {...} (server-side injection)
├── Team C: Uses window.digitaldata = {...} (client-side mutation)
└── Team D: Custom event helpers
All paths lead to → Adobe Launch → Adobe Analytics
Problem: Same event tracked 4 different ways. Regressions happen when shared code changes.
One Unified Contract Layer
↓
App-Level Analytics Builders (business mapping + digitaldata shape)
↓
One Thin Shared SDK (core only)
├── Validate payload
├── Pick dispatch path
└── Call satellite or dataLayer adapter
↓
One Dispatch Path to Adobe Launch
↓
Production Validation and Monitoring
apps/@nvc/search/analytics/contracts).| Area | Allowed in App Layer | Allowed in Shared SDK |
|---|---|---|
| Business event meaning | Yes | No |
| Payload field mapping | Yes | No |
| Feature/page conditions | Yes | No |
| App/domain TypeScript types | Yes | No |
| Contract validation | No | Yes |
| Dispatch routing | No | Yes |
| satellite/dataLayer call | Optional (legacy only) | Yes |
File: apps/@nvc/search/analytics/contracts/search-filter.ts
import { z } from "zod";
export const SEARCH_FILTER_APPLIED = {
name: "SEARCH_FILTER_APPLIED",
version: "1.0.0",
schema: z.object({
filterId: z.string(),
filterValue: z.string(),
vehicleType: z.enum(["sedan", "suv", "truck"]),
market: z.enum(["us-en", "ca-en", "za-en"]),
timestamp: z.number(),
}),
};
File: apps/@nvc/search/components/filterPanel.tsx
import { analytics } from "@analytics/sdk";
import { SEARCH_FILTER_APPLIED } from "../analytics/contracts/search-filter";
export function FilterPanel() {
const handleFilterChange = (filter) => {
// App owns business mapping and payload shape
const eventPayload = {
filterId: filter.id,
filterValue: filter.value,
vehicleType: "sedan",
market: "za-en",
timestamp: Date.now(),
};
analytics.track(SEARCH_FILTER_APPLIED.name, eventPayload);
};
return <div data-removed={handleFilterChange}>...</div>;
}
File: packages/@analytics/sdk/index.ts
export function track(eventName: string, payload: any) {
// Validate against contract
const contract = getContract(eventName);
const validated = contract.schema.parse(payload); // throws if invalid
// Route by policy and dispatch
// No business mapping here
const enriched = applyDispatchMetadata(validated);
const policy = getDispatchPolicy(eventName);
if (policy === "satellite") {
window._satellite?.track(eventName, enriched);
} else if (policy === "dataLayer") {
window.digitaldata.push({
event: eventName,
data: enriched,
});
}
// Log for observability
logEvent(eventName, enriched);
}
Add analytics for search filter events in South Africa market. Events: filter-apply, filter-clear, filter-reset. Include filter ID, value, and result count.
Updates Market Policy
Generates SDK Usage in App
Generates Tests
Opens PR
You approve. Done.
Week 1-2: Foundation
packages/@analytics/sdkapps/@nvc/search/analytics/contracts)Week 3-4: Consolidate
Week 5-6: Agent Setup
Week 7+: Autonomous
| Phase | Effort | Timeline | You Get |
|---|---|---|---|
| Foundation | Med | 2 weeks | Contract + SDK framework |
| Consolidation | Med | 2 weeks | Teams migrated to one SDK |
| Agent MVP | High | 4 weeks | Prompt → PR for new events |
| Production-Ready | Med | 2 weeks | Drift detection + auto-merge policy |
| Total | 10 weeks | Full autonomous delivery |
| Metric | Before | After |
|---|---|---|
| Time to add market to event | 1-2 days | 1 PR (2 hours) |
| Analytics regression rate | 2-3 per month | < 1 per month |
| Regression root cause identified | 3-5 days | Auto-detected in 1 hour |
| Cross-team event consistency | 60% | 99% |
| Manual coding per feature event | 4-6 hours | 0 hours |
Once foundation is live, the agent works like this:
User: "Add tracking for loan calculator in US and ZA"
Agent: "I found calculator in nvc/financing. Need clarification:
1. Should we track open, input-change, and submit? (yes/no)
2. Include loan amount and term as payload? (yes/no)"
User: "yes, yes"
Agent: ✓ Generates contracts ✓ Updates policies ✓ Generates code
✓ Generates tests ✓ Opens PR
You: Review (2 mins) → Approve
System: Merge + Deploy + Monitor
One SDK, many dispatch options.
(Answers help agent understand existing patterns and generate compatible code.)
(Answers help prioritize agent features.)
Today: Multiple teams, multiple approaches, fragile shared code, regressions when shared code changes.
Tomorrow: One contract, one SDK, one entry point. Agent generates code, validates with tests, delivers PR. Teams never manually code analytics again. Market rollouts are config changes, not code reviews.
Result: Faster, more reliable, fewer regressions, less manual work.