DK Studio/Documentation
ProductChangelog

Architecture

DK Studio is two processes and one database, and the split is what makes the product usable in a lab. The platform holds every piece of state β€” agents, licences, users, command history β€” and gives you one browser view of every bench. The agent runs on the machine under test and does the physical work. Because the agent dials out, your benches need no public address, no port forward and no VPN client.

        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β”‚      DK Studio (server)      β”‚
        β”‚                              β”‚
        β”‚  Web UI  Β·  REST API         β”‚
        β”‚  Socket.IO server            β”‚
        β”‚        β”‚                     β”‚
        β”‚   β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”               β”‚
        β”‚   β”‚ Database β”‚  SQLite /     β”‚
        β”‚   β”‚          β”‚  PostgreSQL / β”‚
        β”‚   β”‚          β”‚  MySQL        β”‚
        β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜               β”‚
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                    β”‚  outbound only
                    β”‚  Socket.IO  (websocket, polling fallback)
                    β”‚  HTTP       (register, auth, poll, result)
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β”‚     DK Studio Agent          β”‚
        β”‚   (bench / PC / test rig)    β”‚
        β”‚                              β”‚
        β”‚  Shell  Β·  System info       β”‚
        β”‚  Serial ports  Β·  Device events β”‚
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

The platform

The platform is a Node application that serves the web UI, the REST API and the realtime socket from a single server on a single port. Browser and agents therefore share one origin, one port and one authentication story.

ConcernImplementation
Web UIServer-rendered pages under / and /dashboard, /agents, /settings, /admin
REST APIRoute handlers under /api
RealtimeSocket.IO mounted at /api/socket.io, transports websocket and polling
DatabaseRaw SQL over three interchangeable drivers
AuthSession cookie, three roles: admin, engineer, viewer

Database drivers

The schema is written three times β€” once per dialect β€” in lib/db/init.<driver>.sql. The driver is chosen during setup and recorded in .db-config.json, so the same codebase runs on:

  • SQLite β€” the default. A single file under DATA_DIR. Best for a single-server deployment.
  • PostgreSQL β€” for a shared or clustered deployment.
  • MySQL β€” for organisations that already run MySQL.

The driver is picked once, at setup, and every query in the platform goes through a small factory that speaks the right dialect. There is no ORM in the middle.

The agent

The agent is a small Node service that runs on the bench, next to the reader or the ECU. It does three things: it holds credentials, it keeps a connection to the studio, and it executes the commands it is handed.

ConcernImplementation
Identitydata/agent.json β€” agentId, apiKey, agentSecret, name, studioUrl, registeredAt
ConnectionSocket.IO to the studio, with an HTTP polling fallback every 5000 ms
Executionshell, get_system_info, get_serial_ports, open_serial, close_serial, serial_write
Eventsdevice_event messages carrying serial metadata
Local pageThe agent's own serial console on port 3001

The agent writes the script it is given to <cwd>/.agent_script_<Date.now()>.sh and runs it with /bin/bash. The default command timeout is 300000 ms, enforced on the agent: a command that outruns it is reported back as a timeout result, not as a hung request.

How a command travels

Two transports carry a command, and the agent uses both. They differ only in how the command reaches the agent; everything after that is identical.

The transport

PathRequestReply
PushThe studio emits a command request over the socket, carrying command, args and timeoutThe agent emits a command response, carrying status, output and error
PollThe agent calls GET /api/agent/commands?agentId= every 5000 ms and claims what it is givenThe agent posts the outcome to POST /api/agent/commands/result

Every message on the socket uses the same envelope: v, type, kind, id, timestamp, payload.

The command lifecycle

Both paths write to the same agent_commands table, so the state you see in the UI is the same either way.

pending  ──▢  in_progress  ──▢  completed

A row moves to in_progress when the agent claims it, and to completed when the result is posted. The row keeps command_type, the command_args JSON, the status, and a result JSON holding stdout, stderr, exitCode and durationMs. The result's own status is success, error or timeout.

Where the state lives

DataLives inNotes
Users, agents, licences, command historyThe platform databaseThe source of truth: users, agents, agent_licenses, agent_commands.
Licence entitlementagent_licenses.status and expires_atChecked when an agent registers: available, used or revoked.
Agent credentialsThe agent's data/agent.jsonIssued at registration and never re-shown.
PresenceThe live socket maponline and offline are derived from the connection, never stored as a flag.
Studio configuration.db-config.json, .studio-license.jsonWritten by the setup wizard.
Setup progress.setup-progress.json, .setup-completeThe marker file gates the setup wizard.
Serial byte streamsThe agentThe studio records serial metadata β€” path, manufacturer, serial number, vendor and product id.

Where it is going

Every connection is initiated by the agent. It dials out to the studio over Socket.IO and REST and authenticates there; the studio never dials back to a bench.

One direction only

If the studio can reach the agent, something is misconfigured. The agent must be able to reach the studio; the reverse is neither required nor used.

The agent reaches the studio over two surfaces: the persistent socket for commands and events, and HTTP for registration, authentication, heartbeats and polled results. The studio URL you configure on the agent β€” http://localhost:3000, or the address of your own server β€” is the only address the bench ever needs.