# Project export: TunedIn

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: TreeHacks 2024
- Tagline: TunedIn is a social music review platform where users can rate and review their favorite and most hated music albums within a community of audiophiles and share albums with their friends.
- Devpost: https://devpost.com/software/tunedin-s2odfk
- GitHub: https://github.com/NicholasBottone/TunedIn
- Team: 3 GitHub contributor(s) — LiuHenry9800 (33 commits), Nicholas Bottone (22 commits), shank959 (8 commits)

## Devpost submission (written by the team)

### Inspiration

: We are a team of four who are really into tech and music, We always wanted to have a platform where we could connect to our friends and also review our favorite albums. Our inspiration has come up from that very thing.

### What it does

: So we made a platform for Music geeks who are into music and give them a platform to express their views about certain albums and also share their ratings and reviews with their friends.

### How we built it

: We used Figma and Canva for our UI design. Next.js, React, and TypeScript provided a solid foundation for the intuitive user interface and frontend functionality. PostgreSQL served as the database, while tRPC and Prisma facilitated efficient data management and interaction.Vercel ensured smooth deployment and the potential for TunedIn to reach a global audience. We also used features like Vercel Postgres for database hosting

### Challenges we ran into

: We had some front-end UI related issues when trying to export to our frontend code from Canva and Figma, so we had to go with a backup plan.

### Accomplishments we're proud of

: We completed the entirety within 36 hours and we have been coding for 24 hours straight

### What we learned

: We learned a lot about how the backend framework works

### What's next

?: We are planning to launch an app based on it and further add more features to it. We can use AI features to recommend songs, determine overlap between friends, and so on.

## README (from the GitHub repository)

# Create T3 App

This is a [T3 Stack](https://create.t3.gg/) project bootstrapped with `create-t3-app`.

## What's next? How do I make an app with this?

We try to keep this project as simple as possible, so you can start with just the scaffolding we set up for you, and add additional things later when they become necessary.

If you are not familiar with the different technologies used in this project, please refer to the respective docs. If you still are in the wind, please join our [Discord](https://t3.gg/discord) and ask for help.

- [Next.js](https://nextjs.org)
- [NextAuth.js](https://next-auth.js.org)
- [Prisma](https://prisma.io)
- [Tailwind CSS](https://tailwindcss.com)
- [tRPC](https://trpc.io)

## Learn More

To learn more about the [T3 Stack](https://create.t3.gg/), take a look at the following resources:

- [Documentation](https://create.t3.gg/)
- [Learn the T3 Stack](https://create.t3.gg/en/faq#what-learning-resources-are-currently-available) — Check out these awesome tutorials

You can check out the [create-t3-app GitHub repository](https://github.com/t3-oss/create-t3-app) — your feedback and contributions are welcome!

## How do I deploy this?

Follow our deployment guides for [Vercel](https://create.t3.gg/en/deployment/vercel), [Netlify](https://create.t3.gg/en/deployment/netlify) and [Docker](https://create.t3.gg/en/deployment/docker) for more information.


## Detected evidence (automated analysis)

Indexed codebase: 47 recognized source files, 89 KB.
- CSS (language) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- Next.js (technology) — detected in the code
- React (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code

## Codebase structure (from repository index)

### Files (55 of 55)

```
.env.example
.eslintrc.cjs
.gitignore
bun.lockb
next.config.js
package.json
postcss.config.cjs
prettier.config.js
prisma/schema.prisma
public/index.html
README.md
src/app/_components/album/AlbumInfoComponent.tsx
src/app/_components/album/AppiconRectangle.tsx
src/app/_components/album/LandingPageComponent1.tsx
src/app/_components/album/NavsFrameInstance.tsx
src/app/_components/album/ReviewComponent.tsx
src/app/_components/AlbumCard.tsx
src/app/_components/AppleSignin.tsx
src/app/_components/ArtistnameFrame.tsx
src/app/_components/ArtistRow.tsx
src/app/_components/ArtistRowFrame.tsx
src/app/_components/LandingPageComponent.tsx
src/app/_components/Navs.tsx
src/app/_components/Navs1.tsx
src/app/_components/NavsComponent.tsx
src/app/_components/PersonalTopsComponents.tsx
src/app/_components/SearchBar.tsx
src/app/_components/TopHitComponent.tsx
src/app/_components/TunedinLogoIcon.tsx
src/app/album/[albumId]/page.tsx
src/app/album/[albumId]/reviewform.tsx
src/app/api/[...openapi]/route.ts
src/app/api/auth/[...nextauth]/route.ts
src/app/api/trpc/[trpc]/route.ts
src/app/layout.tsx
src/app/page.tsx
src/app/profile/[profileId]/page.tsx
src/app/search/page.tsx
src/env.js
src/global.css
src/server/api/root.ts
src/server/api/routers/album.ts
src/server/api/routers/playlist.ts
src/server/api/routers/review.ts
src/server/api/routers/user.ts
src/server/api/trpc.ts
src/server/auth.ts
src/server/db.ts
src/styles/globals.css
src/trpc/react.tsx
src/trpc/server.ts
src/trpc/shared.ts
start-database.sh
tailwind.config.ts
tsconfig.json
```

### Dependencies

- package.json: @emotion/react@^11.11.3, @emotion/styled@^11.11.0, @mui/material@^5.15.10, @mui/styles@^5.15.10, @mui/system@^5.15.9, @next-auth/prisma-adapter@^1.0.7, @prisma/client@^5.6.0, @spotify/web-api-ts-sdk@^1.2.0, @t3-oss/env-nextjs@^0.7.1, @tanstack/react-query@^4.36.1, @testing-library/jest-dom@^5.16.5, @testing-library/react@^13.4.0, @testing-library/user-event@^13.5.0, @trpc/client@^10.43.6, @trpc/next@^10.43.6, @trpc/react-query@^10.43.6, @trpc/server@^10.43.6, @types/eslint@^8.44.7, @types/jest@^29.5.0, @types/node@^18.17.0, @types/react@^18.2.37, @types/react-dom@^18.2.15, @types/styled-components@^5.1.34, @typescript-eslint/eslint-plugin@^6.11.0, @typescript-eslint/parser@^6.11.0, autoprefixer@^10.4.14, bootstrap@^5.3.2, eslint@^8.54.0, eslint-config-next@^14.0.4, next@^14.0.4, next-auth@^4.24.5, postcss@^8.4.31, prettier@^3.1.0, prettier-plugin-tailwindcss@^0.5.7, prisma@^5.6.0, react@^18.2.0, react-bootstrap@^2.10.1, react-dom@^18.2.0, react-router-dom@^6.2.1, server-only@^0.0.1, styled-components@^6.1.8, superjson@^2.2.1, tailwindcss@^3.3.5, trpc-openapi@^1.2.0, typescript@^5.1.6, zod@^3.22.4

### Recent commits (newest first)

- Comments Made:
- review
- Merge branch 'main' of https://github.com/NicholasBottone/TunedIn
- Write a Review
- stylized
- style = {{overflow:'scroll'}}
- Merge branch 'main' of https://github.com/NicholasBottone/TunedIn
- album?.releaseDate
- Fix imports and add links to Navs component
- fixed search
- Add openapi
- Add SearchBar component and SearchPage
- mergeeed
- React
- header
- css
- font-sans
- Component
- Track List
- followedBy

## Key source files (fetched from GitHub, selected and truncated for size)

### package.json

```
{
  "name": "tunedin",
  "version": "0.2.0",
  "private": true,
  "type": "module",
  "scripts": {
    "start": "next start",
    "build": "next build",
    "dev": "next dev",
    "test": "react-scripts test",
    "lint": "next lint",
    "db:push": "prisma db push",
    "db:studio": "prisma studio",
    "postinstall": "prisma generate"
  },
  "dependencies": {
    "@emotion/react": "^11.11.3",
    "@emotion/styled": "^11.11.0",
    "@mui/material": "^5.15.10",
    "@mui/styles": "^5.15.10",
    "@mui/system": "^5.15.9",
    "@next-auth/prisma-adapter": "^1.0.7",
    "@prisma/client": "^5.6.0",
    "@spotify/web-api-ts-sdk": "^1.2.0",
    "@t3-oss/env-nextjs": "^0.7.1",
    "@tanstack/react-query": "^4.36.1",
    "@trpc/client": "^10.43.6",
    "@trpc/next": "^10.43.6",
    "@trpc/react-query": "^10.43.6",
    "@trpc/server": "^10.43.6",
    "@types/styled-components": "^5.1.34",
    "bootstrap": "^5.3.2",
    "next": "^14.0.4",
    "next-auth": "^4.24.5",
    "react": "^18.2.0",
    "react-bootstrap": "^2.10.1",
    "react-dom": "^18.2.0",
    "react-router-dom": "^6.2.1",
    "server-only": "^0.0.1",
    "styled-components": "^6.1.8",
    "superjson": "^2.2.1",
    "trpc-openapi": "^1.2.0",
    "zod": "^3.22.4"
  },
  "devDependencies": {
    "@testing-library/jest-dom": "^5.16.5",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "@types/eslint": "^8.44.7",
    "@types/jest": "^29.5.0",
    "@types/node": "^18.17.0",
    "@types/react": "^18.2.37",
    "@types/react-dom": "^18.2.15",
    "@typescript-eslint/eslint-plugin": "^6.11.0",
    "@typescript-eslint/parser": "^6.11.0",
    "autoprefixer": "^10.4.14",
    "eslint": "^8.54.0",
    "eslint-config-next": "^14.0.4",
    "postcss": "^8.4.31",
    "prettier": "^3.1.0",
    "prettier-plugin-tailwindcss": "^0.5.7",
    "prisma": "^5.6.0",
    "tailwindcss": "^3.3.5",
    "typescript": "^5.1.6"
  }
}

```

### src/app/layout.tsx

```typescript
import "~/styles/globals.css";

import { Inter } from "next/font/google";

import { TRPCReactProvider } from "~/trpc/react";

const inter = Inter({
  subsets: ["latin"],
  variable: "--font-sans",
});

export const metadata = {
  title: "Create T3 App",
  description: "Generated by create-t3-app",
  icons: [{ rel: "icon", url: "/favicon.ico" }],
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body className={`font-sans ${inter.variable} width-100vw h-100vh m-0`}>
        <TRPCReactProvider>{children}</TRPCReactProvider>
      </body>
    </html>
  );
}

```

### src/app/page.tsx

```typescript
import React from "react";
import TopHitsComponent from "./_components/TopHitComponent";
import PersonalTopsComponents from "./_components/PersonalTopsComponents";
import LandingPageComponent from "./_components/LandingPageComponent";
import NavsComponent from "./_components/NavsComponent";

import AlbumInfoPage from "./_components/album/AlbumInfoComponent";
import { FunctionComponent } from "react";

const HomePage: FunctionComponent = () => {
  return (
    <div style={{ backgroundColor: "black" }}>
      <NavsComponent />
      <h1
        style={{
          color: "white",
          marginLeft: "200px",
          backgroundColor: "black",
        }}
      >
        Trending Albums
      </h1>
      <TopHitsComponent />
      <h1
        style={{
          color: "white",
          marginLeft: "200px",
          marginTop: "80px",
        }}
      >
        Your Top Albums
      </h1>
      <PersonalTopsComponents />
    </div>
  );
};

export default HomePage;

```

### src/trpc/server.ts

```typescript
import "server-only";

import {
  createTRPCProxyClient,
  loggerLink,
  TRPCClientError,
} from "@trpc/client";
import { callProcedure } from "@trpc/server";
import { observable } from "@trpc/server/observable";
import { type TRPCErrorResponse } from "@trpc/server/rpc";
import { headers } from "next/headers";
import { cache } from "react";

import { appRouter, type AppRouter } from "~/server/api/root";
import { createTRPCContext } from "~/server/api/trpc";
import { transformer } from "./shared";

/**
 * This wraps the `createTRPCContext` helper and provides the required context for the tRPC API when
 * handling a tRPC call from a React Server Component.
 */
export const createContext = cache(() => {
  const heads = new Headers(headers());
  heads.set("x-trpc-source", "rsc");

  return createTRPCContext({
    headers: heads,
  });
});

export const api = createTRPCProxyClient<AppRouter>({
  transformer,
  links: [
    loggerLink({
      enabled: (op) =>
        process.env.NODE_ENV === "development" ||
        (op.direction === "down" && op.result instanceof Error),
    }),
    /**
     * Custom RSC link that lets us invoke procedures without using http requests. Since Server
     * Components always run on the server, we can just call the procedure as a function.
     */
    () =>
      ({ op }) =>
        observable((observer) => {
          createContext()
            .then((ctx) => {
              return callProcedure({
                procedures: appRouter._def.procedures,
                path: op.path,
                rawInput: op.input,
                ctx,
                type: op.type,
              });
            })
            .then((data) => {
              observer.next({ result: { data } });
              observer.complete();
            })
            .catch((cause: TRPCErrorResponse) => {
              observer.error(TRPCClientError.from(cause));
            });
        }),
  ],
});

```

### src/app/search/page.tsx

```typescript
import React from "react";
import LandingPageComponent from "~/app/_components/LandingPageComponent";
import NavsComponent from "~/app/_components/NavsComponent";
import { api } from "~/trpc/server";
import AlbumCard, { AlbumCardProps } from "../_components/AlbumCard";

const SearchPage = async ({
  searchParams,
}: {
  searchParams: { q: string };
}) => {
  console.log("paramsq", searchParams.q);
  const searchResults = await api.album.searchAlbum.query({
    query: searchParams.q,
  });
  console.log(searchResults);

  const albumCards: AlbumCardProps[] = searchResults.map((album) => ({
    id: album.id,
    image: album.image!,
    albumName: album.name,
    artistName: album.artist,
  }));

  return (
    <div style={{ backgroundColor: "black" }}>
      <>
        <NavsComponent />
        <h1
          style={{
            color: "white",
            marginLeft: "220px",
            backgroundColor: "black",
          }}
        >
          Search Results
        </h1>
        <div
          style={{
            display: "flex",
            flexWrap: "wrap",
            justifyContent: "space-between",
            marginLeft: "auto",
            marginRight: "auto",
            marginTop: "20px",
            marginBottom: "20px",
            maxWidth: "1100px",
            backgroundColor: "black",
            height: "320vh",
          }}
        >
          {albumCards.map((album, index) => (
            <AlbumCard key={index} {...album} />
          ))}
        </div>
      </>
    </div>
  );
};

export default SearchPage;

```

### src/app/api/[...openapi]/route.ts

```typescript
import { createOpenApiNextHandler } from "trpc-openapi";

import { appRouter } from "~/server/api/root";
import { createContext } from "~/trpc/server";

export default createOpenApiNextHandler({
  router: appRouter,
  createContext,
});

```

### src/app/album/[albumId]/page.tsx

```typescript
import React from "react";
import Container from "@mui/material/Container";
import Stack from "@mui/material/Stack";
import Divider from "@mui/material/Divider";
import Paper from "@mui/material/Paper";
import List from "@mui/material/List";
import ListItem from "@mui/material/ListItem";
import ListItemAvatar from "@mui/material/ListItemAvatar";
import ListItemIcon from "@mui/material/ListItemIcon";
import ListItemText from "@mui/material/ListItemText";
import Avatar from "@mui/material/Avatar";
import IconButton from "@mui/material/IconButton";
import FormGroup from "@mui/material/FormGroup";
import FormControlLabel from "@mui/material/FormControlLabel";
import Checkbox from "@mui/material/Checkbox";
import Grid from "@mui/material/Grid";
import { api } from "~/trpc/server";
import { getServerAuthSession } from "~/server/auth";
import { TextField, Typography, Button, Box, Rating } from "@mui/material";
import NavsComponent from "../../_components/NavsComponent";

import AlbumReviewForm from "./reviewform";
export default async function AlbumInfoPage({
  params,
}: {
  params: { albumId: string };
}) {
  const album = await api.album.getAlbumById.query({ id: params.albumId });
  const session = await getServerAuthSession();

  const reviews = await api.review.getReviewsByAlbumId.query({
    albumId: params.albumId,
  });
  console.log(album?.image);
  return (
    <Box style={{ backgroundColor: "#391F67", overflow: "hidden" }}>
      <NavsComponent />
      <Stack
        sx={{ height: "100vh", width: "100vw", overflow: "hidden" }}
        direction="row"
        divider={<Divider orientation="vertical" flexItem />}
        spacing={2}
      >
        <Box
          sx={{
            color: "#FFFFFF",
            height: "100vh",
            width: "30vw",
            overflow: "hidden",
          }}
          style = {{overflow:'scroll'}}
        >
          <img
            className="relative max-h-full max-w-full flex-1 self-stretch overflow-hidden"
            alt=""
            src={album.image ?? undefined}
            style={{ maxWidth: "100%", maxHeight: "100%", objectFit: "cover" }}
          />
          <Typography variant="h3" component="h2">
            Track List
          </Typography>
          <List>
            {album?.tracks.map((track) => {
              return (
                <ListItem key={track}>
                  <ListItemText primary={track} style={{ color: "#FFFFFF" }} />
                </ListItem>
              );
            })}
          </List>
        </Box>
        <Box
          sx={{
            color: "#FFFFFF",
            height: "100vh",
            width: "70vw",
            padding: "20px",
          }}
        >
          <Stack
            sx={{ height: "100vh", width: "100vw" }}
            direction="column"
            divider={<Divider orientation="horizontal" flexItem />}
            spacing={2}
            style = {{overflow:'scroll'}}
          >
            <Typography variant="h3" component="h2" style={{ color: "#FFFFFF" }} >
              {album?.name}
            </Typography>
            <Typography variant="h4" component="h2" style={{ color: "#FFFFFF" }} >
              {"Artist: " + album?.artist}
            </Typography>
            <Typography variant="h4" component="h2" style={{ color: "#FFFFFF" }} >
              {"Release Date: " + album?.releaseDate}
            </Typography>
            <AlbumReviewForm albumId={album.id} />
            <List style = {{overflow:'scroll'}}>
              {reviews?.map((review) => {
                return (
                  <Box display="flex" marginBottom="16px" key={review.id}>
                    <Avatar
                      alt={session?.user?.name ?? undefined}
                      src={session?.user.image ?? undefined}
                    />
                    <div>
                      <Typography variant="subtitle1">
                        {session?.user.name}
                      </Typography>
                      <Typography>{review.rating}/10</Typography>
                      <div style={{ marginBottom: "16px" }}>
                        <div
                          style={{
                            display: "flex",
                            alignItems: "center",
                            marginBottom: "8px",
                          }}
                        >
                          <Typography variant="body1">User Rating:</Typography>
                          <Rating
                            name="user-rating"
                            value={review.rating*2}
                            precision={0.5}
                            readOnly
                          />
                          <Typography variant="body1">
                            {review.rating+"/10"}
                          </Typography>
                        </div>
                        <Typography variant="body1">
                          {review.message}
                        </Typography>
                      </div>
                    </div>
                  </Box>
                );
              })}
            </List>
          </Stack>
        </Box>
      </Stack>
    </Box>
  );
}

```

### src/app/profile/[profileId]/page.tsx

```typescript
import { FunctionComponent } from "react";
import {
  Avatar,
  Typography,
  List,
  ListItem,
  ListItemAvatar,
  ListItemText,
  Box,
} from "@mui/material";
import { getServerAuthSession } from "~/server/auth";
import { api } from "~/trpc/server";
import { TextField, Button, Rating } from "@mui/material";

export default async function ProfilePage({
  params,
}: {
  params: { profileId: string };
}) {
  // return (
  //   // <div className="w-full relative bg-midnightblue overflow-hidden flex flex-col items-start justify-start pt-0 px-0 pb-[166px] box-border gap-[34px] tracking-[normal] mq750:gap-[34px]">
  //   //   <Navs1 />
  //   //   <section className="w-[1345px] flex flex-row items-start justify-center py-0 px-5 box-border max-w-full text-left text-xl text-white font-lexend">
  //   //     <div className="w-[1167px] flex flex-col items-start justify-start gap-[158px] max-w-full lg:gap-[158px] mq750:gap-[158px] mq450:gap-[158px]">
  //   //       <div className="w-[385px] flex flex-row items-center justify-between gap-[20px] max-w-full mq450:flex-wrap">
  //   //         <img
  //   //           className="h-52 w-[205px] relative rounded-71xl object-cover mq450:flex-1"
  //   //           loading="eager"
  //   //           alt=""
  //   //           src="/bba1f5779848452287574848905bfa139838c3da68b2474c8a7a0b4d78fe79bf-1@2x.png"
  //   //         />
  //   //         <div className="w-[107px] flex flex-col items-start justify-start pt-[43px] px-0 pb-0 box-border min-w-[107px] mq450:flex-1">
  //   //           <div className="self-stretch flex flex-col items-start justify-start gap-[10px]">
  //   //             <h3 className="m-0 h-[35px] relative text-inherit capitalize font-extralight font-inherit flex items-center shrink-0 mq450:text-base">
  //   //               Friends
  //   //             </h3>
  //   //             <div className="self-stretch flex flex-row items-start justify-start py-0 pr-0 pl-[25px] text-13xl">
  //   //               <b className="flex-1 relative capitalize mq1050:text-7xl mq450:text-lgi">
  //   //                 999
  //   //               </b>
  //   //             </div>
  //   //           </div>
  //   //         </div>
  //   //       </div>
  //   //       <div className="self-stretch flex flex-row items-start justify-end max-w-full">
  //   //         <AlbumRowComponenet />
  //   //       </div>
  //   //     </div>
  //   //   </section>
  //   //   <section className="w-[1038px] my-0 mx-[!important] absolute h-full top-[0px] right-[0px] bottom-[0px] flex flex-row items-start justify-between gap-[20px] max-w-full text-left text-[45px] text-white font-lexend mq1050:flex-wrap">
  //   //     <div className="w-[245px] flex flex-row items-start justify-start relative min-w-[245px] mq1050:flex-1">
  //   //       <h1 className="my-0 mx-[!important] h-8 w-[309px] absolute top-[185px] left-[-92px] text-inherit capitalize font-bold font-inherit flex items-center mq1050:text-17xl mq450:text-[27px]">
  //   //         Username
  //   //       </h1>
  //   //       <img
  //   //         className="h-px w-[451px] absolute my-0 mx-[!important] top-[241px] left-[-120px] object-contain"
  //   //         loading="eager"
  //   //         alt=""
  //   //         src="/line-4.svg"
  //   //       />
  //   //       <div className="flex-1 flex flex-col items-start justify-start pt-[273px] px-0 pb-0 text-xl">
  //   //         <div className="self-stretch flex flex-col items-end justify-start gap-[114px]">
  //   //           <div className="w-[215px] flex flex-col items-start justify-start py-0 pr-0 pl-5 box-border gap-[10px]">
  //   //             <h3 className="m-0 self-stretch h-[35px] relative text-inherit capitalize font-extralight font-inherit flex items-center shrink-0 mq450:text-base">
  //   //               Album’s Reviewed
  //   //             </h3>
  //   //             <div className="w-36 flex flex-row items-start justify-start py-0 px-[31px] box-border text-13xl">
  //   //               <b className="flex-1 relative capitalize z-[1] mq1050:text-7xl mq450:text-lgi">
  //   //                 999
  //   //               </b>
  //   //             </div>
  //   //           </div>
  //   //           <div className="self-stretch h-[37px] flex flex-row items-start justify-start py-0 pr-5 pl-0 box-border text-21xl">
  //   //             <h1 className="m-0 self-stretch flex-1 relative text-inherit capitalize font-extralight font-inherit flex items-center mq1050:text-13xl mq450:text-5xl">
  //   //               Reviewed
  //   //             </h1>
  //   //           </div>
  //   //         </div>
  //   //       </div>
  //   //     </div>
  //   //     <div className="h-[17px] w-[13px] hidden z-[1]" />
  //   //     <div className="w-[586px] flex flex-row items-start justify-start relative min-w-[586px] max-w-full mq1050:flex-1 mq750:min-w-full">
  //   //       <img
  //   //         className="h-[1517.7px] flex-1 relative max-w-full overflow-hidden object-contain mq1050:flex-1"
  //   //         alt=""
  //   //         src="/untitled-design-1-2@2x.png"
  //   //       />
  //   //       <img
  //   //         className="h-6 w-6 absolute my-0 mx-[!important] bottom-[154px] left-[224px] z-[2]"
  //   //         loading="eager"
  //   //         alt=""
  //   //         src="/star-41.svg"
  //   //       />
  //   //       <img
  //   //         className="h-6 w-6 absolute my-0 mx-[!important] bottom-[154px] left-[190px] z-[2]"
  //   //         loading="eager"
  //   //         alt=""
  //   //         src="/star-41.svg"
  //   //       />
  //   //       <img
  //   //         className="h-6 w-6 absolute my-0 mx-[!important] bottom-[154px] left-[156px] z-[2]"
  //   //         loading="eager"
  //   //         alt=""
  //   //         src="/star-41.svg"
  //   //       />
  //   //     </div>
  //   //     <img
  //   //       className="h-6 w-[27px] absolute my-0 mx-[!important] bottom-[154px] left-[381px] z-[2]"
  //   //       lo
[truncated — 2878 more characters]
```

### src/app/api/auth/[...nextauth]/route.ts

```typescript
import NextAuth from "next-auth";

import { authOptions } from "~/server/auth";

// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };

```

### src/app/api/trpc/[trpc]/route.ts

```typescript
import { fetchRequestHandler } from "@trpc/server/adapters/fetch";
import { type NextRequest } from "next/server";

import { env } from "~/env";
import { appRouter } from "~/server/api/root";
import { createTRPCContext } from "~/server/api/trpc";

/**
 * This wraps the `createTRPCContext` helper and provides the required context for the tRPC API when
 * handling a HTTP request (e.g. when you make requests from Client Components).
 */
const createContext = async (req: NextRequest) => {
  return createTRPCContext({
    headers: req.headers,
  });
};

const handler = (req: NextRequest) =>
  fetchRequestHandler({
    endpoint: "/api/trpc",
    req,
    router: appRouter,
    createContext: () => createContext(req),
    onError:
      env.NODE_ENV === "development"
        ? ({ path, error }) => {
            console.error(
              `❌ tRPC failed on ${path ?? "<no-path>"}: ${error.message}`
            );
          }
        : undefined,
  });

export { handler as GET, handler as POST };

```

[37 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]