Skip to content

Add trending and hot climbs feed tabs and search sort options#924

Open
marcodejongh wants to merge 4 commits intomainfrom
claude/trending-hot-climbs-TkH8z
Open

Add trending and hot climbs feed tabs and search sort options#924
marcodejongh wants to merge 4 commits intomainfrom
claude/trending-hot-climbs-TkH8z

Conversation

@marcodejongh
Copy link
Owner

Query board_climb_stats_history to derive two new metrics:

  • Trending: biggest % increase in ascents over a configurable time period
  • Hot: largest absolute increase in ascents over a time period

Changes:

  • Add database index on (board_type, created_at) for efficient time-range queries
  • Add GraphQL types, queries, and backend resolvers for trendingClimbs/hotClimbs
  • Add trending/hot sort options to climb search (correlated subqueries)
  • Add Trending and Hot tabs to home page activity feed with time period selector (7d/14d/30d)
  • Add TrendingClimbCard component with ascent metrics and board navigation
  • Switch home page tabs to scrollable variant for mobile compatibility

https://claude.ai/code/session_0182yMWJM3vhoBrupcV71VZX

@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.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@claude
Copy link

claude bot commented Mar 8, 2026

Claude Review

⚠️ Needs attention - Bug in count query causing incorrect totalCount, missing tests for new functionality.

Issues

  1. Bug: Count query missing layout filter - packages/backend/src/graphql/resolvers/social/trending-feed.ts:147-175

    The count query does not apply the layoutFilterSql that is used in the main query (line 124). When filtering by a boardUuid that has a specific layoutId, the totalCount will include climbs from all layouts instead of only the filtered layout. The count query needs to join board_climbs and apply the same WHERE condition.

  2. Missing tests - No tests added for the new trending/hot GraphQL resolvers, validation schemas, or React components. The codebase has extensive test coverage elsewhere; these new features should follow the same pattern.

  3. Minor: Hardcoded 7-day window in search sorts - packages/backend/src/db/queries/climbs/search-climbs.ts:55,77

    The trending/hot sort columns use a hardcoded 7-day interval, while the feed endpoints support configurable timePeriodDays. Consider if search should also support configurable time periods for consistency.

@claude
Copy link

claude bot commented Mar 8, 2026

Claude Review

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

Issues

  1. Performance: Correlated subqueries in search-climbs.ts:127-173 - The trending and hot sort options use correlated subqueries that execute multiple nested queries against board_climb_stats_history for each row. This could be very slow on large result sets. Consider using a JOIN-based approach or caching.

  2. Inconsistent time period handling in search-climbs.ts:139,161 - The correlated subqueries hardcode 7 days but the GraphQL API accepts configurable timePeriodDays. The search sort doesn't respect the time period parameter.

  3. Unsafe type casting in trending-feed.ts:332-333,386 - Using as unknown as bypasses TypeScript type checking. If the query result shape changes, this could cause runtime errors without compile-time warnings.

  4. Index may not optimize correlated subqueries - The new index board_climb_stats_history_trending_idx on (board_type, created_at) is good for the CTE-based resolver, but the correlated subqueries in search-climbs.ts also filter by climb_uuid and angle, which will not benefit from this index. Consider whether the existing lookup_idx suffices for those queries.

Test Coverage

The PR includes good validation schema tests and frontend component tests, which cover loading, empty, and error states. No test coverage for the backend resolver logic itself, but that may be acceptable given the reliance on raw SQL.

@claude
Copy link

claude bot commented Mar 8, 2026

Claude Review

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

Issues

  1. Hardcoded time period in search sort (packages/backend/src/db/queries/climbs/search-climbs.ts:130,139)

    • The trending and hot sort options hardcode INTERVAL '7 days', but the feed tabs support configurable periods (7/14/30 days). Consider making this consistent or documenting the difference.
  2. Duplicate complex query for count (packages/backend/src/graphql/resolvers/social/trending-feed.ts:162-196)

    • The count query repeats all CTE logic from the main query. For large tables, consider using COUNT(*) OVER() in the main query to avoid running two expensive queries.
  3. Missing backend integration tests

    • Frontend component tests are solid, but no tests for the actual resolver SQL query logic. The validation tests are good, but consider adding integration tests for edge cases like empty history tables or climbs with no ascent changes.
  4. Index could be more optimal (packages/db/drizzle/0065_supreme_doctor_strange.sql)

    • The new index (board_type, created_at) helps with time filtering, but the query also partitions by climb_uuid, angle. The current approach should work for moderate data sizes, but monitor performance.

@claude
Copy link

claude bot commented Mar 8, 2026

Claude Review

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

Issues

  1. Inconsistent time period handling - packages/backend/src/db/queries/climbs/search-climbs.ts:468,477: The trending and hot sort options use hardcoded INTERVAL '7 days' while the GraphQL feed allows configurable timePeriodDays (7/14/30). Users sorting by trending/hot in search will always get 7-day data regardless of any UI selection.

  2. Fallback link to '#' - packages/web/app/components/activity-feed/trending-climb-card.tsx:87: Using href={climbViewPath ?? '#'} as a fallback could cause a jarring scroll-to-top experience if path resolution fails. Consider conditionally rendering the link or using a disabled state.

Test Coverage

Good test coverage with loading, empty, success, error states, and time period selection tested for both trending and hot modes.

claude added 4 commits March 9, 2026 21:31
Query board_climb_stats_history to derive two new metrics:
- Trending: biggest % increase in ascents over a configurable time period
- Hot: largest absolute increase in ascents over a time period

Changes:
- Add database index on (board_type, created_at) for efficient time-range queries
- Add GraphQL types, queries, and backend resolvers for trendingClimbs/hotClimbs
- Add trending/hot sort options to climb search (correlated subqueries)
- Add Trending and Hot tabs to home page activity feed with time period selector (7d/14d/30d)
- Add TrendingClimbCard component with ascent metrics and board navigation
- Switch home page tabs to scrollable variant for mobile compatibility

https://claude.ai/code/session_0182yMWJM3vhoBrupcV71VZX
- Fix trending feed count query to join board_climbs and apply
  layoutFilterSql, matching the main query's behavior
- Add TrendingClimbFeed frontend tests (8 tests): loading, trending/hot
  modes, board UUID filtering, time period selector, error handling
- Add TrendingClimbFeedInputSchema validation tests (13 tests): defaults,
  limits, offsets, time period bounds, boardUuid validation

https://claude.ai/code/session_0182yMWJM3vhoBrupcV71VZX
- Replace correlated subqueries in search sort with single MIN/MAX
  aggregation per climb, reducing from 4 subqueries to 1 per row.
  The existing (board_type, climb_uuid, angle) index covers this well.
- Remove unused boardClimbStatsHistory import from search-climbs.ts
- Add extractRows<T> helper to trending-feed.ts that replaces unsafe
  `as unknown as` casts with a runtime-safe extraction that returns
  empty array if result shape is unexpected
- Move TrendingRow type to module scope as an interface

https://claude.ai/code/session_0182yMWJM3vhoBrupcV71VZX
Use COUNT(*) OVER() window function in the main query to get total
count without a separate CTE execution. Add comprehensive unit tests
for trending-feed resolver covering row mapping, null handling,
pagination, board filter resolution, and extractRows safety.

https://claude.ai/code/session_0182yMWJM3vhoBrupcV71VZX
@marcodejongh marcodejongh force-pushed the claude/trending-hot-climbs-TkH8z branch from b0ea956 to 4dff1d1 Compare March 9, 2026 21:32
@claude
Copy link

claude bot commented Mar 9, 2026

Claude Review

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

Minor Issues

  1. Missing newline at end of migration file - packages/db/drizzle/0065_supreme_doctor_strange.sql:1 - The SQL file is missing a trailing newline character. While functional, this is a minor code style inconsistency.

  2. Index may not be optimal for all query patterns - The new index (board_type, created_at) helps with time-range filtering, but the main CTE query also partitions by climb_uuid and angle. For very large tables, consider whether a covering index including those columns would improve performance. The existing lookup_idx on (board_type, climb_uuid, angle) may partially help, but profiling on production data would confirm.

Observations

  • Test coverage is good: resolver tests, validation tests, and frontend component tests all included
  • SQL injection is properly prevented via drizzle-orm's parameterized sql template literals
  • The minimum delta threshold of 2 ascents is a sensible filter to reduce noise

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.

2 participants