# Project export: RoomeyFinder

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: OpenAI Build Week
- Tagline: RoomeyFinder matches Nigerian students with compatible roommates, so you can split the upfront rent and find a home you actually want to live in.
- Devpost: https://devpost.com/software/roomeyfinder
- GitHub: https://github.com/RoomeyFinder/roomeyfinder-v2
- Demo: https://roomeyfinder.com/
- Video: https://www.youtube.com/embed/-dxp9FOeRVI?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 1 GitHub contributor(s) — exploitenomah (42 commits)

## Devpost submission (written by the team)

### Overview

RoomeyFinder helps people in Nigeria find compatible roommates and shared homes. Users create a profile, describe their living preferences, discover compatible matches, and connect only after mutual interest. The app is built with Next.js and Supabase, with privacy-conscious profile data, authenticated workflows, home listings, photo uploads, and database-backed matching.

### Inspiration

In Nigeria and across Africa today, the skyrocketing cost of housing has made independent living nearly impossible for students and young professionals. To survive economically, pairing up to split the bills has shifted from an option to an absolute necessity. Yet, the current solution is broken. People are still forced to rely on chaotic Facebook groups or random Twitter threads to find housemates. Traditional housing apps focus heavily on property listings, forcing users to endlessly swipe through raw profiles without any real filter for personal alignment. We built RoomeyFinder to completely eliminate the guesswork, friction, and privacy risks of the traditional roommate hunt.

### What it does

RoomeyFinder.com is a privacy-first, compatibility-driven roommate discovery platform designed to end the era of random internet searches. Instead of scrolling through an endless directory of strangers, our algorithm computes compatibility programmatically in the background based on location, budget, lifestyle, and home preferences. Privacy is at the core of the user experience. Personal data, sensitive living preferences, and contact information are fully locked and hidden from public view. When a match is calculated, users only see that they are fundamentally compatible. If you send an interest request, your personal info remains completely hidden until the other party explicitly accepts it. Once mutual interest is confirmed, the profiles unlock, contact details are revealed, and communication can safely begin.

### How we built it

The platform is engineered using a robust, modern stack focused on speed, type-safety, and rigorous data security: Frontend & Routing: Built using Next.js (App Router) and React for fluid, multi-step onboarding flows, styled dynamically with Tailwind CSS. Backend & Database: Powered by Supabase (PostgreSQL), utilizing complex SQL functions to evaluate and rank user compatibility server-side. Security & Data Privacy: Relies heavily on Supabase Row Level Security (RLS) policies and private Storage buckets to ensure no user data is exposed without strict, programmatically verified mutual consent. Animation & UI Primitives: Accessible foundations via Radix UI and Lucide React, paired with clean, intentional motion powered by GSAP.

### Challenges we ran into

This project marked our first time deep in the weeds with the Supabase CLI, requiring an incredibly meticulous loop of configuring migrations, storage rules, and testing database seeds locally. The biggest hurdle came during authentication setup. Our magic-link and social sign-ins kept throwing silent failures due to a URL mismatch between 127.0.0.1 and localhost within the local auth redirect rules. Because the underlying code logic was technically perfect, our AI development collaborator (Codex) couldn’t detect the environmental discrepancy and spent hours trying to refactor working code. The breakthrough came only when we stepped back, stopped relying blindly on AI suggestions, manually audited the environment configuration, and spotted the routing mismatch.

### Accomplishments we're proud of

True Zero-Knowledge Browsing: Successfully implementing an architecture where users can confidently find high-quality living matches without broadcasting their personal lives or exact locations to the public internet. Deterministic Local Testing: Building a comprehensive local testing suite with 48 distinct seed accounts mimicking homeowners, pairs, and seekers, allowing us to validate matching logic instantly. Bulletproof RLS: Forcing authorization directly down into the database layer via PostgreSQL policies rather than relying on flimsy client-side checks.

### What we learned

We walked away with a profound respect for strict local-first database development. More importantly, this hackathon taught us how to effectively pair with cutting-edge LLMs. While Codex and GPT-5.6 are phenomenal for accelerating UI builds and schema generation, they can easily get stuck in a loop when debugging subtle, environment-specific infrastructure bugs. Human intuition and careful system auditing are still irreplaceable.

### What's next

The MVP proves that programmatic compatibility matching works safely. Next, we plan to implement a secure, anonymous real-time chat interface directly into the platform so matched users can iron out living agreements before exchanging telephone numbers. Additionally, we aim to expand our geocoding capabilities to map out neighborhood-specific security ratings, giving young Africans deeper insights into the safety of their potential shared spaces.

## README (from the GitHub repository)

# RoomeyFinder

RoomeyFinder helps people in Nigeria find compatible roommates and shared homes. Users create a profile, describe their living preferences, discover compatible matches, and connect only after mutual interest.

The app is built with Next.js and Supabase, with privacy-conscious profile data, authenticated workflows, home listings, photo uploads, and database-backed matching.

## Repository

Public repository: [github.com/RoomeyFinder/roomeyfinder-v2](https://github.com/RoomeyFinder/roomeyfinder-v2)

## How Codex and GPT-5.6 were used

OpenAI Codex, powered by GPT-5.6, was used as a development collaborator throughout the project. It helped with:

- Planning and implementing the Next.js roommate discovery flows and responsive UI
- Building and refining Supabase authentication, database, Storage, and Row Level Security workflows
- Developing compatibility matching, interest-based contact reveal, and home-listing functionality
- Creating and reviewing validation, seed data, database tests, and developer documentation
- Debugging issues, reviewing code quality, and running the project’s type-check, lint, formatting, build, and database test commands

All generated changes were reviewed, adapted, and tested as part of the project’s development process.

GPT-5.6 was integrated into the development workflow through Codex as an engineering collaborator. It was not called at runtime by the RoomeyFinder application. Codex assisted with planning, implementation, debugging, testing, and code review, while all changes were reviewed and validated by the developer.

## Key product, engineering, and design decisions

- **Mutual-interest contact reveal:** Contact details remain private until both users express interest and the connection is accepted. This supports safer introductions and keeps discovery separate from unsolicited contact.
- **Supabase Row Level Security and private Storage:** User-owned data, private profile information, and uploaded photos are protected with database and Storage policies. This keeps authorization close to the data layer instead of relying only on client-side checks.
- **Structured compatibility matching:** Matching uses practical roommate criteria such as location, budget, lifestyle, and home preferences so users can understand why recommendations are relevant.
- **Guided setup flows:** Profile, preferences, and home details are collected through focused steps to reduce cognitive load and ensure the matching system has useful information.
- **Responsive and reduced-motion-friendly UI:** The interface is designed for mobile and desktop use, with animations kept purposeful and reduced when users prefer less motion. This balances visual polish with accessibility and usability.
- **Database-backed local development:** Deterministic seed data, migrations, and database/RLS tests were chosen so important user journeys and privacy rules can be tested repeatably before deployment.

This project was built with Codex through the Codex extension inside Visual Studio Code. Submission verification is provided through the `/feedback` Session ID from the main development thread:

```text
Feedback Session ID: 019f6dd1-c281-7490-b97a-c00a670f61d2
```

## Features

- Magic-link & social authentication with Supabase Auth
- Guided profile, preference, and home setup flows
- Roommate and shared-home discovery
- Compatibility matching based on location, budget, lifestyle, and home preferences
- Home listings with amenities, availability, and photos
- Mutual-interest workflow before contact details are revealed
- Private Supabase Storage buckets with access policies
- Responsive UI, dark mode, custom illustrations, and reduced-motion-friendly animations
- Local seed data and database tests for development

## Tech stack

- Next.js App Router and React
- TypeScript
- Tailwind CSS
- Supabase Auth, Postgres, Storage, and Row Level Security
- GSAP for interface animation
- Radix UI and Lucide React for accessible interface primitives
- Geoapify for server-side location geocoding

## Requirements

- Node.js 20 or newer
- npm
- A Supabase project for hosted development, or Docker and the Supabase CLI for local development
- A Geoapify API key for the location search endpoint

## Getting started

Install dependencies:

```bash
npm install
```

Create a local environment file:

```bash
cp .env.example .env.local
```

Set the values in `.env.local`:

```env
NEXT_PUBLIC_SUPABASE_URL=your-supabase-project-url
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=your-publishable-or-anon-key
GEOAPIFY_API_KEY=your-geoapify-api-key
```

The Supabase publishable/anon key is safe to expose in the browser when database access is protected by correct Row Level Security policies. Never expose a Supabase service-role key or other secret key through a `NEXT_PUBLIC_` variable.

Start the development server:

```bash
npm run dev
```

Open [http://localhost:3000](http://localhost:3000).

## Local Supabase development

The repository includes migrations, deterministic seed data, storage configuration, and database tests.

Start the local Supabase stack and reset the database:

```bash
npm run db:start
npm run db:reset
```

In a second terminal, serve the local Edge Functions:

```bash
npm run functions:serve
```

Keep this process running while testing account deletion or other Edge
Function-backed flows. Without it, calls to `/functions/v1/delete-account`
return a 503 from the local Supabase gateway.

The local Supabase email inbox is available at [http://localhost:54324](http://localhost:54324). Magic links generated during local development appear there instead of being sent externally.

The seed creates 48 test accounts across homeowner, roommate-pairing, and home-seeker scenarios. Example emails include:

```text
seed.homeowner.01@example.test
seed.pair.17@example.test
seed.home-seeker.33@example.test
```

Seed accounts use the local Supabase email flow. Use the inbox to open a magic link and complete the relevant user journey.

Run the database and RLS/matching tests with:

```bash
npm run test:db
```

## Available scripts

| Command                | Purpose                                        |
| ---------------------- | ---------------------------------------------- |
| `npm run dev`          | Start the Next.js development server           |
| `npm run build`        | Create a production build                      |
| `npm run start`        | Serve the production build                     |
| `npm run typecheck`    | Run TypeScript without emitting files          |
| `npm run lint`         | Run ESLint                                     |
| `npm run lint:fix`     | Apply ESLint fixes where possible              |
| `npm run format`       | Format the repository with Prettier            |
| `npm run format:check` | Verify Prettier formatting                     |
| `npm run db:start`     | Start the local Supabase services              |
| `npm run db:reset`     | Apply migrations and reseed the local database |
| `npm run test:db`      | Run Supabase database tests                    |

Before opening a pull request or submitting a build, run:

```bash
npm run typecheck
npm run lint
npm run format:check
npm run build
npm run test:db
```

## Project structure

```text
app/                    Next.js routes, layouts, auth, and API handlers
components/             Reusable UI and roommate-flow components
hooks/                  Client-side workflow and data hooks
lib/                    Supabase clients, matching, validation, and utilities
assets/illustrations/   React/SVG illustrations used by the product UI
supabase/migrations/    Database schema, policies, functions, and storage rules
supabase/tests/         Database and Row Level Security tests
supabase/seed.sql       Deterministic local development data
public/                 Static assets
```

## Security and privacy

The application uses Supabase Row Level Security to limit access to user-owned and private records.

[README truncated for size]

## Detected evidence (automated analysis)

Indexed codebase: 176 recognized source files, 552 KB.
- CSS (language) — detected in the code
- HTML (language) — detected in the code
- Next.js (technology) — detected in the code
- React (technology) — detected in the code
- SQL (language) — detected in the code
- Supabase (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code

## Codebase structure (from repository index)

### Files (120 of 190)

```
.agents/skills/supabase-postgres-best-practices/CHANGELOG.md
.agents/skills/supabase-postgres-best-practices/references/_contributing.md
.agents/skills/supabase-postgres-best-practices/references/_sections.md
.agents/skills/supabase-postgres-best-practices/references/_template.md
.agents/skills/supabase-postgres-best-practices/references/advanced-full-text-search.md
.agents/skills/supabase-postgres-best-practices/references/advanced-jsonb-indexing.md
.agents/skills/supabase-postgres-best-practices/references/conn-idle-timeout.md
.agents/skills/supabase-postgres-best-practices/references/conn-limits.md
.agents/skills/supabase-postgres-best-practices/references/conn-pooling.md
.agents/skills/supabase-postgres-best-practices/references/conn-prepared-statements.md
.agents/skills/supabase-postgres-best-practices/references/data-batch-inserts.md
.agents/skills/supabase-postgres-best-practices/references/data-n-plus-one.md
.agents/skills/supabase-postgres-best-practices/references/data-pagination.md
.agents/skills/supabase-postgres-best-practices/references/data-upsert.md
.agents/skills/supabase-postgres-best-practices/references/lock-advisory.md
.agents/skills/supabase-postgres-best-practices/references/lock-deadlock-prevention.md
.agents/skills/supabase-postgres-best-practices/references/lock-short-transactions.md
.agents/skills/supabase-postgres-best-practices/references/lock-skip-locked.md
.agents/skills/supabase-postgres-best-practices/references/monitor-explain-analyze.md
.agents/skills/supabase-postgres-best-practices/references/monitor-pg-stat-statements.md
.agents/skills/supabase-postgres-best-practices/references/monitor-vacuum-analyze.md
.agents/skills/supabase-postgres-best-practices/references/query-composite-indexes.md
.agents/skills/supabase-postgres-best-practices/references/query-covering-indexes.md
.agents/skills/supabase-postgres-best-practices/references/query-index-types.md
.agents/skills/supabase-postgres-best-practices/references/query-missing-indexes.md
.agents/skills/supabase-postgres-best-practices/references/query-partial-indexes.md
.agents/skills/supabase-postgres-best-practices/references/schema-constraints.md
.agents/skills/supabase-postgres-best-practices/references/schema-data-types.md
.agents/skills/supabase-postgres-best-practices/references/schema-foreign-key-indexes.md
.agents/skills/supabase-postgres-best-practices/references/schema-lowercase-identifiers.md
.agents/skills/supabase-postgres-best-practices/references/schema-partitioning.md
.agents/skills/supabase-postgres-best-practices/references/schema-primary-keys.md
.agents/skills/supabase-postgres-best-practices/references/security-privileges.md
.agents/skills/supabase-postgres-best-practices/references/security-rls-basics.md
.agents/skills/supabase-postgres-best-practices/references/security-rls-performance.md
.agents/skills/supabase-postgres-best-practices/SKILL.md
.agents/skills/supabase/assets/feedback-issue-template.md
.agents/skills/supabase/CHANGELOG.md
.agents/skills/supabase/references/skill-feedback.md
.agents/skills/supabase/SKILL.md
.env.example
.github/workflows/supabase-migrations.yml
.gitignore
.prettierignore
.prettierrc.json
.vscode/settings.json
app/[username]/layout.tsx
app/[username]/page.tsx
app/about/page.tsx
app/api/geocode/route.ts
app/auth/callback/route.ts
app/auth/confirm/route.ts
app/auth/error/page.tsx
app/auth/layout.tsx
app/auth/login/page.tsx
app/auth/magic-link/route.ts
app/auth/verify/page.tsx
app/contact/page.tsx
app/globals.css
app/interests/layout.tsx
app/interests/page.tsx
app/layout.tsx
app/manifest.ts
app/matches/layout.tsx
app/matches/page.tsx
app/not-found.tsx
app/page.tsx
app/privacy/page.tsx
app/ProximaNova.otf
app/settings/layout.tsx
app/settings/page.tsx
app/setup/layout.tsx
app/setup/page.tsx
app/terms-and-conditions/page.tsx
assets/illustrations/cozy-shared-space.tsx
assets/illustrations/smart-search-and-filter.tsx
assets/illustrations/the-perfect-match.tsx
assets/illustrations/trust-key-handover.tsx
components.json
components/auth-button.tsx
components/back-button.tsx
components/brand-logo.tsx
components/content-page.tsx
components/cursor-backdrop.tsx
components/env-var-warning.tsx
components/hero.tsx
components/home-actions.tsx
components/how-it-works.tsx
components/interest-button.tsx
components/interest-realtime-provider.tsx
components/interests-page.tsx
components/location-picker.tsx
components/login-form.tsx
components/logout-button.tsx
components/matches-page.tsx
components/roommate-flow/constants.ts
components/roommate-flow/discovery-step.tsx
components/roommate-flow/empty-matches.tsx
components/roommate-flow/home-step.tsx
components/roommate-flow/incoming-interests.tsx
components/roommate-flow/index.tsx
components/roommate-flow/match-card.tsx
components/roommate-flow/preferences-step.tsx
components/roommate-flow/profile-step.tsx
components/roommate-flow/setup-warning-modal.tsx
components/roommate-flow/shared.tsx
components/roommate-flow/types.ts
components/settings-page.tsx
components/site-footer.tsx
components/site-header.tsx
components/theme-switcher.tsx
components/toast-provider.tsx
components/ui/badge.tsx
components/ui/button.tsx
components/ui/card.tsx
components/ui/checkbox.tsx
components/ui/dropdown-menu.tsx
components/ui/input.tsx
components/ui/label.tsx
components/user-menu.tsx
[70 more files omitted for size]
```

### Dependencies

- package.json: @eslint/eslintrc@^3, @radix-ui/react-checkbox@^1.3.1, @radix-ui/react-dropdown-menu@^2.1.14, @radix-ui/react-label@^2.1.6, @radix-ui/react-slot@^1.2.2, @supabase/ssr@latest, @supabase/supabase-js@latest, @types/node@^20, @types/react@^19, @types/react-dom@^19, autoprefixer@^10.4.20, class-variance-authority@^0.7.1, clsx@^2.1.1, eslint@^9, eslint-config-next@15.3.1, eslint-config-prettier@^10.1.8, gsap@^3.15.0, lucide-react@^0.511.0, next@latest, next-themes@^0.4.6, postcss@^8, prettier@^3.9.5, prettier-plugin-tailwindcss@^0.8.1, react@^19.0.0, react-dom@^19.0.0, react-toastify@^11.1.0, supabase@^2.109.1, tailwind-merge@^3.3.0, tailwindcss@^3.4.1, tailwindcss-animate@^1.0.7, typescript@^5

### Recent commits (newest first)

- add link to review interest
- deploy edge fns
- Enable account deletion & create settings page
- Add missing preferences fields
- Enable realtime for interest actions
- Enable email notifications for interests
- Hide sensitive profile info
- Setup account inactivity handling
- fix primary photo deletion
- Update Readme
- Update contact email
- Allow view matches only after profile complete
- Allow login page for only logged out users
- Add back button to profile page
- Add appropriate styling for interest button on accepted
- SSetup toast and add duplicate username conflict error
- Fix currency symbol display
- Format & update README.md
- Setup illustrations
- Fix profile pic display

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

### TODO.md

```markdown
# MVP TODO

## Before the hackathon demo

- [x] Fix redirect validation in `app/auth/confirm/route.ts` so `next` only accepts safe internal paths, or remove the unused route.
- [x] Run the project verification commands:
  - [x] `npm run typecheck`
  - [x] `npm run lint`
  - [x] `npm run build`
  - [x] `npm run test:db`
- [x] Remove or implement the footer links for `/about`, `/contact`, `/terms-and-conditions`, and `/privacy` so the demo has no avoidable 404s.
- [x] Test the complete happy path with two accounts:
  - [x] Sign in with a magic link.
  - [x] Complete profile setup.
  - [x] Complete preferences.
  - [x] Create and publish a home listing.
  - [x] Verify seeker and homeowner matching.
  - [x] Send an interest.
  - [x] Accept and decline interests.
  - [x] Verify contact details appear only after acceptance.

## Before public launch

- [x] Protect `/api/geocode` with authentication and/or rate limiting to prevent API-cost abuse.
- [x] Decide whether profile and home photos should be public. If not, make the storage buckets private and use signed URLs consistently.
- [x] Make multi-step profile and home saves resilient to partial failure. Prefer a server action/RPC or add cleanup and retry handling for failed later steps.
- [x] Refresh or update profile-page data after sending, accepting, or declining an interest so newly unlocked contact details appear immediately.
- [ ] Decide whether incomplete setup should be allowed to load matches. If retained, clearly label it as preview mode and prevent unsupported actions.
- [ ] Add a user-facing way to hide a profile by controlling `profiles.is_visible`.
- [ ] Add account deletion, including cleanup of profile data, homes, interests, contacts, and storage objects.
- [ ] Add privacy, terms, about, contact, and FAQ content if those footer links remain.

## Product and quality follow-ups

- [ ] Add automated end-to-end coverage for authentication, onboarding, matching, interests, and contact reveal.
- [ ] Test failed uploads and retries to ensure orphaned storage files and partial database records are cleaned up.
- [ ] Test duplicate interests, concurrent accept/decline actions, archived homes, and users changing from homeowner to seeker.
- [ ] Add monitoring/logging for failed magic links, geocoding failures, matching RPC failures, and photo uploads.
- [ ] Review photo file type, size, and quantity validation on both the client and server/storage layer.
- [ ] Review the public profile and matching data for unintended personal-information exposure before launch.

## Explicitly out of scope for this MVP

- [ ] Messaging/chat between matched users.

```

### docs/interest-notifications.md

```markdown
# Interest email notifications

The `interest-notifications` Edge Function sends two transactional emails:

- when a pending interest is created, to the recipient;
- when a recipient accepts a pending interest, to the original sender.

The function uses the existing Resend configuration:

```text
RESEND_API_KEY=<Resend sending API key>
INACTIVITY_FROM_EMAIL=RoomeyFinder <notifications@mail.roomeyfinder.com>
APP_URL=https://your-production-domain.com
INTEREST_NOTIFICATION_WEBHOOK_SECRET=<long random value>
```

Set these as Supabase Edge Function secrets. Supabase automatically provides
the admin secret key to Edge Functions through `SUPABASE_SECRET_KEYS`; do not
try to create a custom secret whose name starts with `SUPABASE_`. Never add
secrets to a `NEXT_PUBLIC_` variable or commit them to the repository.

## Create the database webhooks

After deploying the function, create two Database Webhooks in the Supabase
Dashboard for `public.interests`:

1. `interest-created`: event `INSERT`
2. `interest-accepted`: event `UPDATE`

Both should call:

```text
https://<project-ref>.supabase.co/functions/v1/interest-notifications
```

Add these request headers to each webhook:

```text
Content-Type: application/json
x-interest-notification-secret: <same value as INTEREST_NOTIFICATION_WEBHOOK_SECRET>
```

The function only sends an INSERT notification for a pending interest and only
sends an UPDATE notification when the status changes from `pending` to
`accepted`. The `interest_notification_events` table prevents duplicate emails
when a webhook is retried.

```

### package.json

```
{
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "functions:serve": "supabase functions serve --env-file .env",
    "lint": "eslint .",
    "lint:fix": "eslint . --fix",
    "format": "prettier --write .",
    "format:check": "prettier --check .",
    "typecheck": "tsc --noEmit",
    "db:start": "supabase start",
    "db:reset": "supabase db reset --local",
    "test:db": "supabase test db --local supabase/tests"
  },
  "dependencies": {
    "@radix-ui/react-checkbox": "^1.3.1",
    "@radix-ui/react-dropdown-menu": "^2.1.14",
    "@radix-ui/react-label": "^2.1.6",
    "@radix-ui/react-slot": "^1.2.2",
    "@supabase/ssr": "latest",
    "@supabase/supabase-js": "latest",
    "class-variance-authority": "^0.7.1",
    "clsx": "^2.1.1",
    "gsap": "^3.15.0",
    "lucide-react": "^0.511.0",
    "next": "latest",
    "next-themes": "^0.4.6",
    "react": "^19.0.0",
    "react-dom": "^19.0.0",
    "react-toastify": "^11.1.0",
    "tailwind-merge": "^3.3.0"
  },
  "devDependencies": {
    "@eslint/eslintrc": "^3",
    "@types/node": "^20",
    "@types/react": "^19",
    "@types/react-dom": "^19",
    "autoprefixer": "^10.4.20",
    "eslint": "^9",
    "eslint-config-next": "15.3.1",
    "eslint-config-prettier": "^10.1.8",
    "postcss": "^8",
    "prettier": "^3.9.5",
    "prettier-plugin-tailwindcss": "^0.8.1",
    "supabase": "^2.109.1",
    "tailwindcss": "^3.4.1",
    "tailwindcss-animate": "^1.0.7",
    "typescript": "^5"
  }
}

```

### app/page.tsx

```typescript
import { Hero } from "@/components/hero";
import { HowItWorks } from "@/components/how-it-works";
import { SiteHeader } from "@/components/site-header";
import { SiteFooter } from "@/components/site-footer";
import { CursorBackdrop } from "@/components/cursor-backdrop";

export default function Home() {
  return (
    <main className="relative flex min-h-screen flex-col items-center overflow-hidden">
      <CursorBackdrop />
      <div className="flex w-full flex-1 flex-col items-center gap-20">
        <SiteHeader />
        <div className="flex w-full max-w-5xl flex-1 flex-col gap-20 p-5">
          <Hero />
          <HowItWorks />
        </div>

        <SiteFooter />
      </div>
    </main>
  );
}

```

### app/layout.tsx

```typescript
import type { Metadata } from "next";
import type { Viewport } from "next";
import localFont from "next/font/local";
import { ThemeProvider } from "next-themes";
import { brand } from "@/lib/brand";
import { InterestRealtimeProvider } from "@/components/interest-realtime-provider";
import { ToastProvider } from "@/components/toast-provider";
import "./globals.css";

export const metadata: Metadata = {
  metadataBase: new URL(brand.url),
  title: "Find a Roommate | Roommate Finder for Students & Professionals",
  description: brand.description,
  keywords:
    "roommate, living situation, housing, accommodation, room, finder, room finder, roomie, roomey, room, nigeria, apartment, flatmate, housemate, shared living, student housing, professional housing, rental, affordable housing, roommate matching, house sharing, flat sharing, co-living, shared apartment, shared room, rental listings, accommodation search, housing search, roommate wanted, room for rent, shared home",
  robots: "index, follow",
  icons: [
    { url: "/favicon.ico", sizes: "64x64" },
    { url: "/icon.ico", sizes: "64x64" },
  ],
  openGraph: {
    title: "Find a Roommate | RoomeyFinder - Nigeria's #1 Roommate Matching Service",
    description: "We make finding your perfect living situation one less hassle.",
    url: brand.url,
    siteName: brand.name,
    images: [
      {
        url: "/images/logo.png",
        width: 364,
        height: 357,
        alt: "RoomeyFinder Logo",
      },
    ],
    locale: "en_NG",
    alternateLocale: ["en_US"],
    type: "website",
  },
  twitter: {
    title: "RoomeyFinder",
    description: "We make finding your perfect living situation one less hassle.",
    site: "roomeyfinder",
    creator: "exploitenomah",
    images: ["/images/logo.png"],
  },
  verification: {
    google: "CMjgKjsziclrkIOp9eyalVvYqfl5uOQ4IxOsEvkbI5M",
  },
  alternates: {
    canonical: brand.url,
    languages: {
      "en-NG": brand.url,
      "en-US": `${brand.url}/us`,
    },
  },
};

export const viewport: Viewport = {
  themeColor: brand.colors.black[500],
  width: "device-width",
  initialScale: 1,
  maximumScale: 1,
};

const proximaNova = localFont({
  src: "./ProximaNova.otf",
  variable: "--font-proxima-nova",
  display: "swap",
});

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en" suppressHydrationWarning>
      <body className={`${proximaNova.className} ${proximaNova.variable}`}>
        <ThemeProvider
          attribute="class"
          defaultTheme="system"
          enableSystem
          disableTransitionOnChange
        >
          <InterestRealtimeProvider>
            {children}
            <ToastProvider />
          </InterestRealtimeProvider>
        </ThemeProvider>
      </body>
    </html>
  );
}

```

### app/matches/page.tsx

```typescript
import { Suspense } from "react";

import { MatchesPage } from "@/components/matches-page";
import { FlowLoading } from "@/components/roommate-flow/shared";
import { requireAuthenticatedUser } from "@/lib/supabase/auth";

export default function MatchesRoute() {
  return (
    <Suspense fallback={<FlowLoading />}>
      <MatchesContent />
    </Suspense>
  );
}

async function MatchesContent() {
  const { userId } = await requireAuthenticatedUser();

  return <MatchesPage userId={userId} />;
}

```

### app/setup/layout.tsx

```typescript
import { SiteFooter } from "@/components/site-footer";
import { SiteHeader } from "@/components/site-header";

export default function SetupLayout({ children }: { children: React.ReactNode }) {
  return (
    <main className="flex min-h-screen flex-col items-center">
      <div className="flex w-full flex-1 flex-col items-center">
        <SiteHeader variant="setup" />
        <div className="w-full flex-1 p-5 py-10 md:py-14">{children}</div>
        <SiteFooter />
      </div>
    </main>
  );
}

```

### app/[username]/layout.tsx

```typescript
import { SiteFooter } from "@/components/site-footer";
import { SiteHeader } from "@/components/site-header";

export default function ProfileLayout({ children }: { children: React.ReactNode }) {
  return (
    <main className="flex min-h-screen flex-col items-center">
      <div className="flex w-full flex-1 flex-col items-center">
        <SiteHeader variant="setup" />
        <div className="w-full flex-1 p-5 py-10 md:py-14">{children}</div>
        <SiteFooter />
      </div>
    </main>
  );
}

```

### app/matches/layout.tsx

```typescript
import { SiteFooter } from "@/components/site-footer";
import { SiteHeader } from "@/components/site-header";

export default function MatchesLayout({ children }: { children: React.ReactNode }) {
  return (
    <main className="flex min-h-screen flex-col items-center">
      <div className="flex w-full flex-1 flex-col items-center">
        <SiteHeader variant="setup" />
        <div className="w-full flex-1 p-5 py-10 md:py-14">{children}</div>
        <SiteFooter />
      </div>
    </main>
  );
}

```

### app/settings/layout.tsx

```typescript
import { SiteFooter } from "@/components/site-footer";
import { SiteHeader } from "@/components/site-header";

export default function SettingsLayout({ children }: { children: React.ReactNode }) {
  return (
    <main className="flex min-h-screen flex-col items-center">
      <div className="flex w-full flex-1 flex-col items-center">
        <SiteHeader variant="setup" />
        <div className="w-full flex-1 p-5 py-10 md:py-14">{children}</div>
        <SiteFooter />
      </div>
    </main>
  );
}

```

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