Skip to content

chore(api): promote test → main (GET /api/admins/artists/pro migration)#482

Merged
sweetmantech merged 1 commit into
mainfrom
test
Apr 24, 2026
Merged

chore(api): promote test → main (GET /api/admins/artists/pro migration)#482
sweetmantech merged 1 commit into
mainfrom
test

Conversation

@sweetmantech

@sweetmantech sweetmantech commented Apr 24, 2026

Copy link
Copy Markdown
Contributor

Promotes the single change on `test` to `main`.

Includes

  • feat(api): migrate GET /api/artists/pro #477 — feat(api): migrate GET /api/artists/pro — new admin-scoped route at `/api/admins/artists/pro`, Stripe→local-subscriptions-mirror refactor, generalized `selectSubscriptions` helper

Test plan

🤖 Generated with Claude Code


Summary by cubic

Adds an admin-only endpoint at GET /api/admins/artists/pro that returns a deduped list of artist IDs for “pro” accounts, sourced from enterprise email domains and the local subscriptions mirror.

  • New Features

    • New route with CORS preflight and admin auth validation.
    • Aggregates and dedupes artist IDs from enterprise-domain accounts and active subscriptions.
    • Returns safe 500 errors without leaking internals.
  • Refactors

    • Introduced selectSubscriptions({ accountIds?, active? }) to query the local billing mirror.
    • Extended selectAccountEmails with a domain filter; added getEnterpriseAccountIds and selectAccountArtistIds helpers.

Written for commit 73fa2ad. Summary will update on new commits.

Summary by CodeRabbit

  • New Features
    • Added a new admin-only API endpoint to retrieve professional artists based on enterprise account affiliations and subscription status, with built-in CORS and error handling support.

* feat(api): migrate GET /api/artists/pro

Admin-scoped flat route returning the deduped list of artist IDs owned by
"pro" accounts (enterprise email domain or active Stripe subscription).
Ports Stripe client + getActiveSubscriptions inline until the subscription
PR lands; reuses validateAdminAuth for scope.

* fix(stripe): defer client init to first call

Next build on Vercel evaluates lib/stripe/client.ts while collecting
page data; throwing at module-load when STRIPE_SECRET_KEY is absent
from the preview env killed the build. Move the guard into a lazy
factory so build-time import is always safe — the first request
still surfaces a 500 via the handler's catch when the secret is
genuinely missing.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* refactor: fold account_emails helpers into generic selectAccountEmails

Add optional domain filter (ilike %@<domain>%) to the existing
selectAccountEmails helper and drop the per-filter wrappers. One
helper, three optional filters (emails, accountIds, domain).

* refactor(stripe): paginate getActiveSubscriptions, drop unused accountId

Use Stripe SDK's async iterator so we're not capped at 100 rows — the
cursor paginates the full active set. The accountId filter param was
dead (no caller passed it); drop rather than carry; reintroduce via
Stripe Search API if a single-account lookup is ever needed.

* refactor(stripe): use autoPagingToArray in getActiveSubscriptions

* refactor(stripe): stream active subscriptions, use native status filter

Swap getActiveSubscriptions for an iterateActiveSubscriptions async
generator. Two wins:

1. status: 'active' is Stripe's native filter — no current_period_end
   vs server-clock comparison (timezone / skew hazards).
2. Yielded incrementally so callers fold results into a Set as they
   arrive; no hard in-memory cap on the active subscription count.

Caller now holds only the deduped accountId strings, not full
Subscription objects.

* refactor: separate stripe from enterprise; rename merge to getProArtists

- lib/stripe/ now owns getActiveSubscriptions + getSubscriberAccountEmails
  (they query Stripe, not enterprise domains).
- lib/enterprise/ keeps only ENTERPRISE_DOMAINS and the domain email fan-out.
- The merge orchestrator moves to lib/artists/getProArtists.ts (enterprise ∪
  subscribers); renamed from getEnterpriseArtists since 'enterprise artists'
  understates what it returns.
- getActiveSubscriptions uses a manual starting_after cursor loop so there is
  no iterator and no hard row cap.

* refactor: project pro sources to account_ids, skip subscriber email round-trip

The subscriber path fetched Stripe subs, extracted metadata.accountId,
round-tripped Supabase to get account_emails rows, then unpacked
account_id again — the email lookup was inert.

- lib/stripe/getSubscriberAccountIds reads metadata.accountId from
  Stripe directly; no Supabase call.
- lib/enterprise/getEnterpriseAccountIds projects the ilike result to
  account_ids at the source.
- getProArtists now merges two string arrays, dedupes once, then hits
  account_artist_ids.

* refactor: inline subscriber accountId extraction into getProArtists

getSubscriberAccountIds was a two-line .map/.filter wrapper. Drop it
and inline against the Stripe result — no useful indirection.

* refactor(stripe): return account_ids directly, skip Subscription hop

getActiveSubscriptions returned full Subscription objects only to have
every caller project down to metadata.accountId. Collapse that into
getActiveSubscriptionAccountIds — strings in, strings out.

* refactor: query local subscriptions mirror instead of Stripe

Supabase has a subscriptions table mirroring billing-provider state
(stripe/lemon-squeezy/paddle) with account_id + active flag. Read from
that and skip Stripe entirely — no pagination, no secret-key env var,
no provider round-trip, and cross-provider correct.

- lib/supabase/subscriptions/selectActiveSubscriptionAccountIds.ts
- lib/stripe/ removed
- stripe package uninstalled

getProArtists now merges two Supabase queries.

* refactor: move route to /api/admins/artists/pro

* refactor: generalize to selectSubscriptions helper

Per review — replace selectActiveSubscriptionAccountIds with a generic
selectSubscriptions({ accountIds?, active? }) helper. Caller projects to
account_ids.

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
@vercel

vercel Bot commented Apr 24, 2026

Copy link
Copy Markdown
Contributor

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

Project Deployment Actions Updated (UTC)
api Ready Ready Preview Apr 24, 2026 7:23pm

Request Review

@coderabbitai

coderabbitai Bot commented Apr 24, 2026

Copy link
Copy Markdown

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

Introduces a new admin API endpoint for retrieving pro artists, combining enterprise domain-based accounts with active Stripe subscription holders. The implementation includes request validation, business logic to fetch and deduplicate artist records, and supporting database query helpers.

Changes

Cohort / File(s) Summary
API Route
app/api/admins/artists/pro/route.ts
Exports OPTIONS for CORS preflight and GET that forwards requests to getArtistsProHandler.
Request Handling
lib/artists/validateGetArtistsProRequest.ts, lib/artists/getArtistsProHandler.ts
Adds admin authorization validation and route handler with error handling; returns NextResponse with CORS headers and error messages on failure.
Business Logic
lib/artists/getProArtists.ts
Fetches pro artists by merging enterprise account IDs with active Stripe subscription IDs, deduplicates results, and retrieves associated artist records.
Enterprise Configuration
lib/enterprise/consts.ts, lib/enterprise/getEnterpriseAccountIds.ts
Defines immutable set of enterprise domains and queries database for accounts matching those domain email patterns.
Data Access Layer
lib/supabase/account_artist_ids/selectAccountArtistIds.ts, lib/supabase/account_emails/selectAccountEmails.ts, lib/supabase/subscriptions/selectSubscriptions.ts
Adds new Supabase query helpers: filters artist IDs by account IDs, extends email queries to support domain-based filtering, and introduces subscriptions query with optional filtering by account ID and active status.

Sequence Diagram

sequenceDiagram
    participant Client as Admin Client
    participant Route as GET /api/admins/artists/pro
    participant Validator as validateGetArtistsProRequest
    participant Handler as getArtistsProHandler
    participant ProLogic as getProArtists
    participant Enterprise as getEnterpriseAccountIds
    participant Subscriptions as selectSubscriptions
    participant ArtistSelect as selectAccountArtistIds
    participant DB as Supabase DB

    Client->>Route: GET /api/admins/artists/pro
    Route->>Validator: validate request
    Validator->>Validator: check admin auth
    alt Auth fails
        Validator-->>Route: NextResponse error
        Route-->>Client: 401/403 response
    else Auth succeeds
        Validator-->>Route: {}
        Route->>Handler: forward request
        Handler->>ProLogic: getProArtists()
        par Fetch Enterprise Accounts
            ProLogic->>Enterprise: getEnterpriseAccountIds()
            Enterprise->>DB: selectAccountEmails(domain filters)
            DB-->>Enterprise: accounts by enterprise domain
            Enterprise-->>ProLogic: enterprise account IDs
        and Fetch Subscription Accounts
            ProLogic->>Subscriptions: selectSubscriptions({active: true})
            Subscriptions->>DB: query active subscriptions
            DB-->>Subscriptions: subscription rows
            Subscriptions-->>ProLogic: subscription account IDs
        end
        ProLogic->>ProLogic: merge & deduplicate IDs
        alt No pro accounts found
            ProLogic-->>Handler: []
        else Pro accounts exist
            ProLogic->>ArtistSelect: selectAccountArtistIds(merged IDs)
            ArtistSelect->>DB: query account_artist_ids table
            DB-->>ArtistSelect: artist rows
            ArtistSelect-->>ProLogic: artist IDs
        end
        ProLogic-->>Handler: artist IDs array
        Handler->>Handler: format response with CORS headers
        Handler-->>Route: NextResponse.json(artists)
        Route-->>Client: 200 with pro artists list
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🎨 Pro Artists Rise 🚀

Enterprise domains dance, subscriptions align,
Deduplicating artists in a JSON design,
CORS headers bloom, admin gates secure—
Pro status confirmed, the endpoint's pure! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Solid & Clean Code ⚠️ Warning PR violates clean code principles by leaving stale documentation and unresolved security vulnerability despite explicit review feedback with proposed fixes. Update docstrings in three files to reference local subscriptions mirror instead of Stripe, and fix email domain pattern in selectAccountEmails.ts by removing trailing wildcard to prevent domain suffix attacks.
✅ Passed checks (2 passed)
Check name Status Explanation
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.

✏️ 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 test

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.

@sweetmantech sweetmantech merged commit 936482e into main Apr 24, 2026
6 of 7 checks passed
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