Friends¶
A friend in Tomoda is a mutual, symmetric, deliberately small thing. The social graph is the substrate every other feature runs on — events, live location, friend-only moments, mutual-friend counts in profiles — and we keep it intentionally narrow.
The story¶
The default in most social products is the asymmetric follow — one person
points at another, no consent required, and the resulting graph scales to
millions. We chose the opposite. A friendship in Tomoda is a single
undirected row with a status — pending, accepted, or blocked — and a
request has to be accepted by the recipient before it counts. There is no
"following", no "fan", no parasocial half-edge. If you're on someone's
friends list, they're on yours.
The reason is what the graph is for. Tomoda's edges aren't there to boost reach; they're there to gate live location and friends-only visibility on everything else. Live location is the most sensitive signal a social product can hold, and we don't want a one-tap follow button to be the access control on it. A mutual graph forces a moment of deliberate consent at the edge — which then makes everything downstream (seeing where a friend is on the map, the "5 friends nearby" radar count, the privacy default on a new moment) feel safe.
The graph is built to stay small. There is no recommended-friends
slot. There is no friend-of-friend ambient nudge. There is no "people you
might know" digest. Finding someone is an active act — a search, a profile
view, a request. The cost of that is slower growth; the benefit is that
the average user's list is people they actually know. The two privacy
shapes that live on top of the graph — the user's own is_location_shared
toggle (controls whether they show up on others' maps) and the per-room
disappearing-messages setting — both assume the graph itself is honest.
What we're optimising for¶
- Mutual over asymmetric. Both sides explicitly accept.
- Small over viral. No friend-recommendation engine. Search and request are the only paths to a new edge.
- Privacy is one-way at the read site. The user's own
is_location_sharedsetting controls whether others see them; it does not restrict what the user can see of friends who share with the user. - Block is severe. A blocked edge removes the user from the other's visibility on every surface — map, search, profile, mutual-friend counts.
- The friend list is the substrate. Friends-only visibility on
events, moments, profile detail, and live location all read from the
same
friendshipstable.
What the graph is not¶
- It is not a "follow" graph. There is no asymmetric edge.
- It is not a directory. We don't surface friend counts publicly as a status symbol; mutual-friend count on a profile is the closest we get and it exists for context, not bragging rights.
- It is not the basis for a recommendation engine. We don't compute "friends of friends" to push at the user; we surface the count when it's contextually useful (looking at a stranger's profile from a shared event, for instance).
See also¶
- Domain spec: Domains → Friends
- Backend implementation: Backend → Friends service
- How the graph feeds the map / radar: Bible → Discovery
- How the graph feeds live location: Bible → Presence
- UX for the connect tab, requests, profile view:
../ux/friends.md(coming soon)