Repository: open-sauced/app
Pull request #2293 (2023-12-08 19:37:06)

feat: Introduce v2 API and user PR Timescale integration
## Description

This adds the new v2 API endpoint with Timescale integrations for `v2/users/{username}/prs`.

Refactors the base URL api fetcher to include a v2 api fetcher.

## What type of PR is this? (check all applicable)

- [x] 🍕 Feature
- [ ] 🐛 Bug Fix
- [ ] 📝 Documentation Update
- [ ] 🎨 Style
- [ ] 🧑‍💻 Code Refactor
- [ ] 🔥 Performance Improvements
- [ ] ✅ Test
- [ ] 🤖 Build
- [ ] 🔁 CI
- [ ] 📦 Chore (Release)
- [ ] ⏩ Revert

## Related Tickets & Documents

Followup to:
- https://github.com/open-sauced/api/pull/442

## Mobile & Desktop Screenshots/Recordings

_Stay tuned ..._

## Steps to QA

_Stay tuned ..._

## Added to documentation?

- [ ] 📜 README.md
- [ ] 📓 docs.opensauced.pizza
- [ ] 🍕 dev.to/opensauced
- [ ] 📕 storybook
- [ ] 🙅 no documentation needed

## [optional] Are there any post-deployment tasks we need to perform?

Will need to cordinate this going into prod with the new v2 endpoints in the API also going out beforehand.

## [optional] What gif best describes this PR or how it makes you feel?

![](https://media.giphy.com/media/8R8RD6Hvtte48/giphy.gif)

<!-- note: PRs with deleted sections will be marked invalid -->

<!--
  For Work In Progress Pull Requests, please use the Draft PR feature,
  see https://github.blog/2019-02-14-introducing-draft-pull-requests/ for further details.
  
  For a timely review/response, please avoid force-pushing additional
  commits if your PR already received reviews or comments.
  
  Before submitting a Pull Request, please ensure you've done the following:
  - 📖 Read the Open Sauced Contributing Guide: https://github.com/open-sauced/.github/blob/main/CONTRIBUTING.md.
  - 📖 Read the Open Sauced Code of Conduct: https://github.com/open-sauced/.github/blob/main/CODE_OF_CONDUCT.md.
  - 👷‍♀️ Create small PRs. In most cases, this will be possible.
  - ✅ Provide tests for your changes.
  - 📝 Use descriptive commit messages.
  - 📗 Update any related documentation and include any relevant screenshots.
-->


netlify[bot]: ### <span aria-hidden="true">👷</span> Deploy request for *oss-insights* pending review.
[Visit the deploys page to approve it](https://app.netlify.com/sites/oss-insights/deploys)

|  Name | Link |
|:-:|------------------------|
|<span aria-hidden="true">🔨</span> Latest commit | ddec0ecb0db1f2f45e51af9ac7154a41c775ac1f |
netlify[bot]: ### <span aria-hidden="true">👷</span> Deploy Preview for *design-insights* processing.


|  Name | Link |
|:-:|------------------------|
|<span aria-hidden="true">🔨</span> Latest commit | ddec0ecb0db1f2f45e51af9ac7154a41c775ac1f |
|<span aria-hidden="true">🔍</span> Latest deploy log | https://app.netlify.com/sites/design-insights/deploys/6573706478d2650008e658d1 |
jpmcb: Near live data flowing in:

![Screenshot 2023-12-08 at 3 07 11 PM](https://github.com/open-sauced/app/assets/23109390/d84dc587-8948-4f7d-9d7c-fd7406461354)

A few notes here:
- we don't have much of a notion of "hours" for PRs that are newer than 1 day: you'll notice that it's just a "-" with really new PRs. This is probably fine for now, but we'll want to start re-thinking really new data.
- The graph breaks here ... looking into it!

@brandonroberts also showed me how to get around busting the app cache to get these to load. Otherwise, the app fails to load this page:

![Screenshot 2023-12-08 at 3 08 40 PM](https://github.com/open-sauced/app/assets/23109390/16f1e863-ad5e-4415-ae54-b802dc39ce7f)

jpmcb: Force pushed to address the line graph using the wrong type:

![Screenshot 2023-12-08 at 3 52 38 PM](https://github.com/open-sauced/app/assets/23109390/f803b71a-bf9f-4408-bbc2-3850afc51634)
jpmcb: I think this needs a few more changes on the API side to see this fully through: there is abit of intermixing of the the types for different functions I need changed.

So, this should really attempt to completely remove the `DbRepo` type in favor of the `DbRepoEvent` type.
jpmcb: Deploy preview is up with changes from https://github.com/open-sauced/api/pull/444

Although there's also `pr/insights` that needs to be updated in the API to _really_ round this out. But this could go in now if we want 🚀 
bdougie: @jpmcb I don't see data on the deploy preview. Is that because we don't dev data for DbRepoEvent yet?


jpmcb: Yeah, good question: `users/{username}/prs` shows up primarily in the user profiles:

<img width="1103" alt="Screenshot 2023-12-20 at 10 11 00 PM" src="https://github.com/open-sauced/app/assets/23109390/988b388b-a43b-411b-894e-582b494931c9">

but you're right: `prs/search` seems abit more nuanced and I'm also not seeing it really pop up in the insight pages, I'll revisit this more tomorrow
jpmcb: I'm actually inclined to get this merged into a feature branch instead of `beta` (since there's alot more work to be done to get `prs/insights` integrated here.

How does a `pr-events` branch sound? I'd much rather tackle this in bit-sized chunks vs. one massive PR to `beta`
jpmcb: > Aside from introducing v2 stuff for the API, most of this is just updating property names from what I can tell?

More or less: it introduces a different type which aligns with what is returned by the v2 PR endpoints. This type drifts slightly from the existing type (for example, the event types don't have labels right now) so it made more sense to just refactor the type all together.

Also introduces a `v2PublicApiFetcher` API fetcher which can be used alongside the normal v1 API fetcher

Patch:
diff --git a/.env b/.env
index a856e0c7..ea62a0af 100644
--- a/.env
+++ b/.env
@@ -1,6 +1,7 @@
 NEXT_PUBLIC_SUPABASE_URL=https://fcqqkxwlntnrtjfbcioz.supabase.co
 NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImZjcXFreHdsbnRucnRqZmJjaW96Iiwicm9sZSI6ImFub24iLCJpYXQiOjE2OTg0MTkyNzQsImV4cCI6MjAxMzk5NTI3NH0.ymWWYdnJC2gsnrJx4lZX2cfSOp-1xVuWFGt1Wr6zwtg
 NEXT_PUBLIC_API_URL=https://beta.api.opensauced.pizza/v1
+NEXT_PUBLIC_V2_API_URL=https://beta.api.opensauced.pizza/v2
 NEXT_PUBLIC_POSTHOG_ID=phc_Y0xz6nK55MEwWjobJsI2P8rsiomZJ6eZLoXehmMy9tt
 NEXT_PUBLIC_CLOUD_NAME=dgxgziswe
 NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=test
diff --git a/components/molecules/ContributorListTableRow/contributor-list-table-row.tsx b/components/molecules/ContributorListTableRow/contributor-list-table-row.tsx
index 7febca65..53ab25fc 100644
--- a/components/molecules/ContributorListTableRow/contributor-list-table-row.tsx
+++ b/components/molecules/ContributorListTableRow/contributor-list-table-row.tsx
@@ -24,26 +24,26 @@ interface ContributorListTableRow {
   range: string;
 }
 
-function getLastContributionDate(contributions: DbRepoPR[]) {
+function getLastContributionDate(contributions: DbRepoPREvents[]) {
   if (contributions.length === 0) {
     return "-";
   }
   const sortedContributions = contributions.sort((a, b) => {
-    return +new Date(b.merged_at) - +new Date(a.merged_at);
+    return +new Date(b.pr_merged_at) - +new Date(a.pr_merged_at);
   });
 
-  return formatDistanceToNowStrict(new Date(sortedContributions[0]?.merged_at), { addSuffix: true });
+  return formatDistanceToNowStrict(new Date(sortedContributions[0]?.pr_merged_at), { addSuffix: true });
 }
 
-function getLastContributedRepo(pullRequests: DbRepoPR[]) {
+function getLastContributedRepo(pullRequests: DbRepoPREvents[]) {
   if (pullRequests.length === 0) {
     return "-";
   }
   const sortedPullRequests = pullRequests.sort((a, b) => {
-    return +new Date(b.last_updated_at) - +new Date(a.last_updated_at);
+    return +new Date(b.pr_updated_at) - +new Date(a.pr_updated_at);
   });
 
-  return sortedPullRequests[0].full_name;
+  return sortedPullRequests[0].repo_name;
 }
 
 function getLanguageAbbreviation(language: string) {
@@ -85,7 +85,7 @@ const ContributorListTableRow = ({
     mostRecent: true,
   });
 
-  const repoList = useRepoList(Array.from(new Set(data.map((prData) => prData.full_name))).join(","));
+  const repoList = useRepoList(Array.from(new Set(data.map((prData) => prData.repo_name))).join(","));
   const contributorLanguageList = user ? getTopContributorLanguages(user) : [];
   const days = getPullRequestsToDays(data, Number(range || "30"));
   const totalPrs = data.length;
@@ -96,7 +96,7 @@ const ContributorListTableRow = ({
       data: days,
     },
   ];
-  const mergedPrs = data.filter((prData) => prData.merged);
+  const mergedPrs = data.filter((prData) => prData.pr_is_merged);
   const [firstContributorLanguage, secondContributorLanguage] = contributorLanguageList;
 
   return (
diff --git a/components/molecules/PullRequestTable/pull-request-table.tsx b/components/molecules/PullRequestTable/pull-request-table.tsx
index 56c7b65d..9a2eea43 100644
--- a/components/molecules/PullRequestTable/pull-request-table.tsx
+++ b/components/molecules/PullRequestTable/pull-request-table.tsx
@@ -47,18 +47,18 @@ const PullRequestTable = ({
           {data.map(
             (
               {
-                title: prName,
-                state: prStatus,
-                merged,
-                draft,
-                merged_at: prMergedTime,
-                created_at: prIssuedTime,
-                changed_files: noOfFilesChanged,
-                additions,
-                deletions,
-                number: prNumber,
-                full_name: fullName,
-                updated_at: prUpdatedTime,
+                pr_title: prName,
+                pr_state: prStatus,
+                pr_is_merged: merged,
+                pr_is_draft: draft,
+                pr_merged_at: prMergedTime,
+                pr_created_at: prIssuedTime,
+                pr_changed_files: noOfFilesChanged,
+                pr_additions: additions,
+                pr_deletions: deletions,
+                pr_number: prNumber,
+                repo_name: fullName,
+                pr_updated_at: prUpdatedTime,
               },
               index
             ) => {
diff --git a/components/molecules/ReportsHistory/csv-download.tsx b/components/molecules/ReportsHistory/csv-download.tsx
index c9a1a333..deea4270 100644
--- a/components/molecules/ReportsHistory/csv-download.tsx
+++ b/components/molecules/ReportsHistory/csv-download.tsx
@@ -5,7 +5,7 @@ import { useSWRConfig } from "swr";
 import Button from "components/atoms/Button/button";
 
 import { Report } from "interfaces/report-type";
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { v2PublicApiFetcher } from "lib/utils/public-api-fetcher";
 
 interface CSVDownloadProps {
   report: Report;
@@ -13,7 +13,7 @@ interface CSVDownloadProps {
 }
 
 interface PaginatedResponse {
-  readonly data: DbRepoPR[];
+  readonly data: DbRepoPREvents[];
   readonly meta: Meta;
 }
 
@@ -48,7 +48,7 @@ const CSVDownload = ({ report, repositories }: CSVDownloadProps) => {
     try {
       setGenerating(true);
       // @ts-ignore
-      const result: PaginatedResponse = await mutate(key, publicApiFetcher(key));
+      const result: PaginatedResponse = await mutate(key, v2PublicApiFetcher(key));
 
       setData(result.data);
     } catch (e) {
diff --git a/components/organisms/Activity/activity.tsx b/components/organisms/Activity/activity.tsx
index 12982d46..657a7b0f 100644
--- a/components/organisms/Activity/activity.tsx
+++ b/components/organisms/Activity/activity.tsx
@@ -11,7 +11,7 @@ import { calcDaysFromToday } from "lib/utils/date-utils";
 import { getAvatarByUsername } from "lib/utils/github";
 
 export type PrStatusFilter = "open" | "closed" | "all";
-type ContributorPrMap = { [contributor: string]: DbRepoPR };
+type ContributorPrMap = { [contributor: string]: DbRepoPREvents };
 
 const Activity = ({ repositories }: { repositories: number[] | undefined }) => {
   const router = useRouter();
@@ -29,18 +29,19 @@ const Activity = ({ repositories }: { repositories: number[] | undefined }) => {
 
   let metadata: ScatterChartMetadata = {
     allPrs: prData.length,
-    openPrs: prData.filter((pr) => pr.state.toLowerCase() === "open").length,
-    closedPrs: prData.filter((pr) => pr.state.toLowerCase() === "closed" || pr.state.toLowerCase() === "merged").length,
+    openPrs: prData.filter((pr) => pr.pr_state.toLowerCase() === "open").length,
+    closedPrs: prData.filter((pr) => pr.pr_state.toLowerCase() === "closed" || pr.pr_state.toLowerCase() === "merged")
+      .length,
   };
 
   const uniqueContributors: ContributorPrMap = prData.reduce((prs, curr) => {
-    if (curr.state.toLowerCase() !== prStateFilter && prStateFilter !== "all") return prs;
+    if (curr.pr_state.toLowerCase() !== prStateFilter && prStateFilter !== "all") return prs;
 
-    if (prs[curr.author_login]) {
-      prs[curr.author_login].linesCount += Math.abs(curr.additions - curr.deletions);
+    if (prs[curr.pr_author_login]) {
+      prs[curr.pr_author_login].linesCount += Math.abs(curr.pr_additions - curr.pr_deletions);
     } else {
-      prs[curr.author_login] = { ...curr };
-      prs[curr.author_login].linesCount = Math.abs(curr.additions - curr.deletions);
+      prs[curr.pr_author_login] = { ...curr };
+      prs[curr.pr_author_login].linesCount = Math.abs(curr.pr_additions - curr.pr_deletions);
     }
 
     return prs;
@@ -59,13 +60,13 @@ const Activity = ({ repositories }: { repositories: number[] | undefined }) => {
   if (prError) {
     scatterChartData = [];
   } else {
-    scatterChartData = prs.map(({ updated_at, linesCount, author_login }) => {
-      const author_image = author_login.includes("[bot]") ? "octocat" : author_login;
+    scatterChartData = prs.map(({ pr_updated_at, linesCount, pr_author_login }) => {
+      const author_image = pr_author_login.includes("[bot]") ? "octocat" : pr_author_login;
 
       const data = {
-        x: calcDaysFromToday(new Date(updated_at)),
+        x: calcDaysFromToday(new Date(pr_updated_at)),
         y: linesCount,
-        contributor: author_login,
+        contributor: pr_author_login,
         image: getAvatarByUsername(author_image, 40),
       };
       return data;
diff --git a/lib/hooks/api/useContributionsByEvolutionType.ts b/lib/hooks/api/useContributionsByEvolutionType.ts
index 8c64e9d7..38c277c0 100644
--- a/lib/hooks/api/useContributionsByEvolutionType.ts
+++ b/lib/hooks/api/useContributionsByEvolutionType.ts
@@ -1,7 +1,7 @@
 import { useState } from "react";
 import useSWR, { Fetcher } from "swr";
 
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 import { ContributionEvolutionByTypeDatum } from "components/molecules/ContributionsEvolutionByTypeCard/contributions-evolution-by-type-card";
 import { ContributorType } from "components/Graphs/shared/contributor-type-filter";
 
diff --git a/lib/hooks/api/useContributionsByProject.ts b/lib/hooks/api/useContributionsByProject.ts
index abfc725b..a75ff979 100644
--- a/lib/hooks/api/useContributionsByProject.ts
+++ b/lib/hooks/api/useContributionsByProject.ts
@@ -1,5 +1,5 @@
 import useSWR, { Fetcher } from "swr";
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 
 export const useContributionsByProject = ({
   listId,
diff --git a/lib/hooks/api/useContributorList.ts b/lib/hooks/api/useContributorList.ts
index a903fb45..e9a535b3 100644
--- a/lib/hooks/api/useContributorList.ts
+++ b/lib/hooks/api/useContributorList.ts
@@ -1,6 +1,6 @@
 import useSWR, { Fetcher } from "swr";
 import { useState } from "react";
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 
 export function convertToContributors(rawContributors: DBListContributor[] = []): DbPRContributor[] {
   const contributors = rawContributors
diff --git a/lib/hooks/api/useContributorPullRequests.ts b/lib/hooks/api/useContributorPullRequests.ts
index 1492c7b6..2436d310 100644
--- a/lib/hooks/api/useContributorPullRequests.ts
+++ b/lib/hooks/api/useContributorPullRequests.ts
@@ -1,11 +1,11 @@
 import useSWR, { Fetcher } from "swr";
 import { useRouter } from "next/router";
 
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { v2PublicApiFetcher } from "lib/utils/public-api-fetcher";
 import getFilterQuery from "lib/utils/get-filter-query";
 
 export interface PaginatedResponse {
-  readonly data: DbRepoPR[];
+  readonly data: DbRepoPREvents[];
   readonly meta: Meta;
 }
 
@@ -45,7 +45,7 @@ export function getContributorPRUrl(
 }
 
 export const fetchContributorPRs = async (...args: Parameters<typeof getContributorPRUrl>) => {
-  return (publicApiFetcher as Fetcher<PaginatedResponse, string>)(getContributorPRUrl(...args));
+  return (v2PublicApiFetcher as Fetcher<PaginatedResponse, string>)(getContributorPRUrl(...args));
 };
 
 interface ContributorPullRequestOptions {
@@ -73,7 +73,7 @@ const useContributorPullRequests = (
 
   const { data, error, mutate } = useSWR<PaginatedResponse, Error>(
     contributor ? endpointString : null,
-    publicApiFetcher as Fetcher<PaginatedResponse, Error>
+    v2PublicApiFetcher as Fetcher<PaginatedResponse, Error>
   );
 
   return {
diff --git a/lib/hooks/api/useContributors.ts b/lib/hooks/api/useContributors.ts
index 73e63525..73a9ce8e 100644
--- a/lib/hooks/api/useContributors.ts
+++ b/lib/hooks/api/useContributors.ts
@@ -2,7 +2,7 @@ import { useState } from "react";
 import useSWR, { Fetcher } from "swr";
 import { useRouter } from "next/router";
 
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 import getFilterQuery from "lib/utils/get-filter-query";
 
 interface PaginatedResponse {
diff --git a/lib/hooks/api/useContributorsByProject.ts b/lib/hooks/api/useContributorsByProject.ts
index 1e8c25a7..41dcd5e8 100644
--- a/lib/hooks/api/useContributorsByProject.ts
+++ b/lib/hooks/api/useContributorsByProject.ts
@@ -1,6 +1,6 @@
 import useSWR, { Fetcher } from "swr";
 import { useState } from "react";
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 
 export const useContributorsByProject = (listId: string, range = 30) => {
   const [repoId, setRepoId] = useState<number | null>(null);
diff --git a/lib/hooks/api/useInsights.ts b/lib/hooks/api/useInsights.ts
index f139a816..803026ba 100644
--- a/lib/hooks/api/useInsights.ts
+++ b/lib/hooks/api/useInsights.ts
@@ -1,7 +1,7 @@
 import { useRouter } from "next/router";
 import useSWR, { Fetcher } from "swr";
 import getFilterQuery from "lib/utils/get-filter-query";
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 
 interface Insight {
   allReposTotal: number;
diff --git a/lib/hooks/api/useMostActiveContributors.ts b/lib/hooks/api/useMostActiveContributors.ts
index 9c772ce4..ec34d8e6 100644
--- a/lib/hooks/api/useMostActiveContributors.ts
+++ b/lib/hooks/api/useMostActiveContributors.ts
@@ -2,7 +2,7 @@ import { useState } from "react";
 import useSWR, { Fetcher } from "swr";
 import { useRouter } from "next/router";
 
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 import { ContributorStat } from "components/molecules/MostActiveContributorsCard/most-active-contributors-card";
 import { ContributorType } from "components/Graphs/shared/contributor-type-filter";
 
diff --git a/lib/hooks/api/usePullRequests.ts b/lib/hooks/api/usePullRequests.ts
index f0c4cd08..889a6b3d 100644
--- a/lib/hooks/api/usePullRequests.ts
+++ b/lib/hooks/api/usePullRequests.ts
@@ -2,11 +2,11 @@ import { useState } from "react";
 import useSWR, { Fetcher } from "swr";
 import { useRouter } from "next/router";
 
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { v2PublicApiFetcher } from "lib/utils/public-api-fetcher";
 import getFilterQuery from "lib/utils/get-filter-query";
 
 interface PaginatedResponse {
-  readonly data: DbRepoPR[];
+  readonly data: DbRepoPREvents[];
   readonly meta: Meta;
 }
 
@@ -47,7 +47,7 @@ const usePullRequests = (intialLimit = 1000, repoIds: number[] = [], range = 30)
 
   const { data, error, mutate } = useSWR<PaginatedResponse, Error>(
     endpointString,
-    publicApiFetcher as Fetcher<PaginatedResponse, Error>
+    v2PublicApiFetcher as Fetcher<PaginatedResponse, Error>
   );
 
   return {
diff --git a/lib/hooks/api/useRepositories.ts b/lib/hooks/api/useRepositories.ts
index 862acf04..2ea59bac 100644
--- a/lib/hooks/api/useRepositories.ts
+++ b/lib/hooks/api/useRepositories.ts
@@ -2,7 +2,7 @@ import { useState } from "react";
 import useSWR, { Fetcher } from "swr";
 import { useRouter } from "next/router";
 
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 import getFilterQuery from "lib/utils/get-filter-query";
 
 interface PaginatedResponse {
diff --git a/lib/hooks/api/useRepositoryPullRequests.ts b/lib/hooks/api/useRepositoryPullRequests.ts
index 00f7802a..2262a0de 100644
--- a/lib/hooks/api/useRepositoryPullRequests.ts
+++ b/lib/hooks/api/useRepositoryPullRequests.ts
@@ -1,11 +1,11 @@
 import useSWR, { Fetcher } from "swr";
 import { useRouter } from "next/router";
 
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { v2PublicApiFetcher } from "lib/utils/public-api-fetcher";
 import getFilterQuery from "lib/utils/get-filter-query";
 
 interface PaginatedResponse {
-  readonly data: DbRepoPR[];
+  readonly data: DbRepoPREvents[];
   readonly meta: Meta;
 }
 
@@ -37,7 +37,7 @@ const useRepositoryPullRequests = (fullName: string, limit = 10, range = 30) =>
 
   const { data, error } = useSWR<PaginatedResponse, Error>(
     fullName ? endpointString : null,
-    publicApiFetcher as Fetcher<PaginatedResponse, Error>
+    v2PublicApiFetcher as Fetcher<PaginatedResponse, Error>
   );
 
   return {
diff --git a/lib/hooks/fetchRecommendationByRepo.ts b/lib/hooks/fetchRecommendationByRepo.ts
index f78e540c..1578e1e6 100644
--- a/lib/hooks/fetchRecommendationByRepo.ts
+++ b/lib/hooks/fetchRecommendationByRepo.ts
@@ -1,5 +1,5 @@
 import useSWR, { Fetcher } from "swr";
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 
 const useFetchRecommendedRepoByRepoName = (owner: string, repo: string) => {
   const { data, error, mutate } = useSWR<DbRepo, Error>(
diff --git a/lib/hooks/useContributorPullRequestsChart.ts b/lib/hooks/useContributorPullRequestsChart.ts
index d506fae3..623e8828 100644
--- a/lib/hooks/useContributorPullRequestsChart.ts
+++ b/lib/hooks/useContributorPullRequestsChart.ts
@@ -63,10 +63,10 @@ const useContributorPullRequestsChart = (
     new Set(
       data
         .filter((prSince) => {
-          const daysSinceUpdated = differenceInDays(new Date(), new Date(prSince.updated_at));
+          const daysSinceUpdated = differenceInDays(new Date(), new Date(prSince.pr_updated_at));
           return daysSinceUpdated <= Number(range);
         })
-        .map((prData) => prData.full_name)
+        .map((prData) => prData.repo_name)
     )
   ).map((repo) => {
     const [repoOwner, repoName] = repo.split("/");
diff --git a/lib/hooks/useFetchAllContributors.ts b/lib/hooks/useFetchAllContributors.ts
index b77d5b28..5c98a6f2 100644
--- a/lib/hooks/useFetchAllContributors.ts
+++ b/lib/hooks/useFetchAllContributors.ts
@@ -1,7 +1,7 @@
 import { useState } from "react";
 import useSWR, { Fetcher, SWRConfiguration } from "swr";
 
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 
 interface PaginatedResponse {
   readonly data: DBListContributor[];
diff --git a/lib/hooks/useFetchAllEmojis.ts b/lib/hooks/useFetchAllEmojis.ts
index 62b7d79e..0b8fc4d6 100644
--- a/lib/hooks/useFetchAllEmojis.ts
+++ b/lib/hooks/useFetchAllEmojis.ts
@@ -1,5 +1,5 @@
 import useSWR, { Fetcher } from "swr";
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 
 interface PaginatedEmojiResponse {
   data: DbEmojis[];
diff --git a/lib/hooks/useFetchAllHighlights.ts b/lib/hooks/useFetchAllHighlights.ts
index f288f306..45dae7d6 100644
--- a/lib/hooks/useFetchAllHighlights.ts
+++ b/lib/hooks/useFetchAllHighlights.ts
@@ -1,6 +1,6 @@
 import { useState } from "react";
 import useSWR, { Fetcher } from "swr";
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 
 interface UseFetchUserHighlightsResponse {
   data: DbHighlight[];
diff --git a/lib/hooks/useFetchAllListContributors.ts b/lib/hooks/useFetchAllListContributors.ts
index 3ffeb2bd..d0ad76f6 100644
--- a/lib/hooks/useFetchAllListContributors.ts
+++ b/lib/hooks/useFetchAllListContributors.ts
@@ -1,7 +1,7 @@
 import { useState } from "react";
 import useSWR, { Fetcher, SWRConfiguration } from "swr";
 
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 
 interface PaginatedResponse {
   readonly data: DbListContributor[];
diff --git a/lib/hooks/useFetchFeaturedHighlights.ts b/lib/hooks/useFetchFeaturedHighlights.ts
index a7e2237c..8bf69c2e 100644
--- a/lib/hooks/useFetchFeaturedHighlights.ts
+++ b/lib/hooks/useFetchFeaturedHighlights.ts
@@ -1,5 +1,5 @@
 import useSWR, { Fetcher } from "swr";
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 
 interface FeaturedHighlightsResponse {
   data: DbHighlight[];
diff --git a/lib/hooks/useFetchFollowingHighlightRepos.ts b/lib/hooks/useFetchFollowingHighlightRepos.ts
index 2bf974fa..7f7e1f47 100644
--- a/lib/hooks/useFetchFollowingHighlightRepos.ts
+++ b/lib/hooks/useFetchFollowingHighlightRepos.ts
@@ -1,6 +1,6 @@
 import { useState } from "react";
 import useSWR, { Fetcher } from "swr";
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 
 interface UseFetchUserHighlightsResponse {
   data: { full_name: string }[];
diff --git a/lib/hooks/useFetchFollowingHighlights.ts b/lib/hooks/useFetchFollowingHighlights.ts
index 14216630..6891c7bc 100644
--- a/lib/hooks/useFetchFollowingHighlights.ts
+++ b/lib/hooks/useFetchFollowingHighlights.ts
@@ -1,6 +1,6 @@
 import { useState } from "react";
 import useSWR, { Fetcher } from "swr";
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 
 interface UseFetchUserHighlightsResponse {
   data: DbHighlight[];
diff --git a/lib/hooks/useFetchHiglightRepos.ts b/lib/hooks/useFetchHiglightRepos.ts
index b7b6938c..447747b3 100644
--- a/lib/hooks/useFetchHiglightRepos.ts
+++ b/lib/hooks/useFetchHiglightRepos.ts
@@ -1,6 +1,6 @@
 import { useState } from "react";
 import useSWR, { Fetcher } from "swr";
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 
 interface UseFetchUserHighlightsResponse {
   data: { full_name: string }[];
diff --git a/lib/hooks/useFetchSingleHighlight.ts b/lib/hooks/useFetchSingleHighlight.ts
index 53cc963e..bfe566a0 100644
--- a/lib/hooks/useFetchSingleHighlight.ts
+++ b/lib/hooks/useFetchSingleHighlight.ts
@@ -1,5 +1,5 @@
 import useSWR, { Fetcher } from "swr";
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 
 interface UseFetchUserHighlightsResponse {
   data: DbHighlight;
diff --git a/lib/hooks/useFetchTopContributors.ts b/lib/hooks/useFetchTopContributors.ts
index 8080ec35..bf2b33e6 100644
--- a/lib/hooks/useFetchTopContributors.ts
+++ b/lib/hooks/useFetchTopContributors.ts
@@ -1,6 +1,6 @@
 import useSWR, { Fetcher } from "swr";
 import { useState } from "react";
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 
 type TopContributorsResponse = {
   data: { login: string }[];
diff --git a/lib/hooks/useFetchUser.ts b/lib/hooks/useFetchUser.ts
index 4e36d091..5c24a79d 100644
--- a/lib/hooks/useFetchUser.ts
+++ b/lib/hooks/useFetchUser.ts
@@ -1,5 +1,5 @@
 import useSWR, { Fetcher, SWRConfiguration } from "swr";
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 
 type UserResponse = DbUser;
 
diff --git a/lib/hooks/useFetchUserHighlights.ts b/lib/hooks/useFetchUserHighlights.ts
index 5ec62eb0..8cc33e24 100644
--- a/lib/hooks/useFetchUserHighlights.ts
+++ b/lib/hooks/useFetchUserHighlights.ts
@@ -1,6 +1,6 @@
 import { useState } from "react";
 import useSWR, { Fetcher } from "swr";
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 
 interface UseFetchUserHighlightsResponse {
   data: DbHighlight[];
diff --git a/lib/hooks/useFilterPrefetch.ts b/lib/hooks/useFilterPrefetch.ts
index 3bb2ae95..84c5b88c 100644
--- a/lib/hooks/useFilterPrefetch.ts
+++ b/lib/hooks/useFilterPrefetch.ts
@@ -2,7 +2,7 @@ import { useRouter } from "next/router";
 import { useEffect, useState } from "react";
 import { useSWRConfig } from "swr";
 import getFilterKey from "lib/utils/get-filter-key";
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 import useFilterOptions from "./useFilterOptions";
 
 type FilterValues = { [name: string]: number | undefined };
diff --git a/lib/hooks/useFollowUser.ts b/lib/hooks/useFollowUser.ts
index a2c9a0ef..c3a6997e 100644
--- a/lib/hooks/useFollowUser.ts
+++ b/lib/hooks/useFollowUser.ts
@@ -1,5 +1,5 @@
 import useSWR, { Fetcher, useSWRConfig } from "swr";
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 import useSupabaseAuth from "./useSupabaseAuth";
 
 interface FollowUserResponse {
diff --git a/lib/hooks/useHighlightReactions.ts b/lib/hooks/useHighlightReactions.ts
index 5c39cc20..da7ce550 100644
--- a/lib/hooks/useHighlightReactions.ts
+++ b/lib/hooks/useHighlightReactions.ts
@@ -1,5 +1,5 @@
 import useSWR, { Fetcher } from "swr";
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 
 export interface HighlightReactionResponse {
   emoji_id: string;
diff --git a/lib/hooks/useInsight.ts b/lib/hooks/useInsight.ts
index d2769a7b..c175a6f1 100644
--- a/lib/hooks/useInsight.ts
+++ b/lib/hooks/useInsight.ts
@@ -1,5 +1,5 @@
 import useSWR, { Fetcher } from "swr";
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 
 const useInsight = (id: string) => {
   const baseEndpoint = `insights/${id}`;
diff --git a/lib/hooks/useInsightMembers.ts b/lib/hooks/useInsightMembers.ts
index f8e496b0..b1e0fe3e 100644
--- a/lib/hooks/useInsightMembers.ts
+++ b/lib/hooks/useInsightMembers.ts
@@ -1,5 +1,5 @@
 import useSWR, { Fetcher } from "swr";
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 import { MemberAccess } from "components/molecules/TeamMembersConfig/team-members-config";
 import useSupabaseAuth from "./useSupabaseAuth";
 interface PaginatedInsightMembers {
diff --git a/lib/hooks/useList.ts b/lib/hooks/useList.ts
index b505d142..96be3f5b 100644
--- a/lib/hooks/useList.ts
+++ b/lib/hooks/useList.ts
@@ -1,7 +1,7 @@
 import useSWR, { Fetcher } from "swr";
 import { useState } from "react";
 
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 import { supabase } from "lib/utils/supabase";
 
 interface PaginatedListResponse {
diff --git a/lib/hooks/useListContributions.ts b/lib/hooks/useListContributions.ts
index 6ed27e74..57c5eb9e 100644
--- a/lib/hooks/useListContributions.ts
+++ b/lib/hooks/useListContributions.ts
@@ -1,10 +1,10 @@
 import { useState } from "react";
 import useSWR, { Fetcher } from "swr";
 
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { v2PublicApiFetcher } from "lib/utils/public-api-fetcher";
 
 interface PaginatedResponse {
-  readonly data: DbRepoPR[];
+  readonly data: DbRepoPREvents[];
   readonly meta: Meta;
 }
 
@@ -29,7 +29,7 @@ const useListContributions = (listId: string, intialLimit = 1000, range = 30) =>
 
   const { data, error, mutate } = useSWR<PaginatedResponse, Error>(
     listId ? endpointString : null,
-    publicApiFetcher as Fetcher<PaginatedResponse, Error>
+    v2PublicApiFetcher as Fetcher<PaginatedResponse, Error>
   );
 
   return {
diff --git a/lib/hooks/useListStats.ts b/lib/hooks/useListStats.ts
index af2c1d99..8da71352 100644
--- a/lib/hooks/useListStats.ts
+++ b/lib/hooks/useListStats.ts
@@ -1,7 +1,7 @@
 import { useState } from "react";
 import useSWR, { Fetcher } from "swr";
 
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 
 interface PaginatedResponse {
   readonly data: DbListContributorStat[];
diff --git a/lib/hooks/useUserConnections.ts b/lib/hooks/useUserConnections.ts
index 1befa8e2..fc44122f 100644
--- a/lib/hooks/useUserConnections.ts
+++ b/lib/hooks/useUserConnections.ts
@@ -1,5 +1,5 @@
 import useSWR, { Fetcher } from "swr";
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 import useSupabaseAuth from "./useSupabaseAuth";
 import { useToast } from "./useToast";
 
diff --git a/lib/hooks/useUserHighlightReactions.ts b/lib/hooks/useUserHighlightReactions.ts
index 6a04a4ef..08480e89 100644
--- a/lib/hooks/useUserHighlightReactions.ts
+++ b/lib/hooks/useUserHighlightReactions.ts
@@ -1,5 +1,5 @@
 import useSWR, { Fetcher } from "swr";
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 import { HighlightReactionResponse } from "./useHighlightReactions";
 import useSupabaseAuth from "./useSupabaseAuth";
 
diff --git a/lib/hooks/useUserInsights.ts b/lib/hooks/useUserInsights.ts
index c9fb2307..e57a37e0 100644
--- a/lib/hooks/useUserInsights.ts
+++ b/lib/hooks/useUserInsights.ts
@@ -1,6 +1,6 @@
 import { useState } from "react";
 import useSWR, { Fetcher } from "swr";
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 
 interface PaginatedInsightsResponse {
   readonly data: DbUserInsight[];
diff --git a/lib/hooks/useUserOrganizations.ts b/lib/hooks/useUserOrganizations.ts
index 85dce84a..adac7d27 100644
--- a/lib/hooks/useUserOrganizations.ts
+++ b/lib/hooks/useUserOrganizations.ts
@@ -1,5 +1,5 @@
 import useSWR, { Fetcher } from "swr";
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 
 interface UserConnectionResponse {
   data?: DbUserOrganization[];
diff --git a/lib/hooks/useUserRepoRecommendations.ts b/lib/hooks/useUserRepoRecommendations.ts
index ea5ee14b..254fd51c 100644
--- a/lib/hooks/useUserRepoRecommendations.ts
+++ b/lib/hooks/useUserRepoRecommendations.ts
@@ -1,5 +1,5 @@
 import useSWR, { Fetcher } from "swr";
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 
 interface RepoRecommendationResponse {
   [name: string]: DbRepo[];
diff --git a/lib/utils/get-contributor-pr-velocity.ts b/lib/utils/get-contributor-pr-velocity.ts
index dcc31db9..6d3f18dc 100644
--- a/lib/utils/get-contributor-pr-velocity.ts
+++ b/lib/utils/get-contributor-pr-velocity.ts
@@ -1,10 +1,10 @@
 import differenceInDays from "date-fns/differenceInDays";
 
-const getContributorPullRequestVelocity = (repositoryPullRequests: DbRepoPR[]) => {
-  const mergedPRs = repositoryPullRequests.filter((prState) => prState.state.toLowerCase() === "merged");
+const getContributorPullRequestVelocity = (repositoryPullRequests: DbRepoPREvents[]) => {
+  const mergedPRs = repositoryPullRequests.filter((prState) => prState.pr_state.toLowerCase() === "merged");
 
-  const totalDays = mergedPRs.reduce((total, pr) => {
-    const daysBetween = differenceInDays(new Date(pr.closed_at), new Date(pr.created_at));
+  const totalDays = mergedPRs.reduce((total, event) => {
+    const daysBetween = differenceInDays(new Date(event.pr_closed_at), new Date(event.pr_created_at));
     return (total += daysBetween);
   }, 0);
 
diff --git a/lib/utils/get-pr-contributors.ts b/lib/utils/get-pr-contributors.ts
index 3a7d5b4b..7f9fffee 100644
--- a/lib/utils/get-pr-contributors.ts
+++ b/lib/utils/get-pr-contributors.ts
@@ -1,11 +1,11 @@
-const getPullRequestsContributors = (repositoryPullRequests: DbRepoPR[]) => {
+const getPullRequestsContributors = (repositoryPullRequests: DbRepoPREvents[]) => {
   const uniqueContributors = Object.keys(
     repositoryPullRequests
-      .filter((pr) => !pr.author_login.includes("[bot]"))
+      .filter((pr) => !pr.pr_author_login.includes("[bot]"))
       .reduce((contributors, pull_request) => {
         return {
           ...contributors,
-          [pull_request.author_login]: true,
+          [pull_request.pr_author_login]: true,
         };
       }, {})
   );
diff --git a/lib/utils/get-prs-to-days.ts b/lib/utils/get-prs-to-days.ts
index 15cbfe0b..4253b03d 100644
--- a/lib/utils/get-prs-to-days.ts
+++ b/lib/utils/get-prs-to-days.ts
@@ -5,9 +5,9 @@ interface GraphData {
   y: number;
 }
 
-const getPullRequestsToDays = (pull_requests: DbRepoPR[], range = 30) => {
-  const graphDays = pull_requests.reduce((days: { [name: string]: number }, curr: DbRepoPR) => {
-    const day = differenceInDays(new Date(), new Date(curr.updated_at));
+const getPullRequestsToDays = (pull_requests: DbRepoPREvents[], range = 30) => {
+  const graphDays = pull_requests.reduce((days: { [name: string]: number }, curr: DbRepoPREvents) => {
+    const day = differenceInDays(new Date(), new Date(curr.pr_updated_at));
 
     if (days[day]) {
       days[day]++;
diff --git a/lib/utils/public-api-fetcher.ts b/lib/utils/public-api-fetcher.ts
index 1d6bb1c0..9ef33191 100644
--- a/lib/utils/public-api-fetcher.ts
+++ b/lib/utils/public-api-fetcher.ts
@@ -1,9 +1,18 @@
 import { Fetcher } from "swr";
 import { supabase } from "./supabase";
 
-const baseUrl = process.env.NEXT_PUBLIC_API_URL;
+const v1BaseUrl = process.env.NEXT_PUBLIC_API_URL;
+const v2BaseUrl = process.env.NEXT_PUBLIC_V2_API_URL;
 
 const publicApiFetcher: Fetcher = async (apiUrl: string) => {
+  return await apiFetcher(v1BaseUrl, apiUrl);
+};
+
+const v2PublicApiFetcher: Fetcher = async (apiUrl: string) => {
+  return await apiFetcher(v2BaseUrl, apiUrl);
+};
+
+const apiFetcher = async (baseUrl: string | undefined, apiUrl: string) => {
   const sessionResponse = await supabase.auth.getSession();
   const sessionToken = sessionResponse?.data.session?.access_token;
 
@@ -28,4 +37,4 @@ const publicApiFetcher: Fetcher = async (apiUrl: string) => {
   return res.json();
 };
 
-export default publicApiFetcher;
+export { publicApiFetcher, v2PublicApiFetcher };
diff --git a/netlify/edge-functions/card.tsx b/netlify/edge-functions/card.tsx
index 2dc0f657..5d0cc7cc 100644
--- a/netlify/edge-functions/card.tsx
+++ b/netlify/edge-functions/card.tsx
@@ -278,7 +278,7 @@ const getAvatarByUsername = (username: string | null, size = 460) =>
   `https://www.github.com/${username ?? "github"}.png?size=${size}`;
 
 async function fetchContributorPRs(username: string) {
-  const url = new URL(`${Deno.env.get("NEXT_PUBLIC_API_URL")}/users/${username}/prs`);
+  const url = new URL(`${Deno.env.get("NEXT_PUBLIC_V2_API_URL")}/users/${username}/prs`);
 
   url.searchParams.set("topic", "*");
   url.searchParams.set("limit", "100");
diff --git a/next-types.d.ts b/next-types.d.ts
index ca935f42..631f41d1 100644
--- a/next-types.d.ts
+++ b/next-types.d.ts
@@ -80,25 +80,31 @@ interface DBListContributor {
   readonly username: string;
 }
 
-interface DbRepoPR {
-  readonly title: string;
-  readonly author_login: string;
-  readonly state: string;
-  readonly created_at: string;
-  readonly closed_at: string;
-  readonly merged_at: string;
-  readonly updated_at: string;
-  readonly filesCount: number;
+interface DbRepoPREvents {
+  readonly event_id: number;
+  readonly pr_number: number;
+  readonly pr_state: string;
+  readonly pr_is_draft: bool;
+  readonly pr_is_merged: bool;
+  readonly pr_mergeable_state: string;
+  readonly pr_is_rebaseable: bool;
+  readonly pr_title: string;
+  readonly pr_head_label: string;
+  readonly pr_base_label: string;
+  readonly pr_head_ref: string;
+  readonly pr_base_ref: string;
+  readonly pr_author_login: string;
+  readonly pr_created_at: string;
+  readonly pr_closed_at: string;
+  readonly pr_merged_at: string;
+  readonly pr_updated_at: string;
+  readonly pr_comments: number;
+  readonly pr_additions: number;
+  readonly pr_deletions: number;
+  readonly pr_changed_files: number;
+  readonly repo_name: string;
+  readonly pr_commits: number;
   linesCount: number;
-  readonly merged: boolean;
-  readonly draft: boolean;
-  readonly full_name: string;
-  readonly number: number;
-  readonly additions: number;
-  readonly deletions: number;
-  readonly changed_files: number;
-  readonly repo_id: number;
-  readonly last_updated_at: string;
 }
 
 interface DbPRContributor {
diff --git a/pages/404.tsx b/pages/404.tsx
index 7b542d18..225ded60 100644
--- a/pages/404.tsx
+++ b/pages/404.tsx
@@ -127,9 +127,9 @@ async function fetchContributorCardData(
   const prs = data.length;
   const prVelocity = getContributorPullRequestVelocity(data);
   const prTotal = meta.itemCount;
-  const mergedPrs = data.filter((prData) => prData.merged);
+  const mergedPrs = data.filter((prData) => prData.pr_is_merged);
   const prMergePercentage = getPercent(prTotal, mergedPrs.length || 0);
-  const repos = getRepoList(Array.from(new Set(data.map((prData) => prData.full_name))).join(",")).length;
+  const repos = getRepoList(Array.from(new Set(data.map((prData) => prData.repo_name))).join(",")).length;
   return {
     prs,
     prVelocity,
diff --git a/pages/_app.tsx b/pages/_app.tsx
index 37fa07c4..d07bf767 100644
--- a/pages/_app.tsx
+++ b/pages/_app.tsx
@@ -14,7 +14,7 @@ import posthog from "posthog-js";
 import { PostHogProvider } from "posthog-js/react";
 import { TipProvider } from "components/atoms/Tooltip/tooltip";
 
-import publicApiFetcher from "lib/utils/public-api-fetcher";
+import { publicApiFetcher } from "lib/utils/public-api-fetcher";
 import { initiateAnalytics } from "lib/utils/analytics";
 import { supabase } from "lib/utils/supabase";
 
diff --git a/pages/lists/[listId]/overview.tsx b/pages/lists/[listId]/overview.tsx
index e66df84d..5c876c9e 100644
--- a/pages/lists/[listId]/overview.tsx
+++ b/pages/lists/[listId]/overview.tsx
@@ -17,7 +17,7 @@ import HighlightCard from "components/molecules/HighlightCard/highlight-card";
 import { fetchApiData, validateListPath } from "helpers/fetchApiData";
 import ClientOnly from "components/atoms/ClientOnly/client-only";
 
-type ContributorPrMap = { [contributor: string]: DbRepoPR };
+type ContributorPrMap = { [contributor: string]: DbRepoPREvents };
 
 interface ListsOverviewProps {
   list: DBList;
@@ -102,11 +102,11 @@ const ListsOverview = ({ list, numberOfContributors, isOwner }: ListsOverviewPro
   let scatterChartData: ScatterChartDataItems[] = [];
 
   const uniqueContributors: ContributorPrMap = prData.reduce((prs, curr) => {
-    if (prs[curr.author_login]) {
-      prs[curr.author_login].linesCount += Math.abs(curr.additions - curr.deletions);
+    if (prs[curr.pr_author_login]) {
+      prs[curr.pr_author_login].linesCount += Math.abs(curr.pr_additions - curr.pr_deletions);
     } else {
-      prs[curr.author_login] = { ...curr };
-      prs[curr.author_login].linesCount = Math.abs(curr.additions - curr.deletions);
+      prs[curr.pr_author_login] = { ...curr };
+      prs[curr.pr_author_login].linesCount = Math.abs(curr.pr_additions - curr.pr_deletions);
     }
 
     return prs;
@@ -125,13 +125,13 @@ const ListsOverview = ({ list, numberOfContributors, isOwner }: ListsOverviewPro
   if (prError) {
     scatterChartData = [];
   } else {
-    scatterChartData = prs.map(({ updated_at, linesCount, author_login }) => {
-      const author_image = author_login.includes("[bot]") ? "octocat" : author_login;
+    scatterChartData = prs.map(({ pr_updated_at, linesCount, pr_author_login }) => {
+      const author_image = pr_author_login.includes("[bot]") ? "octocat" : pr_author_login;
 
       const data = {
-        x: calcDaysFromToday(new Date(updated_at)),
+        x: calcDaysFromToday(new Date(pr_updated_at)),
         y: linesCount,
-        contributor: author_login,
+        contributor: pr_author_login,
         image: getAvatarByUsername(author_image, 40),
       };
       return data;
diff --git a/pages/user/[username]/card.tsx b/pages/user/[username]/card.tsx
index b814b7a5..0be60a57 100644
--- a/pages/user/[username]/card.tsx
+++ b/pages/user/[username]/card.tsx
@@ -77,9 +77,9 @@ async function fetchRemainingCardData(
   const prs = data.length;
   const prVelocity = getContributorPullRequestVelocity(data);
   const prTotal = meta.itemCount;
-  const mergedPrs = data.filter((prData) => prData.merged);
+  const mergedPrs = data.filter((prData) => prData.pr_is_merged);
   const prMergePercentage = getPercent(prTotal, mergedPrs.length || 0);
-  const repos = getRepoList(Array.from(new Set(data.map((prData) => prData.full_name))).join(",")).length;
+  const repos = getRepoList(Array.from(new Set(data.map((prData) => prData.repo_name))).join(",")).length;
   return {
     prs,
     prVelocity,
diff --git a/pages/user/[username]/index.tsx b/pages/user/[username]/index.tsx
index b2805aa5..c1d444eb 100644
--- a/pages/user/[username]/index.tsx
+++ b/pages/user/[username]/index.tsx
@@ -42,8 +42,8 @@ const Contributor: WithPageLayout<ContributorSSRProps> = ({ username, user, ogIm
     mostRecent: false,
   });
   const isError = contributorError;
-  const repoList = useRepoList(Array.from(new Set(contributorPRData.map((prData) => prData.full_name))).join(","));
-  const mergedPrs = contributorPRData.filter((prData) => prData.merged);
+  const repoList = useRepoList(Array.from(new Set(contributorPRData.map((prData) => prData.repo_name))).join(","));
+  const mergedPrs = contributorPRData.filter((prData) => prData.pr_is_merged);
   const contributorLanguageList = useContributorLanguages(username);
   const githubAvatar = getAvatarByUsername(username, 300);
   const prVelocity = getContributorPullRequestVelocity(contributorPRData);


Test patch:
diff --git a/lib/utils/get-contributor-pr-velocity.test.ts b/lib/utils/get-contributor-pr-velocity.test.ts
index 607ba4bd..fbd919b8 100644
--- a/lib/utils/get-contributor-pr-velocity.test.ts
+++ b/lib/utils/get-contributor-pr-velocity.test.ts
@@ -2,296 +2,58 @@ import getContributorPullRequestVelocity from "lib/utils/get-contributor-pr-velo
 
 const data = [
   {
-    id: 1361496755,
-    repo_id: 501028599,
-    number: 1213,
-    state: "MERGED",
-    draft: false,
-    merged: true,
-    mergeable: false,
-    rebaseable: false,
-    title: "ci: move unit and e2e tests into separate jobs",
-    source_label: "",
-    target_label: "",
-    source_branch: "brandonroberts:ci-e2e-tests",
-    target_branch: "open-sauced:beta",
-    author_login: "brandonroberts",
-    author_avatar: "https://avatars.githubusercontent.com/u/42211?u=32763fc85100fa45c5aa5d4bdddc4344e53d0173&v=4",
-    assignee_login: "",
-    assignee_avatar: "",
-    created_at: "2023-05-23T14:08:34.000Z",
-    closed_at: "2023-05-23T14:16:07.000Z",
-    merged_at: "2023-05-23T14:16:07.000Z",
-    updated_at: "2023-05-23T14:21:44.000Z",
-    last_updated_at: "2023-05-23T16:02:14.554Z",
-    comments: 3,
-    additions: 48,
-    deletions: 3,
-    changed_files: 3,
-    full_name: "open-sauced/insights",
+    event_id: 1315260200,
+    pr_number: 3093,
+    pr_state: "merged",
+    pr_is_draft: false,
+    pr_is_merged: true,
+    pr_mergeable_state: "unstable",
+    pr_is_rebaseable: false,
+    pr_title: "fix(@nguniversal/express-engine): export default bootstrap in server template for standalone apps",
+    pr_head_label: "brandonroberts:fix-standalone-prerender",
+    pr_base_label: "angular:main",
+    pr_head_ref: "feat-generate-pr-description",
+    pr_base_ref: "beta",
+    pr_author_login: "brandonroberts",
+    pr_created_at: "2023-04-15T21:55:37.000Z",
+    pr_closed_at: "2023-04-18T12:22:18.000Z",
+    pr_merged_at: "2023-04-18T12:22:18.000Z",
+    pr_updated_at: "2023-05-19T00:09:53.000Z",
+    pr_comments: 1,
+    pr_additions: 1,
+    pr_deletions: 1,
+    pr_changed_files: 1,
+    repo_name: "angular/universal",
+    pr_commits: 1,
+    linesCount: 1,
   },
   {
-    id: 1357648118,
-    repo_id: 499330806,
-    number: 170,
-    state: "MERGED",
-    draft: false,
-    merged: true,
-    mergeable: false,
-    rebaseable: false,
-    title: "feat: add endpoints for managing user collaborations",
-    source_label: "",
-    target_label: "",
-    source_branch: "brandonroberts:feat-user-collaborations",
-    target_branch: "open-sauced:beta",
-    author_login: "brandonroberts",
-    author_avatar: "https://avatars.githubusercontent.com/u/42211?u=32763fc85100fa45c5aa5d4bdddc4344e53d0173&v=4",
-    assignee_login: "",
-    assignee_avatar: "",
-    created_at: "2023-05-19T20:40:52.000Z",
-    closed_at: "2023-05-22T14:03:26.000Z",
-    merged_at: "2023-05-22T14:03:26.000Z",
-    updated_at: "2023-05-23T13:18:53.000Z",
-    last_updated_at: "2023-05-23T14:16:03.974Z",
-    comments: 2,
-    additions: 409,
-    deletions: 2,
-    changed_files: 9,
-    full_name: "open-sauced/api.opensauced.pizza",
+    event_id: 1356191185,
+    pr_number: 168,
+    pr_state: "merged",
+    pr_is_draft: false,
+    pr_is_merged: true,
+    pr_mergeable_state: "dirty",
+    pr_is_rebaseable: false,
+    pr_title: "feat: add endpoint to generate pull request description",
+    pr_head_label: "brandonroberts:feat-generate-pr-description",
+    pr_base_label: "open-sauced:beta",
+    pr_head_ref: "feat-generate-pr-description",
+    pr_base_ref: "beta",
+    pr_author_login: "brandonroberts",
+    pr_created_at: "2023-05-18T19:40:00.000Z",
+    pr_closed_at: "2023-05-18T20:01:40.000Z",
+    pr_merged_at: "2023-05-18T20:01:40.000Z",
+    pr_updated_at: "2023-05-18T20:17:52.000Z",
+    pr_comments: 3,
+    pr_additions: 184,
+    pr_deletions: 3,
+    pr_changed_files: 7,
+    repo_name: "open-sauced/api.opensauced.pizza",
+    pr_commits: 2,
+    linesCount: 123,
   },
-  {
-    id: 1361394082,
-    repo_id: 499330806,
-    number: 172,
-    state: "MERGED",
-    draft: false,
-    merged: true,
-    mergeable: false,
-    rebaseable: false,
-    title: "v1.36.0-beta.2 -> production",
-    source_label: "",
-    target_label: "",
-    source_branch: "brandonroberts:beta",
-    target_branch: "open-sauced:main",
-    author_login: "brandonroberts",
-    author_avatar: "https://avatars.githubusercontent.com/u/42211?u=32763fc85100fa45c5aa5d4bdddc4344e53d0173&v=4",
-    assignee_login: "",
-    assignee_avatar: "",
-    created_at: "2023-05-23T13:06:52.000Z",
-    closed_at: "2023-05-23T13:12:15.000Z",
-    merged_at: "2023-05-23T13:12:15.000Z",
-    updated_at: "2023-05-23T13:18:47.000Z",
-    last_updated_at: "2023-05-23T14:16:03.974Z",
-    comments: 1,
-    additions: 578,
-    deletions: 8,
-    changed_files: 17,
-    full_name: "open-sauced/api.opensauced.pizza",
-  },
-  {
-    id: 1360542042,
-    repo_id: 511199000,
-    number: 415,
-    state: "MERGED",
-    draft: false,
-    merged: true,
-    mergeable: false,
-    rebaseable: false,
-    title: "fix(content): add markdown route component for content routes",
-    source_label: "",
-    target_label: "",
-    source_branch: "brandonroberts:fix-render-markdown",
-    target_branch: "analogjs:main",
-    author_login: "brandonroberts",
-    author_avatar: "https://avatars.githubusercontent.com/u/42211?u=32763fc85100fa45c5aa5d4bdddc4344e53d0173&v=4",
-    assignee_login: "",
-    assignee_avatar: "",
-    created_at: "2023-05-23T03:43:52.000Z",
-    closed_at: "2023-05-23T03:56:46.000Z",
-    merged_at: "2023-05-23T03:56:46.000Z",
-    updated_at: "2023-05-23T03:56:47.000Z",
-    last_updated_at: "2023-05-23T16:01:48.550Z",
-    comments: 3,
-    additions: 56,
-    deletions: 3,
-    changed_files: 3,
-    full_name: "analogjs/analog",
-  },
-  {
-    id: 1360501488,
-    repo_id: 511199000,
-    number: 414,
-    state: "MERGED",
-    draft: false,
-    merged: true,
-    mergeable: false,
-    rebaseable: false,
-    title: "refactor: remove Angular libs from forced optimization",
-    source_label: "",
-    target_label: "",
-    source_branch: "brandonroberts:refactor-optimize-ng-deps",
-    target_branch: "analogjs:main",
-    author_login: "brandonroberts",
-    author_avatar: "https://avatars.githubusercontent.com/u/42211?u=32763fc85100fa45c5aa5d4bdddc4344e53d0173&v=4",
-    assignee_login: "",
-    assignee_avatar: "",
-    created_at: "2023-05-23T02:57:53.000Z",
-    closed_at: "2023-05-23T03:35:48.000Z",
-    merged_at: "2023-05-23T03:35:48.000Z",
-    updated_at: "2023-05-23T03:35:49.000Z",
-    last_updated_at: "2023-05-23T16:01:48.550Z",
-    comments: 3,
-    additions: 5,
-    deletions: 16,
-    changed_files: 2,
-    full_name: "analogjs/analog",
-  },
-  {
-    id: 1357276864,
-    repo_id: 501028599,
-    number: 1205,
-    state: "MERGED",
-    draft: false,
-    merged: true,
-    mergeable: false,
-    rebaseable: false,
-    title: "feat: add OpenGraph image for individual highlights",
-    source_label: "",
-    target_label: "",
-    source_branch: "brandonroberts:feat-highlight-social-card",
-    target_branch: "open-sauced:beta",
-    author_login: "brandonroberts",
-    author_avatar: "https://avatars.githubusercontent.com/u/42211?u=32763fc85100fa45c5aa5d4bdddc4344e53d0173&v=4",
-    assignee_login: "",
-    assignee_avatar: "",
-    created_at: "2023-05-19T14:56:59.000Z",
-    closed_at: "2023-05-19T15:57:48.000Z",
-    merged_at: "2023-05-19T15:57:48.000Z",
-    updated_at: "2023-05-19T16:02:39.000Z",
-    last_updated_at: "2023-05-23T16:02:14.554Z",
-    comments: 3,
-    additions: 189,
-    deletions: 120,
-    changed_files: 2,
-    full_name: "open-sauced/insights",
-  },
-  {
-    id: 1181031673,
-    repo_id: 511199000,
-    number: 192,
-    state: "OPEN",
-    draft: false,
-    merged: false,
-    mergeable: false,
-    rebaseable: false,
-    title: "build: migrate to pnpm",
-    source_label: null,
-    target_label: null,
-    source_branch: "brandonroberts:vite-3-ci",
-    target_branch: "analogjs:main",
-    author_login: "brandonroberts",
-    author_avatar: "https://avatars.githubusercontent.com/u/42211?u=32763fc85100fa45c5aa5d4bdddc4344e53d0173&v=4",
-    assignee_login: "",
-    assignee_avatar: "",
-    created_at: "2022-12-30T16:38:13.000Z",
-    closed_at: null,
-    merged_at: null,
-    updated_at: "2023-05-19T14:51:57.000Z",
-    last_updated_at: "2023-05-23T16:01:48.550Z",
-    comments: 5,
-    additions: 22780,
-    deletions: 20001,
-    changed_files: 6,
-    full_name: "analogjs/analog",
-  },
-  {
-    id: 1356454399,
-    repo_id: 511199000,
-    number: 402,
-    state: "MERGED",
-    draft: false,
-    merged: true,
-    mergeable: false,
-    rebaseable: false,
-    title: "feat(vite-plugin-nitro): add BUILD_PRESET as a server preset alias",
-    source_label: "",
-    target_label: "",
-    source_branch: "brandonroberts:feat-build-preset",
-    target_branch: "analogjs:main",
-    author_login: "brandonroberts",
-    author_avatar: "https://avatars.githubusercontent.com/u/42211?u=32763fc85100fa45c5aa5d4bdddc4344e53d0173&v=4",
-    assignee_login: "",
-    assignee_avatar: "",
-    created_at: "2023-05-19T01:05:53.000Z",
-    closed_at: "2023-05-19T01:44:51.000Z",
-    merged_at: "2023-05-19T01:44:51.000Z",
-    updated_at: "2023-05-19T01:44:53.000Z",
-    last_updated_at: "2023-05-23T16:01:48.550Z",
-    comments: 3,
-    additions: 6,
-    deletions: 5,
-    changed_files: 3,
-    full_name: "analogjs/analog",
-  },
-  {
-    id: 1315260200,
-    repo_id: 37953959,
-    number: 3093,
-    state: "MERGED",
-    draft: false,
-    merged: true,
-    mergeable: false,
-    rebaseable: false,
-    title: "fix(@nguniversal/express-engine): export default bootstrap in server template for standalone apps",
-    source_label: "",
-    target_label: "",
-    source_branch: "brandonroberts:fix-standalone-prerender",
-    target_branch: "angular:main",
-    author_login: "brandonroberts",
-    author_avatar: "https://avatars.githubusercontent.com/u/42211?u=32763fc85100fa45c5aa5d4bdddc4344e53d0173&v=4",
-    assignee_login: "",
-    assignee_avatar: "",
-    created_at: "2023-04-15T21:55:37.000Z",
-    closed_at: "2023-04-18T12:22:18.000Z",
-    merged_at: "2023-04-18T12:22:18.000Z",
-    updated_at: "2023-05-19T00:09:53.000Z",
-    last_updated_at: "2023-05-23T16:04:14.864Z",
-    comments: 1,
-    additions: 1,
-    deletions: 1,
-    changed_files: 1,
-    full_name: "angular/universal",
-  },
-  {
-    id: 1356191185,
-    repo_id: 499330806,
-    number: 168,
-    state: "MERGED",
-    draft: false,
-    merged: true,
-    mergeable: false,
-    rebaseable: false,
-    title: "feat: add endpoint to generate pull request description",
-    source_label: "",
-    target_label: "",
-    source_branch: "brandonroberts:feat-generate-pr-description",
-    target_branch: "open-sauced:beta",
-    author_login: "brandonroberts",
-    author_avatar: "https://avatars.githubusercontent.com/u/42211?u=32763fc85100fa45c5aa5d4bdddc4344e53d0173&v=4",
-    assignee_login: "",
-    assignee_avatar: "",
-    created_at: "2023-05-18T19:40:00.000Z",
-    closed_at: "2023-05-18T20:01:40.000Z",
-    merged_at: "2023-05-18T20:01:40.000Z",
-    updated_at: "2023-05-18T20:17:52.000Z",
-    last_updated_at: "2023-05-23T14:16:03.974Z",
-    comments: 3,
-    additions: 184,
-    deletions: 3,
-    changed_files: 7,
-    full_name: "open-sauced/api.opensauced.pizza",
-  },
-] as DbRepoPR[];
+] as DbRepoPREvents[];
 
 describe("[lib] getContributorPullRequestVelocity()", () => {
   it("should return the average velocity", () => {