Skip to content

Discovery — Domain Spec

Discovery is the read-and-aggregate domain: it answers "what's near me, who's near me, and who is this person" by querying the write domains, never by owning their state. This page is the rules for what's discoverable, at what zoom, under what visibility, and how the search and profile surfaces are shaped.

Mental model

Discovery is a projection layer with one small piece of its own state.

  1. It reads, it doesn't own. Events, locations, moments, friendships, presence, and user rows all live in their own domains. Discovery queries them (directly against the DB and Redis) and composes response shapes. It writes nothing back except the saved pin.
  2. The saved pin is the only owned state. A per-user "area selector" pill (GET / PUT /discovery/pin) remembers where the Find tab is centred between sessions.
  3. Four read shapes. The map (viewport + zoom), the radar (radius), search (natural-language + kind-scoped), and the profile card (one person, aggregated).

Surface area

All routes are under /discovery. Everything except the profile card requires auth; the profile card takes optional auth.

Route Returns
GET /discovery/map Viewport markers for a bounding box + zoom
GET /discovery/radar Friends + strangers within a radius, sorted by distance
GET /discovery/locations/:id Location detail card (highlights, hours, upcoming events)
GET /discovery/search Unified natural-language intent, fanned to events + locations
GET /discovery/search/events Event search near the pin
GET /discovery/search/locations Place search near the pin
GET /discovery/search/users User search by name / username (min 2 chars)
GET / PUT /discovery/pin Read / set the saved area pill
GET /discovery/taxonomy The place + event category vocabulary
GET /discovery/taxonomy/resolve Parse a free-text query into taxonomy terms
GET /discovery/profiles/:id Full aggregated profile card (optional auth)

The map-card detail reads for a single event or place render in the maps surface, and full event detail lives in Events. Discovery owns the location detail card and the aggregated profile card.

Search reuses the shared taxonomy parser plus the semantic resolver for natural-language intent, and the location geocoder to anchor a query on a named city (for example "bars in Toronto" from Ottawa).

Zoom tiers (the map)

Tier Zoom range Shape returned Sponsorship gate
Global ≤ 4 Grid cluster aggregates, ~10° cells
Regional 5–7 Grid cluster aggregates, ~3° cells
City 8–10 Individual markers, caps 200/200/100 (events/locations/moments) sponsorship_tier > 2 filtered out
Neighbourhood 11–13 Individual markers, caps 500/300/150 All tiers visible
Street ≥ 14 Individual markers, caps 1000/500/200 All tiers visible

At Global and Regional the server emits one geo_cluster marker per cell with per-type counts; no individual event/location/moment rows are returned. At City and above the server returns raw rows and the client clusters them visually. Friend markers bypass the cluster path at every zoom: they are always individual IsPriority = true markers.

Discoverable objects

Object When it appears
Event Status in (upcoming / ongoing); visibility honoured (see Events)
Location Always (real-world places are public)
Moment Not yet expired (expires_at > now or journaled); visibility honoured
Friend marker Friend is online AND has is_location_shared = true AND has live coordinates
Stranger (radar) Within radius AND both the requester and the stranger have near_you_enabled AND the stranger has is_location_shared = true

Visibility enforcement

Discovery introduces no new visibility rules. It enforces the rule each source domain already defines.

Read Rule
GET /discovery/profiles/:id Unauthenticated callers get the public-only view; friends-visibility moments and events appear only to an accepted friend
GET /discovery/locations/:id Moment highlights include friends-visibility moments only when the requester is a friend of the author; friend moments are sorted first
GET /discovery/radar A stranger surfaces only when both sides opted in via near_you_enabled and the stranger is actively sharing location
GET /discovery/map Event and moment markers honour the owning domain's visibility mode

The profile card exposes a friendship_status of none, pending_sent, pending_received, or accepted, computed relative to the caller.

Invariants

Invariant Why
Discovery owns no domain state It is a projection; the truth lives in the source domains
Low zoom always clusters Server-side aggregate; no per-marker query at continent scale
Friend markers are never clustered The whole point of the map is "where are my friends"
City zoom filters hyper-local sponsors sponsorship_tier > 2 events are dropped at zoom ≤ 10
The profile card degrades, never 404s on privacy An unauthenticated or non-friend caller gets the public subset, not an error
A cancelled map fetch is a 499, not a 500 Panning aborts in-flight requests; that is normal client behavior

Cross-domain interactions

Other domain Reads
Events Coordinates, status, visibility, sponsorship tier; host / joined / past events for the profile card
Locations Coordinates, category, hours JSON, photos; the geocoder anchors search on a named city
Moments Coordinates, visibility, expiry, like state; recent moments for the profile card
Friends Accepted friendships for the map overlay and radar; mutual counts and friendship_status for the profile card
Presence Live coordinates and online flags via a single Redis MGET per batch
Identity Public profile fields; the lean user card is a separate identity-owned read

See also