This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
# Architecture Conventions
|
||||
|
||||
## Deployment Conventions
|
||||
|
||||
### Multi-brand testing requirement
|
||||
|
||||
Any code change to shared services (audit pipeline, site-tag-analytics,
|
||||
synthesizers, categorizers, conversion type registry) must be verified
|
||||
against at least:
|
||||
|
||||
- One medical brand (cardiology or imaging) for dense events, multi-language
|
||||
data shapes, and HIPAA-relevant surfaces
|
||||
- One service brand (lawn care portfolio) for high-volume events and
|
||||
multi-domain reconciliation
|
||||
- One B2B brand (TPAction / AiGrowth360) for low-event-volume edge cases
|
||||
and lead gen flows
|
||||
- One ecommerce brand if available for product schema and checkout flows
|
||||
|
||||
Verification recipes must specify at least two brands of different verticals.
|
||||
"Verify on cardiology" alone is insufficient.
|
||||
|
||||
Single-brand verification was the root cause of the Phase 19A.16 missed
|
||||
form_filled crash on Fairway Lawns (May 27, 2026).
|
||||
|
||||
### Conversion type registration requirement
|
||||
|
||||
Before merging any change to shared event or conversion categorization code,
|
||||
run the comprehensive type discovery SQL:
|
||||
|
||||
```sql
|
||||
SELECT "brandId", "conversionType", COUNT(*)
|
||||
FROM "SiteConversion"
|
||||
WHERE timestamp >= NOW() - INTERVAL '30 days'
|
||||
AND "conversionType" NOT IN (
|
||||
'appointment_booked','form_submitted','phone_call','email_contact',
|
||||
'sms_contact','purchase','appointment_attempted','form_started',
|
||||
'appointment_intent','chat_initiated','newsletter_signup','add_to_cart',
|
||||
'checkout_started','file_download','waitlist_signup','form_filled',
|
||||
'form_submit','form_submission','phone_number_click','click_to_call',
|
||||
'calendly','booking_confirmed','booking_attempt','email_click',
|
||||
'sms_click','phone_copy','phone_input','form_iframe_present',
|
||||
'error_count_update'
|
||||
)
|
||||
GROUP BY "brandId", "conversionType"
|
||||
ORDER BY count DESC;
|
||||
```
|
||||
|
||||
Confirm zero rows returned, or explicitly handle every type returned before
|
||||
shipping.
|
||||
|
||||
New types must be registered in:
|
||||
1. `SITE_CONVERSION_TYPES` in `src/lib/services/site-tag-analytics.ts`
|
||||
(query allowlist -- unregistered types are silently dropped)
|
||||
2. `CONVERSION_TIERS` in `src/lib/conversions/tiers.ts`
|
||||
(tier mapping -- unregistered types crash route.ts via undefined key lookup)
|
||||
|
||||
The defensive guard at `src/app/api/site-tag/analytics/route.ts` around
|
||||
the `tierTotals[cfg.tier]` access will log a warning and skip rather than
|
||||
crash for any future type that slips through, but the correct fix is always
|
||||
to register the type proactively.
|
||||
|
||||
### Tier assignment guidelines
|
||||
|
||||
| Tier | Description | isCounted | Examples |
|
||||
|------|-------------|-----------|---------|
|
||||
| completed | Definitive conversion action | true | form_submit, phone_call, appointment_booked, purchase |
|
||||
| intent | Started a conversion flow | false | form_filled, appointment_attempted, checkout_started |
|
||||
| signal | Engagement only (no conversion flow) | false | phone_copy, phone_input, form_iframe_present |
|
||||
|
||||
The `DEFAULT_COUNTED_TIERS` constant controls which tiers roll up into the
|
||||
headline conversion count and conversion rate. Only "completed" is counted
|
||||
by default. Brand-level overrides via `BrandConversionConfig.isCounted` can
|
||||
promote intent signals to counted status for specific brands.
|
||||
Reference in New Issue
Block a user