Skip to content
Table of contents

DasherControl: A workspace dashboard across three boundaries

DasherControl brings homelab links and embedded applications into saved workspaces. Vue handles the interface, Rust and Rocket expose the API, and Diesel persists the layout in PostgreSQL. Docker control follows a separate path.

Application and services Docker
  • Updated
  • 8
  • Rust · 46.84%
  • MIT
Rust (Rocket)Vue 3PostgreSQLDocker Compose Rust Node.js cargo test
Documented components
2Explore modules
Source documents
2Read the instructions
Repository languagesRust 46.84%6

Shares calculated from GitHub Linguist bytes.

Rust46.84%
46.84%60,028 bytes
Vue43.67%
43.67%55,958 bytes
JavaScript4%
4%5,121 bytes
Shell2.55%
2.55%3,267 bytes
Language%Bytes
Rust46.84%60,028
Vue43.67%55,958
JavaScript4%5,121
Shell2.55%3,267
Dockerfile2.05%2,628
PLpgSQL0.89%1,145

1. Overview

1.1. Why it exists

Decoupled homelab architecture: Rust/Rocket backend managing Docker daemon via Shiplift, paired with a reactive Vue workspace frontend.

1.2. Best fit

Centralized command dashboard for homelab containerized services, bookmarks, and layout management.

2. Use cases

Rust (Rocket) and Vue dashboard for a home lab: grid workspaces of applets plus basic Docker container control.

Use-case diagram for DasherControl: Sign in to the dashboard; Arrange applets in a grid; Save and switch workspaces; Stop or restart containers; Open a web SSH terminalDasherControlSign in to the dashboardArrange applets in a gridSave and switch workspacesStop or restart containersOpen a web SSH terminalHomelab admin«system»Docker Engine«system»PostgreSQL
People on the left, external systems on the right; each oval is a use case backed by the files cited below.
Sign in to the dashboard
Homelab adminPostgreSQL

cargo run --bin create_admin creates the first account; POST /tenants/api/login checks the bcrypt hash and returns a JWT used by the protected routes.

Arrange applets in a grid
Homelab admin

GridLayoutMain.vue places applets such as IFrame, Shortcut, Editor, Canvas, Terminal and DockerManager on a resizable grid.

Save and switch workspaces
Homelab adminPostgreSQL

The /workspaces/api routes create, update, list and delete workspaces and their applets, stored in PostgreSQL through Diesel.

Stop or restart containers
Homelab adminDocker Engine

/containers/api/docker_list lists containers through shiplift, and /containers/api/stop/<id> and restart/<id> act on one container when a valid token is sent.

Open a web SSH terminal
Homelab admin

src/bin/start_websocket.rs bridges a WebSocket to an ssh2 session for the Terminal applet; the README lists the web terminal as in progress.

2.1. Scenario: Set up the dashboard on an Ubuntu server

  1. Build the frontend with cd frontend && npm install && npm run build.
  2. Set DATABASE_URL in Rocket.toml and .env, then run diesel migration run.
  3. Run cargo run --bin create_admin, then cargo run to start the Rocket server.
  4. Sign in, add IFrame applets for services such as Sonarr or Jellyfin and save the workspace.
  5. Open the DockerManager applet to list containers and restart one.

Files readREADME.mdCargo.tomlsrc/main.rssrc/tenants/handler.rssrc/workspaces/handler.rssrc/containers/handler.rssrc/bin/create_admin.rssrc/bin/start_websocket.rsfrontend/components/GridLayoutMain.vue

3. Getting started

These commands come from the repository documentation. They were not run during this review.

README.md · Install (Tested only on Ubuntu 20.04)
// bash scripts/rust-setup-dev.sh
// bash scripts/js-dev-setup.sh
cd frontend && npm install && npm run build && cd ..
cargo install diesel_cli --no-default-features --features postgres
// go in Rocket.toml and .env and change DATABASE_URL to your postgresql server
diesel migration run
// create admin user
cargo run --bin create_admin
// run web app
cargo run
Tasks declared in manifests

3.1. frontend/package.json

lint
eslint --ext .js,.vue frontend tests/unit
build
npm run clean && webpack --mode production
test
echo "Error: no test specified" && exit 1
docker-compose.yml · Docker
DOCKER_BUILDKIT=1 docker build -t antoinebou13/dashercontrol .
DOCKER_BUILDKIT=1 docker-compose up -d --build && docker-compose logs -f

4. Repository references

The repository does not provide a detailed guide for these steps. Start with its README and the source walkthrough above.

Source documentation

2 documents read from 2 candidates.

5. Features and components 2

Workspace ownership
Workspace list handlers derive a tenant identifier from a token. The applet retrieval handler checks the workspace’s tenant before returning its contents. A workspace and its applets therefore form a persisted user-owned layout.
Container operations
src/containers/docker.rs wraps Shiplift operations for Docker. These calls manage containers and images rather than layout records. Their failure handling matters: a failed list request prints an error and returns an empty vector.

6. Architecture

Expand a component to follow its connections, or explore the full diagram.

System components Context
Mermaid Interactive diagram

System overview of the components and connections verified in the repository.

Static architecture view for DasherControl
Static preview. The interactive diagram replaces it after Mermaid loads.
flowchart LR

subgraph group_dashboard["Dashboard UI"]
  node_main_ui["Dashboard Shell<br/>[Main.vue]"]
  node_grid["Workspace Grid<br/>[GridLayoutMain.vue]"]
  node_grid_item["Grid Items<br/>[GridItemApplet.vue]"]
  node_applet_router["Applet Selector<br/>[Applet.vue]"]
  node_applet_authoring["Applet Creation<br/>[CreateNew.vue]"]
  node_editor["Applet Editor<br/>[Editor.vue]"]
  node_iframe["Embedded Sites"]
  node_shortcut["Shortcuts<br/>[Shortcut.vue]"]
  node_canvas["Canvas Applet<br/>[Canvas.vue]"]
  node_login_ui["Login Screen<br/>[Login.vue]"]
end

subgraph group_identity["Tenant Identity"]
  node_tenant_api["Tenant Endpoints<br/>[handler.rs]"]
  node_tenant_model["Tenant Accounts<br/>[model.rs]"]
  node_token_auth["Token Validation<br/>[token.rs]"]
end

subgraph group_workspace["Workspace Data"]
  node_workspace_api["Workspace Endpoints<br/>[handler.rs]"]
  node_workspace_model["Workspace Records<br/>[model.rs]"]
  node_database[("PostgreSQL Access<br/>[db.rs]")]
  node_schema["Database Schema<br/>[schema.rs]"]
end

subgraph group_integrations["Runtime Integrations"]
  node_docker_ui["Docker Manager<br/>[DockerManager.vue]"]
  node_container_api["Container Endpoints<br/>[handler.rs]"]
  node_docker_engine["Docker Engine<br/>[docker.rs]"]
  node_terminal_ui["Terminal Applet<br/>[Terminal.vue]"]
  node_terminal_ws["Terminal WebSocket<br/>[websocket.rs]"]
  node_server["Rocket Server<br/>[main.rs]"]
end

node_user(("Dashboard User"))

node_user -->|"uses"| node_main_ui
node_main_ui -->|"renders"| node_grid
node_grid -->|"renders"| node_grid_item
node_grid_item -->|"renders"| node_applet_router
node_applet_router -->|"selects"| node_applet_authoring
node_applet_router -->|"selects"| node_editor
node_applet_router -->|"selects"| node_iframe
node_applet_router -->|"selects"| node_shortcut
node_applet_authoring -->|"configures"| node_applet_authoring
node_grid -->|"requests"| node_workspace_api
node_tenant_api -->|"authenticates"| node_tenant_model
node_tenant_api -->|"issues tokens"| node_token_auth
node_token_auth -->|"checks session"| node_tenant_model
node_workspace_api -->|"queries"| node_workspace_model
node_workspace_api -->|"validates"| node_token_auth
node_tenant_model -->|"queries"| node_schema
node_workspace_model -->|"queries"| node_schema
node_tenant_api -->|"uses connection"| node_database
node_workspace_api -->|"uses connection"| node_database
node_docker_ui -->|"requests"| node_container_api
node_container_api -->|"controls"| node_docker_engine
node_applet_router -->|"selects"| node_docker_ui
node_applet_router -->|"selects"| node_terminal_ui
node_server -->|"mounts routes"| node_tenant_api
node_server -->|"mounts routes"| node_workspace_api
node_server -->|"mounts routes"| node_container_api
node_server -->|"references"| node_terminal_ws
node_user -.->|"may use"| node_canvas
node_terminal_ui -.->|"SSH terminal"| node_terminal_ws


class node_main_ui,node_grid,node_grid_item,node_applet_router,node_applet_authoring,node_editor,node_iframe,node_shortcut,node_canvas,node_login_ui,node_user toneBlue
class node_tenant_api,node_tenant_model,node_token_auth toneAmber
class node_workspace_api,node_workspace_model,node_database,node_schema toneMint
class node_docker_ui,node_container_api,node_docker_engine,node_terminal_ui,node_terminal_ws,node_server toneRose

A configurable homelab dashboard where users arrange workspaces of applets. Vue calls Rocket endpoints for persistence, tenant checks and Docker actions; PostgreSQL stores workspace data and a separate adapter talks to Docker.

Components
24
Connections
29
Evidence-backed links
26/29
Text version of the diagram
  • Vue workspace UI → Rocket handlers
  • Rocket handlers → Diesel and PostgreSQL
  • Rocket handlers → Shiplift adapter
  • Shiplift adapter → Docker daemon
Follow one path through the code

Loading a workspace reaches the tenant-aware handlers and then its applet records. Restarting a container goes through the Docker adapter instead. The UI should distinguish an empty workspace, an unavailable Docker service and an iframe blocked by the embedded application.

7. Technical dossier

Built from the source at commit d5e4b5a (66 files). Each item comes from a pattern match in the code, so open the linked file before relying on it.

7.1. Layers and modules

Folders are sorted into layers by name, from the user interface down to data access. Because the sorting uses names only, the diagram says nothing about calls between layers.

Mermaid Layered view
flowchart TB
  subgraph L_presentation["Presentation"]
    direction TB
    presentation_0["frontend/components<br/>20 files"]
    presentation_1["frontend<br/>4 files"]
    presentation_2["frontend/pages<br/>4 files"]
    presentation_3["frontend/public<br/>1 file"]
  end
  subgraph L_interface["Entry points and API"]
    direction TB
    interface_0["bin<br/>2 files"]
    interface_1["(root)<br/>1 file"]
    interface_2["containers<br/>1 file"]
    interface_3["src<br/>1 file"]
    interface_more["+2"]
  end
  subgraph L_application["Application services"]
    direction TB
    application_0["scripts<br/>5 files"]
  end
  subgraph L_domain["Domain and business rules"]
    direction TB
    domain_0["containers<br/>1 file"]
    domain_1["src<br/>1 file"]
    domain_2["tenants<br/>1 file"]
    domain_3["workspaces<br/>1 file"]
  end
  subgraph L_infrastructure["Data and infrastructure"]
    direction TB
    infrastructure_0["src<br/>1 file"]
  end
  subgraph L_core["Core source"]
    direction TB
    core_0["tenants<br/>4 files"]
    core_1["certs<br/>3 files"]
    core_2["containers<br/>3 files"]
    core_3["terminal<br/>3 files"]
    core_more["+2"]
  end
  subgraph L_tests["Tests"]
    direction TB
    tests_0["tests<br/>6 files"]
    tests_1["frontend<br/>1 file"]
  end
  subgraph L_hosting["Build, CI and hosting"]
    direction TB
    hosting_0[".github<br/>6 files"]
    hosting_1["(root)<br/>2 files"]
  end
  L_presentation ~~~ L_interface
  L_interface ~~~ L_application
  L_application ~~~ L_domain
  L_domain ~~~ L_infrastructure
  L_infrastructure ~~~ L_core
  L_core ~~~ L_tests
  L_core ~~~ L_hosting
Modules and their main layer
ModuleLayerFilesTypesExtensions
frontend/componentsPresentation200.vue
tenantsCore source615.rs
containersCore source53.rs
scriptsApplication services50.sh
srcCore source55.rs
workspacesCore source510.rs
frontendPresentation40.js .vue
frontend/pagesPresentation40.vue
certsCore source30.sh
terminalCore source30.rs
binEntry points and API23.rs
(root)Entry points and API10.sh
frontend/publicPresentation10.xml

7.2. C4 model

From system context to code declarations. Each level reflects the available source evidence.

UML 1 · System context
1 · System context

The widest C4 view: who uses the project and which outside systems and data stores it relies on. Rendered with uml-mcp.

PlantUML source
@startuml
!include <C4/C4_Context>
LAYOUT_LEFT_RIGHT()
Person(P_http, "HTTP client")
System(SYS, "DasherControl", "DasherControl brings homelab links and embedded applications into sav…")
SystemDb(D0, "Rust SQL toolkit")
Rel(P_http, SYS, "Uses")
Rel(SYS, D0, "Reads and writes")
@enduml
UML 2 · Containers
2 · Containers

One level closer: the parts that run separately inside the project, their main language and how calls flow between them. Rendered with uml-mcp.

PlantUML source
@startuml
!include <C4/C4_Container>
LAYOUT_LEFT_RIGHT()
Person(P_http, "HTTP client")
System_Boundary(SYS, "DasherControl") {
  Container(APP, "DasherControl", "Rust")
  ContainerDb(DB0, "Rust SQL toolkit", "")
}
Rel(P_http, APP, "Uses")
Rel(APP, DB0, "Reads and writes")
@enduml
UML 3 · Components and layers
3 · Components and layers

Modules grouped by source-layer classification. Boundaries show organization, not runtime isolation or call relationships. Rendered with uml-mcp.

PlantUML source
@startuml
!include <C4/C4_Component>
LAYOUT_TOP_DOWN()
System_Boundary(SYS, "DasherControl") {
Boundary(L0, "Presentation", "layer") {
Component(M0_0, "frontend/components", "Vue", "20 files")
Component(M0_1, "frontend", "JavaScript, Vue", "4 files")
Component(M0_2, "frontend/pages", "Vue", "4 files")
Component(M0_3, "frontend/public", ".xml", "1 files")
}
Boundary(L1, "Entry points and API", "layer") {
Component(M1_0, "bin", "Rust", "2 files")
Component(M1_1, "(root)", ".sh", "1 files")
Component(M1_2, "containers", "Rust", "1 files")
Component(M1_3, "src", "Rust", "1 files")
Component(M1_4, "tenants", "Rust", "1 files")
Component(M1_5, "workspaces", "Rust", "1 files")
}
Boundary(L2, "Application services", "layer") {
Component(M2_0, "scripts", ".sh", "5 files")
}
Boundary(L3, "Domain and business rules", "layer") {
Component(M3_0, "containers", "Rust", "1 files")
Component(M3_1, "src", "Rust", "1 files")
Component(M3_2, "tenants", "Rust", "1 files")
Component(M3_3, "workspaces", "Rust", "1 files")
}
Boundary(L4, "Data and infrastructure", "layer") {
Component(M4_0, "src", "Rust", "1 files")
}
Boundary(L5, "Core source", "layer") {
Component(M5_0, "tenants", "Rust", "4 files")
Component(M5_1, "certs", ".sh", "3 files")
Component(M5_2, "containers", "Rust", "3 files")
Component(M5_3, "terminal", "Rust", "3 files")
Component(M5_4, "workspaces", "Rust", "3 files")
Component(M5_5, "src", "Rust", "2 files")
}
Boundary(L6, "Tests", "layer") {
Component(M6_0, "tests", "Rust", "6 files")
Component(M6_1, "frontend", "JavaScript", "1 files")
}
Boundary(L7, "Build, CI and hosting", "layer") {
Component(M7_0, ".github", ".md, .yml", "6 files")
Component(M7_1, "(root)", "Dockerfile, .yml", "2 files")
}
}
@enduml
UML 4 · Code
4 · Code

Selected declarations, fields and methods grouped by source file. No inheritance or call edges are inferred. Rendered with uml-mcp.

PlantUML source
@startuml
skinparam backgroundColor transparent
skinparam shadowing false
skinparam roundCorner 10
skinparam defaultFontName Arial
skinparam defaultFontSize 13
skinparam ArrowColor #4e6070
skinparam ArrowFontColor #3d4f5f
skinparam titleFontSize 14
skinparam actorBorderColor #006a62
skinparam actorBackgroundColor #e9f3f4
skinparam usecaseBorderColor #006a62
skinparam usecaseBackgroundColor #e9f3f4
skinparam componentBorderColor #006a62
skinparam componentBackgroundColor #e9f3f4
skinparam interfaceBorderColor #006a62
skinparam interfaceBackgroundColor #ffffff
skinparam nodeBorderColor #4e6070
skinparam nodeBackgroundColor #f4f8fb
skinparam databaseBorderColor #006a62
skinparam databaseBackgroundColor #ffffff
skinparam cloudBorderColor #4e6070
skinparam cloudBackgroundColor #f0f5fa
skinparam artifactBorderColor #006a62
skinparam artifactBackgroundColor #ffffff
skinparam rectangleBorderColor #b0c2d3
skinparam activityBorderColor #006a62
skinparam activityBackgroundColor #e9f3f4
skinparam partitionBorderColor #b0c2d3
skinparam stereotypeCBackgroundColor #ffffff
top to bottom direction
hide empty members
package "DasherControl" {
package "src/containers/docker.rs" as F0 {
class "DockerInterface" as T0_0 {
  get_containers()
  get_images()
  docker_info()
  log_container()
  pull_image()
  check_image_exist()
}
}
package "src/tenants/model.rs" as F1 {
class "TenantConfiguration" as T1_0 {
  create()
  all()
  get()
}
class "DBJsonType" as T1_1 {
  from_sql()
  to_sql()
}
class "LoginHistory" as T1_2 {
  create()
  save_login_history()
}
class "Tenant" as T1_3 {
  id
  email
  name
  username
  password
  role
  created_at
  login_session
}
class "NewTenant" as T1_4 {
  email
  name
  username
  password
  role
  created_at
}
class "RegisterTenant" as T1_5 {
  email
  name
  username
  role
  password
  password_confirmation
}
class "RegisterTenantNoRole" as T1_6 {
  email
  name
  username
  role
  password
  password_confirmation
}
class "AuthTenant" as T1_7 {
  email
  username
  password
}
}
package "src/fairing.rs" as F2 {
class "CORS" as T2_0 {
  info()
  on_response()
}
}
package "src/db.rs" as F3 {
class "DbConn" as T3_0 {
  from_request()
  deref()
}
}
package "src/tenants/error.rs" as F4 {
class "MyError" as T4_0 {
  from()
  fmt()
}
}
package "src/workspaces/model.rs" as F5 {
class "Applet" as T5_0 {
  id
  name
  position_x
  position_y
  width
  height
  editable
  applet_data
}
class "NewApplet" as T5_1 {
  name
  position_x
  position_y
  width
  height
  editable
  applet_data
}
class "NewAppletNoWorkspace" as T5_2 {
  name
  position_x
  position_y
  width
  height
  editable
}
class "Workspace" as T5_3 {
  id
  display_order
  name
  tenant_id
}
class "WorkspaceWithApplets" as T5_4 {
  id
  display_order
  name
  tenant_id
}
class "NewWorkspace" as T5_5 {
  display_order
  name
  tenant_id
}
}
package "src/tenants/token.rs" as F6 {
class "Claims" as T6_0 {
  iat
  sub
  exp
  xsrf_token
  email
  username
  role
}
}
package "src/bin/create_admin.rs" as F7 {
class "NewTenant" as T7_0 {
  id
  email
  name
  username
  password
  role
  created_at
}
}
package "src/containers/model.rs" as F8 {
class "Container" as T8_0 {
  id
  name
  tenant_id
}
}
}
@enduml

7.3. Data flow

The calls from the GitDiagram graph, in the order you meet them from the entry points. GitDiagram generates the graph with AI; the file paths it cites were checked against the repository tree.

Mermaid Sequence diagram
sequenceDiagram
  autonumber
  participant P0 as Rocket Server
  participant P1 as Tenant Endpoints
  participant P2 as Workspace Endpoints
  participant P3 as Container Endpoints
  participant P4 as Terminal WebSocket
  participant P5 as Dashboard User
  participant P6 as Dashboard Shell
  participant P7 as Canvas Applet
  participant P8 as Tenant Accounts
  participant P9 as Token Validation
  participant P10 as PostgreSQL Access
  participant P11 as Workspace Records
  participant P12 as Docker Engine
  participant P13 as Workspace Grid
  participant P14 as Database Schema
  P0->>P1: mounts routes
  P0->>P2: mounts routes
  P0->>P3: mounts routes
  P0->>P4: references
  P5->>P6: uses
  P5--)P7: may use
  P1->>P8: authenticates
  P1->>P9: issues tokens
  P1->>P10: uses connection
  P2->>P11: queries
  P2->>P9: validates
  P2->>P10: uses connection
  P3->>P12: controls
  P6->>P13: renders
  P8->>P14: queries
  P9->>P8: checks session
Steps as text (+5)
  1. Rocket Server to Tenant Endpoints mounts routes
  2. Rocket Server to Workspace Endpoints mounts routes
  3. Rocket Server to Container Endpoints mounts routes
  4. Rocket Server to Terminal WebSocket references
  5. Dashboard User to Dashboard Shell uses
  6. Dashboard User to Canvas Applet may use
  7. Tenant Endpoints to Tenant Accounts authenticates
  8. Tenant Endpoints to Token Validation issues tokens
  9. Tenant Endpoints to PostgreSQL Access uses connection
  10. Workspace Endpoints to Workspace Records queries
  11. Workspace Endpoints to Token Validation validates
  12. Workspace Endpoints to PostgreSQL Access uses connection
  13. Container Endpoints to Docker Engine controls
  14. Dashboard Shell to Workspace Grid renders
  15. Tenant Accounts to Database Schema queries
  16. Token Validation to Tenant Accounts checks session
  17. Workspace Records to Database Schema queries
  18. Workspace Grid to Grid Items renders
  19. Workspace Grid to Workspace Endpoints requests
  20. Grid Items to Applet Selector renders
  21. Applet Selector to Applet Creation selects
  22. Applet Selector to Applet Editor selects
  23. Applet Selector to Embedded Sites selects
  24. Applet Selector to Shortcuts selects

7.4. Public interface

Outside code can use everything listed here. The project also declares 36 public types.

UML Use cases
Use cases

Each actor is a kind of caller, linked to what it can ask the project to do. Rendered with uml-mcp.

PlantUML source
@startuml
skinparam backgroundColor transparent
skinparam shadowing false
skinparam roundCorner 10
skinparam defaultFontName Arial
skinparam defaultFontSize 13
skinparam ArrowColor #4e6070
skinparam ArrowFontColor #3d4f5f
skinparam titleFontSize 14
skinparam actorBorderColor #006a62
skinparam actorBackgroundColor #e9f3f4
skinparam usecaseBorderColor #006a62
skinparam usecaseBackgroundColor #e9f3f4
skinparam componentBorderColor #006a62
skinparam componentBackgroundColor #e9f3f4
skinparam interfaceBorderColor #006a62
skinparam interfaceBackgroundColor #ffffff
skinparam nodeBorderColor #4e6070
skinparam nodeBackgroundColor #f4f8fb
skinparam databaseBorderColor #006a62
skinparam databaseBackgroundColor #ffffff
skinparam cloudBorderColor #4e6070
skinparam cloudBackgroundColor #f0f5fa
skinparam artifactBorderColor #006a62
skinparam artifactBackgroundColor #ffffff
skinparam rectangleBorderColor #b0c2d3
skinparam activityBorderColor #006a62
skinparam activityBackgroundColor #e9f3f4
skinparam partitionBorderColor #b0c2d3
skinparam stereotypeCBackgroundColor #ffffff
left to right direction
actor "HTTP client" as A_http
rectangle "DasherControl" {
  usecase "GET/POST/PUT /api (15 routes)" as U0
  usecase "GET /" as U1
  usecase "GET /json" as U2
  usecase "GET /show_count" as U3
  usecase "GET /count" as U4
  usecase "GET /ip" as U5
}
A_http --> U0
A_http --> U1
A_http --> U2
A_http --> U3
A_http --> U4
A_http --> U5
@enduml

HTTP routes 21

Mermaid Route map by prefix
flowchart LR
  api(["HTTP API"])
  g0["/api"]
  api --> g0
  g0r0["GET /api/list"]
  g0 --> g0r0
  g0r1["PUT /api/new"]
  g0 --> g0r1
  g0r2["GET /api/docker_list"]
  g0 --> g0r2
  g0r3["GET /api/create_container"]
  g0 --> g0r3
  g0r4["POST /api/restart/'container_id'"]
  g0 --> g0r4
  g0m["+10"]
  g0 --> g0m
  g1["/"]
  api --> g1
  g1r0["GET /"]
  g1 --> g1r0
  g2["/count"]
  api --> g2
  g2r0["GET /count"]
  g2 --> g2r0
  g3["/ip"]
  api --> g3
  g3r0["GET /ip"]
  g3 --> g3r0
  g4["/json"]
  api --> g4
  g4r0["GET /json"]
  g4 --> g4r0
  g5["/public"]
  api --> g5
  g5r0["GET /public/'file..'"]
  g5 --> g5r0
  g6["/show_count"]
  api --> g6
  g6r0["GET /show_count"]
  g6 --> g6r0
MethodPathSource
GET/api/listsrc/workspaces/handler.rs:29
PUT/api/newsrc/containers/handler.rs:27
GET/api/docker_listsrc/containers/handler.rs:36
GET/api/create_containersrc/containers/handler.rs:43
POST/api/restart/<container_id>src/containers/handler.rs:65
POST/api/stop/<container_id>src/containers/handler.rs:82
GET/src/router.rs:32
GET/jsonsrc/router.rs:38
Show 13 more routes
GET/show_countsrc/router.rs:47
GET/countsrc/router.rs:55
GET/ipsrc/router.rs:61
GET/public/<file..>src/router.rs:67
GET/api/tokensrc/tenants/handler.rs:11
POST/api/createsrc/workspaces/handler.rs:87
POST/api/loginsrc/tenants/handler.rs:65
POST/api/logoutsrc/tenants/handler.rs:106
GET/api/<workspace_id>src/workspaces/handler.rs:10
POST/api/newsrc/workspaces/handler.rs:47
POST/api/updatesrc/workspaces/handler.rs:57
POST/api/applets/createsrc/workspaces/handler.rs:77
POST/api/delete/<workspace_id>src/workspaces/handler.rs:108

Entry points

7.5. Private interface

These names are internal by the language’s conventions: a leading underscore, private, static or pub(crate).

module-private function
24

7.6. Entities and data model 27

Mermaid Entity class diagram
classDiagram
  direction LR
  class E0["Applet"] {
    +i32 id
    +String name
    +i32 position_x
    +i32 position_y
    +i32 width
    +i32 height
  }
  class E1["Tenant"] {
    +i32 id
    +String email
    +String name
    +String username
    +String password
    +String role
  }
  class E2["NewApplet"] {
    +String name
    +i32 position_x
    +i32 position_y
    +i32 width
    +i32 height
    +bool editable
  }
  class E3["Claims"] {
    +i64 iat
    +i32 sub
    +i64 exp
    +String xsrf_token
    +String email
    +String username
  }
  class E4["NewTenant"] {
    +String email
    +String name
    +String username
    +String password
    +String role
    +NaiveDateTime created_at
  }
  class E5["NewAppletNoWorkspace"] {
    +String name
    +i32 position_x
    +i32 position_y
    +i32 width
    +i32 height
    +bool editable
  }
  class E6["RegisterTenant"] {
    +String email
    +String name
    +String username
    +String role
    +String password
    +String password_confirmation
  }
  class E7["RegisterTenantNoRole"] {
    +String email
    +String name
    +String username
    +String role
    +String password
    +String password_confirmation
  }
  class E8["Workspace"] {
    +i32 id
    +i32 display_order
    +String name
    +i32 tenant_id
  }
  class E9["WorkspaceWithApplets"] {
    +i32 id
    +i32 display_order
    +String name
    +i32 tenant_id
  }

An arrow links a field to the entity its type names.

EntityKindFirst fields
AppletRecord or interfaceid, name, position_x, position_y, width, height, editable, applet_data
TenantRecord or interfaceid, email, name, username, password, role, created_at, login_session
NewAppletRecord or interfacename, position_x, position_y, width, height, editable, applet_data
ClaimsRecord or interfaceiat, sub, exp, xsrf_token, email, username, role
NewTenantRecord or interfaceid, email, name, username, password, role, created_at
NewAppletNoWorkspaceRecord or interfacename, position_x, position_y, width, height, editable
NewTenantRecord or interfaceemail, name, username, password, role, created_at
RegisterTenantRecord or interfaceemail, name, username, role, password, password_confirmation
Show 6 more entities
RegisterTenantNoRoleRecord or interfaceemail, name, username, role, password, password_confirmation
WorkspaceRecord or interfaceid, display_order, name, tenant_id
WorkspaceWithAppletsRecord or interfaceid, display_order, name, tenant_id
AuthTenantRecord or interfaceemail, username, password
ContainerRecord or interfaceid, name, tenant_id
NewWorkspaceRecord or interfacedisplay_order, name, tenant_id

7.7. Business logic

Once UI code and the services and entities above are set aside, these classes have the most methods.

DockerInterface Core source, 10 methods
get_containers, get_images, docker_info, log_container, pull_image, check_image_exist
TenantConfiguration Domain and business rules, 3 methods
create, all, get
DBJsonType Domain and business rules, 2 methods
from_sql, to_sql
LoginHistory Domain and business rules, 2 methods
create, save_login_history
CORS Core source, 2 methods
info, on_response
DbConn Data and infrastructure, 2 methods
from_request, deref
MyError Core source, 2 methods
from, fmt

7.8. Database and persistence

Tables and collections 7

users tenants workspaces applets containers login_history tenant_configuration

14 migrations

Data containers

postgres

7.9. External integrations

HTTP clients

axios

7.10. Stack and dependencies

Rust Cargo.toml 22 runtime

Rust edition 2018

Open the manifest

Node.js frontend/package.json 15 runtime, 29 dev

Open the manifest

External dependencies

65 declared packages (37 runtime, 28 development) in Cargo.toml, frontend/package.json.

Package table 65
External dependencies
PackageVersionScopePurposeRegistry
rocket0.4.7runtimeWeb frameworkcrates.io
rocket_contrib0.4.5runtimeCommunity contributed libraries for the Rocket web framework.crates.io
rocket_codegen0.4.7runtimeProcedural macros for the Rocket web framework.crates.io
serde1.0.104runtimeSerializationcrates.io
serde_derive1.0.99runtimeSerializationcrates.io
serde_json1.0.40runtimeSerializationcrates.io
diesel>=1.4.8runtimeDatabase accesscrates.io
chrono0.4.10runtimeDate and time library for Rustcrates.io
dotenv0.15.0runtimeConfigurationcrates.io
jsonwebtoken5.0.1runtimeAuthentication and securitycrates.io
bcrypt0.8.0runtimeAuthentication and securitycrates.io
csrf0.4.0runtimeCSRF protection primitivescrates.io
shiplift0.7runtimeA Rust interface for maneuvering Docker containerscrates.io
tokio1.4.0runtimeAn event-driven, non-blocking I/O platform for writing asynchronous I/O backed applications.crates.io
tokio-tungstenite0.13.0runtimeTokio binding for Tungstenite, the Lightweight stream-based WebSocket implementationcrates.io
log0.4runtimeA lightweight logging facade for Rustcrates.io
fern0.5runtimeSimple, efficient loggingcrates.io
futures0.3.13runtimeAn implementation of futures and streams featuring zero allocations, composability, and iterator-like interfaces.crates.io
futures-util0.3runtimeCommon utilities and extension traits for the futures-rs library.crates.io
uuid0.8.2runtimeA library to generate and parse UUIDs.crates.io
ssh20.9.1runtimeBindings to libssh2 for interacting with SSH servers and executing remote commands, forwarding local ports, etc.crates.io
openssl0.10.33runtimeOpenSSL bindingscrates.io
axios^0.21.1runtimeHTTP clientnpmjs.com
js-cookie3.0.0-rc.1runtimeA simple, lightweight JavaScript API for handling cookiesnpmjs.com
socket.io-client^4.0.1runtimeReal-time messagingnpmjs.com
tiptap^1.32.1runtimeA rich-text editor for Vue.jsnpmjs.com
tiptap-extensions^1.35.1runtimeExtensions for tiptapnpmjs.com
vue^2.6.12runtimeUser interfacenpmjs.com
vue-grid-layout^2.3.12runtimeUser interfacenpmjs.com
vuesax^4.0.1-alpha.25runtimeUser interfacenpmjs.com
vuex^3.6.2runtimeUser interfacenpmjs.com
vuex-persistedstate*runtimeUser interfacenpmjs.com
xterm^4.11.0runtimeFull xterm terminal, in your browsernpmjs.com
xterm-addon-attach^0.6.0runtimeAn addon for xterm.js that enables attaching to a web socket. This addon requires xterm.js v4+.npmjs.com
xterm-addon-fit^0.5.0runtimeAn addon for xterm.js that enables fitting the terminal's dimensions to a containing element. This adnpmjs.com
xterm-addon-search^0.8.0runtimeAn addon for xterm.js that enables searching the buffer. This addon requires xterm.js v4+.npmjs.com
xterm-addon-web-links^0.4.0runtimeAn addon for xterm.js that enables web links. This addon requires xterm.js v4+.npmjs.com
@babel/core^7.13.10developmentBuild toolingnpmjs.com
@babel/preset-env^7.13.10developmentBuild toolingnpmjs.com
babel-loader^8.2.2developmentBuild toolingnpmjs.com
clean-webpack-plugin^3.0.0developmentBuild toolingnpmjs.com
copy-webpack-plugin^8.0.0developmentBuild toolingnpmjs.com
css-loader^5.1.2developmentcss loader module for webpacknpmjs.com
eslint-plugin-vue^7.8.0developmentLinting and formattingnpmjs.com
file-loader^6.2.0developmentA file loader module for webpacknpmjs.com
gulp^4.0.2developmentThe streaming build system.npmjs.com
gulp-eslint^6.0.0developmentLinting and formattingnpmjs.com
html-webpack-plugin^5.3.1developmentBuild toolingnpmjs.com
image-minimizer-webpack-plugin^2.2.0developmentBuild toolingnpmjs.com
imagemin-gifsicle^7.0.0developmentImagemin plugin for Gifsiclenpmjs.com
imagemin-jpegtran^7.0.0developmentjpegtran imagemin pluginnpmjs.com
imagemin-optipng^8.0.0developmentImagemin plugin for OptiPNGnpmjs.com
imagemin-svgo^9.0.0developmentSVGO imagemin pluginnpmjs.com
postcss^8.2.8developmentBuild toolingnpmjs.com
postcss-loader^5.2.0developmentBuild toolingnpmjs.com
rimraf^3.0.2developmentA deep deletion module for node (like rm -rf)npmjs.com
sass^1.32.8developmentBuild toolingnpmjs.com
sass-loader^11.0.1developmentSass loader for webpacknpmjs.com
vue-friendly-iframe^0.20.0developmentUser interfacenpmjs.com
vue-loader^15.9.6developmentUser interfacenpmjs.com
vue-style-loader^4.1.3developmentUser interfacenpmjs.com
vue-template-compiler^2.6.12developmentUser interfacenpmjs.com
webpack^5.26.2developmentBuild toolingnpmjs.com
webpack-cli^4.5.0developmentBuild toolingnpmjs.com
webpack-dev-server^3.11.2developmentBuild toolingnpmjs.com

7.11. CI/CD pipeline

2 GitHub Actions workflows, 2 jobs. Each box is a job; double-bordered boxes publish or deploy, and arrows follow needs.

Mermaid Pipeline flow
flowchart LR
  subgraph wf0["build"]
    direction LR
    wf0_build["build<br/>ubuntu-latest"]
  end
  subgraph wf1["test"]
    direction LR
    wf1_build["build<br/>ubuntu-latest"]
  end
  t0(["Triggers · the · workflow · on · push · or"])
  t0 --> wf0_build
  t0 --> wf1_build
Workflows, triggers, jobs and targets
WorkflowTriggersJobsPublishes to
build
.github/workflows/build.yml
Triggers, the, workflow, on, push, or
  • build ubuntu-latest
    Checkout branch · Install ubuntu Dependencies · Install rust · use default .env file · Run cargo build · Install JS
—
test
.github/workflows/tests.yml
Triggers, the, workflow, on, push, or
  • build ubuntu-latest
    Checkout branch · Install ubuntu Dependencies · Install rust · use default .env file · Run cargo build
—

7.12. Deployment

Mermaid Deployment diagram
flowchart LR
  repo[("GitHub repository")]
  ci[["GitHub Actions<br/>2 workflows"]]
  image["Docker image<br/>FROM jdrouet/rust-nightly:stretch-slim-20201230"]
  repo -->|"push or pull request"| ci
  ci -->|"docker build"| image
UML Deployment
Deployment

The outer node is where the code runs. Each base image points to what it builds, solid arrows lead to databases and dashed ones to outside services. Rendered with uml-mcp.

PlantUML source
@startuml
skinparam backgroundColor transparent
skinparam shadowing false
skinparam roundCorner 10
skinparam defaultFontName Arial
skinparam defaultFontSize 13
skinparam ArrowColor #4e6070
skinparam ArrowFontColor #3d4f5f
skinparam titleFontSize 14
skinparam actorBorderColor #006a62
skinparam actorBackgroundColor #e9f3f4
skinparam usecaseBorderColor #006a62
skinparam usecaseBackgroundColor #e9f3f4
skinparam componentBorderColor #006a62
skinparam componentBackgroundColor #e9f3f4
skinparam interfaceBorderColor #006a62
skinparam interfaceBackgroundColor #ffffff
skinparam nodeBorderColor #4e6070
skinparam nodeBackgroundColor #f4f8fb
skinparam databaseBorderColor #006a62
skinparam databaseBackgroundColor #ffffff
skinparam cloudBorderColor #4e6070
skinparam cloudBackgroundColor #f0f5fa
skinparam artifactBorderColor #006a62
skinparam artifactBackgroundColor #ffffff
skinparam rectangleBorderColor #b0c2d3
skinparam activityBorderColor #006a62
skinparam activityBackgroundColor #e9f3f4
skinparam partitionBorderColor #b0c2d3
skinparam stereotypeCBackgroundColor #ffffff
node "Docker image" as H {
  artifact "DasherControl" as APP
}
artifact "FROM jdrouet/rust-nightly:stretch-slim…" as IMG0
IMG0 ..> APP : builds
artifact "FROM rust:alpine" as IMG1
IMG1 ..> APP : builds
database "Rust SQL toolkit" as DB0
APP --> DB0
cloud "WebSocket" as E0
APP ..> E0
@enduml

Where it runs

Docker base images

jdrouet/rust-nightly:stretch-slim-20201230 rust:alpine

7.13. Monitoring

What the code logs, measures and exposes to tell whether it is working.

Container health checks

7.14. Security

Controls

Environment variables 1

The page lists names without their values and underlines the ones that look like secrets.

NODE_ENV

7.15. Testing

Test files
7
Source files
64
Test cases, about
5
Unit tests
7

No measured coverage report in the analyzed sources.

Where the tests are

src/tests 6 frontend/tests/unit 1

Continuous integration

test
cargo test
UML CI pipeline
CI pipeline

The main GitHub Actions workflow runs these steps. Jobs that run in parallel sit side by side. Rendered with uml-mcp.

PlantUML source
@startuml
skinparam backgroundColor transparent
skinparam shadowing false
skinparam roundCorner 10
skinparam defaultFontName Arial
skinparam defaultFontSize 13
skinparam ArrowColor #4e6070
skinparam ArrowFontColor #3d4f5f
skinparam titleFontSize 14
skinparam actorBorderColor #006a62
skinparam actorBackgroundColor #e9f3f4
skinparam usecaseBorderColor #006a62
skinparam usecaseBackgroundColor #e9f3f4
skinparam componentBorderColor #006a62
skinparam componentBackgroundColor #e9f3f4
skinparam interfaceBorderColor #006a62
skinparam interfaceBackgroundColor #ffffff
skinparam nodeBorderColor #4e6070
skinparam nodeBackgroundColor #f4f8fb
skinparam databaseBorderColor #006a62
skinparam databaseBackgroundColor #ffffff
skinparam cloudBorderColor #4e6070
skinparam cloudBackgroundColor #f0f5fa
skinparam artifactBorderColor #006a62
skinparam artifactBackgroundColor #ffffff
skinparam rectangleBorderColor #b0c2d3
skinparam activityBorderColor #006a62
skinparam activityBackgroundColor #e9f3f4
skinparam partitionBorderColor #b0c2d3
skinparam stereotypeCBackgroundColor #ffffff
title test
start
partition "build" {
  :Checkout branch;
  :Install ubuntu Dependencies;
  :Install rust;
  :use default .env file;
  :Run cargo build;
}
stop
@enduml

Nothing found for: Services.

8. Deployment and operations

The ports, storage, and startup relationships below come from the repository configuration. depends_on records startup order, not service readiness.

Network. Bridge network dasher-net linking the DasherControl web app with PostgreSQL.

Deployment map

Compose topology of documented services, ports, and startup dependencies.

Static architecture view for DasherControl
flowchart LR
  classDef svc fill:#1b3040,stroke:#6fdbd0,color:#edf4fb
  dashercontrol["dashercontrol<br/>8000:8000"]:::svc
  postgres["postgres<br/>5432:5432"]:::svc
  postgres --> dashercontrol
Text version of the diagram
  • dashercontrol — Build from multi-stage Dockerfile · 8000:8000 → postgres, startup healthcheck
  • postgres — postgres:14-alpine · 5432:5432
ServiceImage or buildPublished portsStartupStorage
dashercontrolBuild from multi-stage Dockerfile8000:8000postgres, startup healthcheckNamed volume dasher-data
postgrespostgres:14-alpine5432:5432Named volume pgdata

9. Types and file structure

36 declared types, with 12 in the base-relationship overview.

Type diagram
classDiagram
direction TB
class t883aa4939d84["DockerInterface"] {
  <<struct>>
  new()
  init()
  get_containers()
  get_images()
}
class t6c6e876f9471["NewTenant"] {
  <<struct>>
}
class td007a4775b01["NewTenantConfiguration"] {
  <<struct>>
}
class t9d91c22b8e18["DBJsonType"] {
  <<struct>>
  from_sql()
  to_sql()
}
class t11bf41e6278b["Container"] {
  <<struct>>
  create()
  all()
}
class ta9679a334153["NewContainer"] {
  <<struct>>
}
class tdc82d141f21c["DbConn"] {
  <<struct>>
  from_request()
  deref()
}
class t981fd8c93b75["CORS"] {
  <<struct>>
  info()
  on_response()
}
class te127dc44374a["HitCount"] {
  <<struct>>
}
class t6437f975dc23["TemplateContext"] {
  <<struct>>
}
class tb361ddc722e9["JsonMessage"] {
  <<struct>>
}
class t8722c44b4eb9["MyError"] {
  <<enum>>
  from()
  fmt()
}

Unresolved bases remain labelled; full signatures are not reconstructed.

10. Reference

49 / 49 eligible files read (139 in the tree); 0 oversized, 0 failed reads and 0 syntax diagnostics.

What the scan covers

Known dependency/build folders, credential files and binaries are excluded. The scan covers READMEs, recognized manifests and parser-supported source files.

Linguist statistics cover the whole repository and may include other languages.

12. Files to read 3

13. Glossary

Repository

The versioned source files, configuration, and history of a project.

README

The repository’s entry document, usually covering its purpose and initial setup.

Dependency

A library, tool, or service that another component needs to build or run.

API

An interface through which software components exchange requests and results. An API does not have to use HTTP.

HTTP

A request-and-response protocol used by browsers and web services. A method, path, headers, and optional body describe a request.

Container

An isolated process environment created from an image. Persistent data needs storage outside the container’s disposable filesystem.

Volume and bind mount

A volume is storage managed by the container platform; a bind mount exposes a chosen host path inside a container.

Published port

A host port mapped to a service’s container port. Publishing a port can expose that service beyond its container network.

CLI

A text interface in which commands and arguments select operations. Exit codes let scripts detect success or failure.

Build

The steps that turn source files and dependencies into a runnable program or distributable artifact.

Database

A system for storing and querying structured records. Its schema, access rules, and persistence determine how the application can use that data.

14. References

  1. antoinebou12. (2026, November 5). DasherControl. [Software repository] github.com.
  2. antoinebou12. (2026, November 5). DasherControl: README. [Repository documentation] github.com.
  3. antoinebou12. (2026, November 5). src/workspaces/handler.rs. [Source file] github.com.
  4. antoinebou12. (2026, November 5). src/containers/docker.rs. [Source file] github.com.
  5. antoinebou12. (2026, November 5). Cargo.toml. [Source file] github.com.
  6. Boucher, A. (2026, October 23). DasherControl: a homelab dashboard built around workspaces. [Project article] antoineboucher.info.
  7. Boucher, A. (2021, September 6). DasherControl. [Project article] antoineboucher.info.
  8. Boucher, A. (2026, October 23). DasherControl: A workspace dashboard across three boundaries. [Project article] antoineboucher.info.

Sources without a publication date show the date they were last checked, November 5, 2026. File links retain the inspected revision where available.