Introducing MeetQuorum, a Self-Hosted Meeting Scheduler

Scratching an itch for my team, I build a Doodle clone over a couple of hours while enjoying some lovely wine in a sunny pub garden.

Marcus Povey

If you work in European research infrastructure, you schedule a lot of meetings. A lot of meetings. At Instruct-ERIC, coordinating between scientific teams scattered across a dozen countries, crystallographers in Florence, NMR spectroscopists in Frankfurt, electron microscopists in Utrecht, means that before any science gets discussed, someone first has to figure out when everyone is actually free. Across timezones. In the middle of everyone’s grant deadlines.

We’ve been using Doodle for this, like everyone else, and it’s… fine… it works. But it’s a third-party SaaS tool with our users’ email addresses and meeting metadata on someone else’s servers, and for an infrastructure that takes data sovereignty seriously, that sits increasingly uncomfortably. Plus, the free tier is limited enough to be annoying and the paid tier is more than I want to spend on what is, at its core, a fairly simple piece of software.

So I built a replacement. Over a couple hours and with no PHP written by me personally.

Designing the spec

I started the same way I did with Milkshake… an Obsidian note, a list of required features and nice-to-haves, and then a conversation with an AI to stress-test the ideas.

The core loop is simple enough: authenticated or guest user creates a poll with a title, description, and a set of candidate time slots. They get a permalink. They email it around. Recipients click the link, enter their name and email, and vote yes/no/if-needed on each slot. The creator sees the results ranked by score.

The conversation that followed was, again, more useful than I expected. The AI pushed back on things I’d glossed over, e.g. what happens when a poll closes? Can voters change their mind? What if someone opens the voting link on their phone in a different timezone to the one the poll was created in? (That last one is surprisingly thorny if you think it through properly.) We went back and forth on the guest versus authenticated user question, eventually landing on a “magic link” model for voters that avoids requiring accounts while still letting people return and update their vote.

The one thing I had to be deliberate about, which the Milkshake project didn’t require, was the deployment model. This needs to run on our Kubernetes cluster and talk to an external database cluster, so the AI was helpful in thinking through all the things that bite you when you move from “works on my machine” to “works across three replicas”, namely sessions in Redis, UUID primary keys rather than auto-increment integers, structured logging to stdout. Things that are easy to get right from the start and painful to retrofit.

The build

I asked the AI to write a build prompt from our conversation, which was the same approach as last time, producing a couple of pages of structured Markdown spec for an agentic tool to consume. I was more prescriptive this time, having learned from the Milkshake experience: I included the full data model, the exact ranking algorithm, the auth abstraction layer, the Docker Compose dev setup, and a specific build order. The more you put in, the less the agent has to guess.

I fed this into an agentic coding session. As before, there were a few sensible questions up front, about some subtleties around slot generation UX that hadn’t been fully resolved in the spec. We sorted those out in a quick back and forth, and then it went away and built the thing.

The result

An hour or so later I had a working application. Clean interface, timezone detection working correctly (this was the bit I was most worried about), the voting matrix rendering properly on mobile.

There’s still some wiring to do for the Keycloak SSO integration (we use Keycloak for identity management internally, and others may want to use one of the EOSC AAIs like LS Login) but the auth layer was built with that in mind from the start, so it’s a configuration exercise rather than a surgery job.

What I didn’t build: email notifications. That’s a deliberate v1 call. The “here is your link, please bookmark it” model is inelegant, but it ships, and email is a whole subsystem of its own, and is always a pain.

The take home

This is becoming a pattern now. The activation energy required to go from “this tool doesn’t quite do what I want” to “I have a thing that does exactly what I want, running on my own infrastructure” is dropping fast.

The tool is, objectively, not a complicated piece of software. I could have built it from scratch in a week of focused effort. But I don’t have a week, and I didn’t have to. What I had was a couple of evenings, a clear idea of what I needed, and enough experience to know what questions to ask and when to push back on the AI’s suggestions.

The sovereignty angle matters to me, particularly in a research context. These are real researchers’ schedules, real meeting metadata, real email addresses. Having that on our own infrastructure, under our own policies, is just the right answer regardless of cost.

As I said before, code is now a commodity.

Visit the project on Github...

Leave a Reply