Skip to content

Repo Layout

The workspace root holds four independent git repos and a shared orchestrator script.

<workspace>/
├── ftl-backend/      Go services, migrations, Lua scripts
├── ftl-frontend/     React SPA (Vite, TypeScript)
├── ftl-docs/         Architecture docs, ADRs, living specs, this site
├── ftl-support/      Operator runbooks and lifecycle scripts
└── ftl.sh            Local-dev orchestrator

ftl-backend

All three Go binaries plus shared internal packages.

ftl-backend/
├── cmd/
│   ├── api-server/   main.go for the HTTP API binary
│   ├── ws-server/    main.go for the WebSocket binary
│   └── flusher/      main.go for the background sync binary
├── deployments/
│   ├── docker/       Dockerfile.api, Dockerfile.ws, Dockerfile.flusher
│   └── docker-compose.yml  Local infra (postgres:16-alpine, redis:7-alpine) + all three services
├── internal/         Shared packages (amm, auth, trade, wallet, leaderboard, redis, sportmonks, …)
├── migrations/       Sequential SQL migration files (golang-migrate format, named 000NNN_*.up.sql)
├── scripts/          gen-dev-keys.sh, seed/main.go
├── Makefile          build, test, lint, migrate, run-api, run-ws, run-flusher
├── go.mod
└── go.sum

ftl-frontend

React SPA served from Azure Static Web Apps in production and Vite dev server locally.

ftl-frontend/
├── src/
│   ├── components/   Shared UI components
│   ├── pages/        Route-level views (instruments, portfolio, leaderboard, admin)
│   ├── hooks/        Custom React hooks
│   ├── stores/       State (likely Zustand or similar)
│   └── lib/          API client, WebSocket client
├── tests/            Playwright E2E specs
├── vite.config.ts
├── tsconfig.json
├── package.json
└── pnpm-lock.yaml

ftl-docs

All architecture documents, ADRs, and living specs. This dev-docs site (mkdocs.yml) also lives here.

ftl-docs/
├── architecture/
│   ├── 12-new-stack-architecture.md  PRIMARY architecture reference
│   ├── 13-product-requirements.md    PRD with engineering targets
│   ├── specs/                        Living domain specs (amm-pricing.md, auth-flow.md, …)
│   └── decisions/                    ADRs (0001-*.md, 0002-*.md, …)
├── guides/
│   └── PROD-CUTOVER-2026-04.md       Production cutover runbook
├── reports/
│   ├── azure-cost-audit-2026-05-02.md  Staging revision-mode cost incident
│   └── codexreview-01.md               Scalability and correctness audit
├── proposals/
│   └── 10-client-project-proposal.md
├── pr-reports/                        Per-commit HTML walkthroughs
├── mkdocs.yml
└── CHANGE-MANAGEMENT.md

ftl-support

Runbooks for operators. Not application code.

ftl-support/
├── runbooks/
│   ├── local-dev-quickstart.md
│   └── local-dev-commands.md
└── scripts/

Branch strategy

Each repo uses the same branching model.

Branch Purpose
feat/<slug> New feature. Cut from the current integration branch.
bug/<slug> Bug fix. Cut from the current integration branch.
integration/<theme> Accumulates related feat/ and bug/ PRs before staging promotion. Cut from release/staging.
release/staging Pushing here triggers deploy-staging.yml — runs migrations, rolls staging Container Apps, smoke-checks /health.
release/prod Pushing here triggers deploy-prod.yml with a GitHub Environment approval gate before rolling production.
main Not the integration point. Does not trigger deploys.

The flow is forward-only: feat/integration/<theme>release/stagingrelease/prod.

Warning

Never branch feature or bug work off main. Always cut from the current integration branch, which is itself cut from release/staging.

Decision: two long-lived release branches instead of trunk-based deploy. Staging acts as a pre-production gate; prod requires an explicit approval click in GitHub Environments. This prevents accidental production deploys during the tournament.