Smashboard
A command center for everything going on in your life
The board with seeded data and stub servers — it comes up end to end before anything real is connected.
Smashboard pulls the scattered surfaces of a day into one place. Unread mail, the meetings you have left, the countdown to the thing you are dreading, your todos and habits, your bookmarks, what is happening in your GitHub notifications and your Slack DMs, the weather, the news, and the camera on the porch — all on a single board you arrange yourself.
It is a multiuser Rails app, installable as a PWA, and API-first, so a native client can be layered on later without reimplementing any of it.
Arranging the board
The board is a four-column grid, and each panel's header carries a menu with four named widths — small, medium, large, full — rather than a free resize. Those are the four values that tile without leaving a ragged gap, so the constraint is the feature. Order is drag-and-drop by the header and persists per user; nothing about one person's layout is shared with anyone else's.
Hiding a panel sets enabled: false, which also drops it from /api/v1/dashboard and stops the refresh scheduler working on it. A hidden panel costs nothing — no polling, no payload.
What it connects to
- Google — Calendar for today's meetings, with the video-call link extracted from wherever the invite buried it, and Gmail for unread counts and headers.
- Slack — DMs and mentions, without keeping a client open all day.
- GitHub — notifications, review requests, and the state of things you are waiting on.
- Breaking news and weather — background-polled, with push notifications for the things worth interrupting you.
- Cameras — RTSP/snapshot panels for whatever is pointed at the driveway.
- Local panels — countdowns, todos, habits, and bookmarks, which need no third party at all.
Development mirrors production, deliberately
db:prepare creates three databases — the app's own plus Solid Queue's and Solid Cable's — because the interesting behaviour only exists when they are separate. Jobs run in their own worker process so recurring tasks actually fire, and Action Cable is database-backed so a Turbo Stream broadcast from that worker reaches the browser. A bare rails server gets you a dashboard that never refreshes itself and never notifies, which is not the app.
The test suite is hermetic. WebMock is on, the test environment sets fixed encryption keys, and stub servers in script/ stand in for every upstream, so the whole board can be brought up end to end on a fresh clone with no credentials at all.
Stack
| Framework | Ruby 3.4 on Rails, Hotwire (Turbo + Stimulus), Tailwind |
|---|---|
| Data | PostgreSQL 18, Active Record encryption for stored credentials |
| Background work | Solid Queue in a separate worker process |
| Realtime | Solid Cable — database-backed Action Cable |
| Auth | Devise, with password-challenged credential changes |
| Notifications | Web Push (VAPID) |
| Testing & CI | RSpec + WebMock, RuboCop, Brakeman, bundler-audit |
| Deploy | Docker Compose; one file, no Ruby needed on the host |
