Skip to content

Add setter follows, profiles, and unified search#840

Open
marcodejongh wants to merge 5 commits intomainfrom
feature/setter-follows
Open

Add setter follows, profiles, and unified search#840
marcodejongh wants to merge 5 commits intomainfrom
feature/setter-follows

Conversation

@marcodejongh
Copy link
Owner

Summary

Implements #812 - Allow following of all setters in the climbs dataset.

  • Setter follows: Users can follow any setter (including non-Boardsesh users synced from Aurora API). Following a setter with a linked Boardsesh account also creates a user follow.
  • Setter profile pages: New /setter/[username] route showing setter info, board type badges, follower count, follow button, linked Boardsesh profile link, and paginated created climbs list.
  • Unified search: Search now returns both Boardsesh users and setters, with de-duplication for linked accounts. Setter results show climb count and board type badges.
  • Created climbs on user profiles: Boardsesh user profiles now show a "Created Climbs" section for linked Aurora accounts.
  • Sync notifications: Shared sync detects newly inserted climbs and creates batched new_climbs_synced notifications for setter followers.
  • Notification display: New notification type renders as "{setter} set new climbs" and navigates to the setter profile on click.

Files changed across all packages:

  • db: setter_follows table, new_climbs_synced notification enum, migration, index on board_climbs.setter_username
  • shared-schema: GraphQL types/inputs/queries/mutations + TypeScript interfaces for setter profiles, climbs, unified search
  • backend: Setter follow/unfollow resolvers, profile/climbs queries, unified search with de-duplication, notification enrichment
  • web: Setter profile page, setter climb list component, unified search UI, user profile created climbs, sync notification creation, notification display

Test plan

  • Search for a known setter username → appears in results with climb count and board badges
  • Click setter result → navigates to /setter/[username] with profile and climbs
  • Follow/unfollow setter → follow count updates, persists on reload
  • View Boardsesh user with linked Aurora accounts → "Created Climbs" section appears
  • Run shared sync with new climbs from a followed setter → batched notification appears
  • Click new_climbs_synced notification → navigates to setter profile
  • Linked setter+user search → de-duplicated, shows as single user result with climb count
  • Run npm run typecheck → all packages pass

🤖 Generated with Claude Code

@chatgpt-codex-connector
Copy link

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@vercel
Copy link

vercel bot commented Feb 14, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
boardsesh Building Building Preview, Comment Feb 15, 2026 6:03am

Request Review

@claude
Copy link

claude bot commented Feb 14, 2026

Claude Review

Ready to merge - Minor issues noted below, but nothing blocking.

Issues

  1. Pagination bug in searchUsersAndSetters - packages/backend/src/graphql/resolvers/social/setter-follows.ts:339: The unified search collects all user and setter results into memory, sorts them, then applies offset/limit. This means totalCount reflects the in-memory array length, not the true database count. For large datasets, this could be inefficient and the pagination behavior may be surprising (e.g., total could change between pages). Consider using database-level pagination.

  2. Missing N+1 query optimization in notifications - packages/backend/src/graphql/resolvers/social/notifications.ts:46-62: The new_climbs_synced notification enrichment fetches climb data individually within a loop over groups. If many notifications exist, this will issue many separate queries.

  3. unfollowSetter always removes user_follows - packages/backend/src/graphql/resolvers/social/setter-follows.ts:442-458: When unfollowing a setter with a linked Boardsesh account, the code unconditionally removes the user_follows relationship. This could be unexpected if the user had independently followed the Boardsesh user before they linked their Aurora account. Consider checking if the user_follows was created via setter follow before removing.

  4. Missing index usage verification - The migration adds a partial index on board_climbs.setter_username (WHERE setter_username IS NOT NULL), but queries like ilike(dbSchema.boardClimbs.setterUsername, searchPattern) may not fully utilize this index for pattern matching. This is not a bug but worth verifying query performance.

Documentation

No documentation updates appear to be needed - this is a new feature addition that doesn't modify existing documented systems.

@claude
Copy link

claude bot commented Feb 14, 2026

Claude Review

Ready to merge - Well-structured feature implementation with good test coverage for the new setter follows functionality. Minor issues noted below, but nothing blocking.

Issues

  1. Pagination in unified search loads all results into memory - packages/backend/src/graphql/resolvers/social/setter-follows.ts:1048-1070: Results from both user and setter searches are collected in-memory, merged, sorted, and then paginated. For large datasets, this could cause memory issues. Consider database-level UNION with proper pagination.

  2. N+1 prevention in notifications is incomplete - packages/backend/src/graphql/resolvers/social/notifications.ts:488-498: The new new_climbs_synced notification type is handled but the batched fetching was added for climb data. However, the approach looks correct now with map-based lookups.

  3. unfollowSetter unconditionally removes user_follows - packages/backend/src/graphql/resolvers/social/setter-follows.ts:1264-1289: When unfollowing a setter with a linked Boardsesh account, the code always removes user_follows. If a user had independently followed the Boardsesh account before setter follows existed, unfollowing the setter would remove that relationship. Consider only removing if the follow was created through setter follow.

  4. Missing input sanitization for SQL LIKE patterns - packages/backend/src/graphql/resolvers/social/setter-follows.ts:1017-1019: The escapedQuery escapes %, _, and \, which is good, but the escaped backslash pattern could be wrong depending on how drizzle/postgres handles it. Should be \\$& to produce a literal backslash.

Tests

Good test coverage added:

  • packages/backend/src/__tests__/setter-follows.test.ts - Tests for follow/unfollow mutations including idempotency and linked account handling
  • packages/backend/src/__tests__/social-validation.test.ts - Validation schema tests for new setter-related inputs

Documentation

No documentation updates needed - this is a new feature that doesn't affect existing documented systems.

marcodejongh and others added 5 commits February 14, 2026 12:56
Allow users to follow setters (including non-Boardsesh users synced from
Aurora API), view setter profiles with created climbs, and search for
both users and setters in a unified search.

Key changes:
- Database: setter_follows table, new_climbs_synced notification type
- Backend: setter follow/unfollow, profile, climbs, unified search resolvers
- Shared sync: detect new climbs and notify setter followers
- Frontend: /setter/[username] profile page, unified search results,
  created climbs on user profiles, notification display

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The backend reads NEXTAUTH_SECRET to validate NextAuth JWTs but had no
checked-in env file providing it. Creates .env.development (not
gitignored) with the same dummy secret used by the web package, and
updates the dev script to load it.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…board climb thumbnails

Add setterClimbsFull GraphQL query that returns full Climb data with
litUpHoldsMap for thumbnail rendering. Extend ClimbsList with
boardDetailsMap support for multi-board contexts. Redesign setter
profile page to use shared playlist-view hero card layout with board
filter slider showing all user boards (disabled for boards without
setter climbs). Add unsupported visual state to ClimbCard/ClimbListItem
for climbs from boards the user doesn't own.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Account for the flex gap in the card width calculation so two cards
fit side-by-side instead of wrapping.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Batch notification enrichment to replace per-group DB loop with 3 max
  queries using inArray
- Fix unified search pagination by fetching limit+offset rows from each
  source before in-memory sort and slice
- Add console.error logging to silent navigation catch blocks
- Add composite index on (boardType, setterUsername) for board_climbs
- Extract DEFAULT_ANGLE constant to replace hardcoded magic number 40
- Add validation schema tests for setter follow inputs
- Add resolver tests for followSetter and unfollowSetter mutations

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@marcodejongh marcodejongh force-pushed the feature/setter-follows branch from a0ac778 to bbd0d04 Compare February 15, 2026 06:03
@claude
Copy link

claude bot commented Feb 15, 2026

Claude Review

⚠️ Needs attention - Critical security issue: NEXTAUTH_SECRET hardcoded in tracked files.

Critical Issues

  1. Security: Hardcoded secret in tracked file - packages/backend/.env.development:9 contains a hardcoded NEXTAUTH_SECRET that is being committed to git. While the comment says "should NOT contain production secrets", this same secret value (68cJgCDE39gaXwi8LTVW4WioyhGxwcAd) appears in packages/web/.env.local and will be used for development authentication. Any secret committed to version control is a security risk and should be rotated. Consider using a placeholder value like dev-secret-change-me or sourcing from environment only.

Other Issues

  1. N+1 query risk in unified search - packages/backend/src/graphql/resolvers/social/setter-follows.ts:1071-1086: The de-duplication logic queries userBoardMappings for each user in results. For large result sets, this could cause performance issues. Consider batching with inArray like the notification batching improvement.

  2. Missing migration newline - packages/db/drizzle/0057_volatile_miss_america.sql: File ends without a trailing newline.

  3. Unused import in test file - packages/backend/src/__tests__/setter-follows.test.ts:79: ConnectionContext type is imported but the test uses a mock context function.

Test Coverage Notes

  • Good unit tests added for setter follow mutations with edge cases (idempotent follow, linked account handling)
  • Validation schema tests cover input validation thoroughly
  • No integration tests for the sync notification creation flow in shared-sync

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.

1 participant