> ## Documentation Index
> Fetch the complete documentation index at: https://playbook.smedleygroup.com/llms.txt
> Use this file to discover all available pages before exploring further.

# TalentID Coaching: System Architecture

> The four Lambdas, the topic everything fans out from, and how a timing file becomes competitors, KPIs and telemetry links.

This page describes how TalentID: Coaching is put together. For what the system is for and who uses it, see [TalentID: Coaching](/software/developer/estate/systems/talentid/talentid-coaching).

## Architecture

![TalentID Coaching architecture. Timing arrives as a file and fans out through one topic. Colour shows the kind of component.](https://mintcdn.com/smedley_group/J4Qb1kGrTQEJOjVR/images/software/developer/estate/systems/talentid/architecture.png?fit=max\&auto=format\&n=J4Qb1kGrTQEJOjVR\&q=85\&s=7810da79a1869319c21f1b4ad0a6e05c)

> [!NOTE]
>
> The diagram source is the draw\.io file at `images/software/developer/estate/systems/talentid/architecture.drawio`. To change the diagram, edit that source in draw\.io, re-export it as PNG to `architecture.png` in the same folder, and commit both.

## The Shape Of It

Four Lambdas, one API in two flavours, and a single SNS topic that everything downstream hangs off.

| Lambda | Runtime | Triggered by | Does |
| - | - | - | - |
| `apiGtwHandler` | .NET 8 | API Gateway | Serves events, sessions, competitors, KPIs and the telemetry registry |
| `sqsTimingIngest` | .NET 8 | `TalentIDTimingDataQueue` | Imports a timing file into events, sessions, competitors and laps |
| `sqsClassify` | Python 3.12 | `TalentIDClassifyQueue` | Computes driver KPIs and writes end of session reports |
| `sqsNotificationService` | Python 3.12 | `TalentIDNotificationQueue` | Sends email |

`sqsClassify` carries a pandas Lambda layer. Three of the four Lambdas are given 3008 MB; `sqsTimingIngest` is the exception and runs at the Lambda default, which is worth knowing because it is the one parsing whole timing files.

## How Timing Arrives

Nothing pulls. The whole chain is started by a file landing in a bucket.

**1. AlphaTiming uploads**

The timing laptop at the region uploads the event timing JSON to the ingestion bucket every time results are published, typically as each session finishes.

**2. S3 notifies**

Object creation publishes to `TalentIDTimingDataTopic`, which feeds `TalentIDTimingDataQueue`.

**3. The importer runs**

`sqsTimingIngest` reads the file and creates events, sessions, competitors and laps. See [Comment Types](/software/developer/estate/systems/gkl/talentid-in-gkl#comment-types) for what happens to a competitor with no booking ID.

**4. It announces what it did**

The importer publishes an `EventImported` message to `IngestionNotificationTopic`.

> [!NOTE]
>
> Because AlphaTiming publishes per session, the same event is re-imported repeatedly through a race day, each time with more sessions in it than the last. The chain is built to be run again rather than once.

## The Fan-Out Point

`IngestionNotificationTopic` is the most important object in the system. Everything that happens after an import is a subscriber to it, including one in another repository entirely:

| Subscriber | Consequence |
| - | - |
| `TalentIDClassifyQueue` → `sqsClassify` | KPIs are computed and an end of session report is written to the reports bucket |
| `TalentIDNotificationQueue` → `sqsNotificationService` | Email is sent to [prod.tidoutput@talentid.global](mailto:prod.tidoutput@talentid.global) shared mailbox (dev. for DEV environment) |
| Telemetry reconversion checker, in `can-wifi` | DAQ runs in that event's window are reconverted so their laps line up. See [Timing and Lap Splitting](/software/developer/estate/systems/telemetry/timing-and-lap-splitting) |

> [!WARNING]
>
> That last subscriber is a cross repository dependency with nothing in this repository pointing at it. The topic ARN is published to SSM and the telemetry stack subscribes to it from the other side. Changing or recreating this topic breaks telemetry conversion, and nothing here will tell you.

`UserNotificationTopic` is separate and simpler: the API publishes account related messages to it, and the same notification queue picks them up.

## The Two API Gateways

The API Lambda sits behind both a **public** REGIONAL gateway and a **private** gateway restricted to the VPC endpoint.

* **Public** serves the Operator Dashboard, which calls TalentID directly from the browser, and the telemetry converter.
* **Private** serves the worker Lambdas. `sqsTimingIngest`, `sqsClassify` and `sqsNotificationService` all write and read through the API rather than touching MongoDB directly, and they do it over the private gateway.

That second point is the design decision worth knowing: the workers are API clients, not database clients. Business rules stay in one place, at the cost of a network hop for every write during an import.

## Where The Data Goes

| Store | Holds |
| - | - |
| MongoDB `TalentId_PROD` | Events, sessions, competitors, laps, KPIs, telemetry registry |
| Ingestion bucket | Incoming timing JSON from AlphaTiming |
| Reports bucket | End of session reports produced by `sqsClassify` |

Both buckets and the MongoDB instance are provisioned by [TalentIdPipeline-Infra-CDK](/software/developer/estate/infra/talentidpipeline-infra-cdk), not by this repository.

## Notes

* The pipeline also builds two Lambda packages, a registration emailer and an uninserted credentials emailer, that the application stack does not deploy. They are built on every run and then unused.
* Category and user ID lookup tables are read from JSON files in the CDK project at synth time and passed to the API Lambda as environment variables, so changing them is a deployment rather than a configuration edit.

## Related Documentation

| Page | Relevance |
| - | - |
| [TalentID: Coaching](/software/developer/estate/systems/talentid/talentid-coaching) | What the system is for |
| [TalentID in GKL Platform](/software/developer/estate/systems/gkl/talentid-in-gkl) | Where the Operator Dashboard shows this data, and how drivers are matched |
| [Timing and Lap Splitting](/software/developer/estate/systems/telemetry/timing-and-lap-splitting) | What the telemetry side does with an import |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.