PhoenixKitBoards

Collaborative infinite-canvas boards for PhoenixKit.

Admins open Boards in the sidebar, create a board, and open it — an infinite Fresco canvas with the Etcher drawing layer (shapes, text, images). Multiple people on the same board see each other's edits, cursors, and presence in real time. Each board is one row in phoenix_kit_boards.

Installation

# host app mix.exs
{:phoenix_kit_boards, "~> 0.4"}
mix deps.get
mix phoenix_kit.update # creates the phoenix_kit_boards table

Enable Boards on the admin Modules page. That's it — the sidebar tab, routes, permission, and JS all wire up automatically (PhoenixKit auto-discovers the module).

What you get

How it works

Requirements

Optional: the ephemeral socket

Cursors and in-flight drags are high-rate and worthless a moment later, and through a LiveView every position pays for a render and a diff — queued behind that process's real work: saving edits, uploads, link previews. They can go over a channel of their own instead. Sockets are declared on the endpoint, and that belongs to the host, so this is one line in endpoint.ex:

socket "/phoenix_kit/board", PhoenixKitBoards.Web.BoardSocket, websocket: true

Skipping it loses nothing that worked before: cursors fall back to the LiveView relay, which is where they used to go, and live drags simply don't appear. The client also falls back while the channel is joining and if it fails, so a socket that dies mid-session degrades rather than dropping cursors silently.

Joining is governed by a short-lived signed token naming the board and the peer, minted by the LiveView that rendered the page. The channel re-derives both from it, so a client cannot join a board it was never shown, or present as somebody else. Mounted somewhere other than the default path? Say so, and the client is told rather than left to guess:

config :phoenix_kit_boards, board_socket_path: "/somewhere/else"

License

MIT.