Skip to main content

Developer overview

Floor Walker is one monorepo. The Flex plugin started from the Twilio Professional Services Flex Project Template and keeps its feature system, Flex hooks and utilities; the backend services, the dialer and the desktop recorder were added next to it. For how the parts fit together at runtime, see Architecture.

Repository layout​

DirectoryWhat it is
plugin-tokin-flex/The Flex plugin (React, TypeScript). Features live in src/feature-library/.
serverless-functions/Twilio Functions used by the plugin and Studio
flex-config/Flex ui_attributes and TaskRouter skills per environment
tokin-api/Backend API (Fastify, Postgres, MinIO): CRM, recordings, insights, calendars, wallboard, supervisor console, reports
flex-dialer/Outbound dialer engine (engine/), its scripts and design notes
packages/service-kit/@tokin/service-kit: configuration, auth, database, errors and health checks shared by tokin-api and the dialer engine
flex-agent-screen-recorder/Electron desktop app for screen recording
wallboard-kiosk/Vite app for the TV wallboard; the renderer itself lives in the plugin's feature-library/wallboard/board/
dialer-console/Vite app for the dialer console (/dialer/) and, built with --mode reports, the reports console (/reports/)
deploy/, docker-compose.ymlThe backend stack: Caddy, Postgres and MinIO setup
infra-as-code/Optional Terraform for TaskRouter and Studio resources
addons/Extra deployable packages (empty by default); see Add-ons
scripts/Setup, deploy and maintenance scripts used by npm scripts and CI
docs/This documentation site

packages/service-kit, tokin-api and flex-dialer/engine are npm workspaces of the root package.json. The plugin, serverless functions, recorder, kiosk and consoles have their own package.json and lock file.

Prerequisites​

  • Node.js 20 or later (the backend images use Node 22).
  • Docker with the compose plugin, for the backend.
  • The Twilio CLI with a profile for a Flex account you can change. The root npm install installs a pinned twilio-cli locally, and npm run install-serverless-plugin / npm run install-flex-plugin (in plugin-tokin-flex/) add the CLI plugins.

First-time setup​

twilio profiles:use <your-profile>
npm install

The root npm install runs the setup script (scripts/setup-environment.mjs). For the active Twilio profile it fills the .env files of the serverless functions and flex-config, creates plugin-tokin-flex/public/appConfig.js from appConfig.example.js with the feature settings of flex-config/ui_attributes.common.json (an existing appConfig.js is left alone), and installs each package. Run npm run generate-env to repeat only the configuration step, and see Configuration for its options.

Then the backend:

cp .env.example .env            # fill the <random> values and the Twilio credentials
docker compose up -d --build # Postgres, MinIO, tokin-api, Caddy; add COMPOSE_PROFILES=dialer for the dialer

The API is on http://localhost:8088 (through Caddy) and http://localhost:8090 (direct). Put that URL in custom_data.features.screen_recording.api_url in appConfig.js. For the dialer, copy flex-dialer/.env.example to flex-dialer/.env first; see Outbound Dialer. All backend settings are listed in the configuration reference.

For hot reload of the backend services inside Docker, add the dev overlay:

docker compose -f docker-compose.yml -f docker-compose.dev.yml up --build

Or run a service on the host against the compose Postgres and MinIO: npm run dev -w tokin-api (reads the root .env, where DATABASE_URL and S3_ENDPOINT point at the published ports).

Running Flex locally​

npm start

This starts, in parallel:

ProcessPortScript
Serverless functions (twilio serverless:start, with the Node inspector)3001npm run start:serverless
Flex plugin dev server3000npm run start:plugin
Flex UI dev proxy (for Flex Insights)npm run start:insights

Open http://localhost:3000 and log in to your Flex account. The local plugin reads its feature settings from public/appConfig.js, which overrides the hosted Flex configuration; the local serverless functions are used because appConfig.js points the plugin at localhost:3001.

Callbacks from Twilio and Soniox need a public URL. The compose tunnel profile starts an ngrok tunnel to Caddy (NGROK_AUTHTOKEN, NGROK_API_DOMAIN in .env); set PUBLIC_BASE_URL and S3_PUBLIC_URL to the tunnel URL.

The other apps:

AppCommand
Screen recordercd flex-agent-screen-recorder && npm run dev
Wallboard kioskcd wallboard-kiosk && npm run dev
Dialer console / reports consolecd dialer-console && npm run dev / npm run dev:reports
Docsnpm run start:docs (port 3010)

Tests​

PackageCommandNotes
Plugincd plugin-tokin-flex && npm testJest with jsdom; Flex mocks in __mocks__/. npm run test:watch while working.
tokin-apiTEST_DATABASE_URL=... npm test -w tokin-apiVitest. Integration tests need a throwaway Postgres; the harness recreates the schema for each test file and fakes MinIO, OpenRouter, Soniox and Twilio.
Dialer engineTEST_DATABASE_URL=... npm test -w flex-dialer-engineVitest. Run npm run migrate -w flex-dialer-engine against the test database first (with DATABASE_URL set to it). Database tests are skipped without TEST_DATABASE_URL.
service-kitnpm test -w @tokin/service-kitVitest
Screen recordercd flex-agent-screen-recorder && npm testJest unit tests; npm run test:integration runs against a running tokin-api
Lintnpm run lint / npm run lint:fixESLint over the plugin, serverless functions and add-ons

A throwaway Postgres for the backend tests:

docker run -d --rm --name tokin-test-pg -p 127.0.0.1:55432:5432 \
-e POSTGRES_USER=test -e POSTGRES_PASSWORD=test -e POSTGRES_DB=tokin_test postgres:16-alpine
TEST_DATABASE_URL=postgres://test:test@localhost:55432/tokin_test npm test -w tokin-api

Use a separate database for the dialer engine. Type checks: npm run typecheck -w <workspace>. After changing a drizzle schema, run npm run db:generate -w tokin-api (or -w flex-dialer-engine) and commit the generated SQL in drizzle/.

The same checks run on every pull request; see CI/CD.

Conventions​

  • Localization. Every user-facing string in the plugin goes through a string hook, with an English text and a Hebrew translation in the feature's he.json. Hebrew switches the layout to right-to-left; use the useDirection hook from src/utils/rtl only when logic depends on direction. See Strings.
  • UI. Floor Walker screens use Ant Design inside ThemedLayout (src/utils/design/), which also handles RTL; Twilio Paste is available for Flex-styled elements.
  • Backend calls. Plugin code calls tokin-api through TokinApiClient (src/utils/tokin-api/), which sends the agent's Flex token. Use serverless functions only for work that needs Twilio credentials.

In this section​