# Project export: <PriorityQueue>

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 2025
- Tagline: Democratizing information across the electric grid.
- Devpost: https://devpost.com/software/priorityqueue
- GitHub: https://github.com/shrenikpatel17/treeHacks2025
- Video: https://www.youtube.com/embed/hBLujsLhRaA?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Result: winner (Elastic: Best use of Elasticsearch Serverless ($2,000 Cash [1st] & $1,000 Cash [2nd]))
- Team: 2 GitHub contributor(s) — Shrenik Patel (15 commits), sachelv (2 commits)

## Devpost submission (written by the team)

### Inspiration

🌱 The U.S. interconnection queue faces a massive backlog, with two terawatts of mostly clean energy projects waiting for grid access, more than the 1.25 terawatts currently online, causing delays of three to five years or more. High interconnection costs and uncertainty lead to frequent project dropouts, forcing restudies that further slow the process and subsequently the clean energy transition. The current transmission planning system is inefficient, requiring the next project in line to bear upgrade costs, discouraging development and creating cascading delays. While FERC Order 2023 introduces reforms like batch processing and penalties for delays, the lack of proactive regional transmission planning remains a major bottleneck. Driven by genuine climate interest and frustration about the lack of progress in the energy transition, our team was drawn by the unique challenges that the grid interconnection queue offered, an often overlooked reason for lack of progress in clean energy transition. Like many other climate-adjacent issues, it all comes down to regulation. In a brief published by the Federal Energy Regulatory Commission, the commission detailed the great need for an efficient and transparent queue management system. Highlighted customer insights can be found here. Without one, American energy goals cannot be met. The US is not the first to think about this issue. France, for example, has taken strides to streamline its grid connection processes, leveraging a centralized system to integrate renewable projects faster and ensure grid stability. Similarly, parts of Texas have piloted innovative approaches, such as distributed energy resource integration and priority queues for renewables, to accelerate clean energy deployment. These efforts reflect growing public and institutional support for systems that not only simplify bureaucracy but also unlock the potential for cleaner, more reliable energy. It’s clear that people want this change and believe it will help bridge the gap toward a sustainable energy future.

### What it does

💡 Our solution is a user-centric platform that visualizes geospatial data of generation stations, manages each developer’s projects, and organizes said projects into clusters using proprietary algorithms. Each developer has access to current energy generator information, energy generators in the grid interconnection queue, and their own projects. Developers can take part in a “bidding system”, which will be pooled towards fees associated with connecting to the grid as a cluster. Developers also have access to a RAG agent, Link the Energy Expert, who is contextualized by all of PQ’s data and understanding of the grid interconnection system, and can consult with Link to plan which clusters to join and more. Another user of our platform is the ISO manager, or government-affiliated project manager. This user has access to all project proposals, and has the ability to grant or reject said projects.

### How we built it

🛠️ Our infrastructure is centered around a web app model through NextJS that is both scalable and can easily work with large amounts of data as we use MongoDB as our database. We made extensive use of Elastic for our RAG model and geospatial analysis, along with OpenAI for open-ended location interpretation based on user prompts.

### Challenges we ran into

🌃 As beginner hackers, we were inexperienced in working with the tools we had access to at Treehacks, but we were eager to try out new software. Unfortunately, after spending a great deal of time working through a particular sponsor’s product, we realized that the product was not compatible with our web app, and the information could not be embedded into our final product. A drastic pivot had to be made and we tackled steep learning curves during the latter half of the hackathon.

### What we learned

📝 Many of our teammates have never built out a project of this scale at the speed we worked at during Treehacks. Moreover, we had varying degrees of experience with working with complex project files, so many of us learned an incredible amount about web app files and planning for larger project structures. Due to the research intensity of our project, we now know a significant amount about the nuances of the electric grid problem that we didn’t before. When working with niche pain points such as the interconnection queue, intuition for what our clients need will be built on a lot of painstaking research and prototyping through methods such as speaking with users.

### What's next

? 🚀 PriorityQueue is far from finished. We envision a future where PQ works alongside government and regulation to promote transparency inter-developer and between the ISO and generators. Moreover, PQ currently sets up an environment in which developers can accurately assess the benefits to joining a cluster. However, by incorporating AI-facilitated decision making and analytics, PQ’s consulting service abilities could be bettered by tenfold. Imagine a platform that vertically integrates the energy project planning process, scrapes all the data that exists on which projects are currently being implemented, and can help developers make informed decisions about their business! We are inspired by the potential of PQ to: Foster collaboration and information trade between generators. Accelerate permitting reform & power the country. Develop a dynamic market for generators. Pitch deck can be found here.

## README (from the GitHub repository)

This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).

## Getting Started

First, run the development server:

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.

This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.

## Learn More

To learn more about Next.js, take a look at the following resources:

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!

## Deploy on Vercel

The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.

Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.


## Detected evidence (automated analysis)

Indexed codebase: 30 recognized source files, 132 KB.
- CSS (language) — detected in the code
- JavaScript (language) — detected in the code
- MongoDB (technology) — detected in the code
- Next.js (technology) — detected in the code
- OpenAI (technology) — detected in the code
- React (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code
- Node.js (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (36 of 36)

```
.eslintrc.json
.gitignore
next.config.mjs
package.json
postcss.config.mjs
README.md
src/app/api/auth/route.ts
src/app/api/elasticChat/route.ts
src/app/api/elasticGeo/route.ts
src/app/api/elasticLine/route.ts
src/app/api/generateCoordinates/route.ts
src/app/api/groups/[id]/route.ts
src/app/api/groups/route.ts
src/app/api/projects/[id]/route.ts
src/app/api/projects/route.ts
src/app/api/proxy/route.ts
src/app/api/signup/route.ts
src/app/dashboard/page.jsx
src/app/globals.css
src/app/groups/page.jsx
src/app/isoDashboard/page.jsx
src/app/layout.tsx
src/app/lib/mongodb.js
src/app/login/page.tsx
src/app/loginISO/page.tsx
src/app/models/Group.js
src/app/models/Project.js
src/app/models/User.js
src/app/page.tsx
src/app/signup/page.tsx
src/app/state/provider.jsx
src/app/state/reducers/authSlice.js
src/app/state/stateTypes.ts
src/app/state/store.ts
tailwind.config.ts
tsconfig.json
```

### Dependencies

- package.json: @elastic/elasticsearch@^8.17.0, @reduxjs/toolkit@^2.2.6, @types/bcrypt@^5.0.2, @types/jsonwebtoken@^9.0.6, @types/mapbox-gl@^3.4.1, @types/node@^20, @types/react@^18, @types/react-dom@^18, bcrypt@^5.1.1, chart.js@^4.4.7, eslint@^8, eslint-config-next@14.2.5, jsonwebtoken@^9.0.2, mapbox-gl@^3.10.0, mongodb@^6.8.0, mongoose@^8.5.0, next@14.2.5, openai@^4.85.1, postcss@^8, react@^18, react-chartjs-2@^5.3.0, react-dom@^18, react-redux@^9.1.2, redux@^5.0.1, redux-persist@^6.0.0, tailwindcss@^3.4.1, typescript@^5

### Recent commits (newest first)

- merged branches
- fixing algorithm and coordinate parsing
- fixed chat context
- made map fit to substation
- integrated bidding
- bidding feature
- merged branches
- recommendation algorithm agentic web3 llm edge ai hardware healthtech autonomy
- made maps work on group pages
- added map
- edited group schema, allowed group creation, made elastic commands
- fixed geopoint storage
- made isoDashboard, isoUsers, and status displays and visual indicators
- added geopoints and data visualization for clusters
- UI changes in groups screen
- added group functionality and page
- finished form for project creation w openai api
- added tailwind styles
- added post and get backend for projects
- added models for project and group and configured state to work accordingly

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

### package.json

```
{
  "name": "template",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "@elastic/elasticsearch": "^8.17.0",
    "@reduxjs/toolkit": "^2.2.6",
    "@types/mapbox-gl": "^3.4.1",
    "bcrypt": "^5.1.1",
    "chart.js": "^4.4.7",
    "jsonwebtoken": "^9.0.2",
    "mapbox-gl": "^3.10.0",
    "mongodb": "^6.8.0",
    "mongoose": "^8.5.0",
    "next": "14.2.5",
    "openai": "^4.85.1",
    "react": "^18",
    "react-chartjs-2": "^5.3.0",
    "react-dom": "^18",
    "react-redux": "^9.1.2",
    "redux": "^5.0.1",
    "redux-persist": "^6.0.0"
  },
  "devDependencies": {
    "@types/bcrypt": "^5.0.2",
    "@types/jsonwebtoken": "^9.0.6",
    "@types/node": "^20",
    "@types/react": "^18",
    "@types/react-dom": "^18",
    "eslint": "^8",
    "eslint-config-next": "14.2.5",
    "postcss": "^8",
    "tailwindcss": "^3.4.1",
    "typescript": "^5"
  }
}

```

### src/app/page.tsx

```typescript
import Image from "next/image";

export default function Home() {
  return (
   <>
   Template app. Using redux for state management. Has auth built in.
   Make a .env file and put in it JWT = "" and MONGODB_URI = ""
   </>
  );
}

```

### src/app/layout.tsx

```typescript
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import { Providers } from "./state/provider";
import localFont from "next/font/local";

const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
  title: "Treehacks",
  description: "this is cool",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body className={`antialiased`}><Providers>{children}</Providers></body>
    </html>
  );
}

```

### src/app/login/page.tsx

```typescript
'use client';
import React, { useState } from 'react';
import Image from 'next/image';
import { authActions } from '../state/reducers/authSlice';
import { useSelector, useDispatch } from 'react-redux';
import { useRouter } from "next/navigation";


const SignIn: React.FC = () => {
  const router = useRouter();
  const dispatch = useDispatch();

  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');

  const handleSubmit = async(e: React.ChangeEvent<any>) => {
    e.preventDefault();

    if (!e.target.email.value || !e.target.password.value) {
      return "All fields are required";
    }
    const loggedInResponse = await fetch("api/auth", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(
        {
        email: e.target.email.value,
        password: e.target.password.value,
      }),
    });
    const loggedIn = await loggedInResponse.json();
    console.log(loggedIn);
    if (loggedIn.token) {
      dispatch(
        authActions.setLogin({
          user: loggedIn.user,
          token: loggedIn.token,
        })
      );
      e.target.reset();
      router.push("/dashboard");
    }
    else{
      console.log(loggedIn.msg);
    }
  };

  return (
    <div className="flex items-center justify-center min-h-screen px-4 sm:px-6 lg:px-8">
      <div className="w-full max-w-md bg-transaprent border-transparent rounded-3xl p-8 sm:p-10 lg:p-12">
        <div className="sm:mx-auto sm:w-full sm:max-w-md text-center">
          {/* <Image src={logo} alt="Your Company Logo" className="mx-auto h-8 w-auto" /> */}
          <h2 className="mt-5 text-lg font-RalewayRegular leading-9 text-theme-blue">
            Sign in to your account
          </h2>
        </div>

        <div className="mt-5 sm:mx-auto sm:w-full sm:max-w-md">
          <form onSubmit={handleSubmit} className="space-y-4">
            <div>
              <label htmlFor="email" className="block text-sm font-RalewayRegular leading-6 text-theme-blue">
                Email
              </label>
              <div className="mt-2">
                <input
                  id="email"
                  name="email"
                  type="email"
                  autoComplete="email"
                  required
                  value={email}
                  onChange={(e) => setEmail(e.target.value)}
                  className="p-2 bg-transparent font-RalewayMedium block w-full rounded-2xl border-0 py-1.5 text-theme-blue shadow-sm ring-1 ring-inset ring-theme-blue placeholder:text-light-gray sm:text-sm sm:leading-6"
                />
              </div>
            </div>

            <div>
              <div className="flex items-center justify-between">
                <label htmlFor="password" className="block text-sm font-RalewayRegular leading-6 text-theme-blue">
                  Password
                </label>
                <div className="text-sm">
                  <a className="font-RalewayMedium text-theme-blue hover:text-theme-blue">
                    Forgot password?
                  </a>
                </div>
              </div>
              <div className="mt-2">
                <input
                  id="password"
                  name="password"
                  type="password"
                  autoComplete="current-password"
                  required
                  value={password}
                  onChange={(e) => setPassword(e.target.value)}
                  className="p-2 bg-transparent block w-full rounded-2xl border-0 py-1.5 text-theme-blue shadow-sm ring-1 ring-inset ring-theme-blue placeholder:text-gray-400 sm:text-sm sm:leading-6"
                />
              </div>
            </div>

            <div>
              <button
                type="submit"
                className="flex w-full justify-center rounded-2xl bg-black px-3 py-1.5 text-sm font-RalewayMedium leading-6 text-white shadow-sm hover:bg-hover-blue focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
              >
                Sign in
              </button>
            </div>
          </form>

          <p className="mt-10 text-center text-sm text-theme-blue font-RalewayMedium">
            Don&apos;t have an account?{' '}
            <a href="/signup" className="font-RalewayBold leading-6 theme-blue hover:text-hover-blue">
              Get Started
            </a>
          </p>
        </div>
      </div>
    </div>
  );
};

export default SignIn;

```

### src/app/loginISO/page.tsx

```typescript
'use client';
import React, { useState } from 'react';
import Image from 'next/image';
import { authActions } from '../state/reducers/authSlice';
import { useSelector, useDispatch } from 'react-redux';
import { useRouter } from "next/navigation";


const SignIn: React.FC = () => {
  const router = useRouter();
  const dispatch = useDispatch();

  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');

  const handleSubmit = async(e: React.ChangeEvent<any>) => {
    e.preventDefault();

    if (!e.target.email.value || !e.target.password.value) {
      return "All fields are required";
    }
    const loggedInResponse = await fetch("api/auth", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(
        {
        email: e.target.email.value,
        password: e.target.password.value,
      }),
    });
    const loggedIn = await loggedInResponse.json();
    console.log(loggedIn);
    if (loggedIn.token) {
      dispatch(
        authActions.setLogin({
          user: loggedIn.user,
          token: loggedIn.token,
        })
      );
      e.target.reset();
      router.push("/isoDashboard");
    }
    else{
      console.log(loggedIn.msg);
    }
  };

  return (
    <div className="flex items-center justify-center min-h-screen px-4 sm:px-6 lg:px-8">
      <div className="w-full max-w-md bg-transaprent border-transparent rounded-3xl p-8 sm:p-10 lg:p-12">
        <div className="sm:mx-auto sm:w-full sm:max-w-md text-center">
          {/* <Image src={logo} alt="Your Company Logo" className="mx-auto h-8 w-auto" /> */}
          <h2 className="mt-5 text-lg font-RalewayRegular leading-9 text-theme-blue">
            Sign in to your account
          </h2>
        </div>

        <div className="mt-5 sm:mx-auto sm:w-full sm:max-w-md">
          <form onSubmit={handleSubmit} className="space-y-4">
            <div>
              <label htmlFor="email" className="block text-sm font-RalewayRegular leading-6 text-theme-blue">
                Email
              </label>
              <div className="mt-2">
                <input
                  id="email"
                  name="email"
                  type="email"
                  autoComplete="email"
                  required
                  value={email}
                  onChange={(e) => setEmail(e.target.value)}
                  className="p-2 bg-transparent font-RalewayMedium block w-full rounded-2xl border-0 py-1.5 text-theme-blue shadow-sm ring-1 ring-inset ring-theme-blue placeholder:text-light-gray sm:text-sm sm:leading-6"
                />
              </div>
            </div>

            <div>
              <div className="flex items-center justify-between">
                <label htmlFor="password" className="block text-sm font-RalewayRegular leading-6 text-theme-blue">
                  Password
                </label>
                <div className="text-sm">
                  <a className="font-RalewayMedium text-theme-blue hover:text-theme-blue">
                    Forgot password?
                  </a>
                </div>
              </div>
              <div className="mt-2">
                <input
                  id="password"
                  name="password"
                  type="password"
                  autoComplete="current-password"
                  required
                  value={password}
                  onChange={(e) => setPassword(e.target.value)}
                  className="p-2 bg-transparent block w-full rounded-2xl border-0 py-1.5 text-theme-blue shadow-sm ring-1 ring-inset ring-theme-blue placeholder:text-gray-400 sm:text-sm sm:leading-6"
                />
              </div>
            </div>

            <div>
              <button
                type="submit"
                className="flex w-full justify-center rounded-2xl bg-black px-3 py-1.5 text-sm font-RalewayMedium leading-6 text-white shadow-sm hover:bg-hover-blue focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
              >
                Sign in
              </button>
            </div>
          </form>

          <p className="mt-10 text-center text-sm text-theme-blue font-RalewayMedium">
            Don&apos;t have an account?{' '}
            <a href="/signup" className="font-RalewayBold leading-6 theme-blue hover:text-hover-blue">
              Get Started
            </a>
          </p>
        </div>
      </div>
    </div>
  );
};

export default SignIn;

```

### src/app/signup/page.tsx

```typescript
'use client';
import React, { useState } from 'react';
import Image from 'next/image';
import { useRouter } from "next/navigation";

const GetStarted: React.FC = () => {
  const router = useRouter();

  const [firstName, setFirstName] = useState('');
  const [lastName, setLastName] = useState('');
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');


  const handleSubmit = async () => {
    if (firstName === '' || lastName === '' || email === '' || password === '') {
        return;
    }
    
    try {
        const res = await fetch("api/signup", {
        method: "POST",
        headers: {
            "Content-Type": "application/json",
        },
        body: JSON.stringify({
            firstName: firstName,
            lastName: lastName,
            email: email,
            password: password,
        }),
        });

        if (res.ok) {
          router.push("/login");
          console.log(res)
        } else {
          console.log("User registration failed.");
        }
    } catch (error) {
        console.log("Error during registration: ", error);
    }
    };

  return (
    <div className="flex items-center justify-center min-h-screen px-4 sm:px-6 lg:px-8">
      <div className="w-full max-w-md bg-transparent border-transparent rounded-3xl p-8 sm:p-10 lg:p-12">
        <div className="sm:mx-auto sm:w-full sm:max-w-md text-center">
          {/* <Image src={logo} alt="Your Company Logo" className="mx-auto h-8 w-auto" /> */}
          <h2 className="mt-5 text-lg font-RalewayRegular leading-9 text-theme-blue">
            Get started with your account
          </h2>
        </div>

        <div className="mt-5 sm:mx-auto sm:w-full sm:max-w-md">
          <form className="space-y-4">
            <div>
              <label htmlFor="firstName" className="block text-sm font-RalewayRegular leading-6 text-theme-blue">
                First Name
              </label>
              <div className="mt-2">
                <input
                  id="firstName"
                  name="firstName"
                  type="text"
                  autoComplete="given-name"
                  required
                  value={firstName}
                  onChange={(e) => setFirstName(e.target.value)}
                  className="p-2 bg-transparent font-RalewayMedium block w-full rounded-2xl border-0 py-1.5 text-theme-blue shadow-sm ring-1 ring-inset ring-theme-blue placeholder:text-light-gray sm:text-sm sm:leading-6"
                />
              </div>
            </div>

            <div>
              <label htmlFor="lastName" className="block text-sm font-RalewayRegular leading-6 text-theme-blue">
                Last Name
              </label>
              <div className="mt-2">
                <input
                  id="lastName"
                  name="lastName"
                  type="text"
                  autoComplete="family-name"
                  required
                  value={lastName}
                  onChange={(e) => setLastName(e.target.value)}
                  className="p-2 bg-transparent font-RalewayMedium block w-full rounded-2xl border-0 py-1.5 text-theme-blue shadow-sm ring-1 ring-inset ring-theme-blue placeholder:text-light-gray sm:text-sm sm:leading-6"
                />
              </div>
            </div>

            <div>
              <label htmlFor="email" className="block text-sm font-RalewayRegular leading-6 text-theme-blue">
                Email
              </label>
              <div className="mt-2">
                <input
                  id="email"
                  name="email"
                  type="email"
                  autoComplete="email"
                  required
                  value={email}
                  onChange={(e) => setEmail(e.target.value)}
                  className="p-2 bg-transparent font-RalewayMedium block w-full rounded-2xl border-0 py-1.5 text-theme-blue shadow-sm ring-1 ring-inset ring-theme-blue placeholder:text-light-gray sm:text-sm sm:leading-6"
                />
              </div>
            </div>

            <div>
              <label htmlFor="password" className="block text-sm font-RalewayRegular leading-6 text-theme-blue">
                Password
              </label>
              <div className="mt-2">
                <input
                  id="password"
                  name="password"
                  type="password"
                  autoComplete="current-password"
                  required
                  value={password}
                  onChange={(e) => setPassword(e.target.value)}
                  className="p-2 bg-transparent block w-full rounded-2xl border-0 py-1.5 text-theme-blue shadow-sm ring-1 ring-inset ring-theme-blue placeholder:text-gray-400 sm:text-sm sm:leading-6"
                />
              </div>
            </div>

            <div>
            <button
              onClick={handleSubmit}
              className="z-20 flex w-full justify-center rounded-2xl bg-black px-3 py-1.5 text-sm hover:cursor-pointer font-RalewayMedium leading-6 text-white shadow-sm hover:bg-hover-blue focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
            >
              Sign up
            </button>

            </div>
          </form>

          <p className="mt-10 text-center text-sm text-theme-blue font-RalewayMedium">
            Already have an account?{' '}
            <a href="/login" className="font-RalewayBold leading-6 text-black hover:text-black hover:underline">
              Sign In
            </a>
          </p>
        </div>
      </div>
    </div>
  );
};

export default GetStarted;

```

### src/app/api/proxy/route.ts

```typescript
export async function GET(req: Request) {
    const url = `https://my-deployment-5421f6.kb.us-west1.gcp.cloud.es.io/app/dashboards#/view/8d6d76ec-55eb-4d07-b566-c9e49b60361c`;

    const response = await fetch(url, {
        headers: { host: "my-deployment-5421f6.kb.us-west1.gcp.cloud.es.io" },
    });

    let html = await response.text();

    // Remove CSP meta tags
    html = html.replace(/<meta http-equiv="Content-Security-Policy"[^>]*>/gi, "");

    return new Response(html, {
        status: response.status,
        headers: {
            "Content-Type": "text/html",
            "X-Frame-Options": "ALLOWALL",
            "Content-Security-Policy": "frame-ancestors 'self'",
        },
    });
}

```

### src/app/api/signup/route.ts

```typescript
import { connectMongoDB } from "../../lib/mongodb";
import { NextResponse } from "next/server";
import bcrypt from "bcrypt";
import {User} from "../../models/User";

export async function POST(req: Request) {
  try {
    const { firstName, lastName, email, password, npi } = await req.json();

    const salt = await bcrypt.genSalt();
    const hashedPassword = await bcrypt.hash(password, salt);
    
    await connectMongoDB();
    await User.create({ 
      firstName, 
      lastName, 
      email, 
      password: hashedPassword,
    });

    return NextResponse.json({ message: "User signed up." }, { status: 201 });
  } catch (error) {
    return NextResponse.json(
      { message: "An error occurred during user sign up." },
      { status: 500 }
    );
  }
}
```

### src/app/api/auth/route.ts

```typescript
import { connectMongoDB } from "../../lib/mongodb";
import { NextResponse } from "next/server";
import bcrypt from "bcrypt";
import jwt from "jsonwebtoken";
import { User } from "../../models/User";
import { env } from 'node:process';

export async function POST(req: Request) {
  try{
    const {email, password} = await req.json();

    await connectMongoDB();
    
    const user = await User.findOne({ email: email })
    if (!user) return NextResponse.json({msg: "User does not exist. "}, {status: 400});

    const isMatch = await bcrypt.compare(password, user.password);
    if (!isMatch) return NextResponse.json({msg: "Invalid credentials. "}, {status: 400});

    const token = jwt.sign({ id: user._id }, env.JWT!)

    return NextResponse.json({ token, user }, {status: 201});

} catch (err: any){
  return NextResponse.json({ error: err.message });
}
}
```

### src/app/api/projects/route.ts

```typescript
import { connectMongoDB } from "@/app/lib/mongodb";
import { NextResponse } from "next/server";
import { User } from "@/app/models/User"
import { Project } from "@/app/models/Project";
import mongoose from 'mongoose';

export async function POST( req: Request ) {
    try {
        const { userID, name, metadata } = await req.json();
        
        await connectMongoDB();

        var newProjectObject = {
            name: name,
            metadata: metadata,
        };

        const newProject = await Project.create(newProjectObject);

        await User.findByIdAndUpdate(userID, {
            $push: {
              projects: newProject._id
            },
          });

        return NextResponse.json(
            { data: newProject },
            { status: 201 }
            );
        } 
    catch (error: unknown) {
        return NextResponse.json(
            error,
            { status: 500 }
        );
    }
}

//GET ALL PROJECTS
export async function GET() {
    try {
        await connectMongoDB();

        const projects = await Project.find();

        return NextResponse.json(
            { data: projects },
            { status: 200 }
        );
    } catch (error: unknown) {
        return NextResponse.json(
            { error: "An error occurred while fetching projects." },
            { status: 500 }
        );
    }
}
```

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