--- trigger: always_on description: globs: --- ## Project Structure Compass (compassmeet.com) is a transparent dating platform for forming deep, authentic 1-on-1 connections. - **Next.js React frontend** `/web` - Pages, components, hooks, lib - **Express Node API server** `/backend/api` - **Shared backend utilities** `/backend/shared` - **Email functions** `/backend/email` - **Database schema** `/backend/supabase` - Supabase-generated types in `/backend/supabase/schema.ts` - **Files shared between frontend and backend** `/common` - Types (User, Profile, etc.) and utilities - Try not to add package dependencies to common - **Android app** `/android` ## Deployment - Both dev and prod environments - Backend on GCP (Google Cloud Platform) - Frontend on Vercel - Database on Supabase (PostgreSQL) - Firebase for authentication and storage ## Code Guidelines ### Component Example ```tsx import clsx from 'clsx' import Link from 'next/link' import {User} from 'common/user' import {ProfileRow} from 'common/profiles/profile' import {useUser} from 'web/hooks/use-user' import {useT} from 'web/lib/locale' interface ProfileCardProps { user: User profile: ProfileRow } export function ProfileCard({user, profile}: ProfileCardProps) { const t = useT() return (
{user.name}

{user.name}

{profile.bio}

) } ``` We prefer many smaller components that each represent one logical unit, rather than one large component. Export the main component at the top of the file. Name the component the same as the file (e.g., `profile-card.tsx` → `ProfileCard`). ### API Calls **Server-side (getStaticProps):** ```typescript import {api} from 'web/lib/api' export async function getStaticProps() { const profiles = await api('get-profiles', {}) return { props: {profiles}, revalidate: 30 * 60, // 30 minutes } } ``` **Client-side - use hooks:** ```typescript import {useAPIGetter} from 'web/hooks/use-api-getter' function ProfileList() { const {data, refresh} = useAPIGetter('get-profiles', {}) if (!data) return return (
{ data.profiles.map((profile) => ( )) }