Public Roadmap - 2024 06-19

To broadcast what we're working on at Membrane and make sure we're building what users actually want, we decided to share a public roadmap on our docs.

We use Height for project management, so ideally the roadmap would pull tasks directly from Height, updated in realtime. We wrote a Membrane program to do just that. The program also stores upvotes on each task and serves a form that emails us user feedback.

With Membrane's HTTP endpoints, drivers, persistence, and email, you can build a feature like this in less than an hour instead of days (or deciding not to build it at all).

Fetching tasks

When you visit our roadmap in docs, a GET / request fires to our program's HTTP endpoint to retrieve the latest tasks from our roadmap in Height (to improve page load speed I went with ISR, so the data refreshes every hour).

Data fetching is handled by the Height driver to simplify interaction with Height's API.


To get a sense of demand for tasks on our roadmap, we track upvotes. Membrane state makes it easy to set up persistence for this sort of thing, and Membrane endpoints enable easy API access to that data.

Our program endpoint exposes three routes to handle upvotes: GET /upvotes/:id, POST /upvote/:id, and POST /downvote/:id. Since you don't have to sign in to view docs, we limit upvotes per user (per task) using your IP address.

state.tasks[taskId][ipAddress] = true;

I borrowed this technique from Josh Comeau who uses IP to limit likes per reader on his blog.

That approach has one important flaw: multiple users might share the same IP address. For example, if five coworkers on the same network wanted to upvote the same feature, they would be limited to one upvote. We even ran into this problem ourselves while building the roadmap on a Membrane team onsite!

If you run into that issue, you can nudge us to fix it by upvoting and submitting feedback on our roadmap :)

Feedback form

As a complement to upvotes, we also added a space for more specific user requests.

Our program's endpoint includes a GET /feedback/:id route that serves an HTML form and a POST /feedback/:id route to handle submission. The latter forwards form data right along to us via the built-in Membrane email program.

const params = new URLSearchParams(req.body);
const email = params.get("email") || "anonymous";
const feedback = params.get("feedback");

await{ subject: "Roadmap feedback", body: feedback });

We respond to user emails quickly, so don't hesitate to send us feedback or ask for help setting up something similar for yourself.

- Pete (