Analytics & Reporting $99.99 / mo Updated 2026-04-24 VERSION 2 · NEW

Wallboard Designer — Setup & Widget Guide

Real-time wallboards for contact centers, ops floors, and command centers. Full CRUD over layouts, widgets, and displays via a WallboardEngine class and /crm/api/wallboard.php JSON endpoint. Wire your TVs, monitors, and supervisor desks to the same shared layouts that update in real time.

Overview

Wallboard Designer lets tenant admins build grid-based real-time dashboards — the kind you'd put on TVs around a call center or ops floor. Each wallboard is a layout containing widgets. Widgets can be numeric metrics, charts, tables, gauges, maps, clocks, text, images, iframes, or lists. A display device points at one layout and auto-refreshes on a configurable interval.

V2's scope is the CRUD backbone: creating, reading, updating, deleting, duplicating. The visual drag-and-drop designer canvas is a V2.1 deliverable; for now, widget positions are set via the API or the placement fields on each widget row.

What's new in V2

Full CRUD surface

WallboardEngine ships createLayout, updateLayout, deleteLayout, duplicateLayout, setDefaultLayout, addWidget, updateWidget, removeWidget, addDisplay, removeDisplay, and seedDefaultsForTenant. /crm/api/wallboard.php is the JSON endpoint that wraps each method. Every operation validates tenant ownership before INSERT / UPDATE / DELETE.

Tenant stats from the canonical tables

WallboardEngine::tenantStats() queries wallboard_layouts, wallboard_widgets, wallboard_displays, and wallboard_alerts directly. Real numbers, real tenant scope, real-time refresh.

Tenant isolation on every write

Every engine method validates the layout_id / widget_id / display_id against the current tenant before the INSERT. Cross-tenant crafted POSTs silently match zero rows and return a "not found" error without leaking whether the row exists elsewhere.

Admin gates on destructive actions

Only tenant admins (role_id 1/2/3) can delete a layout, set the tenant default, or register a display. Non-admin agents can create their own layouts and edit layouts they created.

Idempotent seeder

/admin/view-wallboard-state.php has a Seed defaults button that populates 6 widget templates, 3 themes, and a starter layout for any tenant with zero of either. Uses INSERT ... WHERE NOT EXISTS so re-running doesn't create duplicates.

State viewer for supervisor oversight

Six sections: schema health, activity stats, layouts, displays, widget templates, recent alerts. Sysadmin-only. No MySQL CLI needed for any ops or audit task.

Layouts

A layout is a single wallboard. Key fields on wallboard_layouts:

  • layout_name — up to 200 chars
  • grid_columns / grid_rows — up to 96×48 cells. Widget positions live in this coordinate system.
  • background_color — 7-char hex (validated via WallboardEngine::normalizeHexColor())
  • is_public — visible to every tenant user (true) or just creator + admins (false)
  • is_default — exactly one per tenant at a time; setDefaultLayout clears the flag from others in a transaction
  • rotation_enabled / rotation_interval_seconds / rotation_sequence — auto-rotate between layouts on a display (V2.1 wires this into the public view endpoint)

Widgets

Widgets live inside a layout. Ten types: metric, chart, table, gauge, map, clock, text, image, iframe, list. Key fields:

  • position_x / position_y / width / height — grid cells. A 24-column grid with a 6-wide widget at x=0 means the widget takes the left quarter of the screen.
  • z_index — overlap ordering
  • data_source — free-form string identifying where the widget's data comes from (api, database, custom)
  • refresh_interval_seconds — how often the widget re-queries (5-3600)
  • display_config — JSON blob with type-specific settings. Charts store chart type, thresholds, axes; tables store column lists; gauges store min/max/threshold colors.
  • background_color / text_color / border_* / opacity — per-widget styling overrides

Display devices

A display is a physical TV / monitor running a browser. Register each one in the Display Management tab or via add_display API:

  • device_name / device_location — "Ops floor TV 1" / "Second floor lobby"
  • device_identifier — you can supply your own (MAC address, unique string) or let V2 auto-generate one like RUBI-A1B2C3D4
  • assigned_layout_id — which wallboard this display shows (can be reassigned at any time)
  • screen_width / screen_height / orientation — helps future V2.1 designer render in the right aspect ratio
  • auto_refresh_enabled / refresh_interval_minutes — browser-side refresh cadence
  • last_heartbeat / status — V2.1 will ship the heartbeat endpoint; status flips online / offline / error

Permissions

ActionNon-admin agentTenant admin (1/2/3)
List layouts✅ all tenant layouts✅ all tenant layouts
Create layout
Edit layout⚠️ only their own✅ any
Delete layout
Set tenant default
Add / remove display
Add / edit / remove widget✅ on their own layouts✅ on any tenant layout
Seed defaults✅ (via sysadmin state viewer)

Quick start ≈ 15 minutes

  1. Activate the module at RubiMine. $99.99/mo.
  2. Sysadmin verifies schema at /admin/run-wallboard-v2-migration.php. All 8 tables should show ✅.
  3. Seed defaults from /admin/view-wallboard-state.php. Picks tenant, clicks Seed. Starter layout + 6 templates + 3 themes land in one click.
  4. Open the CRM Wallboards tab as a tenant admin. The starter layout "My First Wallboard" appears in the grid.
  5. Click Create Wallboard to add another. Name, description, grid dims, background color — save.
  6. Register a display in the Display Management tab. Supply name, location, resolution, and the layout to show.
  7. Star your tenant default — clicking the star sets the tenant-wide default layout, which any new display without an assignment falls back to.

API endpoints

All on /crm/api/wallboard.php. Session-authenticated, tenant-scoped.

Layouts

POST action=list_layouts
POST action=get_layout          (layout_id)  → includes widgets array
POST action=create_layout       (layout_name, layout_description?, grid_columns?, grid_rows?, background_color?, is_public?)
POST action=update_layout       (layout_id, layout_name?, ...)
POST action=set_default_layout  (layout_id) — admin only
POST action=delete_layout       (layout_id) — admin only
POST action=duplicate_layout    (layout_id)

Widgets

POST action=add_widget          (layout_id, widget_type, widget_title?, position_x?, position_y?, width?, height?, data_source?, refresh_interval_seconds?, display_config?)
POST action=update_widget       (widget_id, ...)
POST action=remove_widget       (widget_id)

Templates / themes / displays

POST action=list_widget_templates
POST action=list_themes
POST action=list_displays
POST action=add_display         (device_name, device_location?, device_identifier?, screen_width?, screen_height?, orientation?, assigned_layout_id?) — admin only
POST action=remove_display      (display_id) — admin only

Known limitations (V2)

  • Visual drag-and-drop designer — the Designer tab's grid canvas is still a V1 placeholder. V2 ships CRUD; V2.1 adds drag-to-place / drag-to-resize / snap-to-grid.
  • Public view endpoint/wallboard-view.php?display=<identifier> for display devices to render without a login session is a V2.1 ship. Today, display devices need a logged-in session.
  • Heartbeat endpoint — display status stays at "offline" because the heartbeat receiver isn't live. V2.1 adds POST /api/wallboard/heartbeat.
  • Widget data fetching — the engine stores data_source + data_query but doesn't execute them server-side. Widgets are expected to fetch their own data (e.g. via Chart.js + a separate API endpoint). A unified POST action=fetch_widget_data is on the V2.1 roadmap.
  • Alert ruleswallboard_alert_history + alert_condition field exist but nothing evaluates them yet. V2.1 will add a cron-driven alert evaluator.
  • Rotationrotation_enabled + rotation_sequence are stored but the public view doesn't rotate yet. Part of the V2.1 view endpoint.
  • Data sourceswallboard_data_sources table exists for future database / API / webhook sources; V2 doesn't populate it automatically.

Frequently asked questions

What does the engine do?
WallboardEngine is the single source of truth for layout / widget / display CRUD. Every write validates tenant ownership before the INSERT or UPDATE — cross-tenant access returns "not found" without leaking existence. tenantStats() reads the canonical wallboard_layouts, wallboard_widgets, wallboard_displays, and wallboard_alerts tables for live counts.
How is tenant isolation enforced?
Every engine method runs a tenant-verification query before the write. Cross-tenant layout_ids return "not found" without leaking existence. Delete uses WHERE id = ? AND tenant_id = ?; cross-tenant deletes match zero rows.
Can agents edit admin wallboards?
Only the creator or a tenant admin (role_id 1/2/3). updateLayout() checks created_by and refuses otherwise.
What widget types are supported?
Ten: metric, chart, table, gauge, map, clock, text, image, iframe, list. Each stores display_config JSON for type-specific settings.
How do display devices work?
Each TV / monitor runs a browser pointed at a public view URL. Registered in wallboard_displays with an identifier, assigned layout, resolution, refresh interval. Heartbeat endpoint is V2.1.
Is the drag-and-drop designer in V2?
Not yet. V2 ships the CRUD backbone. V2.1 adds the visual designer canvas with drag-to-resize + snap-to-grid.
How do I seed a new tenant?
From /admin/view-wallboard-state.php, pick the tenant and click Seed. Idempotent (INSERT ... WHERE NOT EXISTS). Seeds 6 templates + 3 themes + one starter layout.
How do public wallboards work?
is_public means visible to every user in the tenant — not the internet. V2.1 will add an unauthenticated display view endpoint for TVs.
How much does this cost?
$99.99 / month / tenant. Unlimited layouts, widgets, templates, themes, and display devices.

Ready to build wallboards that actually persist?

Activate, verify schema, seed, create. Your first wallboard in 15 minutes.