Pamela Estivam Marques← Back to work

Community tool · Design & build

The Connection Wall

A wall of clickable profiles a community builds itself in the twenty minutes it takes to go around a room. No accounts, no app, no one collecting a spreadsheet afterwards — just an address you can read out loud.

Role
Product & build — concept, interface, data model, ship
Built for
Coletivo Delas, then every group after it
Status
Live, in use
Visit
theconnectionwall.com ↗
theconnectionwall.com/stanfordclass

The Connection Wall

Room: Stanford Class

The wallStanford Class6 people
  • MB

    Maya Brooks

    Product designer learning to build her own front-end.

    View profile ↗
  • JR

    Jordan Reyes

    Data analyst at a fintech. Dashboards, mostly.

    View profile ↗
  • DW

    Danielle Ward

    Front-end dev. React and accessibility.

    View profile ↗
  • TC

    Tyler Cole

    Moving from law into UX research.

    View profile ↗
  • PN

    Priya Natarajan

    Community lead. I connect people for a living.

    View profile ↗
  • SO

    Sam Okafor

    Back-end engineer. Node, Postgres, coffee.

    View profile ↗

Add yourself

Name
Maya Brooks
LinkedIn URL
https://linkedin.com/in/mayabrooks
Short description
Product designer learning to build her own front-end.

54/280 characters

Generate profile
← Back to the wall
MB

Maya Brooks

Product designer learning to build her own front-end.

Visit LinkedIn profile ↗

Interface reproduction · sample profilesWall / Add yourself / Profile

The problem

A group meets — a collective, a cohort, a class — and everyone wants to find everyone else afterwards. What actually happens is a chat thread of pasted links that scrolls away by the next morning, or a signup sheet someone promises to type up and never does.

The information isn't hard to collect. Each person has one link and one sentence about themselves. The friction is entirely in the collecting: any tool that asks sixty people to make an account has already lost most of them, and a tool that asks one organiser to do the typing has just moved the work rather than removing it.

Design goal: from hearing a URL to being on the wall in under a minute, on a phone, standing up, with no password involved.

What it is

A room is a URL, and the URL is the whole invitation. An organiser names a room and picks the platform it runs on — LinkedIn for a professional group, Instagram for a creative one — which produces an address at the site root, like theconnectionwall.com/coletivodelas, ready to read off a stage or drop in a group chat.

Everyone who opens it sees the same page: a short form and the wall as it stands. Add your name, your link, and one line about yourself, and you become a circle other people can click straight through — there's no members-only view, because there are no members. The first room was built for Coletivo Delas, a women-in-tech collective, and it runs live today.

How it works

  1. 01

    Name the room

    The organiser names the room and picks the platform its members will link — LinkedIn today, with Instagram, X and the rest already in the picker.

  2. 02

    Share one link

    Members open it and fill three fields. Validation is immediate and human: “Use a full LinkedIn URL”, not “invalid input”. The description caps at 280 characters, with the counter running live.

  3. 03

    The wall fills in

    Each person lands as a circle carrying their initials, name and one line. Hovering lifts the tile; clicking opens their profile page, and from there, their LinkedIn.

Decisions

Decision 01

No accounts — so the database had to say no instead

Anyone with the link can add themselves, which is also the whole attack surface. The public database role holds SELECT and nothing more; every write passes through a server function that validates first. A leaked anon key gets someone a copy of a public wall, not a way to write to it.

supabase/migrations

Decision 02

Every room name has to produce a usable address

Room names fold into lowercase alphanumeric slugs, but a name in Japanese, an emoji, or something like “admin” leaves nothing safe behind. Every name still gets a room — it just gets a generated address when the slug collides or comes back empty, with a reserved list keeping rooms from ever shadowing a real route.

src/lib/rooms.functions.ts

Decision 03

One person, one tile — decided on the link, not the string

The same person rarely pastes the same URL twice. The wall stores exactly what was typed, but compares a normalised form — host without www, path without case or trailing slash, query dropped — so two slightly different pastes still land as one tile, with a unique index as the backstop.

src/lib/profiles.functions.ts

Decision 04

Rejection belongs under the field, not in a toast

Early versions surfaced one error at a time in a toast that vanished — bad on a phone, mid-form, at an event. Validation now reports every problem at once, under the field it belongs to, moves focus to the first one, and clears the message the moment that field is edited.

src/components/wall-form.tsx

Decision 05

The room decides which links are acceptable — never the client

Platforms live in one table that drives the dropdown, the label, the placeholder and the accepted hosts, on both sides of the wire. The server re-reads the room to find out what counts as valid rather than trusting whatever platform the form sent, and URLs are parsed rather than regex-matched.

src/lib/platforms.ts

Decision 06

Ship the code before the migration, without taking the wall down

Rooms were introduced after one wall was already live. Deploying code and applying a migration are separate events, so every read tries the new schema first and falls back to the old shape until the migration lands — which adopts every existing profile into a room at its already-published slug.

src/lib/legacy-schema.ts

Build order

Built narrow before general: each stage below only started once the previous one was in real use, which is why the hardest problem turned out to be generalising without breaking what was already live.

  1. Stage 01

    One hard-coded wall

    A single LinkedIn wall at a fixed path, profiles in one table, no concept of an owner — just enough to find out whether people would actually add themselves.

  2. Stage 02

    Identity: logo, favicon, dark palette

    A node-graph mark, eight nodes around a hub, two of them cyan — the shape that also decided the tile layout: circles, not cards.

  3. Stage 03

    Rooms as real rows at their own URLs

    Slugs, reserved paths, eight platforms, and a migration that adopted every existing profile so the already-published address kept working.

  4. Stage 04

    The things a real event exposed

    A copy-the-link button, because the address bar is the worst place to copy from on a phone. A duplicate guard, because people submit twice. Inline errors, because toasts disappear.

Built with

  • React 19
  • TypeScript
  • TanStack Start
  • TanStack Router
  • TanStack Query
  • Tailwind v4
  • shadcn/ui
  • Radix
  • Supabase
  • Zod
  • Vite 8
  • Bun

Server-rendered with file-based routing and typed server functions, so the wall is readable before JavaScript loads and shareable links resolve on the server.

What I’d do next

  • Ownership without accounts. A creator token in the link would let an organiser remove a tile or close a room — the one power the current model can't express.

  • Retire the compatibility bridge. The legacy fallbacks stop being reachable the moment the migration is applied; the file already names its own deletion criteria.

  • Room-level moderation. Public write access with no login has exactly one failure mode, and it needs an answer before a wall runs unattended.

  • Measure the funnel. Opens versus submissions per room is the number that would say whether the under-a-minute goal is actually met.

Craft notes

Small things took disproportionate care: the room name is stored as typed and uppercased in CSS, so every wall header reads alike without shouting at whoever named it. The share link reads its origin from the browser instead of a hard-coded domain, so preview deploys copy their own URL, not production's. Tiles are circles at a fixed aspect ratio with clamped text, so one long name can't break the grid.

The product is one form and one grid. Almost all of the work is in what happens when someone uses it imperfectly.