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.
- Languages
- 6Code breakdown
- Documented components
- 2Explore modules
- Source documents
- 2Read the instructions
Repository languagesRust 46.84%6
Shares calculated from GitHub Linguist bytes.
| Language | % | Bytes |
|---|---|---|
| Rust | 60,028 | |
| Vue | 55,958 | |
| JavaScript | 5,121 | |
| Shell | 3,267 | |
| Dockerfile | 2,628 | |
| PLpgSQL | 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.
- 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
- Build the frontend with cd frontend && npm install && npm run build.
- Set DATABASE_URL in Rocket.toml and .env, then run diesel migration run.
- Run cargo run --bin create_admin, then cargo run to start the Rocket server.
- Sign in, add IFrame applets for services such as Sonarr or Jellyfin and save the workspace.
- 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.
// 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 runTasks declared in manifests
3.1. frontend/package.json
linteslint --ext .js,.vue frontend tests/unitbuildnpm run clean && webpack --mode productiontestecho "Error: no test specified" && exit 1
DOCKER_BUILDKIT=1 docker build -t antoinebou13/dashercontrol .
DOCKER_BUILDKIT=1 docker-compose up -d --build && docker-compose logs -f4. Repository references
The repository does not provide a detailed guide for these steps. Start with its README and the source walkthrough above.
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.
Vue workspace UI
Rocket handlers
Diesel and PostgreSQL
- From Rocket handlers
Shiplift adapter
- From Rocket handlers
- To Docker daemon
Docker daemon
- From Shiplift adapter
Mermaid Interactive diagram
System overview of the components and connections verified in the repository.

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 toneRoseA 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
| Module | Layer | Files | Types | Extensions |
|---|---|---|---|---|
frontend/components | Presentation | 20 | 0 | .vue |
tenants | Core source | 6 | 15 | .rs |
containers | Core source | 5 | 3 | .rs |
scripts | Application services | 5 | 0 | .sh |
src | Core source | 5 | 5 | .rs |
workspaces | Core source | 5 | 10 | .rs |
frontend | Presentation | 4 | 0 | .js .vue |
frontend/pages | Presentation | 4 | 0 | .vue |
certs | Core source | 3 | 0 | .sh |
terminal | Core source | 3 | 0 | .rs |
bin | Entry points and API | 2 | 3 | .rs |
(root) | Entry points and API | 1 | 0 | .sh |
frontend/public | Presentation | 1 | 0 | .xml |
7.2. C4 model
From system context to code declarations. Each level reflects the available source evidence.
UML 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
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
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
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)
- Rocket Server to Tenant Endpoints mounts routes
- Rocket Server to Workspace Endpoints mounts routes
- Rocket Server to Container Endpoints mounts routes
- Rocket Server to Terminal WebSocket references
- Dashboard User to Dashboard Shell uses
- Dashboard User to Canvas Applet may use
- Tenant Endpoints to Tenant Accounts authenticates
- Tenant Endpoints to Token Validation issues tokens
- Tenant Endpoints to PostgreSQL Access uses connection
- Workspace Endpoints to Workspace Records queries
- Workspace Endpoints to Token Validation validates
- Workspace Endpoints to PostgreSQL Access uses connection
- Container Endpoints to Docker Engine controls
- Dashboard Shell to Workspace Grid renders
- Tenant Accounts to Database Schema queries
- Token Validation to Tenant Accounts checks session
- Workspace Records to Database Schema queries
- Workspace Grid to Grid Items renders
- Workspace Grid to Workspace Endpoints requests
- Grid Items to Applet Selector renders
- Applet Selector to Applet Creation selects
- Applet Selector to Applet Editor selects
- Applet Selector to Embedded Sites selects
- 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
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
| Method | Path | Source |
|---|---|---|
| GET | /api/list | src/workspaces/handler.rs:29 |
| PUT | /api/new | src/containers/handler.rs:27 |
| GET | /api/docker_list | src/containers/handler.rs:36 |
| GET | /api/create_container | src/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 | /json | src/router.rs:38 |
Show 13 more routes
| GET | /show_count | src/router.rs:47 |
| GET | /count | src/router.rs:55 |
| GET | /ip | src/router.rs:61 |
| GET | /public/<file..> | src/router.rs:67 |
| GET | /api/token | src/tenants/handler.rs:11 |
| POST | /api/create | src/workspaces/handler.rs:87 |
| POST | /api/login | src/tenants/handler.rs:65 |
| POST | /api/logout | src/tenants/handler.rs:106 |
| GET | /api/<workspace_id> | src/workspaces/handler.rs:10 |
| POST | /api/new | src/workspaces/handler.rs:47 |
| POST | /api/update | src/workspaces/handler.rs:57 |
| POST | /api/applets/create | src/workspaces/handler.rs:77 |
| POST | /api/delete/<workspace_id> | src/workspaces/handler.rs:108 |
Entry points
frontend/main.jsentry filemainpackage exportmain.jsfrontend/package.jsonsrc/main.rsentry file
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
get_connectionsrc/bin/create_admin.rs:65mainsrc/bin/create_admin.rs:72from_sqlsrc/bin/create_admin.rs:120
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.
| Entity | Kind | First fields |
|---|---|---|
Applet | Record or interface | id, name, position_x, position_y, width, height, editable, applet_data |
Tenant | Record or interface | id, email, name, username, password, role, created_at, login_session |
NewApplet | Record or interface | name, position_x, position_y, width, height, editable, applet_data |
Claims | Record or interface | iat, sub, exp, xsrf_token, email, username, role |
NewTenant | Record or interface | id, email, name, username, password, role, created_at |
NewAppletNoWorkspace | Record or interface | name, position_x, position_y, width, height, editable |
NewTenant | Record or interface | email, name, username, password, role, created_at |
RegisterTenant | Record or interface | email, name, username, role, password, password_confirmation |
Show 6 more entities
RegisterTenantNoRole | Record or interface | email, name, username, role, password, password_confirmation |
|---|---|---|
Workspace | Record or interface | id, display_order, name, tenant_id |
WorkspaceWithApplets | Record or interface | id, display_order, name, tenant_id |
AuthTenant | Record or interface | email, username, password |
Container | Record or interface | id, name, tenant_id |
NewWorkspace | Record or interface | display_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.
DockerInterfaceCore source, 10 methodsget_containers, get_images, docker_info, log_container, pull_image, check_image_existTenantConfigurationDomain and business rules, 3 methodscreate, all, getDBJsonTypeDomain and business rules, 2 methodsfrom_sql, to_sqlLoginHistoryDomain and business rules, 2 methodscreate, save_login_historyCORSCore source, 2 methodsinfo, on_responseDbConnData and infrastructure, 2 methodsfrom_request, derefMyErrorCore source, 2 methodsfrom, fmt
7.8. Database and persistence
Tables and collections 7
users tenants workspaces applets containers login_history tenant_configuration
Data containers
7.9. External integrations
HTTP clients
7.10. Stack and dependencies
Node.js frontend/package.json 15 runtime, 29 dev
External dependencies
65 declared packages (37 runtime, 28 development) in Cargo.toml, frontend/package.json.
Package table 65
| Package | Version | Scope | Purpose | Registry |
|---|---|---|---|---|
rocket | 0.4.7 | runtime | Web framework | crates.io |
rocket_contrib | 0.4.5 | runtime | Community contributed libraries for the Rocket web framework. | crates.io |
rocket_codegen | 0.4.7 | runtime | Procedural macros for the Rocket web framework. | crates.io |
serde | 1.0.104 | runtime | Serialization | crates.io |
serde_derive | 1.0.99 | runtime | Serialization | crates.io |
serde_json | 1.0.40 | runtime | Serialization | crates.io |
diesel | >=1.4.8 | runtime | Database access | crates.io |
chrono | 0.4.10 | runtime | Date and time library for Rust | crates.io |
dotenv | 0.15.0 | runtime | Configuration | crates.io |
jsonwebtoken | 5.0.1 | runtime | Authentication and security | crates.io |
bcrypt | 0.8.0 | runtime | Authentication and security | crates.io |
csrf | 0.4.0 | runtime | CSRF protection primitives | crates.io |
shiplift | 0.7 | runtime | A Rust interface for maneuvering Docker containers | crates.io |
tokio | 1.4.0 | runtime | An event-driven, non-blocking I/O platform for writing asynchronous I/O backed applications. | crates.io |
tokio-tungstenite | 0.13.0 | runtime | Tokio binding for Tungstenite, the Lightweight stream-based WebSocket implementation | crates.io |
log | 0.4 | runtime | A lightweight logging facade for Rust | crates.io |
fern | 0.5 | runtime | Simple, efficient logging | crates.io |
futures | 0.3.13 | runtime | An implementation of futures and streams featuring zero allocations, composability, and iterator-like interfaces. | crates.io |
futures-util | 0.3 | runtime | Common utilities and extension traits for the futures-rs library. | crates.io |
uuid | 0.8.2 | runtime | A library to generate and parse UUIDs. | crates.io |
ssh2 | 0.9.1 | runtime | Bindings to libssh2 for interacting with SSH servers and executing remote commands, forwarding local ports, etc. | crates.io |
openssl | 0.10.33 | runtime | OpenSSL bindings | crates.io |
axios | ^0.21.1 | runtime | HTTP client | npmjs.com |
js-cookie | 3.0.0-rc.1 | runtime | A simple, lightweight JavaScript API for handling cookies | npmjs.com |
socket.io-client | ^4.0.1 | runtime | Real-time messaging | npmjs.com |
tiptap | ^1.32.1 | runtime | A rich-text editor for Vue.js | npmjs.com |
tiptap-extensions | ^1.35.1 | runtime | Extensions for tiptap | npmjs.com |
vue | ^2.6.12 | runtime | User interface | npmjs.com |
vue-grid-layout | ^2.3.12 | runtime | User interface | npmjs.com |
vuesax | ^4.0.1-alpha.25 | runtime | User interface | npmjs.com |
vuex | ^3.6.2 | runtime | User interface | npmjs.com |
vuex-persistedstate | * | runtime | User interface | npmjs.com |
xterm | ^4.11.0 | runtime | Full xterm terminal, in your browser | npmjs.com |
xterm-addon-attach | ^0.6.0 | runtime | An addon for xterm.js that enables attaching to a web socket. This addon requires xterm.js v4+. | npmjs.com |
xterm-addon-fit | ^0.5.0 | runtime | An addon for xterm.js that enables fitting the terminal's dimensions to a containing element. This ad | npmjs.com |
xterm-addon-search | ^0.8.0 | runtime | An addon for xterm.js that enables searching the buffer. This addon requires xterm.js v4+. | npmjs.com |
xterm-addon-web-links | ^0.4.0 | runtime | An addon for xterm.js that enables web links. This addon requires xterm.js v4+. | npmjs.com |
@babel/core | ^7.13.10 | development | Build tooling | npmjs.com |
@babel/preset-env | ^7.13.10 | development | Build tooling | npmjs.com |
babel-loader | ^8.2.2 | development | Build tooling | npmjs.com |
clean-webpack-plugin | ^3.0.0 | development | Build tooling | npmjs.com |
copy-webpack-plugin | ^8.0.0 | development | Build tooling | npmjs.com |
css-loader | ^5.1.2 | development | css loader module for webpack | npmjs.com |
eslint-plugin-vue | ^7.8.0 | development | Linting and formatting | npmjs.com |
file-loader | ^6.2.0 | development | A file loader module for webpack | npmjs.com |
gulp | ^4.0.2 | development | The streaming build system. | npmjs.com |
gulp-eslint | ^6.0.0 | development | Linting and formatting | npmjs.com |
html-webpack-plugin | ^5.3.1 | development | Build tooling | npmjs.com |
image-minimizer-webpack-plugin | ^2.2.0 | development | Build tooling | npmjs.com |
imagemin-gifsicle | ^7.0.0 | development | Imagemin plugin for Gifsicle | npmjs.com |
imagemin-jpegtran | ^7.0.0 | development | jpegtran imagemin plugin | npmjs.com |
imagemin-optipng | ^8.0.0 | development | Imagemin plugin for OptiPNG | npmjs.com |
imagemin-svgo | ^9.0.0 | development | SVGO imagemin plugin | npmjs.com |
postcss | ^8.2.8 | development | Build tooling | npmjs.com |
postcss-loader | ^5.2.0 | development | Build tooling | npmjs.com |
rimraf | ^3.0.2 | development | A deep deletion module for node (like rm -rf) | npmjs.com |
sass | ^1.32.8 | development | Build tooling | npmjs.com |
sass-loader | ^11.0.1 | development | Sass loader for webpack | npmjs.com |
vue-friendly-iframe | ^0.20.0 | development | User interface | npmjs.com |
vue-loader | ^15.9.6 | development | User interface | npmjs.com |
vue-style-loader | ^4.1.3 | development | User interface | npmjs.com |
vue-template-compiler | ^2.6.12 | development | User interface | npmjs.com |
webpack | ^5.26.2 | development | Build tooling | npmjs.com |
webpack-cli | ^4.5.0 | development | Build tooling | npmjs.com |
webpack-dev-server | ^3.11.2 | development | Build tooling | npmjs.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
| Workflow | Triggers | Jobs | Publishes to |
|---|---|---|---|
build.github/workflows/build.yml | Triggers, the, workflow, on, push, or |
| — |
test.github/workflows/tests.yml | Triggers, the, workflow, on, push, or |
| — |
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
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
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.
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
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.

flowchart LR
classDef svc fill:#1b3040,stroke:#6fdbd0,color:#edf4fb
dashercontrol["dashercontrol<br/>8000:8000"]:::svc
postgres["postgres<br/>5432:5432"]:::svc
postgres --> dashercontrolText version of the diagram
- dashercontrol — Build from multi-stage Dockerfile · 8000:8000 → postgres, startup healthcheck
- postgres — postgres:14-alpine · 5432:5432
| Service | Image or build | Published ports | Startup | Storage |
|---|---|---|---|---|
| dashercontrol | Build from multi-stage Dockerfile | 8000:8000 | postgres, startup healthcheck | Named volume dasher-data |
| postgres | postgres:14-alpine | 5432:5432 | Named 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
- antoinebou12. (2026, November 5). DasherControl. [Software repository] github.com.
- antoinebou12. (2026, November 5). DasherControl: README. [Repository documentation] github.com.
- antoinebou12. (2026, November 5). src/workspaces/handler.rs. [Source file] github.com.
- antoinebou12. (2026, November 5). src/containers/docker.rs. [Source file] github.com.
- antoinebou12. (2026, November 5). Cargo.toml. [Source file] github.com.
- Boucher, A. (2026, October 23). DasherControl: a homelab dashboard built around workspaces. [Project article] antoineboucher.info.
- Boucher, A. (2021, September 6). DasherControl. [Project article] antoineboucher.info.
- 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.
Project facts