# Project export: Yatra

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: Historically-grounded AI walkthroughs - RAG-backed, not hallucinated. Pick any place and era, get a narrated journey through daily life there, with generated scenes.
- Devpost: https://devpost.com/software/yatra-vyq3na
- GitHub: https://github.com/magnusinst84-sudo/Yatra
- Demo: https://yatram-neon.vercel.app/
- Video: https://www.youtube.com/embed/Tu9xTVAojvM?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 5 GitHub contributor(s) — magnusinst84-sudo (29 commits), scalicious (8 commits), saksham-mittal29 (6 commits), Aryan Raghuwanshi (2 commits), copilot-swe-agent[bot] (1 commits)

## Devpost submission (written by the team)

### Overview

Yatra is an AI-generated historical walkthrough app. A user picks a place and an era; the backend retrieves grounded historical context via RAG, generates a 3–5 stop narrated walkthrough with images, and serves it as an interactive, shareable experience.

### Inspiration

The idea originated in 10th grade when it was formed through two independent concepts. One of my friends mentioned the need for something to be created with the help of which you can restore artifacts. And later back in December 2025 , I had been to The Museum of the Future in Dubai, where I saw a scanner that could display information about the artifact pointed out by the user. Although none of the ideas alone resonated, their synthesis remained in my head. And taking into account the richness of historical places in India, the idea of accessibility of history continued to appear in my mind. Historical textbooks or Wikipedia provide you with the factual information regarding the certain time period and the place; however, there is no feeling of presence in time. One AI-generated image gives you one frame with no story in it. Thus, Yatra falls somewhere in between, giving you an opportunity to walk through the historical place itself, see it, read information about the life there and move from scene to scene.

### What it does

Search -user selects a place and era on the frontend. Global cache check - MongoDB is checked for an existing system-owned walkthrough for that exact place/era. If found, served instantly. RAG retrieval - on a cache miss, a local Chroma vector store is queried for historically grounded context. Agent generation - a Gemini agent turns that context into a structured 3–5 stop JSON walkthrough (second-person narration, daily-life facts, continuity-aware image prompts). Image generation - each stop's image prompt runs through a fallback chain: Imagen 4 (fast → standard → ultra) → Pollinations.ai → transparent placeholder. Persistence - the finished walkthrough (including Base64 image URLs) is saved to MongoDB under user_uid="system" and returned to the frontend. Users can also save a copy to their own account (clone, not move) and generate an 8-character share slug for public, unauthenticated viewing.

### How we built it

Backend: FastAPI, with a RAG layer (OpenAI embeddings over a curated 25-place/era corpus, indexed in Chroma) feeding historical context into an agent step that generates the structured walkthrough JSON. Agent: runs on Google Gemini, with a same-provider fallback across Gemini's own model tiers for resilience against quota limits. Image generation: a multi-tier fallback chain, landing on a working free-tier image source when primary options weren't accessible namely Pollination Persistence: MongoDB Atlas completed walkthroughs are saved verbatim, so reopening or sharing one replays the exact original result rather than regenerating it. Auth: Firebase (Google + email/password). Frontend: React/Vite, merged from two independently-built pieces , a landing/auth experience and the core walkthrough dashboard into one integrated web- app during the build.

### Challenges we ran into

Provider quota limits forced real architecture decisions under time pressure we ended up routing the agent through Gemini and building a same-provider fallback chain rather than a single hardcoded model call, which made the pipeline meaningfully more resilient than our original design. Image generation reliability was a recurring fight primary providers weren't consistently accessible, so we built a multi-tier fallback with a placeholder as a last resort, ensuring a single failed image never breaks the whole walkthrough. Merging two independently-built frontend pieces (built by different people, different tooling versions, different design systems) into one coherent web-app without regressing either required an isolated dependency upgrade pass before the actual merge to keep the two changes separable.

### Accomplishments we're proud of

Agent JSON validity held at or above our >90% target across a real batch of historical place/era pairs, not just a handful of manual tests. Firebase Auth and MongoDB persistence both work correctly, including correct per-user isolation on saved walkthrough history. Kept the core loop demoable throughout, even while absorbing a full extra role's worth of scope with a smaller team than planned.

### What we learned

Coordinating a multi-stage AI pipeline madee up of RAG retrieval, structured generation, and image synthesis all depending on each other's output, turned out to be harder than treating each stage in isolation. Small inconsistencies early in the chain (a vague retrieved context, an ambiguous image prompt) compound by the final stop. We learned to invest heavily in structuring the intermediate JSON contract between stages so failures were caught early rather than surfacing as a garbled walkthrough downstream.

### What's next

Wire up the supported places list - connect the frontend to GET /api/walkthrough/places so users can't submit unsupported place/era combinations and hit a 400. Finish sharing — stabilize public link generation and add a proper "Walkthrough Not Found" state for broken/invalid share links. Move off Base64 image storage - upload generated images to Firebase Storage and store only the CDN URL, instead of bloating MongoDB with data URIs. Migrate off deprecated Imagen models - move to imagen-3.0-generate-001 or native Gemini image generation ahead of the late-2026 deprecation. Expand the historical corpus - support more place/era combinations beyond the initial set. Mobile-responsive layout. Dedicated viewer page - a proper standalone view for walkthroughs instead of the current modal-based flow. User profiles - persistent identity beyond auth, surfacing saved walkthroughs and history. Conversational agent - a chat interface for asking follow-up questions about a stop's historical context. Gamification - mark visited places, track progress across walkthroughs.

## README (from the GitHub repository)

# Yatra

Yatra is an AI-generated historical walkthrough app. A user picks a place and an era; the backend retrieves grounded historical context via RAG, generates a 3–5 stop narrated walkthrough with images, and serves it as an interactive, shareable experience.

## How it works

1. **Search** — user selects a place and era on the frontend.
2. **Global cache check** — MongoDB is checked for an existing `system`-owned walkthrough for that exact place/era. If found, served instantly.
3. **RAG retrieval** — on a cache miss, a local Chroma vector store is queried for historically grounded context.
4. **Agent generation** — a Gemini agent turns that context into a structured 3–5 stop JSON walkthrough (second-person narration, daily-life facts, continuity-aware image prompts).
5. **Image generation** — each stop's image prompt runs through a fallback chain: Imagen 4 (fast → standard → ultra) → Pollinations.ai → transparent placeholder.
6. **Persistence** — the finished walkthrough (including Base64 image URLs) is saved to MongoDB under `user_uid="system"` and returned to the frontend.

Users can also save a copy to their own account (clone, not move) and generate an 8-character share slug for public, unauthenticated viewing.

```mermaid
flowchart TD
    A[User selects place + era] --> B{Cache check<br/>MongoDB system-owned}
    B -->|Hit| C[Serve cached walkthrough]
    B -->|Miss| D[RAG retrieval<br/>Chroma vector store]
    D --> E[Gemini agent<br/>generates 3-5 stop JSON]
    E --> F[Image generation<br/>Imagen 4 → Pollinations → placeholder]
    F --> G[Persist to MongoDB<br/>user_uid=system]
    G --> H[Return to frontend]
```

## Tech stack

| Layer | Technology |
|---|---|
| Frontend | React + Vite + Tailwind, state-based routing (no router library) |
| Backend | FastAPI (Python), routes mounted in `main.py` |
| Agent | Google Gemini (`google.genai` SDK) |
| RAG / Vector store | Chroma, local + persistent, runs in a thread pool off the asyncio loop |
| Image generation | Imagen 4 tiers → Pollinations.ai HTTP fallback → static placeholder |
| Auth | Firebase Auth (Google OAuth), JWT `idToken` in `Authorization` header |
| Database | MongoDB (global cache + per-user history + share slugs) |

## Architecture notes

- **Frontend** uses conditional state rendering rather than `react-router-dom`. `App.tsx` owns `user`/`idToken` context and renders `<Dashboard>` or `<LandingPage>`. `<WalkthroughModal>` is injected at the top level so guests can open shared links without authenticating.
- **Backend** is organized into an API layer (`backend/api/walkthrough.py`), a RAG pipeline (`backend/rag/`), an agent engine (`backend/agent/`), and an image fallback pipeline (`backend/services/image_gen.py`).
- **Save vs. clone**: saving a walkthrough clones the `system` document with a new UUID and the user's UID, clears any `share_slug`, and leaves the original in the global cache untouched.

## API reference

All routes mounted directly via `main.py`.

| Method & Path | Auth | Purpose |
|---|---|---|
| `GET /api/walkthrough/places` | No | Returns the 25 statically supported place/era combinations |
| `POST /api/walkthrough` | No | Direct RAG + AI generation, no caching/DB check |
| `POST /api/walkthrough/start` | No (defaults to `user_uid="system"`) | Cache check → generate → generate images → save to global pool |
| `GET /api/walkthrough/mine` | Yes | Thumbnail summaries of the authenticated user's walkthroughs |
| `POST /api/walkthrough/{id}/save` | Yes | Clones a system walkthrough into the user's account |
| `POST /api/walkthrough/{id}/share` | Yes | Validates ownership, generates an 8-char slug |
| `GET /api/walkthrough/shared/{slug}` | No | Public retrieval for shared links |
| `GET /api/walkthrough/{id}` | No | Public retrieval by exact ID (used by History tab) |
| `GET /api/walkthrough/{id}/stop/{n}` | No | Polling endpoint for per-stop image generation status |

`POST /api/walkthrough/start` payload: `{"place": "string", "era": "string", "rag_context": "string (optional)"}`

## Environment variables

| Variable | Used by |
|---|---|
| `GEMINI_API_KEY` | Agent — world-state generation |
| `OPENAI_API_KEY` | Embeddings + image generation |
| `CHROMA_PERSIST_DIR` | RAG vector store path |
| `NEXT_PUBLIC_API_URL` | Frontend — backend base URL |
| `FIREBASE_ADMIN_SDK_JSON` | FastAPI — Firebase Admin SDK service account (keep secret) |
| `MONGODB_URI` | FastAPI — MongoDB connection string (keep secret) |
| `NEXT_PUBLIC_FIREBASE_CONFIG` | Frontend — Firebase client config (public, safe to expose) |

## Known gaps / tech debt

1. **Hardcoded search inputs** — `Home.jsx` uses free-text/hardcoded selects instead of calling `GET /api/walkthrough/places`, so users can submit unsupported combinations and get a 400.
2. **Deprecated Imagen models** — `imagen-4.0-fast-generate-001` and related tags are slated for deprecation in late 2026; migration to `imagen-3.0-generate-001` or native Gemini image paths is needed eventually.
3. **No shared-link error UI** — a failed `/shared/[slug]` fetch only logs to console; there's no "Walkthrough Not Found" state for guests.
4. **Base64 images stored in MongoDB** — Pollinations and placeholder images are saved as Base64 data URIs directly in documents, which bloats the DB. The intended fix (upload to Firebase Storage, store only the CDN URL) is stubbed but unimplemented.



## Detected evidence (automated analysis)

Indexed codebase: 127 recognized source files, 365 KB.
- CSS (language) — detected in the code
- FastAPI (technology) — detected in the code
- Firebase (technology) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- SQL (language) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code
- Google Gemini (technology) — claimed on Devpost, not found in the code
- MongoDB (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (120 of 225)

```
.DS_Store
.env.example
.gitignore
backend/__init__.py
backend/.env.example
backend/.gitignore
backend/agent/__init__.py
backend/agent/gemini_client.py
backend/agent/parser.py
backend/agent/prompts.py
backend/agent/world_state.py
backend/api/auth.py
backend/api/routes.py
backend/api/walkthrough.py
backend/auth/jwt.py
backend/auth/oauth.py
backend/clients.py
backend/config.py
backend/database/crud.py
backend/database/db.py
backend/database/mongo_client.py
backend/database/schema.sql
backend/dependencies.py
backend/generate_pdf_guide.py
backend/main.py
backend/models.py
backend/models/user.py
backend/models/walkthrough.py
backend/rag/chroma_db/chroma.sqlite3
backend/rag/chunk_text.py
backend/rag/chunks/Agra_Mughal.txt
backend/rag/chunks/Amritsar_Sikh.txt
backend/rag/chunks/Badami_Chalukya.txt
backend/rag/chunks/Belur_Hoysala.txt
backend/rag/chunks/Delhi_Delhi.txt
backend/rag/chunks/Delhi_Indian.txt
backend/rag/chunks/Dholavira_Indus.txt
backend/rag/chunks/Ellora_Rashtrakuta.txt
backend/rag/chunks/Fatehpur Sikri_Mughal.txt
backend/rag/chunks/Hampi_Vijayanagara.txt
backend/rag/chunks/Hastinapur_Late.txt
backend/rag/chunks/Kolkata_British.txt
backend/rag/chunks/Madurai_Pandya.txt
backend/rag/chunks/Mahabalipuram_Pallava.txt
backend/rag/chunks/Mohenjo-daro_Indus.txt
backend/rag/chunks/Nalanda_Gupta.txt
backend/rag/chunks/Patna_Maurya.txt
backend/rag/chunks/Pune_Maratha.txt
backend/rag/chunks/Rajgir_Mahajanapadas.txt
backend/rag/chunks/Shimla_British.txt
backend/rag/chunks/snapshot_index.json
backend/rag/chunks/Srirangapatna_Kingdom.txt
backend/rag/chunks/Taxila_Maurya.txt
backend/rag/chunks/Thanjavur_Chola.txt
backend/rag/chunks/Ujjain_Gupta.txt
backend/rag/chunks/Warangal_Kakatiya.txt
backend/rag/clean_text.py
backend/rag/clean/Agra_Mughal.txt
backend/rag/clean/Amritsar_Sikh.txt
backend/rag/clean/Badami_Chalukya.txt
backend/rag/clean/Belur_Hoysala.txt
backend/rag/clean/Delhi_Delhi.txt
backend/rag/clean/Delhi_Indian.txt
backend/rag/clean/Dholavira_Indus.txt
backend/rag/clean/Ellora_Rashtrakuta.txt
backend/rag/clean/Fatehpur Sikri_Mughal.txt
backend/rag/clean/Hampi_Vijayanagara.txt
backend/rag/clean/Hastinapur_Late.txt
backend/rag/clean/Kolkata_British.txt
backend/rag/clean/Madurai_Pandya.txt
backend/rag/clean/Mahabalipuram_Pallava.txt
backend/rag/clean/Mohenjo-daro_Indus.txt
backend/rag/clean/Nalanda_Gupta.txt
backend/rag/clean/Patna_Maurya.txt
backend/rag/clean/Pune_Maratha.txt
backend/rag/clean/Rajgir_Mahajanapadas.txt
backend/rag/clean/Shimla_British.txt
backend/rag/clean/Srirangapatna_Kingdom.txt
backend/rag/clean/Taxila_Maurya.txt
backend/rag/clean/Thanjavur_Chola.txt
backend/rag/clean/Ujjain_Gupta.txt
backend/rag/clean/Warangal_Kakatiya.txt
backend/rag/embed_and_store.py
backend/rag/places.py
backend/rag/raw/Agra_Mughal.txt
backend/rag/raw/Amritsar_Sikh.txt
backend/rag/raw/Badami_Chalukya.txt
backend/rag/raw/Belur_Hoysala.txt
backend/rag/raw/Delhi_Delhi.txt
backend/rag/raw/Delhi_Indian.txt
backend/rag/raw/Dholavira_Indus.txt
backend/rag/raw/Ellora_Rashtrakuta.txt
backend/rag/raw/Fatehpur Sikri_Mughal.txt
backend/rag/raw/Hampi_Vijayanagara.txt
backend/rag/raw/Hastinapur_Late.txt
backend/rag/raw/Kolkata_British.txt
backend/rag/raw/Madurai_Pandya.txt
backend/rag/raw/Mahabalipuram_Pallava.txt
backend/rag/raw/Mohenjo-daro_Indus.txt
backend/rag/raw/Nalanda_Gupta.txt
backend/rag/raw/Patna_Maurya.txt
backend/rag/raw/Pune_Maratha.txt
backend/rag/raw/Rajgir_Mahajanapadas.txt
backend/rag/raw/Shimla_British.txt
backend/rag/raw/Srirangapatna_Kingdom.txt
backend/rag/raw/Taxila_Maurya.txt
backend/rag/raw/Thanjavur_Chola.txt
backend/rag/raw/Ujjain_Gupta.txt
backend/rag/raw/Warangal_Kakatiya.txt
backend/rag/README.md
backend/rag/retrieval.py
backend/rag/scrape.py
backend/rag/test_retrieval.py
backend/README_RAG_TEST.md
backend/requirements.txt
backend/scripts/batch_test.py
backend/scripts/check_models_full.py
backend/scripts/check_models.py
backend/scripts/dedupe.py
backend/scripts/extract_images.py
[105 more files omitted for size]
```

### Dependencies

- backend/requirements.txt: chromadb, fastapi, firebase-admin, google-genai, httpx, motor, pydantic, uvicorn[standard]
- frontend/package.json: @types/react@^19.2.17, @types/react-dom@^19.2.3, @vitejs/plugin-react@^6.0.3, autoprefixer@^10.4.19, firebase@^12.16.0, framer-motion@^12.42.2, lucide-react@^1.25.0, postcss@^8.4.38, react@^19.2.7, react-dom@^19.2.7, tailwindcss@^3.4.4, typescript@^5.2.2, vite@^8.1.1
- old_frontend_segments/frontend/package.json: @types/react@^18.3.3, @types/react-dom@^18.3.0, @vitejs/plugin-react@^4.3.1, autoprefixer@^10.4.19, firebase@^12.16.0, postcss@^8.4.38, react@^18.3.1, react-dom@^18.3.1, tailwindcss@^3.4.4, typescript@^5.2.2, vite@^5.3.1
- old_frontend_segments/landing_page/package.json: @types/node@^24.13.2, @types/react@^19.2.17, @types/react-dom@^19.2.3, @vitejs/plugin-react@^6.0.3, autoprefixer@^10.5.4, framer-motion@^12.42.2, lucide-react@^1.25.0, oxlint@^1.71.0, postcss@^8.5.19, react@^19.2.7, react-dom@^19.2.7, tailwindcss@^3.4.19, typescript@~6.0.2, vite@^8.1.1
- requirements.txt: chromadb, fastapi, firebase-admin, google-genai, httpx, motor, nltk, pydantic, python-dotenv, uvicorn[standard], wikipedia-api

### Recent commits (newest first)

- Merge pull request #17 from magnusinst84-sudo/fix/walkthrough-race-conditions
- Merge branch 'main' into fix/walkthrough-race-conditions
- fix: resolve duplicate walkthrough race conditions and wire Home UI
- Remove status caveats from README
- Merge branch 'feature/ui-frontendandREADME-fixes' of https://github.com/magnusinst84-sudo/Yatra into feature/ui-frontendandREADME-fixes
- docs: remove outdated project status caveats from README
- Merge pull request #16 from magnusinst84-sudo/feature/ui-frontendandREADME-fixes
- Merge branch 'main' into feature/ui-frontendandREADME-fixes
- Fix AuthForm, Home and README
- Merge pull request #15 from magnusinst84-sudo/saksham
- feat: bug fixes
- Merge pull request #14 from magnusinst84-sudo/image_gen
- working image generation changed upadte
- Merge pull request #13 from magnusinst84-sudo/feature/ui-backend-fixes
- Merge branch 'main' into feature/ui-backend-fixes
- Add complete architecture docs, project audit findings, and updated requirements.txt
- chore: remove unused review_image.jpg asset
- Fix UI rendering schema mismatch, add shared routing, and restore Pollinations image generation
- Merge pull request #12 from magnusinst84-sudo/frontend-integration
- Wire Firebase auth between landing page and dashboard

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

### docs/backend.md

```markdown
# Backend Architecture & Audit

## Image Generation Fallback Chain
*Source: `backend/services/image_gen.py`, `generate_image_with_fallback()`*

The backend currently attempts to generate images in the following exact fallback order:
1. **Tier 1:** `imagen-4.0-fast-generate-001` (via `genai.Client.models.generate_images`)
2. **Tier 2:** `imagen-4.0-generate-001`
3. **Tier 3:** `imagen-4.0-ultra-generate-001`
4. **Tier 4 (HTTP Fallback):** `https://image.pollinations.ai/prompt/{prompt}` (via `httpx.AsyncClient.get`)
5. **Final Fallback:** 1x1 Transparent PNG placeholder (`data:image/png;base64,iVBORw0...`)

All successful tiers return a Base64-encoded Data URL string.

## Walkthrough Clone Logic (`/save` route)
*Source: `backend/api/walkthrough.py`, `save_user_walkthrough()` (Lines 210-229)*

**Confirmed:** The `/save` route explicitly performs clone/copy logic so the global system document remains untouched.

```python
@router.post("/walkthrough/{walkthrough_id}/save")
async def save_user_walkthrough(walkthrough_id: str, user=Depends(get_current_user)):
    # ...
    wt = await db_instance.walkthroughs.find_one({"walkthrough_id": walkthrough_id})
    # Clone the document for the user so the original stays in the global cache pool
    wt.pop("_id", None)
    new_walkthrough_id = str(uuid.uuid4())
    wt["walkthrough_id"] = new_walkthrough_id
    wt["user_uid"] = user["uid"]
    # Clear any share_slug so the clone doesn't inherit a public link
    wt.pop("share_slug", None) 
    
    await db_instance.walkthroughs.insert_one(wt)
    # ...
```

```

### docs/api-reference.md

```markdown
# API Reference

*Source: `backend/api/walkthrough.py` and `backend/main.py`*

All routes are mounted directly via `main.py` (`app.include_router(walkthrough_router)`).

### 1. `GET /api/walkthrough/places`
* **Auth Required:** No
* **Purpose:** Returns the statically defined list of 25 supported place/era combinations.

### 2. `POST /api/walkthrough`
* **Auth Required:** No
* **Purpose:** Direct RAG + AI generation (No caching/DB check).

### 3. `POST /api/walkthrough/start`
* **Auth Required:** No (Defaults to `user_uid="system"` if no token provided)
* **Payload Shape:** `{"place": "string", "era": "string", "rag_context": "string (optional)"}`
* **Purpose:** Checks cache -> Runs generation -> Generates Images -> Saves to global pool.

### 4. `GET /api/walkthrough/mine`
* **Auth Required:** **YES** (`Depends(get_current_user)`)
* **Purpose:** Returns thumbnail summaries of all walkthroughs claimed by the authenticated user's UID.

### 5. `POST /api/walkthrough/{walkthrough_id}/save`
* **Auth Required:** **YES** (`Depends(get_current_user)`)
* **Purpose:** Clones a system walkthrough to the authenticated user's account.

### 6. `POST /api/walkthrough/{walkthrough_id}/share`
* **Auth Required:** **YES** (`Depends(get_current_user)`)
* **Purpose:** Validates ownership, generates an 8-character slug, and updates the database.

### 7. `GET /api/walkthrough/shared/{slug}`
* **Auth Required:** No
* **Purpose:** Public retrieval endpoint for guests viewing shared links.

### 8. `GET /api/walkthrough/{walkthrough_id}`
* **Auth Required:** No
* **Purpose:** Public retrieval by exact ID (used by History tab to expand thumbnails).

### 9. `GET /api/walkthrough/{walkthrough_id}/stop/{n}`
* **Auth Required:** No
* **Purpose:** Polling endpoint to check if an image has finished generating for a specific stop.

```

### requirements.txt

```
wikipedia-api
nltk
google-genai
chromadb
firebase-admin
fastapi
uvicorn[standard]
motor
python-dotenv
pydantic
httpx
```

### backend/requirements.txt

```
fastapi
uvicorn[standard]
pydantic
motor
google-genai
httpx
chromadb
firebase-admin

```

### frontend/package.json

```
{
  "name": "yatra-frontend",
  "private": true,
  "version": "0.1.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
    "preview": "vite preview"
  },
  "dependencies": {
    "firebase": "^12.16.0",
    "framer-motion": "^12.42.2",
    "lucide-react": "^1.25.0",
    "react": "^19.2.7",
    "react-dom": "^19.2.7"
  },
  "devDependencies": {
    "@types/react": "^19.2.17",
    "@types/react-dom": "^19.2.3",
    "@vitejs/plugin-react": "^6.0.3",
    "autoprefixer": "^10.4.19",
    "postcss": "^8.4.38",
    "tailwindcss": "^3.4.4",
    "typescript": "^5.2.2",
    "vite": "^8.1.1"
  }
}

```

### old_frontend_segments/frontend/package.json

```
{
  "name": "yatra-frontend",
  "private": true,
  "version": "0.1.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
    "preview": "vite preview"
  },
  "dependencies": {
    "firebase": "^12.16.0",
    "react": "^18.3.1",
    "react-dom": "^18.3.1"
  },
  "devDependencies": {
    "@types/react": "^18.3.3",
    "@types/react-dom": "^18.3.0",
    "@vitejs/plugin-react": "^4.3.1",
    "autoprefixer": "^10.4.19",
    "postcss": "^8.4.38",
    "tailwindcss": "^3.4.4",
    "typescript": "^5.2.2",
    "vite": "^5.3.1"
  }
}

```

### old_frontend_segments/landing_page/package.json

```
{
  "name": "landing_page",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc -b && vite build",
    "lint": "oxlint",
    "preview": "vite preview"
  },
  "dependencies": {
    "framer-motion": "^12.42.2",
    "lucide-react": "^1.25.0",
    "react": "^19.2.7",
    "react-dom": "^19.2.7"
  },
  "devDependencies": {
    "@types/node": "^24.13.2",
    "@types/react": "^19.2.17",
    "@types/react-dom": "^19.2.3",
    "@vitejs/plugin-react": "^6.0.3",
    "autoprefixer": "^10.5.4",
    "oxlint": "^1.71.0",
    "postcss": "^8.5.19",
    "tailwindcss": "^3.4.19",
    "typescript": "~6.0.2",
    "vite": "^8.1.1"
  }
}

```

### backend/main.py

```python
"""
backend/main.py
FastAPI application entry point.
"""

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from contextlib import asynccontextmanager
from dotenv import load_dotenv
import os

load_dotenv(os.path.join(os.path.dirname(__file__), ".env"))

from backend.database.mongo_client import init_db, close_db
from backend.api.walkthrough import router as walkthrough_router


@asynccontextmanager
async def lifespan(app: FastAPI):
    # Startup: Initialize MongoDB (Firebase already inits on import in jwt.py)
    print("Starting up... Connecting to MongoDB.")
    await init_db()
    yield
    # Shutdown: Close MongoDB connection
    print("Shutting down... Closing MongoDB connection.")
    await close_db()


app = FastAPI(
    title="Yatra API",
    version="0.1.0",
    description="Backend for the Yatra AI Walkthrough App",
    lifespan=lifespan,
)

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],   # tighten before production
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# ---------------------------------------------------------------------------
# Routers
# ---------------------------------------------------------------------------
app.include_router(walkthrough_router, prefix="/api")


@app.get("/health")
async def health() -> dict:
    """Simple health check endpoint."""
    return {"status": "ok", "message": "Yatra backend is running!"}

```

### frontend/src/main.jsx

```javascript
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.tsx';
import './index.css';

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

```

### frontend/src/App.tsx

```typescript
import { useState, useEffect, createContext } from 'react';
import type { User } from 'firebase/auth';
import { LandingPage } from './landing/components/LandingPage';
import Dashboard from './Dashboard';
import WalkthroughModal from './components/WalkthroughModal';
import { auth } from './services/firebase';
import { getSharedWalkthrough } from './services/api';
import './landing/index.css';
import './index.css';

// ── Auth Context ──────────────────────────────────────────────────────────────
interface AuthContextType {
  user: User | null;
  idToken: string | null;
}

export const AuthContext = createContext<AuthContextType>({
  user: null,
  idToken: null,
});
// ─────────────────────────────────────────────────────────────────────────────

function App() {
  const [user, setUser]       = useState<User | null>(null);
  const [idToken, setIdToken] = useState<string | null>(null);
  const [sharedWalkthrough, setSharedWalkthrough] = useState<any>(null);

  useEffect(() => {
    // Check for shared link in URL (e.g., /shared/aB3x9Q21)
    const path = window.location.pathname;
    if (path.startsWith('/shared/')) {
      const slug = path.split('/')[2];
      if (slug) {
        getSharedWalkthrough(slug)
          .then(setSharedWalkthrough)
          .catch(err => console.error('Shared link failed:', err));
      }
    }

    if (!auth) return;

    const unsub = auth.onAuthStateChanged(async (firebaseUser) => {
      setUser(firebaseUser ?? null);
      if (firebaseUser) {
        const token = await firebaseUser.getIdToken();
        setIdToken(token);
      } else {
        setIdToken(null);
      }
    });

    return () => unsub();
  }, []);

  const handleCloseShared = () => {
    setSharedWalkthrough(null);
    window.history.replaceState({}, '', '/');
  };

  return (
    <AuthContext.Provider value={{ user, idToken }}>
      <div className="w-full min-h-screen landing-wrapper relative">
        {user ? <Dashboard /> : <LandingPage />}
        
        {/* Render shared walkthrough directly on top if opened via link */}
        {sharedWalkthrough && (
           <WalkthroughModal 
              walkthrough={sharedWalkthrough} 
              onClose={handleCloseShared} 
           />
        )}
      </div>
    </AuthContext.Provider>
  );
}

export default App;

```

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