Boards discovers what it really is

The boards app started as ambition. A Visual Work OS, we called it — flexible boards with multiple views, automations, an offline exporter, the works. The first commit landed a kanban, a table, a calendar, a chart, and the saved-views machinery. It was good, and it was wrong.

It was wrong because every other app already had its own list of records. Tasks had a list. Projects had a list. Reminders, places, recipes, media, contacts — all of them had a list, and most of them had hand-rolled their own kanban or table somewhere along the way. Boards as a peer of those apps would just be another opinionated container — the user would have to pick which surface to live in, and changes in one wouldn't show in the other. That wasn't infrastructure; that was duplication wearing a different paint job.

The reframe took two days to find and one afternoon to build. Boards isn't an app. Boards is a view layer over data other apps own. The contract is small enough to write down in three lines: every integratable app exposes list_all() (return your records as a flat list), set_field(id, field, value) (write through to your storage), and a class-level SETTABLE_FIELDS whitelist naming which fields are safe to flip from outside. The boards engine reads through list_all, renders kanban or table or gallery or calendar or timeline against any column you point it at, and routes inline edits and drag-drops back through set_field. The app keeps domain orchestration; boards handles N-record presentation.

Five apps were wired up under the new contract in a single sitting. Their custom pages didn't change — they're still where you go for the per-record deep work, the AI features, anything that needs a capability call. But now each one has a kanban grouped by status, a gallery grouped by cover image, a calendar grouped by due date, the same filter and sort and bulk-edit surface, the same saved-views story. None of them implemented any of that themselves. The integration cost per app was about thirty lines.

The whitelist matters more than it looks. SETTABLE_FIELDS is the explicit boundary between fields that are safe to flip from anywhere and fields that need the app's own form or workflow. A status change on a job application can be a kanban drag-drop because it's a single string write that emits a domain event. A status change that triggers a multi-step process — emailing someone, generating a draft, kicking off a render — that stays off the whitelist and stays on the app's own page. The contract makes the safety boundary visible instead of accidental.

The shape generalised. We added a gallery view type — cover-grid with configurable image, title, subtitle, badge, and meta fields — and every integrated app got it the same day, no app code changes. That's the test for whether the substrate is real: does adding a primitive lift everything that speaks the contract, or do you have to walk the apps and wire each one? The answer here is the former, and that's the moment "another UI" became "infrastructure."

We hit one architectural temptation hard. Halfway through the wiring we caught ourselves about to extract a shared eos-board-view.js module that the consuming apps would import to render their own boards inline. Six hours of work, maybe. We reverted it. The shared rendering module would have been a weak duplicate of the boards engine — about a hundred and fifty lines pretending to be the two and a half thousand the real engine had grown. The right shape was an embed mode on the existing boards page: ?embed=1 hides the chrome and renders only the view, and any app that wants an inline rich-board view drops in an iframe with feature-detection. One source of truth for kanban-and-friends, zero parallel implementations.

What's still rough. App-sourced boards default to read-only — single-user system, the frontend toggle is enough — but the create-from-board path isn't defined yet. New items still get created in the source app's own UI. We'll spec that contract when the second app needs it, not today. And the failure mode for missing apps lands soft (a red banner naming what's gone, an empty list, no 500), but the diagnostic story for "why did this row stop showing up" is still grep-the-logs.

Boards keeps showing us what it wanted to be all along. We just had to stop building it as a peer.

Related Posts

← Back to posts