# EMEA Lambda Tasks

This directory groups the EMEA Lambda codebases in one clean layout.

- `monitor/`: active tenant monitor fan-out dispatcher/worker code.
- `scoring/`: tenant scoring Lambda (`scoring_function.py`).
- `summary/`: tenant summary Lambda (`summary_function.py`).
- `weekly_metrics/`: weekly tenant metrics Lambda (`weekly_metrics_function.py`).

Vendored dependency folders, `.dist-info`, `__pycache__`, and local packaging artifacts are intentionally not copied here.

## Responsibilities

### `monitor/`

The monitor task is the data ingestion and enrichment pipeline. The production dispatcher sends one SQS message per tenant, and the worker enriches each tenant with billing, cluster usage, email-domain intelligence, and related metadata before upserting the result into `emea_active_tenants`.

It is responsible for keeping these tenant fields current:

- tenant identity and CRM fields, such as `tenant_id`, `name`, `email`, `country`, `plan`, `sales_force_region`, and owner fields
- billing and usage signals, such as `has_credit_card`, `billing_config_id`, active credits, total and per-service-plan cluster counts, and `tenant_avg_qps`
- domain intelligence fields, such as `email_domain`, `entity_ai_category`, `business_description`, and `official_website`
- `source_type`, `processed_at`, and `error_message`

When configured with the scoring queue URL, it emits one message per processed tenant so the scoring task can recalculate that tenant's score asynchronously.

### `scoring/`

The scoring task is the prioritization Lambda. It consumes scoring messages that contain a `tenant_id`, reloads the latest row from `emea_active_tenants`, applies the scoring model in `calculate_signal_score`, and updates:

- `total_score`
- `priority`
- `key_lead`

It also writes the daily score snapshot for the tenant. After the database
transaction commits, it updates `emea_pql_priority_tier` on the existing
HubSpot Contact matched by exact tenant email. The score uses the latest
category, QPS, cluster count, credit-card state, plan, tenant age, and error
state from `emea_active_tenants`.

### `summary/`

The summary task is the reporting Lambda. It reads the already ingested and scored rows from `emea_active_tenants`, groups and formats them, and generates the EMEA tenant summary report.

It does not perform enrichment or scoring. It assumes monitor has already populated tenant/domain fields and scoring has already updated `total_score` and `priority`.

### `weekly_metrics/`

The weekly metrics task is a lightweight reporting Lambda. It reads aggregate counts from `emea_active_tenants` and sends them to a Feishu group every Monday at 15:00 Asia/Shanghai.

It reports EMEA stock tenants from `active_candidate`, previous complete UTC Sunday-to-Saturday new signups, EMEA P0 + P1 tenants, connected tenants (`track_step = 2`), paid tenants (`has_credit_card = 1`), and P0 + P1 connected/paid subsets.

## How They Work Together

The normal pipeline is:

1. The monitor dispatcher runs on its schedule and sends one message per tenant to the monitor queue.
2. The monitor worker consumes those messages and upserts enriched tenant rows into `emea_active_tenants`.
3. The monitor worker sends scoring messages, one per tenant, to the scoring queue.
4. `scoring` consumes those messages and updates `total_score`, `priority`, and `key_lead`.
5. `summary` runs after monitor and scoring have finished, then reads `emea_active_tenants` to produce the report.

Operationally, run or deploy them in this order when refreshing the full workflow:

```text
monitor dispatcher -> monitor worker -> scoring -> summary
```

If only tenant enrichment or domain intelligence changed, rerun `scoring` for affected tenants before running `summary`, because priority depends on the latest `entity_ai_category` and usage signals.

## Packaging Notes

Each task has its own `requirements.txt`. Build each Lambda package from inside that task directory, install dependencies into a temporary package directory, then zip the dependencies together with the task source files.

Example pattern:

```bash
python3 -m pip install -r requirements.txt -t package/
cp *.py package/
cd package
zip -r ../function.zip .
```

The exact handler differs by task:

- monitor dispatcher: `dispatcher_function.lambda_handler`
- monitor worker: `worker_function.lambda_handler`
- scoring: `scoring_function.lambda_handler`
- summary: `summary_function.lambda_handler`
- weekly_metrics: `weekly_metrics_function.lambda_handler`
