The standard for each surface comes first, followed by the platform-wide baseline. Each team’s pages list the exact tools used in each area.
By surface
- Language: Scala 2.13 on JDK 17-21
- Deploy: Kubernetes on GKE (Kustomize + Flux); Cloud Run for event-driven
- How it fits together: architecture and CI/CD
- Language: Python, for clearing and back-office
- How it fits together: architecture
- Language: TypeScript, front and back
- Framework: React 19 + Strata; Astro 7 SSR
- Deploy: Cloudflare Pages + R2
Platform-wide
| Concern | Standard |
|---|---|
| Source control | GitHub |
| Build & CI | GitHub Actions on self-hosted runners; reusable actions from NT-NinjaTrader/gh-actions. See CI/CD. |
| CI to cloud auth | Workload Identity, no long-lived keys. See security. |
| Containers & registry | Docker to Artifact Registry; build once and promote. |
| Infrastructure | Terraform on GCP (Atlantis on PRs) |
| Secrets | GCP Secret Manager via Workload Identity (external-secrets operator in-cluster). See security. |
| Feature flags | Statsig. See feature flags. |
| Client error tracking | Sentry (web, mobile, desktop) |
| Service error tracking | OpenTelemetry with structured logs, no dedicated tracker. See observability. |
| Telemetry & tracing | OpenTelemetry to Cloud Trace |
| Logs | Cloud Logging (log-based metrics drive alerting) |
| Dashboards & alerts | Cloud Monitoring, defined in Terraform |
| Paging | PagerDuty. See release and incidents. |
| Product analytics | Statsig Web Analytics |
| Consent | OneTrust |
| Data warehouse | BigQuery |
| Domain model | Defined once in tradovate/master-scheme, generated downstream. See architecture. |
Version-support policy
A language name alone can become outdated. Set the supported version range so readers know the minimum version, not just the tool name.
| Surface | Baseline | Support window |
|---|---|---|
| Backend JVM | JDK LTS 17 and 21 | Track the LTS cadence; the drop rule is open (see open questions) |
| Backend Scala | Scala 2.13 (current) | Scala 3 direction, see the note below |
| FCM | Python 3.12+ | LTS-supported CPython only |
| Web / services | Node LTS only | Even-numbered active or maintenance LTS |
| Mobile | Dart / Flutter, current stable | Track upstream stable |
| Desktop | .NET, current LTS | Track the .NET LTS cadence |
Keep the JVM on Java SE LTS releases. Set the minimum version in the build config, not just in prose:
// build.sbt, the version floor is enforced, not documented
ThisBuild / scalaVersion := "2.13.14"
ThisBuild / javacOptions ++= Seq("--release", "17")
ThisBuild / scalacOptions ++= Seq("-release:17", "-Werror", "-Wunused:all", "-deprecation")Quality-tooling baseline
Each surface sets a formatter, a linter, and a type or static-analysis check. These are the specific checks that the quality gates run in CI.
| Surface | Format | Lint / static analysis | Types |
|---|---|---|---|
| Scala | scalafmt | scalafix | compiler -Werror |
| Python | ruff format | ruff | mypy |
| TypeScript | Prettier | ESLint | tsc strict |
| Dart | dart format |
dart analyze |
built-in |
| C# | dotnet format |
Roslyn analyzers | built-in |
| Go | gofmt |
go vet + staticcheck |
compiler |
| Rust | rustfmt |
Clippy | compiler |
Run locally the same checks that CI runs:
sbt scalafmtCheckAll compile # compile carries -Werrorruff format --check . && ruff check . && mypy .pnpm prettier --check . && pnpm eslint . && pnpm tsc --noEmitdart format --set-exit-if-changed . && dart analyzedotnet format --verify-no-changes && dotnet buildgofmt -l . && go vet ./... && staticcheck ./...cargo fmt --check && cargo clippy -- -D warnings && cargo buildBuild and dependency management
List the build and dependency manager for each surface so “one build toolchain” has a clear meaning.
| Surface | Build / dependency manager |
|---|---|
| Scala | sbt + coursier |
| Python | uv |
| TypeScript | pnpm |
| Dart | pub |
| C# | NuGet |
| Go | Go modules |
| Rust | Cargo |
Commit the lockfile for every project. Pin direct dependencies. Use Renovate to keep dependencies current, so the minimum version stays clear instead of drifting:
// renovate.json, org-wide dependency currency policy
{
"extends": ["config:recommended"],
"lockFileMaintenance": { "enabled": true },
"vulnerabilityAlerts": { "labels": ["security"] }
}Supply chain
The registry process is build once and promote (see The Twelve-Factor App build/release/run separation and the Artifact Registry docs). Add these supply-chain rules:
- Generate an SBOM at build time and retain it with the artifact.
- Scan dependencies with Renovate or Dependabot; treat vulnerability alerts as work.
- Sign images and record build provenance so a promoted digest is verifiable downstream.
Governance
This table is a standard, not a suggestion. Changes require review.
- An owner group owns the table and reviews it on a set cadence; the exact owner and cadence are still being ratified (see the note below).
- Changing an existing standard requires an ADR that records the decision and its context.
- Introducing a new language or tool routes through the exceptions process before it lands here.
- The shared CI toolchain lives in
NT-NinjaTrader/gh-actions; reuse those actions rather than re-implementing per repository. - Define the domain model once in
tradovate/master-scheme, and generate downstream. Never redefine a shared entity in a service.