Skip to content

feat: suggest who to follow from the API - #990

Merged
nunomaduro merged 2 commits into
dev-null-sh:productionfrom
Taldres:feat/who-to-follow-api
Oct 26, 2026
Merged

nunomaduro merged 2 commits into
dev-null-sh:productionfrom
Taldres:feat/who-to-follow-api

Conversation

@Taldres

@Taldres Taldres commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Lets the mobile app show who to follow as the web does. It follows #130 and is for the app's roadmap item, NativePHP/dev-null-app#72.

The web gets its suggestions as the suggestedUsers Inertia prop and dismisses them through POST /@{user}/dismiss, neither of which a signed request can reach. Both endpoints reuse what the web runs: SuggestedUsersQuery and CreateSuggestionDismissal.

Endpoints

GET /api/v1/me/suggested-users answers with the people the web would suggest, as UserResources: three to show and three spares to fill the place of one dismissed, as the web asks for them. Each one has followers_count, followed_by_following_count (new on UserResource, only set here) and follows_you for the reason line and the follow-back, and is_followed: false, as other lists of people say it. ?round=N is the next page of the day's picks, as the web's refresh button moves through them with its who_to_follow_round cookie. A missing or empty round is the first.

?username= or ?commit_id= asks for the suggestions as the web shows them beside that profile or commit since #1021: the people the profile follows, or the thread's other participants, come first, and the regular suggestions fill the rest. The commit has to be one the user can see, as its page requires, otherwise the answer is 422 with "That commit is no longer available." An unknown username is 422 too, and so is passing both. Across a block, a profile is ignored and the suggestions are the regular ones, as on the web. Without either, nothing changes.

{"data": [{"id": "…", "username": "octocat", "name": "The Octocat", "lane": 3, "followers_count": 12, "followed_by_following_count": 2, "follows_you": false, "is_followed": false, "…": "…"}]}

POST /api/v1/users/{username}/dismiss marks someone Not interested and answers 204. As on the web, they are never suggested again, nothing else changes, and dismissing yourself is 403.

Muted people, anyone across a block, and dismissed people are left out, as the query already does for the web.

Testing

Pint, Rector, PHPStan, type coverage at 100%, and all 4,149 tests pass locally (without the coverage driver, so line coverage is CI's to confirm). The new tests cover both halves of the mix, rounds, dismissals, mutes and blocks, the profile and commit context, commits the user can't see, validation, and unsigned requests, and that the endpoint answers what the web does for the same profile or commit page.

The app side is NativePHP/dev-null-app#74. It ran against this branch on an iOS simulator: following, dismissing with the spares moving up, and the next round. The app only shows who to follow in the Log, as the web does on smaller screens, so it doesn't pass a context.

Summary by CodeRabbit

  • New Features
    • Added suggestions for developers, available in profile and commit contexts.
    • Suggestions can be browsed in pages and include how many people you follow also follow each developer.
    • Added an option to dismiss a suggestion, without muting or unfollowing that developer.

@Taldres
Taldres force-pushed the feat/who-to-follow-api branch from f06d54c to 6dd6f0c Compare October 22, 2026 20:26
Taldres added a commit to Taldres/dev-null-app that referenced this pull request Oct 23, 2026
Three people you might want to follow sit under the fifth commit, each
with why they're suggested, Follow and Not interested. Devnull sends
three spares, so one dismissed gives their place to the next, and the
round is asked again to top the spares up. The refresh moves to the next
page of the day's picks. Don't show again hides it with an Undo, and a
switch in settings brings it back.

Needs GET /api/v1/me/suggested-users and POST /api/v1/users/{username}/dismiss
from dev-null-sh/dev-null.sh#990.
@Taldres
Taldres force-pushed the feat/who-to-follow-api branch from 6dd6f0c to 7b64f62 Compare October 23, 2026 12:32
@simonhamp

Copy link
Copy Markdown
Contributor

@xHeaven @nunomaduro can we get this into the API so we can show "Who to follow?"

@xHeaven

xHeaven commented Oct 23, 2026

Copy link
Copy Markdown
Member

@xHeaven @nunomaduro can we get this into the API so we can show "Who to follow?"

The "Who to follow" algo changed a bit in #1021, can you guys check if this PR needs to be adjusted?

@Taldres

Taldres commented Oct 23, 2026

Copy link
Copy Markdown
Contributor Author

Yep. I'll check it later

@Taldres
Taldres force-pushed the feat/who-to-follow-api branch from 7b64f62 to 43fee92 Compare October 24, 2026 05:24
Taldres added a commit to Taldres/dev-null-app that referenced this pull request Oct 24, 2026
Three people you might want to follow sit under the fifth commit, each
with why they're suggested, Follow and Not interested. Devnull sends
three spares, so one dismissed gives their place to the next, and the
round is asked again to top the spares up. The refresh moves to the next
page of the day's picks. Don't show again hides it with an Undo, and a
switch in settings brings it back.

Needs GET /api/v1/me/suggested-users and POST /api/v1/users/{username}/dismiss
from dev-null-sh/dev-null.sh#990.
@Taldres

Taldres commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor Author

@xHeaven @nunomaduro can we get this into the API so we can show "Who to follow?"

The "Who to follow" algo changed a bit in #1021, can you guys check if this PR needs to be adjusted?

@xHeaven Thanks for the hint! I updated the branch for #1021.

GET /api/v1/me/suggested-users now accepts the same context as the web:

  • ?username= for a profile page
  • ?commit_id= for a commit page (only commits the user is allowed to see)

Without these parameters, nothing changes. A test checks that the API returns the same suggestions as the web for the same page.

The mobile app can show who to follow as the web does: the same three
people and three spares, a new page of the day's picks each round, with
why each one is suggested and whether they follow you. Not interested
keeps someone out of the suggestions for good, as on the web.
Takes the context the web passes since dev-null-sh#1021: `username` for a profile, `commit_id` for a commit the user can see, as its page requires. Without either, the suggestions stay as they were.
@Taldres
Taldres force-pushed the feat/who-to-follow-api branch from 9fe7624 to b646908 Compare October 26, 2026 05:48
@coderabbitai

coderabbitai Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 7f09953e-7f1e-4373-bbdd-4ea7868057a7
Commits

Reviewing files that changed from the base of the PR and between e9aac0f and b646908.

Files selected for processing: 9
  • KNOWLEDGE_BASE.md
  • app/Http/Controllers/Api/SuggestedUserController.php
  • app/Http/Controllers/Api/SuggestionDismissalController.php
  • app/Http/Requests/CreateApiSuggestionDismissalRequest.php
  • app/Http/Requests/ListApiSuggestedUsersRequest.php
  • app/Http/Resources/UserResource.php
  • routes/api.php
  • tests/Feature/Controllers/Api/SuggestedUserControllerTest.php
  • tests/Feature/Controllers/Api/SuggestionDismissalControllerTest.php

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

Walkthrough

The signed API adds an endpoint to list suggested users by round and optional profile or commit context, and an endpoint to dismiss a suggested user. The listing response includes follower counts when available.

Changes: Suggested users API

Layer / File(s) Summary
List suggestions
app/Http/Requests/ListApiSuggestedUsersRequest.php, app/Http/Controllers/Api/SuggestedUserController.php, app/Http/Resources/UserResource.php, routes/api.php, tests/Feature/Controllers/Api/SuggestedUserControllerTest.php, KNOWLEDGE_BASE.md
The request validates pagination and optional profile or visible commit context. The controller retrieves suggestions and returns a resource collection. The resource conditionally includes followed_by_following_count. Routes and feature tests cover the signed API behavior.
Dismiss a suggestion
app/Http/Requests/CreateApiSuggestionDismissalRequest.php, app/Http/Controllers/Api/SuggestionDismissalController.php, tests/Feature/Controllers/Api/SuggestionDismissalControllerTest.php
The request rejects self-dismissal. The controller records dismissal and returns no content. Tests cover repeated dismissal, follow and mute behavior, unknown usernames, and unsigned requests.

Priority: Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant ListApiSuggestedUsersRequest
  participant SuggestedUserController
  participant SuggestedUsersQuery
  participant UserResource
  ListApiSuggestedUsersRequest->>SuggestedUserController: validated round and context
  SuggestedUserController->>SuggestedUsersQuery: user, round, context, and 3 spares
  SuggestedUsersQuery-->>SuggestedUserController: suggested users
  SuggestedUserController->>UserResource: return suggestions as a resource collection
Loading

Possibly related issues

  • dev-null-sh/dev-null.sh#938 — This adds suggested-user API access, but does not add organizations to suggestions.
  • dev-null-sh/dev-null.sh#1095 — This exposes the suggestion flow through an API, but does not establish GitHub as a suggestion source.
  • dev-null-sh/dev-null.sh#897 — This exposes the same suggestion flow, but the changes do not establish a fix for the reported list behavior.
  • dev-null-sh/dev-null.sh#857 — The PR adds API endpoints, but does not add API documentation.

Possibly related PRs

Suggested reviewers: xheaven

Merge Risk: Minimal · up to b6469

The suggested-users API is mergeable after normal checks; no actionable merge-blocking issue is established.

Security architecture risk: Low · up to b6469

The endpoints reuse existing suggestion and dismissal logic and keep mutations tied to the signed-in account. No authorization bypass was identified in the reviewed paths. Concurrent duplicate-request responses remain unverified.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — An authenticated device can request public-profile suggestions and viewer-relative relationship counts, or add dismissal preferences owned by its associated account. The traced mutation does not modify the target account, follow relationships, or mute relationships.

Trust Boundaries and Controls

  • observed — Both new routes are inside the required signed-request group, not the optional guest group. Successful authentication binds the verified device owner to Auth; the requests and CurrentUser controller parameters use that identity.
  • observed — Commit context does not grant visibility independently of the caller. The visibility rule and context lookup both use visibleTo for the authenticated user; that policy admits approved or caller-owned commits while excluding authors across blocks.

Resilience and Maintainability Implications

  • inferred — Dismissal has no new multi-resource transition: it writes one actor-to-target pivot relationship. The composite primary key prevents duplicate persisted pairs, and cascading foreign keys remove preferences when either user is deleted. Interruption or repetition can affect completion or response status, but cannot create duplicate preference ownership. Concurrent duplicate success responses are not established by the available framework evidence.
Pre-merge checks: Passed 5
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the primary change: adding suggested-user functionality to the API.
Docstring Coverage Passed Docstring coverage is 85.71% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 7 functions across 8 files. (1 skipped: 1 u…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 85.71% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 7 functions across 8 files. (1 skipped: 1 unsupported.)

Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@Taldres

Taldres commented Oct 26, 2026

Copy link
Copy Markdown
Contributor Author

@xHeaven Sorry to bother you! Just following up to see if you’ve had a chance to review this PR. Let me know if there’s anything you need from me. Thanks!

@nunomaduro
nunomaduro merged commit 1856f4e into dev-null-sh:production Oct 26, 2026
1 check passed
Taldres added a commit to Taldres/dev-null-app that referenced this pull request Oct 26, 2026
Three people you might want to follow sit under the fifth commit, each
with why they're suggested, Follow and Not interested. Devnull sends
three spares, so one dismissed gives their place to the next, and the
round is asked again to top the spares up. The refresh moves to the next
page of the day's picks. Don't show again hides it with an Undo, and a
switch in settings brings it back.

Needs GET /api/v1/me/suggested-users and POST /api/v1/users/{username}/dismiss
from dev-null-sh/dev-null.sh#990.
@kachelle kachelle mentioned this pull request Oct 26, 2026
nunomaduro pushed a commit that referenced this pull request Oct 26, 2026
#1178)

The users table lost its username column when handles moved to profiles
(#1157), but the who-to-follow API (#990) and the README tests (#886) were
written against it: the dismiss route bound users by username, and the
username filter of the suggestions validated and looked it up on users.
They now go through the profile's handle, like the other API routes. The
API keeps calling it username, as its user resources do.
Taldres added a commit to Taldres/dev-null-app that referenced this pull request Oct 26, 2026
Three people you might want to follow sit under the fifth commit, each
with why they're suggested, Follow and Not interested. Devnull sends
three spares, so one dismissed gives their place to the next, and the
round is asked again to top the spares up. The refresh moves to the next
page of the day's picks. Don't show again hides it with an Undo, and a
switch in settings brings it back.

Needs GET /api/v1/me/suggested-users and POST /api/v1/users/{username}/dismiss
from dev-null-sh/dev-null.sh#990.
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.

4 participants