[ Case Study ]

Taulu

The digital bulletin board — events are posters, and the people and calendars you share them with are the boards they pin to.

  • React
  • Vite
  • Drizzle
  • GraphQL
  • PostgreSQL

No longer launching

Taulu is no longer intended to launch. As development continued, apps with similar ideas came to market with funding and an established user base behind them — not a race a solo build wins. No risk, no reward, so no hard feelings.

The marketing site is still up at taulu.net (opens in a new tab)

[ The Problem ]

The bulletin board used to hang somewhere real — the library corkboard, the cafe window, the community-center hallway. It's how you found the chess club, the run group, the open mic. Strangers posting to strangers, in a place everyone already passed through.

Those places are thinning out. The third spaces where community used to form — where you'd stumble onto something and just show up — keep closing or moving behind a screen. What's left is the group chat you're already in: fine for the plans you'd make anyway, useless for finding the ones you wouldn't.

The corkboard didn't just hold the plan. It's where you found the group in the first place.

Taulu is that board, online. An event is a poster, and the people and groups you share it with are the boards it's pinned to. Some boards are private: you and the friends you already have. Others are public: a community's board that a stranger nearby can find, follow and show up to.

[ Architecture ]

Taulu is three pieces: the model the whole thing runs on, the app, and the backend under it.

  1. 01

    The model

    The whole app is one idea made concrete: an event is a poster, and its host is either a person or a group, the board it's pinned to. A board can be private, for you and your friends, or public, a community anyone nearby can find and join. With that model right, discovery, the feed and who can see what all follow from how the pieces relate.

  2. 02

    The app

    A web app in React, built on Loom so it looks and behaves like a finished product rather than a prototype. A native iOS and Android app came first and was set aside: the web app reaches people without an app-store release in the way.

  3. 03

    The backend

    A GraphQL API over a Postgres database, with each part of the app in its own module and the database typed end to end, so a change to the data shows up as a reviewable change in code rather than a surprise at runtime.

[ Decisions ]

Discovery you opt into, not a feed that grabs you. The public side could have been an endless ranked feed, the move every social app makes. Taulu's isn't. Finding a group is a search by distance, interest or name, and nothing appears that you didn't ask for. That's the corkboard on purpose: a bulletin board doesn't decide what you see; you walk up and read it. The cost is that discovery takes a little intent. The point is that it should: the goal is getting people to something in the real world, not holding them in the app.

The simplicity is the product. Some features were ruled out for good, not postponed: messaging, ranked or recommended feeds, AI features, taking payments, photo albums, ratings and reviews. Each is easy to add later and impossible to take back once people depend on it, and each pulls the app away from what it is for. Messaging is the clearest case: even a free-text note on an invite is where a chat app begins, so invites carry none.

[ Built to Go Public ]

A public app is probed by automated scripts from the day it goes up, and a small one is an easy target. So before anyone outside could sign up, the app went through a security review, run with a checklist I built into JAMIE, my development system, and grounded in the industry's standard lists of web risks.

What it led to is unglamorous, which is the point. The app reaches its database through a role that can read and write rows but never change their structure. A sign-in is a session the server can end at once, from one device or all of them. Signing in, signing up and changing a password are rate-limited, since those are where someone guesses at passwords. And the API stops answering questions about its own shape, and stops returning internal error details, to anyone outside. It's the difference between an app that's ready to be public and one that hasn't been attacked yet.

[ Under the Hood ]

Two slices — the bulletin-board concept in the type system, and the discovery query that lets a stranger find a public group nearby.

The bulletin-board concept, in the type system. An event's hostis a union — a person or a calendar group — so "posted to a board" is a real type, not a convention. The computed fields are viewer-relative: the same query answers friendsGoingCount and available differently for every requester.

> server/api/Event/Event.schema.ts
union EventHost = User | CalendarGroup

type Event {
  id: ID!
  title: String!
  host: EventHost!            # a user or a calendar group
  cohosts: [User!]!           # share edit powers, except removal
  start: DateTime!
  venue: String
  city: City                  # canonical city (carries coordinates)
  price: Money                # null = free
  capacity: Int               # null = unlimited
  visibility: EventVisibility!
  interests: [Interest!]!
  goingAttendees(limit: Int): [RSVP!]!

  # Viewer-relative, computed from RSVPs.
  friendsGoingCount: Int!     # GOING RSVPs whose user is a friend of the requester
  myRsvp: RSVP
  canManage: Boolean!         # host, host-group organizer, or co-host
  available: Boolean!         # open spots AND the viewer's calendar is free
}

[ More Case Studies ]

JAMIE

A persistent AI development partner built on agent harnessing and context engineering.

[ read case study ]

Loom

A design system generator — describe a brand in one file, get the styles and Figma library every project is built from.

[ read case study ]

Paperboy

A news digest and the monitor behind it: charts that show which feeds are failing, and how.

[ read case study ]