# 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.