Skip to content

feat: show nearbuilders.org builders and projects on community pages - #452

Open
adenarc wants to merge 12 commits into
mainfrom
feat/community-nearbuilders
Open

adenarc wants to merge 12 commits into
mainfrom
feat/community-nearbuilders

Conversation

@adenarc

@adenarc adenarc commented Oct 26, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #451, part of NEARBuilders/nearbuilders.org#285

Adds a "Builders and projects" section to the public community page (/n/$slug), read from nearbuilders.org.

  • The API builds the community path from the node and its parents (illinois/chicago, or illinois for a top-level one) and reads /v1/builders?cityNode= and /v1/projects?cityNode= server-side (new public getCommunityBuilders).
  • Only items whose cityNode matches the path are kept. Production nearbuilders.org ignores the param today and returns everything, so this keeps the section on the empty state until feat: tag builders and projects with their citynode.app community nearbuilders.org#301 ships.
  • If nearbuilders.org is down or slow (5s timeout), the section shows a quiet "couldn't load" note and the page still renders. Good results are cached for 2 minutes, the last good result is served for up to an hour during an outage, and failures back off for 30s.
  • Shows up to 6 builders (name, avatar from their NEAR profile, account) and 6 projects (title, short description, logo), each linking to its nearbuilders.org page, plus "See all on NEAR Builders" when there are more. Empty state links to nearbuilders.org/join.
  • Base URL is the nearbuildersUrl API variable, default https://nearbuilders.org.
  • Strings in en/es/fr/zh. Read-only, no auth changes.

No changeset: main no longer has a .changeset folder.

Tested

  • pnpm run typecheck, pnpm run lint, pnpm run test pass. New API integration tests (nested path, top-level path with the filter ignored, nearbuilders down, unknown node) and UI tests (list + links, empty state, down state), all with made-up data.

  • Locally in the browser, with a stub of the two nearbuilders endpoints serving made-up builders/projects and three made-up communities in the dev DB: nested community list, empty state, nearbuilders-down state, signed out at desktop and 375px, and signed in. No console errors from this change.

  • Against live nearbuilders.org (no stub): the API returns ok with no items in ~1s, and the page shows the empty state, signed out, no console errors.

  • Review follow-ups: outage backoff (30s), shared in-flight request, stale fallback up to an hour, https-only logos, and no path when a community's parent chain is broken. All have unit tests.

Not tested

Screenshots

Nested community (Illinois / Chicago), signed out, desktop

Nested community, 375px

Empty state, desktop

Empty state, 375px

nearbuilders.org down

Signed in

Against live nearbuilders.org today (filter not deployed yet): empty state

Adds a Builders and projects section to the public community page. The
API builds the community path from the node and its parents, reads
nearbuilders.org /v1/builders and /v1/projects with ?cityNode=, keeps
only items tagged with that path, and reports nearbuilders.org as
unavailable instead of failing. The base URL is the nearbuildersUrl API
variable (default https://nearbuilders.org).

Closes #451
@multi-review

multi-review Bot commented Oct 26, 2026

Copy link
Copy Markdown

Multi Review · 8c627e2

Adds a public getCommunityBuilders endpoint. It builds the community path from the node's parent chain, fetches builders and projects from nearbuilders.org with a 5s timeout and a 2-minute cache of good results, and keeps only items tagged with that path. A new "Builders and projects" section on /n/$slug renders the result. The change is read-only and well contained: errors fall back to an "unavailable" state, logo URLs are limited to http(s), and the node lookup only exposes the same data as the already-public getNode. The one issue is low severity: failed fetches aren't cached.

1 issue(s)

What was checked (10 areas)
  • getCommunityBuilders handler in api/src/index.ts and its use of nodes.getById (same data already public via getNode)
  • communityPath loop: unknown node returns null, cycle guard and MAX_DEPTH, partial chain when a parent is missing
  • createNearbuilders.forPath: cache hit/miss, error fallback to stale or unavailable, Effect.promise never rejects
  • matchedPage total heuristic when the server ignores the filter and when it applies it, and how total is used in the UI (only for See all)
  • request(): URL building, timeout, non-OK handling, pageSchema parse failure caught
  • httpUrl sanitizing logoUrl; builder and project URLs built from the normalized baseUrl
  • NearbuildersSection states (loading, error, unavailable, empty, list) and BuilderCard calling authClient.near.getProfile (same use as $accountId.tsx)
  • SectionHeader props, useAuthClient and useApiClient exports, i18n keys
  • nearbuildersUrl variable in the plugin config and bos.app.ts
  • integration and UI tests against the implementation

Findings

  • 🟡 Low api/src/services/nearbuilders.ts:175 No negative caching: while nearbuilders.org is down or slow, every community page view waits up to 5s and makes 2 new outbound requests
    forPath only caches successful loads. If nearbuilders.org hangs or returns errors, every getCommunityBuilders call (one per community page view and per client cache expiry) runs load() again. That means two fresh fetches that can each wait the full 5s AbortSignal.timeout before falling back to unavailable. Concurrent requests for the same path aren't merged either. During an outage the API keeps one request open for about 5s per page view and sends a steady stream of retries to the failing upstream, and users see the skeleton for 5s before the 'couldn't load' note.
    Suggested fix: Cache the unavailable result (or the stale fallback) for a short backoff window, e.g. 15–30s, and/or keep an in-flight promise per path so concurrent requests share one upstream call.

Comment @multi-review to re-review new commits, or @multi-review full for a full review.

Comment thread api/src/services/nearbuilders.ts Resolved
Comment thread api/src/services/nearbuilders.ts Resolved
Comment thread api/src/services/nearbuilders.ts Resolved
Comment thread api/src/services/nearbuilders.ts Resolved
Comment thread ui/src/routes/_public/n/$slug.tsx Resolved
Return no path when a community's ancestor chain doesn't reach a root,
keep only https project logos, count totals from raw tags, share one
in-flight request per path, prune stale cache entries after an hour,
and read the join link from the API base URL.
Use Effect.fn for communityPath, derive the result type from the
contract schema, validate nearbuildersUrl in the config schema instead
of falling back silently, and tidy names and imports in the section.
…ilders

# Conflicts:
#	api/src/index.ts
#	bos.app.ts
…ilders

# Conflicts:
#	api/src/discovery-contract.ts
…ilders

# Conflicts:
#	api/src/index.ts
#	ui/src/routes/_public/n/-node-page.test.tsx
…ilders

# Conflicts:
#	ui/src/routes/_public/n/-node-page.test.tsx
@somewherelostt
somewherelostt requested review from elliotBraem and itexpert120 and removed request for elliotBraem October 29, 2026 11:58

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Show nearbuilders.org builders and projects on community pages

1 participant