diff --git a/graffify/README.md b/graffify/README.md new file mode 100644 index 0000000..907a67f --- /dev/null +++ b/graffify/README.md @@ -0,0 +1,24 @@ +# /graffify — Agent Context Hub + +This folder exists so that **AI agents** (GitHub Copilot, Claude, GPT, etc.) can instantly understand the RideHub codebase **without scanning every source file**, saving tokens and reducing latency. + +## Why this folder? + +Reading an entire repository file-by-file is expensive in tokens. A full scan of RideHub (TypeScript source + config + lock files) costs thousands of tokens before any useful work begins. This folder provides a **pre-digested, structured summary** of the whole repo so agents can orient themselves in one or two reads. + +## Files in this folder + +| File | What it covers | +|---|---| +| [`context.md`](./context.md) | Repo overview, tech stack, env vars, project structure, scripts, and key file paths | +| [`architecture.md`](./architecture.md) | Pages, component tree, auth flow, API integration, and data flow | +| [`types.md`](./types.md) | All TypeScript interfaces and types used across the codebase | + +## How agents should use this folder + +1. **Start here** — read `context.md` first for a complete orientation. +2. **Drill into architecture** — read `architecture.md` to understand pages, components, and the request/response flow. +3. **Check types** — read `types.md` before writing or editing any TypeScript. +4. **Then** read specific source files only as needed for the exact change you are making. + +> Keep these files up-to-date when adding new pages, components, types, or dependencies. diff --git a/graffify/architecture.md b/graffify/architecture.md new file mode 100644 index 0000000..b2facb1 --- /dev/null +++ b/graffify/architecture.md @@ -0,0 +1,165 @@ +# RideHub — Architecture & Component Reference + +## Page Map + +| Route | File | Description | +|---|---|---| +| `/` | `app/page.tsx` | Home: hero, search bar, ride options, promotions, recent rides | +| `/login` | `app/login/page.tsx` | Auth: guest / Google / username+password | +| `/results` | `app/results/page.tsx` | Ride results with Leaflet map, filter tabs, ride cards | +| `/bookings` | `app/bookings/page.tsx` | Booking history (requires auth) | +| `/profile` | `app/profile/page.tsx` | Profile dashboard (real user or guest mock) | + +--- + +## Component Tree + +``` +app/layout.tsx +└── ThemeProvider (next-themes) + └── Providers (QueryClientProvider + AuthProvider) + ├── Navbar (components/layout/navbar.tsx) + │ ├── Desktop nav links + │ └── Mobile floating pill nav + └── + +app/page.tsx (Home) +├── HeroSection +├── SearchBar ← useNominatim hook, geolocation, date picker +├── RideOptions +├── PromotionsSlider +└── RecentRides + +app/results/page.tsx +├── Filter tabs (Fastest / Cheapest / Eco / Public) +├── Leaflet Map ← road polyline overlay +└── Ride Cards ← per provider (Uber, Ola, Rapido, Metro, Bus) + +app/login/page.tsx +├── Guest login button +├── Google OAuth button +└── Username/Password form ← react-hook-form + zod + +app/bookings/page.tsx +└── Booking list ← fetches GET /bookings/{uid} + +app/profile/page.tsx +├── ProfileInfo +├── PreferencesForm +└── PaymentMethods +``` + +--- + +## Data Flow: Ride Search + +``` +SearchBar (app/page.tsx) + │ User enters From/To, optional schedule time + │ useNominatim → GET Nominatim API (browser, proximity-biased) + │ + ▼ +/results page (app/results/page.tsx) + │ + ├── POST /route/ (backend → OSRM) + │ → { distance_km, duration_min, polyline } + │ + ├── POST /rides/search (backend → fare engine) + │ → [ { service, type, price, eta, distance } ] + │ + ├── Leaflet map renders polyline + └── Ride cards rendered + filter tabs applied +``` + +--- + +## Data Flow: Booking + +``` +/results page + │ User clicks "Book" on a ride card + ▼ +POST /bookings/ (backend → Supabase) + → { booking_id } + │ + ▼ +/bookings page + GET /bookings/{uid} + → [ Booking[] ] +``` + +--- + +## Auth Context API (`components/auth/auth-context.tsx`) + +```ts +interface AuthContextValue { + user: User | null; + isGuest: boolean; + isLoading: boolean; + login(username: string, password: string): Promise; + signup(username: string, password: string): Promise; + loginWithGoogle(google_id: string): void; + loginAsGuest(): void; + logout(): void; +} +``` + +Usage in any component: +```ts +import { useAuth } from '@/components/auth/auth-context'; +const { user, login, logout } = useAuth(); +``` + +--- + +## Hooks + +### `use-nominatim.ts` +Debounced location search using the OpenStreetMap Nominatim API. +- Accepts a query string and optional user coordinates for proximity bias. +- Returns `{ results, isLoading }` where results are sorted by distance to the user. + +### `use-toast.ts` +Wrapper around the shadcn/ui toast system. Returns `{ toast }`. + +--- + +## Key Library Utilities + +### `lib/utils.ts` +```ts +cn(...inputs): string // clsx + tailwind-merge — use for all conditional class strings +``` + +### `lib/api.ts` +```ts +const API: string // = process.env.NEXT_PUBLIC_API_URL ?? "http://localhost:8000" +``` + +### `lib/animations.ts` +Shared Framer Motion animation variants (fadeIn, slideUp, stagger, etc.) — import and apply via `variants` prop. + +### `lib/mock-data.tsx` +Fallback ride options used in guest mode or when the backend is unavailable. + +--- + +## Mobile (Capacitor) + +- `capacitor.config.ts` — app ID `com.ridehub.app`, webDir `out`. +- `BUILD_TARGET=mobile` triggers static export in `next.config.js`. +- Google OAuth does **not** work in the Capacitor in-app browser — use username/password or guest mode on Android. + +--- + +## Configuration Files + +| File | Purpose | +|---|---| +| `next.config.js` | Next.js config; static export when `BUILD_TARGET=mobile` | +| `tailwind.config.ts` | Theme tokens, dark mode class, shadcn/ui content paths | +| `tsconfig.json` | `@/` alias → repo root | +| `capacitor.config.ts` | Capacitor app settings | +| `.eslintrc.json` | ESLint rules (extends next/core-web-vitals) | +| `components.json` | shadcn/ui component configuration | diff --git a/graffify/context.md b/graffify/context.md new file mode 100644 index 0000000..7a3671a --- /dev/null +++ b/graffify/context.md @@ -0,0 +1,145 @@ +# RideHub — Repository Context + +## What is RideHub? + +RideHub is a **ride aggregation platform** (frontend only in this repo). Users can search, compare, and book rides across Uber, Ola, Rapido, Metro, and Bus — all from one interface. The backend is a separate **private** FastAPI + Supabase repository. + +--- + +## Tech Stack + +| Layer | Technology | +|---|---| +| Framework | Next.js 15 (App Router) | +| Language | TypeScript | +| Styling | Tailwind CSS + shadcn/ui (Radix UI primitives) | +| Animations | Framer Motion | +| Icons | Lucide React | +| Maps | Leaflet + react-leaflet | +| Location Search | Nominatim (OpenStreetMap) | +| Road Routing | OSRM (via backend proxy) | +| Auth | Custom username/password + Google OAuth + Guest mode | +| Auth State | React Context (`AuthContext`) with hydration guard | +| Theme | next-themes with View Transition API ripple | +| Mobile | Capacitor (Android APK) | +| Forms | react-hook-form + zod | +| Data fetching | @tanstack/react-query | + +--- + +## Environment Variables + +| Variable | Description | +|---|---| +| `NEXT_PUBLIC_API_URL` | Base URL of the RideHub FastAPI backend (default: `http://localhost:8000`) | + +Set in `.env.local` (copy from `.env.example`). + +--- + +## NPM Scripts + +| Script | Purpose | +|---|---| +| `npm run dev` | Start Next.js dev server with Turbopack | +| `npm run build` | Production build | +| `npm run build:mobile` | Mobile build (`BUILD_TARGET=mobile`) | +| `npm run start` | Start production server | +| `npm run lint` | ESLint | +| `npm run cap:sync` | Build + sync to Capacitor | +| `npm run cap:android` | Build + open in Android Studio | + +--- + +## Project Structure + +``` +RideHub/ +├── graffify/ ← Agent context hub (this folder) +├── app/ +│ ├── layout.tsx # Root layout: Navbar, ThemeProvider, Providers +│ ├── page.tsx # Home page (HeroSection, SearchBar, RideOptions, Promotions, RecentRides) +│ ├── providers.tsx # Wraps children with QueryClientProvider + AuthProvider +│ ├── globals.css # Global Tailwind CSS +│ ├── login/ +│ │ └── page.tsx # Auth page: guest / Google OAuth / username+password +│ ├── results/ +│ │ └── page.tsx # Ride results: map, filter tabs, ride cards +│ ├── bookings/ +│ │ └── page.tsx # Booking history list +│ └── profile/ +│ └── page.tsx # Profile dashboard (real user or guest mock) +├── components/ +│ ├── auth/ +│ │ └── auth-context.tsx # AuthContext: login, signup, loginWithGoogle, loginAsGuest, logout +│ ├── home/ +│ │ ├── hero-section.tsx +│ │ ├── search-bar.tsx # From/To inputs, date picker, Nominatim suggestions +│ │ ├── ride-options.tsx +│ │ ├── promotions-slider.tsx +│ │ └── recent-rides.tsx +│ ├── layout/ +│ │ └── navbar.tsx # Top nav (desktop) + floating bottom pill nav (mobile) +│ ├── results/ # Ride result cards, Leaflet map, filter tabs +│ ├── bookings/ # Booking list UI components +│ ├── profile/ # ProfileInfo, PreferencesForm, PaymentMethods +│ └── ui/ # shadcn/ui primitives (button, card, dialog, etc.) +├── hooks/ +│ ├── use-nominatim.ts # Debounced Nominatim location search with proximity bias +│ └── use-toast.ts # Toast notification hook +├── lib/ +│ ├── api.ts # Exports `API` base URL from NEXT_PUBLIC_API_URL +│ ├── mock-data.tsx # Fallback/mock ride recommendations for guest mode +│ ├── animations.ts # Shared Framer Motion variants +│ └── utils.ts # cn() (clsx + tailwind-merge) and misc helpers +├── types/ +│ ├── location.ts # Location, RideOption, RideRecommendation +│ └── booking.ts # Booking, RideStatus, BookingType +├── public/ # Static assets +├── android/ # Capacitor Android project +├── .env.example +├── next.config.js +├── tailwind.config.ts +├── tsconfig.json +├── capacitor.config.ts +└── package.json +``` + +--- + +## Key Conventions + +- **Path alias**: `@/` maps to the repo root (configured in `tsconfig.json`). +- **Styling**: Always use Tailwind utility classes. Use `cn()` from `lib/utils.ts` for conditional classes. +- **Components**: Use shadcn/ui primitives from `components/ui/`. New components go in `components//`. +- **Auth**: Use `useAuth()` hook (from `AuthContext`) to access user state and auth methods. +- **API calls**: Import base URL from `lib/api.ts` (`import API from '@/lib/api'`). +- **Types**: Always import types from `types/` — never inline type definitions in component files. +- **Animations**: Use shared variants from `lib/animations.ts` with Framer Motion. +- **Routing**: Next.js App Router — all routes are `app//page.tsx`. + +--- + +## Backend API Endpoints (called from frontend) + +| Method | Path | Purpose | +|---|---|---| +| GET | `/health` | Wake/ping backend | +| POST | `/auth/login` | Username+password login | +| POST | `/auth/signup` | Username+password signup | +| GET | `/auth/google` | Start Google OAuth flow | +| GET | `/auth/google/callback` | Google OAuth callback | +| POST | `/route/` | Real road routing (OSRM) → distance, duration, polyline | +| POST | `/rides/search` | Fare calculation for all providers | +| POST | `/bookings/` | Create a booking (saved to Supabase) | +| GET | `/bookings/{uid}` | Fetch user's booking history | + +--- + +## Auth Flow Summary + +- **Guest**: instant access, mock profile, no backend calls, stored as `ridehub_guest` in localStorage. +- **Username/Password**: POST `/auth/login` or `/auth/signup` → JWT-free session stored in `ridehub_user` in localStorage. Parsed in `try/catch` to guard against corrupt JSON (resets auth state on parse error). +- **Google OAuth**: redirect to `/auth/google` (backend) → Google consent → callback → redirect to `/login?google_id=...` → `loginWithGoogle()` → stored in context → redirect to `/profile`. +- **Cross-tab sync**: `storage` event listener keeps auth state consistent across tabs. +- **Hydration guard**: profile page waits for localStorage hydration before deciding to redirect. diff --git a/graffify/types.md b/graffify/types.md new file mode 100644 index 0000000..fcae130 --- /dev/null +++ b/graffify/types.md @@ -0,0 +1,138 @@ +# RideHub — TypeScript Types & Interfaces + +All types live in `types/`. Always import from there rather than defining inline. + +--- + +## `types/booking.ts` + +```ts +type RideStatus = 'scheduled' | 'completed' | 'canceled' | 'in-progress'; + +type BookingType = 'upcoming' | 'past' | 'canceled'; + +interface Booking { + id: string; + user_id?: string; + from_location: string; + to_location: string; + service: string; // "Uber" | "Ola" | "Rapido" | "Metro" | "Bus" + ride_type: string; // e.g. "UberGo", "OlaMini", "Rapido Bike" + price: number; + distance: number; // km + duration: number; // minutes + status: RideStatus; + // Prototype display-only fields (not stored in backend): + date?: string; + time?: string; + driverName?: string; + driverRating?: number; + vehicleDetails?: string; +} +``` + +--- + +## `types/location.ts` + +```ts +interface Location { + id: string; + name: string; + address: string; + coordinates: { + lat: number; + lng: number; + }; +} + +interface RideOption { + id: string; + service: string; + type: string; + estimatedTime: number; // minutes + estimatedPrice: number; // INR + distance: number; // km + ecoFriendly: boolean; + icon: string; // emoji or icon identifier +} + +interface RideRecommendation { + service: string; + type: string; + estimatedPrice: number; + estimatedTime: number; + distance: number; + available: boolean; +} +``` + +--- + +## Auth-related types (inferred from `components/auth/auth-context.tsx`) + +```ts +interface User { + id: string; + username?: string; + google_id?: string; + email?: string; + // additional profile fields as returned by backend /auth/login or /auth/signup +} + +interface AuthContextValue { + user: User | null; + isGuest: boolean; + isLoading: boolean; + login(username: string, password: string): Promise; + signup(username: string, password: string): Promise; + loginWithGoogle(google_id: string): void; + loginAsGuest(): void; + logout(): void; +} +``` + +--- + +## Backend API Response shapes (inferred from usage) + +### `POST /route/` response +```ts +interface RouteResponse { + distance_km: number; + duration_min: number; + polyline: [number, number][]; // array of [lat, lng] coordinate pairs +} +``` + +### `POST /rides/search` response +```ts +// Returns an array of RideRecommendation[] +``` + +### `POST /bookings/` response +```ts +interface CreateBookingResponse { + booking_id: string; +} +``` + +--- + +## Nominatim result shape (from `hooks/use-nominatim.ts`) + +```ts +interface NominatimResult { + place_id: number; + display_name: string; + lat: string; + lon: string; + // additional OSM fields omitted +} +``` + +--- + +## CSS module declaration (`types/css.d.ts`) + +Declares `*.module.css` as `{ [key: string]: string }` for TypeScript compatibility.