# tkaardvark/axis architecture

> Architecture diagram of the GitHub repository tkaardvark/axis, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-06-27). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/tkaardvark/axis
- Repository: https://github.com/tkaardvark/axis

## Overview

1. **High-level shape**
   Axis Analytics is a two-tier application: a React frontend in `client/` and an Express/PostgreSQL backend at the repo root. The frontend renders NAIA basketball analytics views, while the backend serves JSON APIs, computes/serves derived metrics, and hosts the scheduled data-ingestion jobs.

2. **User-facing frontend**
   The client is a Vite-built React 19 app with React Router. The main page areas are team analytics, players, conferences, tournament bracket projection, and scouting/comparison tools. The app is organized as feature components rather than by technical layer, so each route has its own assembled view and supporting panels/charts.

3. **Frontend data boundary**
   Frontend components pull data through `client/src/utils/api.js` and related helpers, which form the boundary to the backend. The app also includes formatting/normalization utilities, chart helpers, and stat-group definitions, indicating that raw API data is transformed on the client into table rows, chart series, tooltips, and comparison metrics.

4. **State, gating, and personalization**
   `ThemeContext` and `TeamLinkContext` provide cross-app UI state. Authentication-related wrappers such as `RequireAuth`, `AdminOnly`, and `PostAuthRedirect`, plus hooks like `useUserTeam` and `useUserTier`, show that some experiences are personalized or restricted, especially scouting/admin surfaces. This creates a clear split between public analytics pages and authenticated staff tooling.

5. **Design system**
   `client/src/design-system` is a separate internal UI system with tokenized colors, spacing, typography, and elevation, plus reusable primitives like Button, Card, Badge, SearchInput, Select, and Tabs. That subsystem acts as the visual foundation for the app and also contains standalone UI-kit examples and guidelines, so the main product UI is built from a controlled set of presentation primitives.

6. **Backend API and domain routes**
   The server side is centered on `server.js`, with route modules for `teams`, `players`, `conferences`, `matchup`, `tournament`, `bracketcast`, `scoutingReports`, `staffHub`, and `metadata`. These route files represent the API surface area and likely map directly to the major pages in the frontend. `db/pool.js` is the shared PostgreSQL connection layer.

7. **Analytics and domain logic**
   The repo keeps core business logic in root-level `utils/`, including adjusted ratings, percentile math, tournament classification, team resolution, conference champions, geometry/quadrant helpers, and dynamic box-score/stat transforms. This means the backend is not just CRUD; it synthesizes advanced basketball metrics and projections from imported game and player data.

8. **Data model and migrations**
   Schema evolution is managed by the `migrations/` directory, which adds players, import logs, game flags, box-score stats, analytics fields, location data, excluded-team handling, season metadata, tournament flags, aliases, and player photos over time. The presence of many additive migrations suggests a long-lived analytics schema with computed fields and historical data correctness requirements.

9. **Data pipeline**
   The repository’s most important non-UI subsystem is the ingestion pipeline. Scripts like `scrape-team-urls.js`, `scrape-conferences.js`, `scrape-logos.js`, `scrape-player-photos.js`, and the `import-*.js` scripts pull data from Presto Sports, then populate PostgreSQL. After import, analytics scripts and helpers compute derived ratings, standings, and tournament-related outputs. The official NAIA stats provider is therefore an external dependency that feeds the entire product.

10. **Scheduled automation**
   `scheduler.js` runs the production refresh cycle via `node-cron`. In production, the app periodically scrapes, imports, and recalculates analytics without manual intervention. That makes the backend both an API service and a data-processing worker, with scheduling tied into the same Node deployment.

11. **Configuration and season-specific reference data**
   The `config/` directory contains domain reference data such as excluded teams, conference areas, team locations, exhibition overrides, and tournament bracket definitions. JSON mappings like `team-urls-2024-25.json` and `team-urls-2025-26.json` indicate the system is season-aware and relies on cached discovery results for external source endpoints.

12. **Deployment and runtime boundaries**
   The app is designed for Render: a Node.js API service, a static frontend build from `client/dist`, and managed PostgreSQL. Root and client `package.json` files reflect the split runtime, with the API handling server-side logic and cron jobs, and the client serving as a separate static SPA.

13. **Documentation as architecture support**
   The `docs/` folder is substantial and appears to be part of the system design, not incidental notes. It documents the data pipeline, database schema, API contracts, legal copy, and stakeholder-facing behavior, which is useful for understanding how the backend, database, and frontend are intended to interact.

Main entry points: [`client/src/components`](https://github.com/tkaardvark/axis/tree/main/client/src/components) (Route views), [`db/pool.js`](https://github.com/tkaardvark/axis/blob/main/db/pool.js) (DB pool), [`routes/teams.js`](https://github.com/tkaardvark/axis/blob/main/routes/teams.js) (API routes), [`utils/computeAdjustedRatings.js`](https://github.com/tkaardvark/axis/blob/main/utils/computeAdjustedRatings.js) (Domain logic)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_frontend["Client app"]
  node_client_app["React app<br/>SPA frontend<br/>[App.jsx]"]
  node_routes_views["Route views<br/>feature screens"]
  node_data_boundary["API client<br/>frontend data layer<br/>[api.js]"]
  node_state_access(("State & access<br/>ui state/auth<br/>[ThemeContext.jsx]"))
  node_design_system["Design system<br/>ui foundation"]
  node_analytics_helpers["Client analytics<br/>chart helpers<br/>[statGroups.js]"]
end

subgraph group_backend["Server & data"]
  node_server_entry["Server entry<br/>Express app<br/>[server.js]"]
  node_api_routes["API routes<br/>REST surface<br/>[teams.js]"]
  node_db_pool[("DB pool<br/>PostgreSQL access<br/>[pool.js]")]
  node_domain_logic["Domain logic<br/>analytics core"]
  node_data_models["Schema & migrations<br/>database schema"]
  node_ingestion_jobs["Ingestion jobs<br/>pipeline<br/>[import-players.js]"]
  node_scrapers["Scrapers<br/>external fetch"]
end

subgraph group_ops["Automation & config"]
  node_scheduler(("Scheduler<br/>cron worker<br/>[scheduler.js]"))
  node_season_config["Season config<br/>reference data"]
  node_deployment["Render deploy<br/>runtime<br/>[render.yaml]"]
end

node_client_app -->|"renders"| node_routes_views
node_routes_views -->|"loads data"| node_data_boundary
node_routes_views -->|"uses"| node_state_access
node_routes_views -->|"builds with"| node_design_system
node_routes_views -->|"transforms"| node_analytics_helpers
node_data_boundary -->|"calls"| node_api_routes
node_server_entry -->|"mounts"| node_api_routes
node_api_routes -->|"queries"| node_db_pool
node_api_routes -->|"computes"| node_domain_logic
node_domain_logic -->|"reads/writes"| node_db_pool
node_data_models -->|"defines"| node_db_pool
node_ingestion_jobs -->|"populate"| node_db_pool
node_scrapers -->|"feed"| node_ingestion_jobs
node_scheduler -->|"triggers"| node_scrapers
node_scheduler -->|"runs"| node_ingestion_jobs
node_scheduler -->|"recalculates"| node_domain_logic
node_season_config -->|"guides"| node_scrapers
node_season_config -->|"parameterizes"| node_domain_logic
node_deployment -->|"hosts"| node_server_entry
node_deployment -->|"serves build"| node_client_app
node_deployment -->|"connects to"| node_db_pool

click node_client_app "https://github.com/tkaardvark/axis/blob/main/client/src/App.jsx"
click node_routes_views "https://github.com/tkaardvark/axis/tree/main/client/src/components"
click node_data_boundary "https://github.com/tkaardvark/axis/blob/main/client/src/utils/api.js"
click node_state_access "https://github.com/tkaardvark/axis/blob/main/client/src/contexts/ThemeContext.jsx"
click node_design_system "https://github.com/tkaardvark/axis/tree/main/client/src/design-system"
click node_analytics_helpers "https://github.com/tkaardvark/axis/blob/main/client/src/utils/statGroups.js"
click node_server_entry "https://github.com/tkaardvark/axis/blob/main/server.js"
click node_api_routes "https://github.com/tkaardvark/axis/blob/main/routes/teams.js"
click node_db_pool "https://github.com/tkaardvark/axis/blob/main/db/pool.js"
click node_domain_logic "https://github.com/tkaardvark/axis/blob/main/utils/computeAdjustedRatings.js"
click node_data_models "https://github.com/tkaardvark/axis/tree/main/migrations"
click node_ingestion_jobs "https://github.com/tkaardvark/axis/blob/main/import-players.js"
click node_scrapers "https://github.com/tkaardvark/axis/blob/main/scrape-team-urls.js"
click node_scheduler "https://github.com/tkaardvark/axis/blob/main/scheduler.js"
click node_season_config "https://github.com/tkaardvark/axis/blob/main/config/tournament-bracket-2026.js"
click node_deployment "https://github.com/tkaardvark/axis/blob/main/render.yaml"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_client_app,node_routes_views,node_data_boundary,node_state_access,node_design_system,node_analytics_helpers toneBlue
class node_server_entry,node_api_routes,node_db_pool,node_domain_logic,node_data_models,node_ingestion_jobs,node_scrapers toneAmber
class node_scheduler,node_season_config,node_deployment toneMint
```

## Components

### Client app

React/Vite single-page app for analytics, scouting, and legal pages.

- [React app](https://github.com/tkaardvark/axis/blob/main/client/src/App.jsx): SPA frontend · Main Vite-built React application with routed analytics views. · `client/src/App.jsx`
- [Route views](https://github.com/tkaardvark/axis/tree/main/client/src/components): feature screens · Team, player, conference, matchup, tournament, bracketcast, and scouting pages assembled as feature components. · `client/src/components`
- [API client](https://github.com/tkaardvark/axis/blob/main/client/src/utils/api.js): frontend data layer · Helpers that fetch, normalize, and format backend data for tables, charts, and tooltips. · `client/src/utils/api.js`
- [State & access](https://github.com/tkaardvark/axis/blob/main/client/src/contexts/ThemeContext.jsx): ui state/auth · Theme, team-link state, and auth gating for personalized or restricted surfaces. · `client/src/contexts/ThemeContext.jsx`
- [Design system](https://github.com/tkaardvark/axis/tree/main/client/src/design-system): ui foundation · Tokenized UI kit and reusable primitives that underpin the product interface. · `client/src/design-system`
- [Client analytics](https://github.com/tkaardvark/axis/blob/main/client/src/utils/statGroups.js): chart helpers · Client-side stat grouping, percentiles, normalizers, and chart/tooltip helpers. · `client/src/utils/statGroups.js`

### Server & data

Express API, database layer, analytics logic, ingestion jobs, and schema evolution.

- [Server entry](https://github.com/tkaardvark/axis/blob/main/server.js): Express app · Root Node service that mounts routes and serves the API. · `server.js`
- [API routes](https://github.com/tkaardvark/axis/blob/main/routes/teams.js): REST surface · Domain route modules for teams, players, conferences, matchup, tournament, bracketcast, scouting, staff, and metadata. · `routes/teams.js`
- [DB pool](https://github.com/tkaardvark/axis/blob/main/db/pool.js): PostgreSQL access · Shared PostgreSQL connection pool used by the API and jobs. · `db/pool.js`
- [Domain logic](https://github.com/tkaardvark/axis/blob/main/utils/computeAdjustedRatings.js): analytics core · Basketball calculations for adjusted ratings, tournament classification, team resolution, champions, geometry, and box-score transforms. · `utils/computeAdjustedRatings.js`
- [Schema & migrations](https://github.com/tkaardvark/axis/tree/main/migrations): database schema · Additive migration history for players, games, analytics fields, season metadata, aliases, photos, and tournament flags. · `migrations`
- [Ingestion jobs](https://github.com/tkaardvark/axis/blob/main/import-players.js): pipeline · Import and scrape scripts that pull Presto Sports data and populate the database. · `import-players.js`
- [Scrapers](https://github.com/tkaardvark/axis/blob/main/scrape-team-urls.js): external fetch · Scripts that discover team URLs, conferences, logos, and player photos from upstream sources. · `scrape-team-urls.js`

### Automation & config

Scheduled refresh, season reference data, and deployment/runtime boundaries.

- [Scheduler](https://github.com/tkaardvark/axis/blob/main/scheduler.js): cron worker · Production refresh orchestration that periodically runs scraping, importing, and recalculation tasks. · `scheduler.js`
- [Season config](https://github.com/tkaardvark/axis/blob/main/config/tournament-bracket-2026.js): reference data · Conference areas, excluded teams, locations, bracket definitions, and cached season URL maps. · `config/tournament-bracket-2026.js`
- [Render deploy](https://github.com/tkaardvark/axis/blob/main/render.yaml): runtime · Node API service, static frontend build, and managed PostgreSQL deployment boundary. · `render.yaml`

## Connections

- React app → Route views: renders · The app composes its main pages from feature-oriented route components.
- Route views → API client: loads data · Screens retrieve analytics and domain data through the client API helpers.
- Route views → State & access: uses · Views depend on shared theme, team-link, and access-control wrappers.
- Route views → Design system: builds with · Product UI is assembled from shared design-system primitives and tokens.
- Route views → Client analytics: transforms · Route components turn raw responses into chart series, tables, and comparisons.
- API client → API routes: calls · Frontend helpers request JSON from the backend route surface.
- Server entry → API routes: mounts · Express server registers the domain route modules.
- API routes → DB pool: queries · Routes read and write through the shared PostgreSQL pool.
- API routes → Domain logic: computes · API responses incorporate derived basketball metrics and projections.
- Domain logic → DB pool: reads/writes · Analytics helpers and refresh flows operate on persisted team, player, and game data.
- Schema & migrations → DB pool: defines · Migrations shape the schema used by the shared database connection.
- Ingestion jobs → DB pool: populate · Import scripts load source data into PostgreSQL tables.
- Scrapers → Ingestion jobs: feed · Scraping scripts discover upstream source URLs and assets for imports.
- Scheduler → Scrapers: triggers · Cron orchestration kicks off periodic discovery and refresh jobs.
- Scheduler → Ingestion jobs: runs · Scheduled automation executes the import and backfill pipeline.
- Scheduler → Domain logic: recalculates · Refresh cycles recompute ratings, standings, and projections after ingestion.
- Season config → Scrapers: guides · Reference data constrains source discovery, team mapping, and bracket logic.
- Season config → Domain logic: parameterizes · Season-specific exclusions and bracket rules shape analytics calculations.
- Render deploy → Server entry: hosts · The Render runtime serves the Node API and scheduled worker.
- Render deploy → React app: serves build · The frontend is deployed as a static SPA build.
- Render deploy → DB pool: connects to · Managed PostgreSQL backs the application data layer.
