Adds a Kanban board to Request Tracker with real-time WebSocket updates, drag-and-drop ticket management, and a fully configurable lane layout.
Features
- Real-time updates across all connected browsers via WebSockets — no page reloads
- Drag-and-drop ticket operations with automatic field updates
- Powerful display filters with regular expression support
- Highly configurable lanes with custom queries and drop actions
- Search-integrated view — open any saved search as a Kanban board directly from the Feeds menu
- Queue-scoped owner dropdown — only users who can own tickets in the relevant queue are listed
- Lane width adapts to the number of lanes, making full use of available screen width
- Fullscreen mode for large monitors
- Bootstrap 5 / Dark Mode compatible UI (RT 6)
| Component | Minimum version |
|---|---|
| Request Tracker | 6.0.0 |
| Perl | 5.26 |
| Redis | 5.0 (for WebSocket live updates) |
| Mojolicious | 9.0 (for WebSocket server) |
| Mojo::Redis | 3.27 (for WebSocket server) |
perl Makefile.PL
make
sudo make installThe installer copies files into /opt/rt6/local/plugins/RT-Extension-KANBAN/.
Add to /opt/rt6/etc/RT_SiteConfig.pm:
Plugin('RT::Extension::KANBAN');sudo rm -rf /opt/rt6/var/mason_data/obj/*
sudo systemctl restart apache2 # or nginx / your web serverIn RT → Tools → Dashboard → Edit add the Kanban element to any dashboard column.
The Kanban board is also available directly from any ticket search: run a search, then open Feeds → Kanban in the search navigation to view the results as a Kanban board.
Configuration lives in /opt/rt6/etc/RT_SiteConfig.pm.
Set( %KanbanConfigs, (
MyBoard => q(
{
"lanes": [
{
"Name": "New / Open",
"Change": {"Status": "open"},
"Query": "(Status='open' OR Status='new')"
},
{
"Name": "Stalled",
"Change": {"Status": "stalled"},
"Query": "(Status='stalled') AND (Owner='{{=it.CurrentUser}}')"
},
{
"Name": "Resolved",
"Change": {"Status": "resolved"},
"Query": "(Status='resolved') AND (LastUpdated > '{{=it.Date}}')",
"timeOffset": 7
}
]
})
));Always clear the Mason cache after changing %KanbanConfigs.
| Field | Required | Description |
|---|---|---|
Name |
yes | Column header text |
Query |
yes | RT search query for tickets in this lane. Supports AND, OR, NOT, =, !=, <, <=, >, >= |
Change |
no | Ticket fields to update when a ticket is dropped into this lane, e.g. {"Status": "open"} |
timeOffset |
no | Days subtracted from today when expanding {{=it.Date}}. Default: 5 |
CallOnEnter |
no | JavaScript function body called on drop; receives ticket; must return an array of field names to save |
| Variable | Replaced with |
|---|---|
{{=it.Date}} |
Today's date minus timeOffset days (ISO format) |
{{=it.CurrentUser}} |
The logged-in RT username |
# Available to all users by default
Set(@KanbanDefault, "MyBoard", "OtherBoard");
# Override for a specific user (replaces @KanbanDefault for that user)
Set(@Kanban_alice, "MyBoard");Set($KanbanReadOnly_alice, 1);Set($cutCreatorName, 12); # default: 10Any ticket search can be opened as a Kanban board. After running a search in RT, the navigation bar shows a Feeds menu — select Kanban to open the current search results as a board.
The Kanban respects the active search query: each lane only shows tickets that match both the lane's own query and the search filter. Dragging a ticket between lanes still applies the lane's Change fields (e.g. updating Status or Owner) as usual.
The lane configuration (columns, queries, drop actions) is the same as for the dashboard widget and is controlled via %KanbanConfigs in RT_SiteConfig.pm.
When viewing tickets from a specific queue, the owner dropdown on each ticket card only lists users who have the OwnTicket right in that ticket's queue (including users with global rights). This avoids polluting the dropdown with users who cannot be assigned tickets in the relevant queue.
No additional configuration is required — the filtering is automatic.
The WebSocket server (bin/rt-kanban-websocket) subscribes to a Redis pub/sub channel and pushes ticket-update events to all connected browser tabs in real time.
RT (Perl) ──publishes ticket ID──► Redis channel "rt-ticket-activity"
│
rt-kanban-websocket (Mojolicious)
│
◄── JSON push ──────┴──── all connected browsers
RT publishes a ticket ID to Redis whenever a ticket changes. The WebSocket server debounces rapid successive events (200 ms window), then broadcasts { "updateTicket": { "id": "42", "sequence": N } } to every authenticated client. Each browser tab fetches the updated ticket data via REST 2.0 and re-renders only the affected card.
Install the required Perl modules:
sudo cpanm Mojolicious Mojo::Redis
# or
sudo cpanm --installdeps /opt/rt6/local/plugins/RT-Extension-KANBAN/Redis must be running and accessible:
sudo systemctl enable --now redis
redis-cli ping # should return PONGCopy and edit the configuration file:
sudo cp /opt/rt6/local/plugins/RT-Extension-KANBAN/etc/rt-kanban-websocket.conf \
/opt/rt6/local/plugins/RT-Extension-KANBAN/etc/rt-kanban-websocket.confEdit /opt/rt6/local/plugins/RT-Extension-KANBAN/etc/rt-kanban-websocket.conf:
{
# Redis connection URL
redis_url => 'redis://localhost',
# Pub/sub channel — must match the channel in KANBAN.pm
channel => 'rt-ticket-activity',
# Base URL of your RT instance (no trailing slash)
rt_url => 'https://rt.example.com',
# Cookie domain — must match your RT domain
rt_domain => 'rt.example.com',
rt_path => '/',
# REST 2.0 endpoint used to validate session cookies.
# Any ticket that exists works; use ticket 1 or another permanent ticket.
auth_probe_url => 'https://rt.example.com/REST/2.0/ticket/1',
log_level => 'info', # debug | info | warn | error | fatal
}sudo cp /opt/rt6/local/plugins/RT-Extension-KANBAN/etc/rt-kanban-websocket.service \
/etc/systemd/system/rt-kanban-websocket.service
sudo systemctl daemon-reload
sudo systemctl enable --now rt-kanban-websocket
# Verify
sudo systemctl status rt-kanban-websocket
journalctl -u rt-kanban-websocket -fThe service runs as www-data on port 5000 by default. Adjust User, Group, and the -l http://*:5000 listen address in the service file to match your environment.
Expose the WebSocket server under the same origin as RT so the browser can connect without CORS issues and the session cookie is forwarded automatically.
server {
listen 443 ssl;
server_name rt.example.com;
# ... your SSL certificate directives ...
# RT application
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# WebSocket server — same origin, different path
location /websocket {
proxy_pass http://127.0.0.1:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_read_timeout 600s;
proxy_send_timeout 600s;
}
}<VirtualHost *:443>
ServerName rt.example.com
# ... SSL directives ...
# RT application
ProxyPass / http://127.0.0.1:8080/
ProxyPassReverse / http://127.0.0.1:8080/
# WebSocket server
ProxyPass /websocket ws://127.0.0.1:5000/websocket
ProxyPassReverse /websocket ws://127.0.0.1:5000/websocket
</VirtualHost>
# Required modules: mod_proxy, mod_proxy_http, mod_proxy_wstunnelWith a reverse proxy in place the Kanban JavaScript connects to wss://rt.example.com/websocket automatically — no extra RT configuration is needed.
If you run the WebSocket server on a different port without a reverse proxy, tell RT which port to use:
# /opt/rt6/etc/RT_SiteConfig.pm
Set($WebsocketPort, "5000");The Kanban JavaScript will then connect to wss://rt.example.com:5000/websocket.
Both RT and the WebSocket server must be on the same domain so the browser forwards the session cookie.
Clear the Mason cache after any change to $WebsocketPort.
After starting the service, open the debug console in a browser while logged in to RT:
https://rt.example.com/websocket
The page shows a live WebSocket connection log with all incoming events.
The extension hooks into RT's callback system. Whenever a ticket is created or updated, RT publishes the ticket ID to the configured Redis channel. No changes to RT core are required — the hook lives in:
local/plugins/RT-Extension-KANBAN/lib/RT/Extension/KANBAN.pm
- Torsten Brumm rt.informationen@picturepunxx.de
- Paul Seitz paul.m.seitz@gmail.com
- Joachim Schiele js@lastlog.de
Please report bugs at https://github.com/nixcloud/rt-extension-kanban/issues.
- LiHAS Stuttgart for sponsoring this work
- Bob Cravens for his original Kanban example
- Christian Loos cloos@netcologne.de, Shawn Moore, Jim Brandt — for RT guidance
Copyright (c) 2016 Joachim Schiele / Paul Seitz.
Licensed under the GNU General Public License, Version 2 (GPL-2.0).


