# kimyeongseong/qa-device-farm architecture

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

- Interactive diagram: https://gitdiagram.com/kimyeongseong/qa-device-farm
- Repository: https://github.com/kimyeongseong/qa-device-farm

## Overview

QA Device Farm lets browser users and CLI/CI clients share Android devices through a FastAPI service, with leases, device operations, logs, macros, and streaming. The main workflow is client → API → device control or stream → result; ws-scrcpy supplies the low-latency browser stream, while the README also documents a simpler server-side fallback. Python endpoint details and most dashboard implementation are consolidated or absent from the supplied tree, so those capabilities are represented at their documented service boundary; ws-scrcpy edges are limited to indexed source references and excerpts.

Main entry points: [`server.py`](https://github.com/kimyeongseong/qa-device-farm/blob/main/server.py) (Farm API), [`ws-scrcpy/src/app/googDevice/client/StreamClientScrcpy.ts`](https://github.com/kimyeongseong/qa-device-farm/blob/main/ws-scrcpy/src/app/googDevice/client/StreamClientScrcpy.ts) (Scrcpy stream client), [`ws-scrcpy/src/app/googDevice/client/FileListingClient.ts`](https://github.com/kimyeongseong/qa-device-farm/blob/main/ws-scrcpy/src/app/googDevice/client/FileListingClient.ts) (File listing), [`ws-scrcpy/src/app/client/ManagerClient.ts`](https://github.com/kimyeongseong/qa-device-farm/blob/main/ws-scrcpy/src/app/client/ManagerClient.ts) (Client connections)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_clients["Farm clients"]
  node_dashboard["Device dashboard"]
  node_cli["Farm CLI<br/>[cli.py]"]
end

subgraph group_farm["Farm API"]
  node_api["Farm API<br/>[server.py]"]
  node_leases["Device leases<br/>[server.py]"]
  node_device_view["Device inventory<br/>[server.py]"]
  node_batch["Batch operations<br/>[server.py]"]
  node_logs["Logcat and crashes<br/>[server.py]"]
  node_macro["Macro record / replay<br/>[server.py]"]
  node_fallback["Basic stream fallback<br/>[server.py]"]
  node_log_analysis["Crash log analysis<br/>[analyze_logs.py]"]
end

subgraph group_device["Device operations"]
  node_device_ops["Device controls<br/>[server.py]"]
  node_adb["ADB"]
  node_android["Android devices"]
end

subgraph group_stream["Streaming"]
  node_stream_server["Stream server<br/>[index.ts]"]
  node_stream_client["Scrcpy stream client"]
  node_player["Video player<br/>[BasePlayer.ts]"]
  node_interaction["Input interaction"]
  node_connection["Client connections<br/>[ManagerClient.ts]"]
  node_multiplexer["WebSocket multiplexer<br/>[Multiplexer.ts]"]
  node_file_listing["File listing"]
  node_file_push["File push handler<br/>[FilePushHandler.ts]"]
end

node_browser(("Browser user"))
node_ci(("CLI / CI"))

node_browser -->|"uses"| node_dashboard
node_dashboard -->|"calls"| node_api
node_ci -->|"runs"| node_cli
node_cli -->|"calls"| node_api
node_api -->|"manages"| node_leases
node_api -->|"lists"| node_device_view
node_api -->|"dispatches"| node_batch
node_api -->|"collects"| node_logs
node_api -->|"records / replays"| node_macro
node_api -->|"controls"| node_device_ops
node_device_ops -->|"invokes"| node_adb
node_adb -->|"controls"| node_android
node_dashboard -->|"opens stream"| node_stream_client
node_stream_client -->|"renders with"| node_player
node_stream_client -->|"uses input"| node_interaction
node_stream_client -.->|"extends"| node_connection
node_connection -->|"creates channels"| node_multiplexer
node_dashboard -->|"opens fallback"| node_fallback
node_api -.->|"supports log review"| node_log_analysis
node_stream_server -->|"streams device"| node_android
node_file_listing -->|"uses"| node_connection
node_file_listing -->|"opens channels"| node_multiplexer
node_file_listing -->|"uses uploads"| node_file_push

click node_cli "https://github.com/kimyeongseong/qa-device-farm/blob/main/cli.py"
click node_api "https://github.com/kimyeongseong/qa-device-farm/blob/main/server.py"
click node_leases "https://github.com/kimyeongseong/qa-device-farm/blob/main/server.py"
click node_device_view "https://github.com/kimyeongseong/qa-device-farm/blob/main/server.py"
click node_batch "https://github.com/kimyeongseong/qa-device-farm/blob/main/server.py"
click node_logs "https://github.com/kimyeongseong/qa-device-farm/blob/main/server.py"
click node_macro "https://github.com/kimyeongseong/qa-device-farm/blob/main/server.py"
click node_device_ops "https://github.com/kimyeongseong/qa-device-farm/blob/main/server.py"
click node_stream_server "https://github.com/kimyeongseong/qa-device-farm/blob/main/ws-scrcpy/src/server/index.ts"
click node_stream_client "https://github.com/kimyeongseong/qa-device-farm/blob/main/ws-scrcpy/src/app/googDevice/client/StreamClientScrcpy.ts"
click node_player "https://github.com/kimyeongseong/qa-device-farm/blob/main/ws-scrcpy/src/app/player/BasePlayer.ts"
click node_interaction "https://github.com/kimyeongseong/qa-device-farm/blob/main/ws-scrcpy/src/app/interactionHandler/InteractionHandler.ts"
click node_connection "https://github.com/kimyeongseong/qa-device-farm/blob/main/ws-scrcpy/src/app/client/ManagerClient.ts"
click node_multiplexer "https://github.com/kimyeongseong/qa-device-farm/blob/main/ws-scrcpy/src/packages/multiplexer/Multiplexer.ts"
click node_file_listing "https://github.com/kimyeongseong/qa-device-farm/blob/main/ws-scrcpy/src/app/googDevice/client/FileListingClient.ts"
click node_file_push "https://github.com/kimyeongseong/qa-device-farm/blob/main/ws-scrcpy/src/app/googDevice/filePush/FilePushHandler.ts"
click node_fallback "https://github.com/kimyeongseong/qa-device-farm/blob/main/server.py"
click node_log_analysis "https://github.com/kimyeongseong/qa-device-farm/blob/main/analyze_logs.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_dashboard,node_cli,node_browser toneBlue
class node_api,node_leases,node_device_view,node_batch,node_logs,node_macro,node_fallback,node_log_analysis toneAmber
class node_device_ops,node_adb,node_android toneMint
class node_stream_server,node_stream_client,node_player,node_interaction,node_connection,node_multiplexer,node_file_listing,node_file_push toneRose
class node_ci toneIndigo
```

## Components

### Farm clients

- **Device dashboard**
- [Farm CLI](https://github.com/kimyeongseong/qa-device-farm/blob/main/cli.py): `cli.py`

### Farm API

- [Farm API](https://github.com/kimyeongseong/qa-device-farm/blob/main/server.py): `server.py`
- [Device leases](https://github.com/kimyeongseong/qa-device-farm/blob/main/server.py): `server.py`
- [Device inventory](https://github.com/kimyeongseong/qa-device-farm/blob/main/server.py): `server.py`
- [Batch operations](https://github.com/kimyeongseong/qa-device-farm/blob/main/server.py): `server.py`
- [Logcat and crashes](https://github.com/kimyeongseong/qa-device-farm/blob/main/server.py): `server.py`
- [Macro record / replay](https://github.com/kimyeongseong/qa-device-farm/blob/main/server.py): `server.py`
- [Basic stream fallback](https://github.com/kimyeongseong/qa-device-farm/blob/main/server.py): `server.py`
- [Crash log analysis](https://github.com/kimyeongseong/qa-device-farm/blob/main/analyze_logs.py): `analyze_logs.py`

### Device operations

- [Device controls](https://github.com/kimyeongseong/qa-device-farm/blob/main/server.py): `server.py`
- **ADB**
- **Android devices**

### Streaming

- [Stream server](https://github.com/kimyeongseong/qa-device-farm/blob/main/ws-scrcpy/src/server/index.ts): `ws-scrcpy/src/server/index.ts`
- [Scrcpy stream client](https://github.com/kimyeongseong/qa-device-farm/blob/main/ws-scrcpy/src/app/googDevice/client/StreamClientScrcpy.ts): `ws-scrcpy/src/app/googDevice/client/StreamClientScrcpy.ts`
- [Video player](https://github.com/kimyeongseong/qa-device-farm/blob/main/ws-scrcpy/src/app/player/BasePlayer.ts): `ws-scrcpy/src/app/player/BasePlayer.ts`
- [Input interaction](https://github.com/kimyeongseong/qa-device-farm/blob/main/ws-scrcpy/src/app/interactionHandler/InteractionHandler.ts): `ws-scrcpy/src/app/interactionHandler/InteractionHandler.ts`
- [Client connections](https://github.com/kimyeongseong/qa-device-farm/blob/main/ws-scrcpy/src/app/client/ManagerClient.ts): `ws-scrcpy/src/app/client/ManagerClient.ts`
- [WebSocket multiplexer](https://github.com/kimyeongseong/qa-device-farm/blob/main/ws-scrcpy/src/packages/multiplexer/Multiplexer.ts): `ws-scrcpy/src/packages/multiplexer/Multiplexer.ts`
- [File listing](https://github.com/kimyeongseong/qa-device-farm/blob/main/ws-scrcpy/src/app/googDevice/client/FileListingClient.ts): `ws-scrcpy/src/app/googDevice/client/FileListingClient.ts`
- [File push handler](https://github.com/kimyeongseong/qa-device-farm/blob/main/ws-scrcpy/src/app/googDevice/filePush/FilePushHandler.ts): `ws-scrcpy/src/app/googDevice/filePush/FilePushHandler.ts`

### Other components

- **Browser user**
- **CLI / CI**

## Connections

- Browser user → Device dashboard: uses
- Device dashboard → Farm API: calls
- CLI / CI → Farm CLI: runs
- Farm CLI → Farm API: calls
- Farm API → Device leases: manages (evidence: `server.py`)
- Farm API → Device inventory: lists (evidence: `server.py`)
- Farm API → Batch operations: dispatches (evidence: `server.py`)
- Farm API → Logcat and crashes: collects (evidence: `server.py`)
- Farm API → Macro record / replay: records / replays (evidence: `server.py`)
- Farm API → Device controls: controls (evidence: `server.py`)
- Device controls → ADB: invokes
- ADB → Android devices: controls
- Device dashboard → Scrcpy stream client: opens stream
- Scrcpy stream client → Video player: renders with (evidence: `ws-scrcpy/src/app/googDevice/client/StreamClientScrcpy.ts`)
- Scrcpy stream client → Input interaction: uses input (evidence: `ws-scrcpy/src/app/googDevice/client/StreamClientScrcpy.ts`)
- Scrcpy stream client → Client connections: extends
- Client connections → WebSocket multiplexer: creates channels (evidence: `ws-scrcpy/src/app/client/ManagerClient.ts`)
- Device dashboard → Basic stream fallback: opens fallback
- Farm API → Crash log analysis: supports log review
- Stream server → Android devices: streams device
- File listing → Client connections: uses (evidence: `ws-scrcpy/src/app/googDevice/client/FileListingClient.ts`)
- File listing → WebSocket multiplexer: opens channels (evidence: `ws-scrcpy/src/app/googDevice/client/FileListingClient.ts`)
- File listing → File push handler: uses uploads (evidence: `ws-scrcpy/src/app/googDevice/client/FileListingClient.ts`)
