# teerxwat/shooting_range-pi architecture

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

- Interactive diagram: https://gitdiagram.com/teerxwat/shooting_range-pi
- Repository: https://github.com/teerxwat/shooting_range-pi

## Overview

Shooting Range combines an on-site kiosk and GoPro capture system with a cloud service for clip access, purchases, rendering, downloads, and statistics. The main journey runs from lane selection and recording through upload, customer PIN lookup, preview, order, payment, and download. README capabilities fill in cloud and kiosk behavior where source excerpts were not provided; those connections are documented rather than verified from sampled implementations. The separate LianLian API gateway is modeled as an optional payment integration, not as wired into the mock payment flow.

Main entry points: [`server/src/routes/customer.js`](https://github.com/teerxwat/shooting_range-pi/blob/main/server/src/routes/customer.js) (Customer endpoints), [`local/Gopro-connect/server.py`](https://github.com/teerxwat/shooting_range-pi/blob/main/local/Gopro-connect/server.py) (Lane sessions), [`server/src/index.js`](https://github.com/teerxwat/shooting_range-pi/blob/main/server/src/index.js) (Cloud API), [`api_gateway/app.py`](https://github.com/teerxwat/shooting_range-pi/blob/main/api_gateway/app.py) (Transfer API)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_field["Range capture"]
  node_local_api["Camera API<br/>[server.py]"]
  node_lane_manager["Lane sessions<br/>[server.py]"]
  node_camera["GoPro cameras"]
  node_detection["Pose detection<br/>[detect_stream.py]"]
  node_recording["Clip recording<br/>[recorder.py]"]
  node_clip_processing["Clip processing<br/>[server.py]"]
  node_uploader["Cloud uploader<br/>[uploader.py]"]
end

subgraph group_cloud["Cloud media commerce"]
  node_cloud_api["Cloud API<br/>[index.js]"]
  node_ingest["Session and clip ingest<br/>[ingest.js]"]
  node_customer_api["Customer endpoints<br/>[customer.js]"]
  node_media["Preview and render<br/>[media.js]"]
  node_commerce["Orders and payments<br/>[payment.js]"]
  node_admin["Statistics and events<br/>[admin.js]"]
  node_cloud_db[("Cloud database<br/>[db.js]")]
end

subgraph group_web["Web experiences"]
  node_kiosk_app["Kiosk app<br/>[App.jsx]"]
  node_lane_select["Lane selection<br/>[LaneSelect.jsx]"]
  node_live_view["Live capture view<br/>[LiveView.jsx]"]
  node_replay["Replay playback<br/>[ReplayList.jsx]"]
  node_customer_app["Customer app<br/>[App.jsx]"]
  node_lookup["Session PIN lookup<br/>[Lookup.jsx]"]
  node_videos["Video catalog<br/>[Videos.jsx]"]
  node_studio["Clip studio<br/>[Studio.jsx]"]
end

subgraph group_gateway["Payment gateway"]
  node_gateway_api["Transfer API<br/>[app.py]"]
  node_lianlian_client["LianLian client<br/>[client.py]"]
  node_gateway_db[("Transfer database<br/>[db.py]")]
end

node_range_customer(("Range customer"))
node_admin_actor(("Administrator"))
node_gateway_client(("Project client"))
node_lianlian["LianLian Pay"]

node_range_customer -->|"uses"| node_kiosk_app
node_kiosk_app -->|"routes to"| node_lane_select
node_lane_select -->|"lists lanes"| node_local_api
node_live_view -->|"controls session"| node_local_api
node_local_api -->|"dispatches"| node_lane_manager
node_lane_manager -->|"controls"| node_camera
node_lane_manager -->|"starts detection"| node_detection
node_lane_manager -->|"starts recording"| node_recording
node_recording -->|"queues clips"| node_clip_processing
node_clip_processing -->|"uploads clips"| node_uploader
node_replay -->|"requests playback"| node_local_api
node_uploader -->|"sends sessions and clips"| node_cloud_api
node_cloud_api -->|"routes ingest"| node_ingest
node_cloud_api -->|"routes customer"| node_customer_api
node_cloud_api -->|"routes admin"| node_admin
node_ingest -->|"stores session and clip records"| node_cloud_db
node_ingest -->|"creates preview"| node_media
node_customer_app -->|"routes to"| node_lookup
node_range_customer -->|"uses"| node_customer_app
node_lookup -->|"submits session and PIN"| node_customer_api
node_customer_api -->|"reads and updates"| node_cloud_db
node_customer_api -->|"serves preview and download"| node_media
node_customer_api -->|"creates and pays orders"| node_commerce
node_videos -->|"loads videos"| node_customer_api
node_studio -->|"requests preview and order"| node_customer_api
node_commerce -->|"requests render"| node_media
node_commerce -->|"records orders and payments"| node_cloud_db
node_admin_actor -->|"requests reports"| node_admin
node_admin -->|"queries statistics"| node_cloud_db
node_gateway_client -->|"creates or checks transfer"| node_gateway_api
node_gateway_api -->|"creates and queries payment"| node_lianlian_client
node_gateway_api -->|"logs transactions"| node_gateway_db
node_lianlian_client -.->|"calls payment API"| node_lianlian
node_lianlian -.->|"sends webhook"| node_gateway_api

click node_kiosk_app "https://github.com/teerxwat/shooting_range-pi/blob/main/web/src/kiosk/App.jsx"
click node_lane_select "https://github.com/teerxwat/shooting_range-pi/blob/main/web/src/kiosk/pages/LaneSelect.jsx"
click node_live_view "https://github.com/teerxwat/shooting_range-pi/blob/main/web/src/kiosk/pages/LiveView.jsx"
click node_replay "https://github.com/teerxwat/shooting_range-pi/blob/main/web/src/kiosk/pages/ReplayList.jsx"
click node_local_api "https://github.com/teerxwat/shooting_range-pi/blob/main/local/Gopro-connect/server.py"
click node_lane_manager "https://github.com/teerxwat/shooting_range-pi/blob/main/local/Gopro-connect/server.py"
click node_detection "https://github.com/teerxwat/shooting_range-pi/blob/main/local/Gopro-connect/detect_stream.py"
click node_recording "https://github.com/teerxwat/shooting_range-pi/blob/main/local/Gopro-connect/recorder.py"
click node_clip_processing "https://github.com/teerxwat/shooting_range-pi/blob/main/local/Gopro-connect/server.py"
click node_uploader "https://github.com/teerxwat/shooting_range-pi/blob/main/local/Gopro-connect/uploader.py"
click node_cloud_api "https://github.com/teerxwat/shooting_range-pi/blob/main/server/src/index.js"
click node_ingest "https://github.com/teerxwat/shooting_range-pi/blob/main/server/src/routes/ingest.js"
click node_customer_api "https://github.com/teerxwat/shooting_range-pi/blob/main/server/src/routes/customer.js"
click node_media "https://github.com/teerxwat/shooting_range-pi/blob/main/server/src/media.js"
click node_commerce "https://github.com/teerxwat/shooting_range-pi/blob/main/server/src/payment.js"
click node_admin "https://github.com/teerxwat/shooting_range-pi/blob/main/server/src/routes/admin.js"
click node_cloud_db "https://github.com/teerxwat/shooting_range-pi/blob/main/server/src/db.js"
click node_customer_app "https://github.com/teerxwat/shooting_range-pi/blob/main/web/src/customer/App.jsx"
click node_lookup "https://github.com/teerxwat/shooting_range-pi/blob/main/web/src/customer/pages/Lookup.jsx"
click node_videos "https://github.com/teerxwat/shooting_range-pi/blob/main/web/src/customer/pages/Videos.jsx"
click node_studio "https://github.com/teerxwat/shooting_range-pi/blob/main/web/src/customer/pages/Studio.jsx"
click node_gateway_api "https://github.com/teerxwat/shooting_range-pi/blob/main/api_gateway/app.py"
click node_lianlian_client "https://github.com/teerxwat/shooting_range-pi/blob/main/api_gateway/lianlian/client.py"
click node_gateway_db "https://github.com/teerxwat/shooting_range-pi/blob/main/api_gateway/lianlian/db.py"

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_local_api,node_lane_manager,node_camera,node_detection,node_recording,node_clip_processing,node_uploader,node_gateway_client toneBlue
class node_cloud_api,node_ingest,node_customer_api,node_media,node_commerce,node_admin,node_cloud_db toneAmber
class node_kiosk_app,node_lane_select,node_live_view,node_replay,node_customer_app,node_lookup,node_videos,node_studio toneMint
class node_gateway_api,node_lianlian_client,node_gateway_db toneRose
class node_range_customer,node_admin_actor,node_lianlian toneIndigo
```

## Components

### Range capture

- [Camera API](https://github.com/teerxwat/shooting_range-pi/blob/main/local/Gopro-connect/server.py): `local/Gopro-connect/server.py`
- [Lane sessions](https://github.com/teerxwat/shooting_range-pi/blob/main/local/Gopro-connect/server.py): `local/Gopro-connect/server.py`
- **GoPro cameras**
- [Pose detection](https://github.com/teerxwat/shooting_range-pi/blob/main/local/Gopro-connect/detect_stream.py): `local/Gopro-connect/detect_stream.py`
- [Clip recording](https://github.com/teerxwat/shooting_range-pi/blob/main/local/Gopro-connect/recorder.py): `local/Gopro-connect/recorder.py`
- [Clip processing](https://github.com/teerxwat/shooting_range-pi/blob/main/local/Gopro-connect/server.py): `local/Gopro-connect/server.py`
- [Cloud uploader](https://github.com/teerxwat/shooting_range-pi/blob/main/local/Gopro-connect/uploader.py): `local/Gopro-connect/uploader.py`

### Cloud media commerce

- [Cloud API](https://github.com/teerxwat/shooting_range-pi/blob/main/server/src/index.js): `server/src/index.js`
- [Session and clip ingest](https://github.com/teerxwat/shooting_range-pi/blob/main/server/src/routes/ingest.js): `server/src/routes/ingest.js`
- [Customer endpoints](https://github.com/teerxwat/shooting_range-pi/blob/main/server/src/routes/customer.js): `server/src/routes/customer.js`
- [Preview and render](https://github.com/teerxwat/shooting_range-pi/blob/main/server/src/media.js): `server/src/media.js`
- [Orders and payments](https://github.com/teerxwat/shooting_range-pi/blob/main/server/src/payment.js): `server/src/payment.js`
- [Statistics and events](https://github.com/teerxwat/shooting_range-pi/blob/main/server/src/routes/admin.js): `server/src/routes/admin.js`
- [Cloud database](https://github.com/teerxwat/shooting_range-pi/blob/main/server/src/db.js): `server/src/db.js`

### Web experiences

- [Kiosk app](https://github.com/teerxwat/shooting_range-pi/blob/main/web/src/kiosk/App.jsx): `web/src/kiosk/App.jsx`
- [Lane selection](https://github.com/teerxwat/shooting_range-pi/blob/main/web/src/kiosk/pages/LaneSelect.jsx): `web/src/kiosk/pages/LaneSelect.jsx`
- [Live capture view](https://github.com/teerxwat/shooting_range-pi/blob/main/web/src/kiosk/pages/LiveView.jsx): `web/src/kiosk/pages/LiveView.jsx`
- [Replay playback](https://github.com/teerxwat/shooting_range-pi/blob/main/web/src/kiosk/pages/ReplayList.jsx): `web/src/kiosk/pages/ReplayList.jsx`
- [Customer app](https://github.com/teerxwat/shooting_range-pi/blob/main/web/src/customer/App.jsx): `web/src/customer/App.jsx`
- [Session PIN lookup](https://github.com/teerxwat/shooting_range-pi/blob/main/web/src/customer/pages/Lookup.jsx): `web/src/customer/pages/Lookup.jsx`
- [Video catalog](https://github.com/teerxwat/shooting_range-pi/blob/main/web/src/customer/pages/Videos.jsx): `web/src/customer/pages/Videos.jsx`
- [Clip studio](https://github.com/teerxwat/shooting_range-pi/blob/main/web/src/customer/pages/Studio.jsx): `web/src/customer/pages/Studio.jsx`

### Payment gateway

- [Transfer API](https://github.com/teerxwat/shooting_range-pi/blob/main/api_gateway/app.py): `api_gateway/app.py`
- [LianLian client](https://github.com/teerxwat/shooting_range-pi/blob/main/api_gateway/lianlian/client.py): `api_gateway/lianlian/client.py`
- [Transfer database](https://github.com/teerxwat/shooting_range-pi/blob/main/api_gateway/lianlian/db.py): `api_gateway/lianlian/db.py`

### Other components

- **Range customer**
- **Administrator**
- **Project client**
- **LianLian Pay**

## Connections

- Range customer → Kiosk app: uses
- Kiosk app → Lane selection: routes to
- Lane selection → Camera API: lists lanes
- Live capture view → Camera API: controls session
- Camera API → Lane sessions: dispatches
- Lane sessions → GoPro cameras: controls
- Lane sessions → Pose detection: starts detection
- Lane sessions → Clip recording: starts recording
- Clip recording → Clip processing: queues clips
- Clip processing → Cloud uploader: uploads clips
- Replay playback → Camera API: requests playback
- Cloud uploader → Cloud API: sends sessions and clips
- Cloud API → Session and clip ingest: routes ingest
- Cloud API → Customer endpoints: routes customer
- Cloud API → Statistics and events: routes admin
- Session and clip ingest → Cloud database: stores session and clip records
- Session and clip ingest → Preview and render: creates preview
- Customer app → Session PIN lookup: routes to
- Range customer → Customer app: uses
- Session PIN lookup → Customer endpoints: submits session and PIN
- Customer endpoints → Cloud database: reads and updates
- Customer endpoints → Preview and render: serves preview and download
- Customer endpoints → Orders and payments: creates and pays orders
- Video catalog → Customer endpoints: loads videos
- Clip studio → Customer endpoints: requests preview and order
- Orders and payments → Preview and render: requests render
- Orders and payments → Cloud database: records orders and payments
- Administrator → Statistics and events: requests reports
- Statistics and events → Cloud database: queries statistics
- Project client → Transfer API: creates or checks transfer
- Transfer API → LianLian client: creates and queries payment
- Transfer API → Transfer database: logs transactions
- LianLian client → LianLian Pay: calls payment API
- LianLian Pay → Transfer API: sends webhook
