# baloise/catcast architecture

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

- Interactive diagram: https://gitdiagram.com/baloise/catcast
- Repository: https://github.com/baloise/catcast

## Overview

1. **Overall shape**
   CatCast is a three-part Rust workspace for remote digital signage:
   - **catstage** runs on the display machine and shows content full-screen.
   - **catc** is the operator CLI used from a laptop to configure and control stages.
   - **catsocks** is the relay broker, deployed as a Cloudflare Worker/WebSocket endpoint.

2. **Primary trust boundary**
   The system is designed so the broker is not trusted with content or control data. catc and catstage communicate through catsocks using **end-to-end encrypted** messages, so the relay only sees opaque ciphertext and forwards it between peers.

3. **Control plane flow**
   The operator uses **catc** to initialize a room, register stages, import config, and issue navigation/control commands. Those commands travel over the broker to the target stage. The stage applies them locally and persists enough state to survive restarts and broker outages.

4. **Display/runtime boundary**
   **catstage** is the device-side runtime. It is a **Tauri / WebView2** app, intended to be dropped onto a Windows machine and run without admin rights. Its role is to receive remote state, manage the local viewer, and keep the display running in fullscreen.

5. **Stage internals**
   catstage is split into focused modules:
   - **socks**: network connectivity to the broker
   - **scheduler**: timing and rotation of display items
   - **logic**: execution of display behavior/policy
   - **persist**: local durable state
   - **autostart**: install/start-at-login behavior
   - **about**: local status/about-page data

6. **Operator-side internals**
   **catc** is a command-line client with separate config and networking layers:
   - **cfg**: command/config parsing and local configuration
   - **net**: broker/stage communication
   - **cli**: the user-facing commands
   - **main**: wiring and process startup  
   This makes catc the orchestration tool, not the display runtime.

7. **Shared domain and protocol**
   The workspace includes two shared crates:
   - **catcast-proto**: wire-level message/types for stage control and sync
   - **catcast-core**: shared configuration and state primitives  
   These crates define the common language between catc and catstage and keep protocol/state logic out of the app binaries.

8. **Broker implementation**
   **catsocks** is intentionally minimal: a dumb WebSocket relay, with no account system and no application-level business logic. It is deployed separately via **Wrangler** to Cloudflare Workers, which matches the repository’s “free-tier broker” design.

9. **Local persistence and recovery**
   Stage-side persistence is a first-class concern. catstage stores state locally so that a reboot or temporary broker outage does not erase the current signage state. That makes the display machine the source of truth for “what is currently shown,” while the broker is only a transport.

10. **Policy / content logic**
   The repo includes **default-logic/default.rhai** and example YAML configs, which suggests content behavior is scriptable or policy-driven rather than hard-coded. The stage likely executes this logic to decide what to show and for how long, while catc supplies configuration and overrides.

11. **Packaging and deployment**
   The workspace is set up for multi-binary build/release:
   - GitHub Actions for CI/release/deploy
   - a Tauri app package for catstage
   - a Worker deployment target for catsocks
   - examples for config and aliases  
   This indicates a split deployment model: desktop app on endpoints, serverless relay in the cloud, CLI on the operator machine.

12. **Architecture diagram summary**
   A useful diagram should show three nodes:
   - **Operator laptop**: catc
   - **Cloud relay**: catsocks on Cloudflare Workers
   - **Stage machine**: catstage  
   Connect catc and catstage through catsocks with encrypted WebSocket traffic, and show shared protocol/state crates feeding both clients. Add local persistence on catstage and the script/config inputs that shape display behavior.

Main entry points: [`crates/catstage/src/main.rs`](https://github.com/baloise/catcast/blob/main/crates/catstage/src/main.rs) (catstage main), [`crates/catsocks/src/lib.rs`](https://github.com/baloise/catcast/blob/main/crates/catsocks/src/lib.rs) (Relay core), [`crates/catc/src/main.rs`](https://github.com/baloise/catcast/blob/main/crates/catc/src/main.rs) (catc main), [`crates/catc/src/cfg.rs`](https://github.com/baloise/catcast/blob/main/crates/catc/src/cfg.rs) (Config)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_operator["Operator"]
  node_catc_main["catc main<br/>cli entry<br/>[main.rs]"]
  node_catc_cli["Commands<br/>CLI<br/>[cli.rs]"]
  node_catc_cfg["Config<br/>[cfg.rs]"]
  node_catc_net["Networking<br/>client net<br/>[net.rs]"]
end

subgraph group_stage["Stage"]
  node_stage_main["catstage main<br/>desktop app<br/>[main.rs]"]
  node_stage_socks["Socks<br/>broker link<br/>[socks.rs]"]
  node_stage_sched["Scheduler<br/>rotation<br/>[scheduler.rs]"]
  node_stage_logic["Logic<br/>policy engine<br/>[logic.rs]"]
  node_stage_persist[("Persist<br/>local store<br/>[persist.rs]")]
  node_stage_autostart["Autostart<br/>login setup<br/>[autostart.rs]"]
  node_stage_about["About<br/>status ui<br/>[about.rs]"]
end

subgraph group_shared["Shared"]
  node_proto["Protocol<br/>wire types<br/>[lib.rs]"]
  node_core_config["Core config<br/>shared config<br/>[config.rs]"]
  node_core_state["Core state<br/>shared state<br/>[state.rs]"]
end

subgraph group_broker["Relay"]
  node_catsocks_bin["catsocks<br/>relay bin<br/>[catsocks.rs]"]
  node_catsocks_lib["Relay core<br/>ws relay<br/>[lib.rs]"]
end

subgraph group_deploy["Deploy"]
  node_socks_deploy["Deploy workflow<br/>ci/deploy<br/>[socks-deploy.yml]"]
end

node_default_logic["Default logic<br/>rhai script<br/>[default.rhai]"]
node_example_config["Example config<br/>yaml example<br/>[config.yaml]"]
node_example_aliases["Aliases<br/>yaml example<br/>[aliases.yaml]"]

node_catc_main -->|"uses"| node_catc_cli
node_catc_main -->|"loads"| node_catc_cfg
node_catc_main -->|"drives"| node_catc_net
node_catc_net -->|"encodes"| node_proto
node_catc_cfg -->|"maps to"| node_core_config
node_catsocks_bin -->|"runs"| node_catsocks_lib
node_catsocks_lib -->|"forwards"| node_proto
node_catc_net -->|"connects"| node_catsocks_lib
node_stage_main -->|"uses"| node_stage_socks
node_stage_main -->|"uses"| node_stage_sched
node_stage_main -->|"uses"| node_stage_logic
node_stage_main -->|"uses"| node_stage_persist
node_stage_main -->|"uses"| node_stage_autostart
node_stage_main -->|"uses"| node_stage_about
node_stage_socks -->|"decodes"| node_proto
node_stage_logic -->|"reads"| node_core_state
node_stage_persist -->|"stores"| node_core_state
node_stage_logic -->|"scripts"| node_default_logic
node_catc_cfg -.->|"example"| node_example_config
node_catc_cli -.->|"example"| node_example_aliases
node_socks_deploy -->|"deploys"| node_catsocks_bin
node_socks_deploy -->|"packages"| node_catsocks_lib

click node_catc_main "https://github.com/baloise/catcast/blob/main/crates/catc/src/main.rs"
click node_catc_cli "https://github.com/baloise/catcast/blob/main/crates/catc/src/cli.rs"
click node_catc_cfg "https://github.com/baloise/catcast/blob/main/crates/catc/src/cfg.rs"
click node_catc_net "https://github.com/baloise/catcast/blob/main/crates/catc/src/net.rs"
click node_proto "https://github.com/baloise/catcast/blob/main/crates/catcast-proto/src/lib.rs"
click node_core_config "https://github.com/baloise/catcast/blob/main/crates/catcast-core/src/config.rs"
click node_core_state "https://github.com/baloise/catcast/blob/main/crates/catcast-core/src/state.rs"
click node_catsocks_bin "https://github.com/baloise/catcast/blob/main/crates/catsocks/src/bin/catsocks.rs"
click node_catsocks_lib "https://github.com/baloise/catcast/blob/main/crates/catsocks/src/lib.rs"
click node_stage_main "https://github.com/baloise/catcast/blob/main/crates/catstage/src/main.rs"
click node_stage_socks "https://github.com/baloise/catcast/blob/main/crates/catstage/src/socks.rs"
click node_stage_sched "https://github.com/baloise/catcast/blob/main/crates/catstage/src/scheduler.rs"
click node_stage_logic "https://github.com/baloise/catcast/blob/main/crates/catstage/src/logic.rs"
click node_stage_persist "https://github.com/baloise/catcast/blob/main/crates/catstage/src/persist.rs"
click node_stage_autostart "https://github.com/baloise/catcast/blob/main/crates/catstage/src/autostart.rs"
click node_stage_about "https://github.com/baloise/catcast/blob/main/crates/catstage/src/about.rs"
click node_default_logic "https://github.com/baloise/catcast/blob/main/default-logic/default.rhai"
click node_example_config "https://github.com/baloise/catcast/blob/main/examples/config.yaml"
click node_example_aliases "https://github.com/baloise/catcast/blob/main/examples/aliases.yaml"
click node_socks_deploy "https://github.com/baloise/catcast/blob/main/.github/workflows/socks-deploy.yml"

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_catc_main,node_catc_cli,node_catc_cfg,node_catc_net toneBlue
class node_stage_main,node_stage_socks,node_stage_sched,node_stage_logic,node_stage_persist,node_stage_autostart,node_stage_about toneAmber
class node_proto,node_core_config,node_core_state toneMint
class node_catsocks_bin,node_catsocks_lib toneRose
class node_socks_deploy toneIndigo
class node_default_logic,node_example_config,node_example_aliases toneNeutral
```

## Components

### Operator

Laptop-side control plane and CLI

- [catc main](https://github.com/baloise/catcast/blob/main/crates/catc/src/main.rs): cli entry · Wires command parsing, config, and networking · `crates/catc/src/main.rs`
- [Commands](https://github.com/baloise/catcast/blob/main/crates/catc/src/cli.rs): CLI · User-facing commands for room and stage control · `crates/catc/src/cli.rs`
- [Config](https://github.com/baloise/catcast/blob/main/crates/catc/src/cfg.rs): config · Parses local configuration and settings · `crates/catc/src/cfg.rs`
- [Networking](https://github.com/baloise/catcast/blob/main/crates/catc/src/net.rs): client net · Connects to broker and stages · `crates/catc/src/net.rs`

### Stage

Display-machine runtime and local state

- [catstage main](https://github.com/baloise/catcast/blob/main/crates/catstage/src/main.rs): desktop app · Tauri runtime wiring for the display machine · `crates/catstage/src/main.rs`
- [Socks](https://github.com/baloise/catcast/blob/main/crates/catstage/src/socks.rs): broker link · Connectivity to the relay broker · `crates/catstage/src/socks.rs`
- [Scheduler](https://github.com/baloise/catcast/blob/main/crates/catstage/src/scheduler.rs): rotation · Times and rotates display items · `crates/catstage/src/scheduler.rs`
- [Logic](https://github.com/baloise/catcast/blob/main/crates/catstage/src/logic.rs): policy engine · Executes display behavior and policy · `crates/catstage/src/logic.rs`
- [Persist](https://github.com/baloise/catcast/blob/main/crates/catstage/src/persist.rs): local store · Durable local state for recovery · `crates/catstage/src/persist.rs`
- [Autostart](https://github.com/baloise/catcast/blob/main/crates/catstage/src/autostart.rs): login setup · Install and start-at-login behavior · `crates/catstage/src/autostart.rs`
- [About](https://github.com/baloise/catcast/blob/main/crates/catstage/src/about.rs): status ui · Local status and about-page data · `crates/catstage/src/about.rs`

### Shared

Protocol and domain crates reused by clients

- [Protocol](https://github.com/baloise/catcast/blob/main/crates/catcast-proto/src/lib.rs): wire types · Wire-level messages for sync and control · `crates/catcast-proto/src/lib.rs`
- [Core config](https://github.com/baloise/catcast/blob/main/crates/catcast-core/src/config.rs): shared config · Shared configuration primitives · `crates/catcast-core/src/config.rs`
- [Core state](https://github.com/baloise/catcast/blob/main/crates/catcast-core/src/state.rs): shared state · Shared state model and persistence primitives · `crates/catcast-core/src/state.rs`

### Relay

Minimal WebSocket broker

- [catsocks](https://github.com/baloise/catcast/blob/main/crates/catsocks/src/bin/catsocks.rs): relay bin · Cloudflare Worker relay entrypoint · `crates/catsocks/src/bin/catsocks.rs`
- [Relay core](https://github.com/baloise/catcast/blob/main/crates/catsocks/src/lib.rs): ws relay · Minimal WebSocket forwarding logic · `crates/catsocks/src/lib.rs`

### Deploy

Release and deployment glue

- [Deploy workflow](https://github.com/baloise/catcast/blob/main/.github/workflows/socks-deploy.yml): ci/deploy · Worker deployment automation · `.github/workflows/socks-deploy.yml`

### Other components

- [Default logic](https://github.com/baloise/catcast/blob/main/default-logic/default.rhai): rhai script · Scriptable default display policy · `default-logic/default.rhai`
- [Example config](https://github.com/baloise/catcast/blob/main/examples/config.yaml): yaml example · Sample runtime configuration · `examples/config.yaml`
- [Aliases](https://github.com/baloise/catcast/blob/main/examples/aliases.yaml): yaml example · Sample command aliases · `examples/aliases.yaml`

## Connections

- catc main → Commands: uses · Command entry dispatches user operations
- catc main → Config: loads · Startup reads local configuration
- catc main → Networking: drives · CLI actions are executed through networking
- Networking → Protocol: encodes · Uses shared wire messages
- Config → Core config: maps to · Operator config aligns with shared config primitives
- catsocks → Relay core: runs · Worker entrypoint delegates to relay logic
- Relay core → Protocol: forwards · Relays opaque protocol frames without business logic
- Networking → Relay core: connects · Operator client reaches the broker over WebSocket
- catstage main → Socks: uses · Runtime wires broker connectivity
- catstage main → Scheduler: uses · Runtime schedules what is shown
- catstage main → Logic: uses · Runtime executes display policy
- catstage main → Persist: uses · Runtime persists recovery state
- catstage main → Autostart: uses · Runtime supports login startup
- catstage main → About: uses · Runtime exposes local status
- Socks → Protocol: decodes · Stage speaks the shared protocol through the broker
- Logic → Core state: reads · Display behavior depends on shared state model
- Persist → Core state: stores · Durable state is based on shared state primitives
- Logic → Default logic: scripts · Default policy is script-driven
- Config → Example config: example · Sample config informs operator setup
- Commands → Aliases: example · Sample aliases shape CLI usage
- Deploy workflow → catsocks: deploys · Workflow publishes the relay
- Deploy workflow → Relay core: packages · Deployment builds the worker runtime
