# GTM Startup Region Display

## Table of Contents

- [GTM Startup Region Display](#gtm-startup-region-display)
  - [Table of Contents](#table-of-contents)
  - [Introduction](#introduction)
  - [Motivation or Background](#motivation-or-background)
  - [Detailed Design](#detailed-design)
  - [Test Design](#test-design)
    - [Functional Tests](#functional-tests)
    - [Scenario Tests](#scenario-tests)
    - [Compatibility Tests](#compatibility-tests)
  - [Impacts \& Risks](#impacts--risks)
  - [Unresolved Questions](#unresolved-questions)

## Introduction

This document proposes a refinement to the DevOps user behavior startup event flow used by GTM notifications. Startup tenant cards should use tenant Salesforce region as the primary business region when it is available, while allowing the Lark card display region to show LATAM or EMEA when company headquarters enrichment indicates a LATAM or EMEA headquarters.

## Motivation or Background

The current startup tenant notification text is built from `startupUBEvent.bizRegion`:

```text
[ NA ] New non-individual tenant qd's Org(id: 1372813089209331573).
Email domain is 2925.com
```

For startup events, `bizRegion` is currently derived from the account service org country:

```go
ret.country = org.GetCountry()
bizRegion := string(region.CountryToRegion(strings.ToUpper(ret.country)))
v.bizRegion = &bizRegion
```

This means a tenant whose account country maps to NA will show NA even if the tenant service has a more accurate `SalesForceRegion`. It also means LATAM companies can be displayed as NA when the tenant's business region is NA, even if enrichment identifies the company headquarters as LATAM.

The goal is to make the startup GTM notification easier for sales and GTM reviewers to interpret without changing GTM lead persistence or email delivery history schemas.

Non-goals:

- Do not add a region column to `gtm_leads` or `gtm_sent_emails`.
- Do not change user behavior subscription storage.
- Do not infer headquarters region by free-form string matching if a structured country code can be used.
- Do not make tenant service lookup failure block startup notifications.

## Detailed Design

### Current Data Flow

The startup event enters through `HandleDBaasAITenantEvent`, which creates a `startupUBEvent` and dispatches it through `DispatchUBEvents`.

During `PreprocessUBEvent`, the startup branch:

1. Loads org data from account service by `OrgId`.
2. Sets `tenantName` from `org.Name`.
3. Sets `country` from `org.GetCountry()`.
4. Computes `bizRegion` by `region.CountryToRegion(country)`.
5. Extracts `emailDomain` from `org.Email`.
6. Runs enrichment.
7. Uses `bizRegion` for subscription filtering, GTM geo gating, and card display.

`bizRegion` is not persisted in `GTMLead` or `GTMSentEmail`. It is an in-memory event field.

### Proposed Region Semantics

Split region usage into two concepts:

- `bizRegion`: the business region used for subscription filtering and GTM geo gating.
- `displayRegion`: the region rendered in the Lark card header text.

`bizRegion` should prefer tenant Salesforce region when it is available:

1. Load account org as today.
2. Compute fallback region from `org.Country`.
3. Best-effort load tenant from `tenantSvc.GetTenant(ctx, orgID)`.
4. If `tenant.SalesForceRegion` is set and not `UNKNOWN`, use it as `bizRegion`.
5. Otherwise keep the fallback region from account country.

Tenant service errors should be logged and should fall back to the current account-country behavior. This avoids dropping notifications during the org activation path if tenant data is not yet available.

Pseudo-code:

```go
country := strings.ToUpper(org.GetCountry())
bizRegion := string(region.CountryToRegion(country))

tenant, err := s.tenantSvc.GetTenant(ctx, v.OrgId)
if err != nil {
    logger.Info("fallback to account country region for startup event", "tenant_id", v.OrgId, "error", err)
} else if tenant.SalesForceRegion != tntent.TenantRegionUnknown {
    bizRegion = string(tenant.SalesForceRegion)
}

v.bizRegion = &bizRegion
ret.bizRegion = bizRegion
ret.country = org.GetCountry()
```

### Headquarters Display Override

If enrichment determines that the company's headquarters belongs to LATAM or EMEA, the Lark card should display that headquarters region even when the business region is different.

This should affect card display only. It should not change:

- subscription region matching;
- `GTM.EnabledGeoSelectors` matching;
- `GTMLead` or `GTMSentEmail` persisted fields;
- email queueing, sending, or suppression behavior.

The preferred implementation is to extend GTM enrichment parsing with a structured headquarters country code:

```json
{
  "company_name": "Example",
  "headquarter": "Mexico City, Mexico",
  "headquarter_country_code": "MX",
  "vertical": "SaaS",
  "business_model": "B2B",
  "approximate_annual_revenue": "Unknown",
  "funding_series": "Unknown",
  "ai_confidence_level": "high"
}
```

Then derive headquarters region by existing region mapping:

```go
displayRegion := *e.bizRegion
if enrichment.HeadquarterCountryCode != "" {
    hqRegion := region.CountryToRegion(strings.ToUpper(enrichment.HeadquarterCountryCode))
    if hqRegion == tntent.TenantRegionLATAM || hqRegion == tntent.TenantRegionEMEA {
        displayRegion = string(hqRegion)
    }
}
```

The card builders should render `displayRegion` instead of directly rendering `*e.bizRegion`.

Recommended structural change:

- Add optional `displayRegion *string` to `startupUBEvent`.
- Set it after enrichment if headquarters country maps to LATAM or EMEA.
- Keep `bizRegion` unchanged for filters and GTM geo gate.
- Provide a helper such as `startupDisplayRegion()` so both `DefaultText` and `buildGTMResultCard` use the same display logic.

Example:

```go
func (e *startupUBEvent) startupDisplayRegion() string {
    if e.displayRegion != nil && *e.displayRegion != "" {
        return *e.displayRegion
    }
    if e.bizRegion != nil {
        return *e.bizRegion
    }
    return string(tntent.TenantRegionUnknown)
}
```

### Enrichment Parser Changes

`pkg/service/userbehavior/gtm.CompanyEnrichment` should add:

```go
HeadquarterCountryCode string
```

`ParseEnrichmentJSON` should read `headquarter_country_code`. Text fallback can leave the field empty unless a future prompt or parser format makes a country code reliable.

The enrichment prompt should ask the LLM to return ISO 3166-1 alpha-2 `headquarter_country_code`. If the country is unknown, it should return an empty string.

### Compatibility

Existing enrichment responses without `headquarter_country_code` remain valid. JSON unmarshalling leaves the new field empty, and display falls back to the normal business region.

Existing GTM lead and sent email rows remain compatible because no schema changes are required.

Existing subscriptions remain compatible because region filtering continues to use `eventInfo.bizRegion`, not `displayRegion`.

## Test Design

### Functional Tests

Add or update Ginkgo tests around `PreprocessUBEvent` startup handling:

- `SalesForceRegion=EMEA` and account country `US` results in `bizRegion=EMEA`.
- `SalesForceRegion=UNKNOWN` and account country `US` results in `bizRegion=NA`.
- tenant service returns an error and account country `US` results in fallback `bizRegion=NA`.

Add parser tests in `pkg/service/userbehavior/gtm`:

- JSON enrichment with `headquarter_country_code` populates `CompanyEnrichment.HeadquarterCountryCode`.
- JSON enrichment without `headquarter_country_code` still parses successfully with an empty field.

Add card rendering tests for `startupUBEvent`:

- `bizRegion=NA` and `displayRegion=LATAM` renders `[ LATAM ]`.
- `bizRegion=NA` and `displayRegion=EMEA` renders `[ EMEA ]`.
- `bizRegion=NA` and no `displayRegion` renders `[ NA ]`.
- Both `DefaultText` and GTM custom card use the same display region.

### Scenario Tests

Scenario 1: account country is `US`, tenant Salesforce region is `EMEA`.

- Subscription filtering and GTM geo gating use `EMEA`.
- Card displays `EMEA` unless headquarters override applies.

Scenario 2: account country is `US`, tenant Salesforce region is `NA`, enrichment HQ country is `MX`.

- Subscription filtering and GTM geo gating use `NA`.
- Card displays `LATAM`.
- GTM lead and sent email records do not store LATAM unless already present in raw enrichment text.

Scenario 3: tenant service lookup fails during activation.

- Startup notification still proceeds using account country region.
- Logs include the fallback reason.

### Compatibility Tests

- Verify existing startup card tests pass for enrichment responses without headquarters country code.
- Verify existing GTM geo selector tests continue to use `bizRegion` and country.
- Verify no migration is required and existing `gtm_leads` / `gtm_sent_emails` models are unchanged.

## Impacts & Risks

Impacts:

- Startup GTM cards will display regions that better match Salesforce ownership and LATAM headquarters review needs.
- GTM geo gating can change for startup events when tenant Salesforce region differs from account country derived region.
- No database migration is required.

Risks:

- Tenant service data may not exist at org activation time. The design mitigates this by falling back to account country region.
- Salesforce region may be stale or inconsistent with account country. This is intentional because Salesforce region is the requested business-region source of truth.
- LLM enrichment may produce an incorrect headquarters country code. The LATAM override is limited to display only to avoid changing delivery behavior based on uncertain enrichment.
- If future reviewers expect the card region to match the GTM geo gate exactly, `LATAM` display override could be confusing. The card may need an additional enrichment line showing headquarters country/region if that becomes a concern.

## Unresolved Questions

- Should LATAM display override apply only when enrichment confidence is `high` or `medium`, or should it apply whenever `headquarter_country_code` maps to LATAM?
- Should the card explicitly show both business region and headquarters region, for example `NA / HQ LATAM`, instead of replacing the visible region with `LATAM`?
- Should non-startup user behavior events adopt the same Salesforce region preference, or should this remain scoped to startup GTM notifications?
