Skip to content

feat: cut segment list to dedicated GET /api/artists/{id}/segments#1680

Closed
arpitgupta1214 wants to merge 2 commits intotestfrom
feat/chat-cutover-get-artists-segments
Closed

feat: cut segment list to dedicated GET /api/artists/{id}/segments#1680
arpitgupta1214 wants to merge 2 commits intotestfrom
feat/chat-cutover-get-artists-segments

Conversation

@arpitgupta1214
Copy link
Copy Markdown
Collaborator

@arpitgupta1214 arpitgupta1214 commented Apr 15, 2026

Summary

Cuts the segment list UI over from the local /api/segments?artistId=... route to the nested dedicated GET /api/artists/{id}/segments endpoint.

  • hooks/useArtistSegments.ts now calls ${API_BASE}/api/artists/{artistId}/segments with a Privy Bearer token (mirroring useAccountOrganizations), then maps the paginated { status, segments, pagination } envelope into the existing Segment[] consumer shape. The s.size > 0 filter is preserved at the hook layer.
  • Components (SegmentsWrapper, FanGroupNavItem, MiniMenu, Segments, SegmentButton) do not change behaviorally. The Segment consumer type moved from the deleted supabase helper into a dedicated types/Segment.ts; components/Segments/Segments.tsx and components/Segments/SegmentButton.tsx updated their imports accordingly.
  • Updated the MCP get_artist_segments tool (lib/tools/getArtistSegments.ts) to the nested URL too, since the matching api PR removes the legacy flat GET /api/artist/segments in the same release. Without this, AI tool calls would 404 once the api PR merges.
  • Removed the local route and the supabase helpers that only backed it:
    • app/api/segments/route.ts
    • lib/supabase/getArtistSegments.ts
    • lib/supabase/getArtistSegmentNames.ts
    • lib/supabase/getSegmentCounts.ts
    • lib/supabase/fan_segments/selectFanSegments.ts

Mapping

The dedicated payload does not include a fans roster. Segment.fans stays optional in the consumer type; SegmentButton already falls back to an empty avatar list when fans is missing (const fansWithAvatars = segment.fans?.filter(...) || []), so the UI degrades to the users-icon placeholder without code changes.

Dependencies and ordering

Coordination with sibling chat PR

A parallel chat PR on feat/chat-cutover-post-segments handles the Create cutover and deletes app/api/segments/create/route.ts. This PR deletes the sibling app/api/segments/route.ts (GET) and leaves app/api/segments/create/ untouched.

Grep confirmation

  • No remaining references to the local GET /api/segments?artistId=... or GET /api/artist/segments in the chat repo.
  • /api/segments/create remains (owned by the sibling Create PR).

Test plan

  • Deploy a Vercel preview once api PR feat: GET /api/artists/{id}/segments (replaces /api/artist/segments) api#443 lands on test.
  • Verify SegmentsWrapper renders the same segments list it did before, with the size > 0 filter preserved.
  • Verify FanGroupNavItem in the sidebar conditionally renders only when the hook returns >= 1 segment.
  • Verify MiniMenu (collapsed sidebar) shows the segments affordance under the same condition.
  • Confirm the MCP get_artist_segments tool returns the same paginated envelope against the new URL.
  • npx tsc --noEmit — no new errors on touched files.
  • npx eslint hooks/useArtistSegments.ts components/Segments/ components/Sidebar/ lib/tools/getArtistSegments.ts types/Segment.ts — clean.

Summary by cubic

Switch the segments list to the dedicated GET /api/artists/{id}/segments endpoint and remove the local route and Supabase helpers. UI behavior is unchanged; this aligns chat with the API cutover.

  • Refactors

    • hooks/useArtistSegments now uses usePrivy and calls lib/artists/getArtistSegments (Bearer auth), enables the query only when authenticated, maps { status, segments, pagination } to Segment[], and keeps the size > 0 filter.
    • Moved the consumer Segment type to types/Segment.ts; updated imports in Segments and SegmentButton only.
    • Updated MCP tool lib/tools/getArtistSegments.ts to the nested URL.
    • Removed app/api/segments/route.ts and Supabase helpers: lib/supabase/getArtistSegments.ts, getArtistSegmentNames.ts, getSegmentCounts.ts, fan_segments/selectFanSegments.ts.
  • Migration

Written for commit 11911ef. Summary will update on new commits.

Summary by CodeRabbit

Release Notes

  • Refactor
    • Restructured how artist segments are retrieved and loaded to improve data flow efficiency
    • Updated segment data source integration to require authentication for improved security
    • Consolidated segment type definitions to a unified location for better maintainability

Migrate the segments list UI off the local `/api/segments?artistId=...`
route and onto the dedicated, nested `GET /api/artists/{id}/segments`
endpoint (api PR #443).

- `hooks/useArtistSegments.ts` now calls the dedicated endpoint with a
  Bearer token via `getClientApiBaseUrl()`, maps the paginated
  `{ status, segments, pagination }` envelope into the existing
  `Segment[]` consumer shape, and preserves the `s.size > 0` filter.
- Extracted the `Segment` consumer type into `types/Segment.ts` so
  components can depend on a type-only module after the supabase-backed
  helpers go away. `components/Segments/Segments.tsx` and
  `components/Segments/SegmentButton.tsx` now import from there. No
  other consumer changes needed (SegmentsWrapper, FanGroupNavItem,
  MiniMenu already depended on the hook's return shape).
- Updated the MCP `get_artist_segments` tool to call the nested
  dedicated URL as well, since api PR #443 removes the legacy flat
  `GET /api/artist/segments` in the same release.
- Removed the local `app/api/segments/route.ts` and the supabase
  helpers that only backed it: `lib/supabase/getArtistSegments.ts`,
  `getArtistSegmentNames.ts`, `getSegmentCounts.ts`, and
  `fan_segments/selectFanSegments.ts`.

Follows SEGMENTS_SURFACE_MIGRATION_PLAN.md step "List -> chat PR".

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 15, 2026

📝 Walkthrough

Walkthrough

This PR migrates segment data fetching from internal Supabase queries to a client API approach. The /api/segments endpoint is removed, replaced by a new getArtistSegments function that calls a client API with Privy authentication. Supabase query functions are eliminated, and components/hooks are updated to reference the new type location and authentication pattern.

Changes

Cohort / File(s) Summary
API Endpoint Removal
app/api/segments/route.ts
Removed the entire GET handler and all route-level caching/dynamic configuration exports (dynamic, fetchCache, revalidate).
Supabase Functions Removal
lib/supabase/getArtistSegments.ts, lib/supabase/getArtistSegmentNames.ts, lib/supabase/fan_segments/selectFanSegments.ts, lib/supabase/getSegmentCounts.ts
Removed four Supabase-based segment retrieval functions (~173 lines total), including type definitions (Segment, ArtistSegment, etc.) previously exported from the main module.
Type Import Migration
components/Segments/SegmentButton.tsx, components/Segments/Segments.tsx
Updated Segment type imports from @/lib/supabase/getArtistSegments to @/types/Segment using type-only imports.
Client API Implementation
lib/artists/getArtistSegments.ts
Added new function that fetches segments from client API endpoint with Bearer token authorization, includes error validation and data transformation (filters size > 0).
Hook & Token Authentication
hooks/useArtistSegments.ts
Migrated from /api/segments endpoint to new getArtistSegments function with Privy authentication; conditionally enables query based on artistId and authenticated status.
Tool Endpoint Migration
lib/tools/getArtistSegments.ts
Updated URL construction from query parameter style (/api/artist/segments?artist_account_id=...) to path parameter style (/api/artists/{artist_account_id}/segments).

Sequence Diagram(s)

sequenceDiagram
    participant App as Client App
    participant Hook as useArtistSegments
    participant Privy as Privy Auth
    participant ClientAPI as Client API<br/>(segments endpoint)

    App->>Hook: useArtistSegments(artistId)
    activate Hook
    Note over Hook: Query enabled when<br/>artistId && authenticated
    Hook->>Privy: usePrivy().getAccessToken()
    activate Privy
    Privy-->>Hook: accessToken
    deactivate Privy
    Hook->>ClientAPI: fetch with Bearer token<br/>/api/artists/{artistId}/segments
    activate ClientAPI
    ClientAPI-->>Hook: JSON response
    deactivate ClientAPI
    Note over Hook: Transform & filter<br/>(size > 0)
    Hook-->>App: Segment[]
    deactivate Hook
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested reviewers

  • sweetmantech
  • cubic-dev-ai

🚀 Segments take flight with Privy's grace,
From Supabase queries to client API's embrace,
Auth tokens flow, filters refine,
A cleaner architecture—architects align! ✨

🚥 Pre-merge checks | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Solid & Clean Code ⚠️ Warning Pull request violates SOLID and clean code principles: missing URL encoding of artistId, unsafe non-null assertions in hook, code duplication in error handling patterns, and insufficient explicit validation. URL-encode artistId in getArtistSegments.ts, remove non-null assertions with explicit error handling, extract common API validation into reusable utility, add explicit artistId validation guard in queryFn.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/chat-cutover-get-artists-segments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Apr 15, 2026

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

Project Deployment Actions Updated (UTC)
recoup-chat Ready Ready Preview Apr 15, 2026 9:17pm

Request Review

Following project pattern (fetchArtists, deleteArtist) — network call lives
in lib/artists/*, the hook just wires Privy auth + react-query.
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 11911ef130

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

throw new Error(data.error || "Failed to fetch segments");
}

return (data.segments || [])
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Fetch all segment pages before returning UI data

This helper returns only data.segments from a single response even though the API contract is explicitly paginated (pagination.total_pages is present), so any artist whose segments span multiple pages will silently lose segments in the sidebar and segments screen after this cutover. The previous local Supabase route returned the full set; this migration should either request a sufficiently large limit or iterate through all pages before mapping/filtering.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 11 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Requires human review: Refactor and API cutover involving authentication (Privy) and external data source changes require human verification of the integration and dependencies.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
lib/tools/getArtistSegments.ts (2)

15-24: ⚠️ Potential issue | 🟠 Major

Align response typing and status handling with the new endpoint contract.

Segment is still typed as the legacy shape, and the return path marks success: true without checking data.status. That can surface false-positive successes.

Suggested fix
 interface Segment {
   id: string;
-  artist_account_id: string;
-  segment_id: string;
-  updated_at: string;
-  segment_name: string;
-  artist_name: string;
+  name: string;
+  size: number;
+  icon?: string;
 }

 // ...
 const data = (await response.json()) as SegmentResponse;

-if (!response.ok) {
-  throw new Error(`API request failed with status ${response.status}`);
+if (!response.ok || data.status === "error") {
+  throw new Error(
+    `API request failed with status ${response.status}`,
+  );
 }

As per coding guidelines, "For utility functions, ensure: Proper error handling."

Also applies to: 60-65

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/tools/getArtistSegments.ts` around lines 15 - 24, The response typing and
success handling in getArtistSegments.ts must match the new endpoint contract:
update the Segment type used by the SegmentResponse interface to the new shape
expected by the endpoint, and in the getArtistSegments function (or whichever
function processes the fetch) check data.status === "success" before returning a
success result; if data.status !== "success" or the payload is missing/invalid,
return/throw an error path (or a failure result) instead of always marking
success: true. Also adjust the function's return type to reflect the revised
SegmentResponse shape and ensure proper error handling/logging when status is
"error".

39-54: ⚠️ Potential issue | 🔴 Critical

Add Bearer auth to this request before shipping.

This tool now targets the protected nested endpoint, but the request is unauthenticated. It will fail once the legacy route is gone.

Suggested fix
 const schema = z.object({
   artist_account_id: z.string().min(1, "Artist account ID is required"),
+  access_token: z.string().min(1, "Access token is required"),
   page: z.number().min(1).optional().default(1),
   limit: z.number().min(1).max(100).optional().default(20),
 });

 const getArtistSegments = tool({
   inputSchema: schema,
-  execute: async ({ artist_account_id, page, limit }) => {
+  execute: async ({ artist_account_id, access_token, page, limit }) => {
     // ...
     const response = await fetch(url.toString(), {
       method: "GET",
       headers: {
         "Content-Type": "application/json",
+        Authorization: `Bearer ${access_token}`,
       },
     });

As per coding guidelines, "Implement built-in security practices for authentication and data handling."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/tools/getArtistSegments.ts` around lines 39 - 54, The request to the
protected nested endpoint currently omits authentication; before calling fetch
in getArtistSegments (where getClientApiBaseUrl(), artist_account_id, page,
limit and the fetch(...) call are used) obtain a valid access token from the
app's auth helper (e.g., getAuthToken() or equivalent) and include it as an
Authorization: Bearer <token> header in the fetch headers; if no helper exists,
call the central auth provider to retrieve the token and fail-fast with a clear
error when token retrieval fails. Ensure the Authorization header is added
alongside Content-Type in the headers object passed to fetch.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@hooks/useArtistSegments.ts`:
- Around line 9-13: Remove the non-null assertions in the queryFn and add
explicit checks: inside the queryFn of useArtistSegments.ts, call
getAccessToken() and verify the returned accessToken is a non-empty string (and
that artistId is defined) before calling getArtistSegments; if either is missing
throw or return a clear Error with a descriptive message (e.g., "Missing access
token" or "Missing artistId") so you don't rely on the ! assertions and the
enabled guard alone.

In `@lib/artists/getArtistSegments.ts`:
- Line 35: The URL is built by directly interpolating artistId into the path in
getArtistSegments (the
`${getClientApiBaseUrl()}/api/artists/${artistId}/segments` expression);
URL-encode artistId with encodeURIComponent before composing the URL (either
inline `${encodeURIComponent(artistId)}` or assign `const encodedArtistId =
encodeURIComponent(artistId)` and use that) so the request path is safe for any
characters in artistId.

---

Outside diff comments:
In `@lib/tools/getArtistSegments.ts`:
- Around line 15-24: The response typing and success handling in
getArtistSegments.ts must match the new endpoint contract: update the Segment
type used by the SegmentResponse interface to the new shape expected by the
endpoint, and in the getArtistSegments function (or whichever function processes
the fetch) check data.status === "success" before returning a success result; if
data.status !== "success" or the payload is missing/invalid, return/throw an
error path (or a failure result) instead of always marking success: true. Also
adjust the function's return type to reflect the revised SegmentResponse shape
and ensure proper error handling/logging when status is "error".
- Around line 39-54: The request to the protected nested endpoint currently
omits authentication; before calling fetch in getArtistSegments (where
getClientApiBaseUrl(), artist_account_id, page, limit and the fetch(...) call
are used) obtain a valid access token from the app's auth helper (e.g.,
getAuthToken() or equivalent) and include it as an Authorization: Bearer <token>
header in the fetch headers; if no helper exists, call the central auth provider
to retrieve the token and fail-fast with a clear error when token retrieval
fails. Ensure the Authorization header is added alongside Content-Type in the
headers object passed to fetch.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fe4e4142-9363-44fe-b798-dd6e45459097

📥 Commits

Reviewing files that changed from the base of the PR and between ab21089 and 11911ef.

⛔ Files ignored due to path filters (1)
  • types/Segment.ts is excluded by none and included by none
📒 Files selected for processing (10)
  • app/api/segments/route.ts
  • components/Segments/SegmentButton.tsx
  • components/Segments/Segments.tsx
  • hooks/useArtistSegments.ts
  • lib/artists/getArtistSegments.ts
  • lib/supabase/fan_segments/selectFanSegments.ts
  • lib/supabase/getArtistSegmentNames.ts
  • lib/supabase/getArtistSegments.ts
  • lib/supabase/getSegmentCounts.ts
  • lib/tools/getArtistSegments.ts
💤 Files with no reviewable changes (5)
  • lib/supabase/getSegmentCounts.ts
  • lib/supabase/getArtistSegmentNames.ts
  • app/api/segments/route.ts
  • lib/supabase/fan_segments/selectFanSegments.ts
  • lib/supabase/getArtistSegments.ts

Comment on lines +9 to +13
queryFn: async () => {
const accessToken = await getAccessToken();
return getArtistSegments(accessToken!, artistId!);
},
enabled: !!artistId && authenticated,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

In @privy-io/react-auth, can usePrivy().getAccessToken() return null/undefined even when authenticated is true? Please cite the official docs/type signature.

💡 Result:

No, usePrivy.getAccessToken does not return null/undefined when authenticated is true. The official Privy documentation states that when a user is authenticated, Privy issues an app access token, and getAccessToken retrieves this token as a string, automatically refreshing it if expired. The docs show it used without checking authentication first and describe it returning a string. The authenticated boolean from usePrivy indicates the user has a valid session with an access token. If not authenticated, calling getAccessToken would fail (likely throw), but when authenticated is true, it succeeds and returns the token string. No type signature explicitly showing | null was found in docs or npm pages, and examples treat it as Promise<string>.

Citations:


Remove non-null assertions and add explicit error handling for better clarity.

The enabled guard and Privy's contract ensure getAccessToken() returns a string when authenticated is true, making the assertions on accessToken redundant. However, for production auth code, explicit checks with clear error messages are better practice than relying on assertions.

Suggested fix
     queryFn: async () => {
+      if (!artistId) {
+        throw new Error("Artist ID is required for fetching segments");
+      }
       const accessToken = await getAccessToken();
-      return getArtistSegments(accessToken!, artistId!);
+      return getArtistSegments(accessToken, artistId);
     },

Per Privy documentation, getAccessToken() returns Promise<string> when authenticated is true, and throws on error rather than returning null. The enabled guard prevents query execution when either condition is false, so the assertions are safe but unnecessary. Removing them improves readability and aligns with the guideline to handle edge cases explicitly in auth code.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@hooks/useArtistSegments.ts` around lines 9 - 13, Remove the non-null
assertions in the queryFn and add explicit checks: inside the queryFn of
useArtistSegments.ts, call getAccessToken() and verify the returned accessToken
is a non-empty string (and that artistId is defined) before calling
getArtistSegments; if either is missing throw or return a clear Error with a
descriptive message (e.g., "Missing access token" or "Missing artistId") so you
don't rely on the ! assertions and the enabled guard alone.

artistId: string,
): Promise<Segment[]> {
const response = await fetch(
`${getClientApiBaseUrl()}/api/artists/${artistId}/segments`,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

URL-encode artistId before path interpolation.

Direct interpolation can produce malformed paths for unexpected IDs. Encode it before composing the URL.

Suggested fix
-    `${getClientApiBaseUrl()}/api/artists/${artistId}/segments`,
+    `${getClientApiBaseUrl()}/api/artists/${encodeURIComponent(artistId)}/segments`,

As per coding guidelines, "Implement built-in security practices for authentication and data handling."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
`${getClientApiBaseUrl()}/api/artists/${artistId}/segments`,
`${getClientApiBaseUrl()}/api/artists/${encodeURIComponent(artistId)}/segments`,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/artists/getArtistSegments.ts` at line 35, The URL is built by directly
interpolating artistId into the path in getArtistSegments (the
`${getClientApiBaseUrl()}/api/artists/${artistId}/segments` expression);
URL-encode artistId with encodeURIComponent before composing the URL (either
inline `${encodeURIComponent(artistId)}` or assign `const encodedArtistId =
encodeURIComponent(artistId)` and use that) so the request path is safe for any
characters in artistId.

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