# Project export: Market Shield

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: UC Berkeley AI Hackathon 2025
- Tagline: Market Shield is your AI-powered financial radar, tracking global conflict and trends to deliver personalized tips that help you avoid price hikes, delays, and risk before it’s too late.
- Devpost: https://devpost.com/software/marketshield
- GitHub: https://github.com/Miiu64/market-shield
- Video: https://www.youtube.com/embed/FgtXCd8TOGw?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 4 GitHub contributor(s) — PopsicleSnow (35 commits), Miiu64 (24 commits), Sh1384 (23 commits), Mohamed Homsi (13 commits)

## Devpost submission (written by the team)

### Inspiration

In today's interconnected world, global events unfold at a dizzying pace. A conflict in one region can ripple across the globe, affecting everything from the price of gas to the value of our retirement savings. Yet, for the average person, translating complex geopolitical news into tangible financial decisions is a daunting task. We were inspired by this challenge: to bridge the gap between abstract global events and the concrete financial realities of everyday life, empowering users to not just react to market changes, but to anticipate them.

### What it does

Market Shield is an intelligent dashboard that provides clear, personalized, and actionable financial recommendations based on an AI's analysis of geopolitical conflicts. It ingests a user's unique profile—including their location, commute, spending habits, and travel plans—and cross-references it with real-time market data and conflict reports from the ACLED (Armed Conflict Location & Event Data Project). The result is a simple, actionable list of recommendations (e.g., "Postpone electronics purchases due to supply chain risks," or "Fill up your gas tank before an expected price hike") that helps users navigate market volatility, all generated by Anthropic's Claude. Beyond AI-powered insights, Market Shield features a Community page where users can report and track local price changes in real-time. This crowdsourced intelligence allows users to see what others in their area are experiencing—from gas price spikes to grocery shortages—creating a collaborative early warning system that complements the AI analysis.

### How we built it

Market Shield was built with a modern, modular architecture designed for performance and type safety. Frontend: We used a React and Vite stack with TypeScript for robust type safety. The UI was crafted with shadcn/ui and Tailwind CSS for a sleek, modern look. All asynchronous data fetching and state management was handled by React Query, and user authentication was managed via the Supabase client library. Frontend: We used a React and Vite stack with TypeScript for robust type safety. The UI was crafted with shadcn/ui and Tailwind CSS for a sleek, modern look. All asynchronous data fetching and state management was handled by React Query, and user authentication was managed via the Supabase client library. Backend: We chose FastAPI (Python) for its high performance, asynchronous capabilities, and automatic data validation with Pydantic. This backend serves as the brain, processing requests and orchestrating the AI. Backend: We chose FastAPI (Python) for its high performance, asynchronous capabilities, and automatic data validation with Pydantic. This backend serves as the brain, processing requests and orchestrating the AI. AI Agent and Model Tuning: Our AI is powered by Anthropic's Claude through the Letta platform for our specific domain which we implemented with sophisticated prompt engineering for our AI Agents. Contextual Prompts: We developed a system to dynamically construct highly detailed prompts. This context provides the AI with a persona ("You are Market Shield, an expert AI..."), the user's complete financial profile, a summary of recent global conflicts sourced from the ACLED API, and crucial domain knowledge about how specific market assets react to conflict. We explicitly hardcoded these relationships to guide the AI's analysis, including: GLD: Gold ETF - A safe haven during conflicts. XLE: Energy Sector ETF - Sensitive to oil/gas price impacts. JETS: Airlines ETF - A key indicator for travel disruption. SOXX: Semiconductor ETF - For tracking tech supply chain risks. ^VIX: Volatility Index - The market's "fear gauge." USO: Oil ETF - For direct oil price exposure. Strict Output Formatting: A major part of the tuning was forcing the model to respond only in a specific JSON format. This was crucial for reliability, as it allowed our frontend to parse the recommendations without fail. AI Agent and Model Tuning: Our AI is powered by Anthropic's Claude through the Letta platform for our specific domain which we implemented with sophisticated prompt engineering for our AI Agents. Contextual Prompts: We developed a system to dynamically construct highly detailed prompts. This context provides the AI with a persona ("You are Market Shield, an expert AI..."), the user's complete financial profile, a summary of recent global conflicts sourced from the ACLED API, and crucial domain knowledge about how specific market assets react to conflict. We explicitly hardcoded these relationships to guide the AI's analysis, including: GLD: Gold ETF - A safe haven during conflicts. XLE: Energy Sector ETF - Sensitive to oil/gas price impacts. JETS: Airlines ETF - A key indicator for travel disruption. SOXX: Semiconductor ETF - For tracking tech supply chain risks. ^VIX: Volatility Index - The market's "fear gauge." USO: Oil ETF - For direct oil price exposure. GLD: Gold ETF - A safe haven during conflicts. XLE: Energy Sector ETF - Sensitive to oil/gas price impacts. JETS: Airlines ETF - A key indicator for travel disruption. SOXX: Semiconductor ETF - For tracking tech supply chain risks. ^VIX: Volatility Index - The market's "fear gauge." USO: Oil ETF - For direct oil price exposure. Strict Output Formatting: A major part of the tuning was forcing the model to respond only in a specific JSON format. This was crucial for reliability, as it allowed our frontend to parse the recommendations without fail.

### Challenges we ran into

Database Synchronization: Our biggest initial hurdle was ensuring that a user created via Supabase Auth was also created in our custom public.users table. We solved this by creating a client-side AuthInsertListener. During debugging, we even faced mysterious database hangs, which we eventually traced to a corrupted table that had to be entirely recreated. Database Synchronization: Our biggest initial hurdle was ensuring that a user created via Supabase Auth was also created in our custom public.users table. We solved this by creating a client-side AuthInsertListener. During debugging, we even faced mysterious database hangs, which we eventually traced to a corrupted table that had to be entirely recreated. The Disappearing Modal: We hit a frustrating bug where our "User Preferences" modal refused to open. The browser's console provided a warning about ref forwarding, which led us to discover an incompatibility in how we nested our Tooltip and Dialog components. Correctly restructuring the component composition fixed the issue. The Disappearing Modal: We hit a frustrating bug where our "User Preferences" modal refused to open. The browser's console provided a warning about ref forwarding, which led us to discover an incompatibility in how we nested our Tooltip and Dialog components. Correctly restructuring the component composition fixed the issue. Keeping the UI in Sync: After implementing the "Save Preferences" feature, we noticed the recommendations weren't updating. The frontend had no way of knowing the data on the server had changed. The solution was to use React Query's queryClient to manually invalidateQueries, which told our app to discard the old data and refetch, creating a seamless user experience. Keeping the UI in Sync: After implementing the "Save Preferences" feature, we noticed the recommendations weren't updating. The frontend had no way of knowing the data on the server had changed. The solution was to use React Query's queryClient to manually invalidateQueries, which told our app to discard the old data and refetch, creating a seamless user experience.

### Accomplishments we're proud of

Full-Stack System Integration: We successfully built and integrated a complete system, connecting a React frontend, a Python backend, a Supabase database, and the Letta AI platform into a single, cohesive application. Full-Stack System Integration: We successfully built and integrated a complete system, connecting a React frontend, a Python backend, a Supabase database, and the Letta AI platform into a single, cohesive application. A Truly Personalized AI: We're proud of creating an AI system that goes beyond generic advice. By dynamically injecting user data into detailed prompts, we were able to generate recommendations that are genuinely tailored to an individual's life and financial habits. A Truly Personalized AI: We're proud of creating an AI system that goes beyond generic advice. By dynamically injecting user data into detailed prompts, we were able to generate recommendations that are genuinely tailored to an individual's life and financial habits. Solving Complex Bugs: We navigated several non-trivial challenges, from database corruption to subtle component library issues. Overcoming these hurdles taught us invaluable debugging skills and deepened our understanding of our tech stack. Solving Complex Bugs: We navigated several non-trivial challenges, from database corruption to subtle component library issues. Overcoming these hurdles taught us invaluable debugging skills and deepened our understanding of our tech stack.

### What we learned

The Power of Prompt Engineering: By mastering prompt engineering, we were able to use Anthropic's Claude as an Agentic AI to create a specialized financial analyst. The Power of Prompt Engineering: By mastering prompt engineering, we were able to use Anthropic's Claude as an Agentic AI to create a specialized financial analyst. Advanced State Management: We learned that for complex applications, simple state management isn't enough. Using a dedicated library like React Query is essential for handling server state, caching, and ensuring the UI stays in sync with the database. Advanced State Management: We learned that for complex applications, simple state management isn't enough. Using a dedicated library like React Query is essential for handling server state, caching, and ensuring the UI stays in sync with the database. The Importance of Modularity: From the separate frontend and backend to the modular UI components, our architecture made it easier to develop, debug, and scale the application. The Importance of Modularity: From the separate frontend and backend to the modular UI components, our architecture made it easier to develop, debug, and scale the application.

### What's next

Real-Time Push Notifications: Implement a system to send users critical alerts when a new global event directly impacts their personal profile. Real-Time Push Notifications: Implement a system to send users critical alerts when a new global event directly impacts their personal profile. Deeper Data Integration: Incorporate more data sources, such as social media sentiment analysis and shipping lane data, to provide even more accurate and timely recommendations. Deeper Data Integration: Incorporate more data sources, such as social media sentiment analysis and shipping lane data, to provide even more accurate and timely recommendations. Expanded Financial Products: Broaden our analysis to include recommendations for other asset classes, such as cryptocurrencies and commodities. Expanded Financial Products: Broaden our analysis to include recommendations for other asset classes, such as cryptocurrencies and commodities. Interactive Visualizations: Enhance the dashboard with more interactive charts and maps that allow users to explore the connections between global events and market performance on their own. Interactive Visualizations: Enhance the dashboard with more interactive charts and maps that allow users to explore the connections between global events and market performance on their own. Built With Languages: TypeScript, Python Frameworks: React, FastAPI, Vite Platforms & Cloud Services: Supabase (Database & Auth), Letta (AI Platform) Database: PostgreSQL (via Supabase) UI/UX: shadcn/ui, Radix UI, Tailwind CSS Frontend Libraries: React Query, React Router Backend Libraries: Pydantic, Uvicorn Version Control: Git & GitHub

## README (from the GitHub repository)

# Market Shield

A modern web application for market conflict detection and analysis, built with React frontend and FastAPI backend.

## Tech Stack

### Frontend
- Vite
- TypeScript
- React
- shadcn/ui
- Tailwind CSS

### Backend
- FastAPI
- Python

## Prerequisites

- **Node.js & npm** - [Install with nvm](https://github.com/nvm-sh/nvm#installing-and-updating)
- **Python 3.7+** - [Download from python.org](https://www.python.org/downloads/)

## Setup Instructions

### 1. Clone the Repository

```bash
git clone <repository-url>
cd market-shield
```

### 2. Backend Setup (Python/FastAPI)

#### Create Python Virtual Environment

```bash
python3 -m venv myenv
```

#### Activate the Virtual Environment

**On macOS/Linux:**
```bash
source myenv/bin/activate
```

**On Windows:**
```bash
myenv\Scripts\activate
```

#### Set Up Environment Variables

Copy the example environment file and add your API keys:

```bash
cp .env-example .env
```

Then edit the `.env` file and add your API keys:

```
CLAUDE_API=your_claude_api_key_here
GRONQ_API=your_groq_api_key_here
LETTA_API=your_letta_api_key_here
```

#### Install Python Dependencies

```bash
pip3 install -r requirements.txt
```

### 3. Frontend Setup (React/Vite)

Navigate to the frontend directory and install dependencies:

```bash
cd app/frontend
npm install
```

## Running the Application

### Start the Backend (FastAPI)

From the root directory, with your virtual environment activated:

```bash
fastapi dev app/backend/main.py
```

Alternatively, you can use uvicorn directly:

```bash
uvicorn app.backend.main:app --reload
```

The FastAPI backend will be available at:
- **API**: `http://localhost:8000`
- **API Documentation (Swagger UI)**: `http://localhost:8000/docs`
- **Alternative API Documentation (ReDoc)**: `http://localhost:8000/redoc`

### Start the Frontend (React)

In a new terminal, navigate to the frontend directory and start the development server:

```bash
cd app/frontend
npm run dev
```

The React frontend will be available at `http://localhost:5173` by default.

## Development

### Backend Development

Make sure to keep your virtual environment activated while developing:

```bash
source myenv/bin/activate  # On macOS/Linux
# or
myenv\Scripts\activate     # On Windows
```

To deactivate the virtual environment when you're done:

```bash
deactivate
```

### Frontend Development

Available scripts in the frontend directory:

- `npm run dev` - Start development server
- `npm run build` - Build for production
- `npm run build:dev` - Build for development
- `npm run lint` - Run ESLint
- `npm run preview` - Preview production build

## Project Structure

```
market-shield/
├── app/
│   ├── backend/           # FastAPI backend
│   │   └── main.py
│   ├── frontend/          # React frontend
│   │   ├── src/
│   │   ├── public/
│   │   └── package.json
│   ├── data/              # Data files
│   └── models/            # ML models
├── myenv/                 # Python virtual environment
├── requirements.txt       # Python dependencies
└── README.md
```

## Detected evidence (automated analysis)

Indexed codebase: 103 recognized source files, 556 KB.
- CSS (language) — detected in the code
- FastAPI (technology) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- OpenAI (technology) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- Supabase (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code
- PostgreSQL (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (119 of 119)

```
.env-example
.gitignore
app/backend/conflictsense_conflicts.csv
app/backend/conflictsense_market_data.csv
app/backend/dependencies.py
app/backend/example_usage.py
app/backend/main.py
app/backend/read_acled.py
app/backend/read_yahoo.py
app/backend/recommendations_conflict_data.csv
app/backend/recommendations_market_data.csv
app/backend/routers/__init__.py
app/backend/routers/conflictsense.py
app/backend/test_app.py
app/backend/test_personalized_chatbot.py
app/backend/tools/__init__.py
app/backend/tools/conflictsense_tools.py
app/data/acled_conflicts.csv
app/frontend/bun.lockb
app/frontend/components.json
app/frontend/eslint.config.js
app/frontend/index.html
app/frontend/package.json
app/frontend/postcss.config.js
app/frontend/public/robots.txt
app/frontend/public/site.webmanifest
app/frontend/src/App.css
app/frontend/src/App.tsx
app/frontend/src/components/AuthInsertListener.tsx
app/frontend/src/components/CommunityPanel.tsx
app/frontend/src/components/ConflictCalendar.tsx
app/frontend/src/components/ConflictMap.tsx
app/frontend/src/components/Dashboard.tsx
app/frontend/src/components/DashboardWrapper.tsx
app/frontend/src/components/FaviconIcon.tsx
app/frontend/src/components/LettaChatExample.tsx
app/frontend/src/components/LettaWebSocketChat.tsx
app/frontend/src/components/OnboardingFlow.tsx
app/frontend/src/components/PersonalizedChatbot.tsx
app/frontend/src/components/ProtectedRoute.tsx
app/frontend/src/components/RecommendationsWidget.tsx
app/frontend/src/components/ui/accordion.tsx
app/frontend/src/components/ui/alert-dialog.tsx
app/frontend/src/components/ui/alert.tsx
app/frontend/src/components/ui/aspect-ratio.tsx
app/frontend/src/components/ui/avatar.tsx
app/frontend/src/components/ui/badge.tsx
app/frontend/src/components/ui/breadcrumb.tsx
app/frontend/src/components/ui/button.tsx
app/frontend/src/components/ui/calendar.tsx
app/frontend/src/components/ui/card.tsx
app/frontend/src/components/ui/carousel.tsx
app/frontend/src/components/ui/chart.tsx
app/frontend/src/components/ui/checkbox.tsx
app/frontend/src/components/ui/collapsible.tsx
app/frontend/src/components/ui/command.tsx
app/frontend/src/components/ui/context-menu.tsx
app/frontend/src/components/ui/dialog.tsx
app/frontend/src/components/ui/drawer.tsx
app/frontend/src/components/ui/dropdown-menu.tsx
app/frontend/src/components/ui/form.tsx
app/frontend/src/components/ui/hover-card.tsx
app/frontend/src/components/ui/input-otp.tsx
app/frontend/src/components/ui/input.tsx
app/frontend/src/components/ui/label.tsx
app/frontend/src/components/ui/menubar.tsx
app/frontend/src/components/ui/navigation-menu.tsx
app/frontend/src/components/ui/pagination.tsx
app/frontend/src/components/ui/popover.tsx
app/frontend/src/components/ui/progress.tsx
app/frontend/src/components/ui/radio-group.tsx
app/frontend/src/components/ui/resizable.tsx
app/frontend/src/components/ui/scroll-area.tsx
app/frontend/src/components/ui/select.tsx
app/frontend/src/components/ui/separator.tsx
app/frontend/src/components/ui/sheet.tsx
app/frontend/src/components/ui/sidebar.tsx
app/frontend/src/components/ui/skeleton.tsx
app/frontend/src/components/ui/slider.tsx
app/frontend/src/components/ui/sonner.tsx
app/frontend/src/components/ui/switch.tsx
app/frontend/src/components/ui/table.tsx
app/frontend/src/components/ui/tabs.tsx
app/frontend/src/components/ui/textarea.tsx
app/frontend/src/components/ui/toast.tsx
app/frontend/src/components/ui/toaster.tsx
app/frontend/src/components/ui/toggle-group.tsx
app/frontend/src/components/ui/toggle.tsx
app/frontend/src/components/ui/tooltip.tsx
app/frontend/src/components/ui/use-toast.ts
app/frontend/src/components/UserPreferencesModal.tsx
app/frontend/src/hooks/use-mobile.tsx
app/frontend/src/hooks/use-toast.ts
app/frontend/src/hooks/useAuth.tsx
app/frontend/src/hooks/useConflictData.ts
app/frontend/src/hooks/useConflictMap.ts
app/frontend/src/hooks/useRecommendations.ts
app/frontend/src/hooks/useUserProfile.ts
app/frontend/src/index.css
app/frontend/src/main.tsx
app/frontend/src/pages/DashboardWrapper.tsx
app/frontend/src/pages/Index.tsx
app/frontend/src/pages/Login.tsx
app/frontend/src/pages/NotFound.tsx
app/frontend/src/pages/OnboardingFlow.tsx
app/frontend/src/pages/OnboardingFlowWrapper.tsx
app/frontend/src/pages/Signup.tsx
app/frontend/src/utils/supabaseClient.ts
app/frontend/src/vite-env.d.ts
app/frontend/tailwind.config.ts
app/frontend/tsconfig.app.json
app/frontend/tsconfig.json
app/frontend/tsconfig.node.json
app/frontend/vite.config.ts
app/letta/read_acled_letta.py
app/letta/read_alpha_letta.py
app/models/train_model.py
README.md
requirements.txt
```

### Dependencies

- app/frontend/package.json: @eslint/js@^9.9.0, @hookform/resolvers@^3.9.0, @nivo/bar@^0.87.0, @radix-ui/react-accordion@^1.2.0, @radix-ui/react-alert-dialog@^1.1.1, @radix-ui/react-aspect-ratio@^1.1.0, @radix-ui/react-avatar@^1.1.0, @radix-ui/react-checkbox@^1.1.1, @radix-ui/react-collapsible@^1.1.0, @radix-ui/react-context-menu@^2.2.1, @radix-ui/react-dialog@^1.1.2, @radix-ui/react-dropdown-menu@^2.1.1, @radix-ui/react-hover-card@^1.1.1, @radix-ui/react-label@^2.1.0, @radix-ui/react-menubar@^1.1.1, @radix-ui/react-navigation-menu@^1.2.0, @radix-ui/react-popover@^1.1.1, @radix-ui/react-progress@^1.1.0, @radix-ui/react-radio-group@^1.2.0, @radix-ui/react-scroll-area@^1.1.0, @radix-ui/react-select@^2.1.1, @radix-ui/react-separator@^1.1.0, @radix-ui/react-slider@^1.2.0, @radix-ui/react-slot@^1.1.0, @radix-ui/react-switch@^1.1.0, @radix-ui/react-tabs@^1.1.0, @radix-ui/react-toast@^1.2.1, @radix-ui/react-toggle@^1.1.0, @radix-ui/react-toggle-group@^1.1.0, @radix-ui/react-tooltip@^1.1.4, @supabase/supabase-js@^2.50.0, @tailwindcss/typography@^0.5.15, @tanstack/react-query@^5.56.2, @types/leaflet@^1.9.18, @types/node@^22.5.5, @types/react@^18.3.23, @types/react-dom@^18.3.7, @vitejs/plugin-react-swc@^3.5.0, autoprefixer@^10.4.20, caniuse-lite@^1.0.30001724, class-variance-authority@^0.7.1, clsx@^2.1.1, cmdk@^1.0.0, date-fns@^3.6.0, embla-carousel-react@^8.3.0, eslint@^9.9.0, eslint-plugin-react-hooks@^5.1.0-rc.0, eslint-plugin-react-refresh@^0.4.9, globals@^15.9.0, input-otp@^1.2.4, leaflet@^1.9.4, lovable-tagger@^1.1.7, lucide-react@^0.462.0, next-themes@^0.3.0, postcss@^8.4.47, react@^18.2.0, react-day-picker@^8.10.1, react-dom@^18.3.1, react-hook-form@^7.53.0, react-leaflet@^4.2.1, react-resizable-panels@^2.1.3, react-router-dom@^6.26.2, recharts@^2.12.7, sonner@^1.5.0, tailwind-merge@^2.5.2, tailwindcss@^3.4.11, tailwindcss-animate@^1.0.7, typescript@^5.5.3, typescript-eslint@^8.0.1, vaul@^0.9.3, vite@^5.4.1, zod@^3.23.8
- requirements.txt: fastapi@==0.115.0, letta-client, numpy, openai@==1.57.0, pandas, pydantic, python-dotenv, requests@==2.31.0, uvicorn[standard], watchdog, websockets, yfinance

### Recent commits (newest first)

- Merge pull request #9 from Miiu64/community
- finish community
- fix up bugs
- resovle merge conflig
- better chatbot
- use new icon
- change 8 to medium severity
- Revert "change 8 to medium severity"
- change 8 to medium severity
- rename conflict sense to walletshield
- change favicon and implement category risk
- fix dashboarded, add events to calendar
- added option to change preferences
- Merge pull request #8 from Miiu64/frontend/actual-onboarding
- added new file
- new changes
- yoooo
- Merge branch 'frontend/actual-onboarding' of github.com:Miiu64/market-shield into frontend/actual-onboarding
- new stuff
- fix calendar

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

### requirements.txt

```
watchdog
numpy
fastapi==0.115.0
uvicorn[standard]
openai==1.57.0
pandas
requests==2.31.0
yfinance
python-dotenv
letta-client
pydantic
websockets
```

### app/frontend/package.json

```
{
  "name": "vite_react_shadcn_ts",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "build:dev": "vite build --mode development",
    "lint": "eslint .",
    "preview": "vite preview"
  },
  "dependencies": {
    "@hookform/resolvers": "^3.9.0",
    "@nivo/bar": "^0.87.0",
    "@radix-ui/react-accordion": "^1.2.0",
    "@radix-ui/react-alert-dialog": "^1.1.1",
    "@radix-ui/react-aspect-ratio": "^1.1.0",
    "@radix-ui/react-avatar": "^1.1.0",
    "@radix-ui/react-checkbox": "^1.1.1",
    "@radix-ui/react-collapsible": "^1.1.0",
    "@radix-ui/react-context-menu": "^2.2.1",
    "@radix-ui/react-dialog": "^1.1.2",
    "@radix-ui/react-dropdown-menu": "^2.1.1",
    "@radix-ui/react-hover-card": "^1.1.1",
    "@radix-ui/react-label": "^2.1.0",
    "@radix-ui/react-menubar": "^1.1.1",
    "@radix-ui/react-navigation-menu": "^1.2.0",
    "@radix-ui/react-popover": "^1.1.1",
    "@radix-ui/react-progress": "^1.1.0",
    "@radix-ui/react-radio-group": "^1.2.0",
    "@radix-ui/react-scroll-area": "^1.1.0",
    "@radix-ui/react-select": "^2.1.1",
    "@radix-ui/react-separator": "^1.1.0",
    "@radix-ui/react-slider": "^1.2.0",
    "@radix-ui/react-slot": "^1.1.0",
    "@radix-ui/react-switch": "^1.1.0",
    "@radix-ui/react-tabs": "^1.1.0",
    "@radix-ui/react-toast": "^1.2.1",
    "@radix-ui/react-toggle": "^1.1.0",
    "@radix-ui/react-toggle-group": "^1.1.0",
    "@radix-ui/react-tooltip": "^1.1.4",
    "@supabase/supabase-js": "^2.50.0",
    "@tanstack/react-query": "^5.56.2",
    "@types/leaflet": "^1.9.18",
    "caniuse-lite": "^1.0.30001724",
    "class-variance-authority": "^0.7.1",
    "clsx": "^2.1.1",
    "cmdk": "^1.0.0",
    "date-fns": "^3.6.0",
    "embla-carousel-react": "^8.3.0",
    "input-otp": "^1.2.4",
    "leaflet": "^1.9.4",
    "lucide-react": "^0.462.0",
    "next-themes": "^0.3.0",
    "react": "^18.2.0",
    "react-day-picker": "^8.10.1",
    "react-dom": "^18.3.1",
    "react-hook-form": "^7.53.0",
    "react-leaflet": "^4.2.1",
    "react-resizable-panels": "^2.1.3",
    "react-router-dom": "^6.26.2",
    "recharts": "^2.12.7",
    "sonner": "^1.5.0",
    "tailwind-merge": "^2.5.2",
    "tailwindcss-animate": "^1.0.7",
    "vaul": "^0.9.3",
    "zod": "^3.23.8"
  },
  "devDependencies": {
    "@eslint/js": "^9.9.0",
    "@tailwindcss/typography": "^0.5.15",
    "@types/node": "^22.5.5",
    "@types/react": "^18.3.23",
    "@types/react-dom": "^18.3.7",
    "@vitejs/plugin-react-swc": "^3.5.0",
    "autoprefixer": "^10.4.20",
    "eslint": "^9.9.0",
    "eslint-plugin-react-hooks": "^5.1.0-rc.0",
    "eslint-plugin-react-refresh": "^0.4.9",
    "globals": "^15.9.0",
    "lovable-tagger": "^1.1.7",
    "postcss": "^8.4.47",
    "tailwindcss": "^3.4.11",
    "typescript": "^5.5.3",
    "typescript-eslint": "^8.0.1",
    "vite": "^5.4.1"
  }
}

```

### app/frontend/src/main.tsx

```typescript
import { createRoot } from 'react-dom/client'
import App from './App.tsx'
import './index.css'

createRoot(document.getElementById("root")!).render(<App />);


```

### app/frontend/src/App.tsx

```typescript
import { Toaster } from "@/components/ui/toaster";
import { Toaster as Sonner } from "@/components/ui/sonner";
import { TooltipProvider } from "@/components/ui/tooltip";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Index from "./pages/Index";
import NotFound from "./pages/NotFound";
import Signup from "./pages/Signup";
import Login from "./pages/Login";
import DashboardWrapper from "./components/DashboardWrapper";
import OnboardingFlow from "./pages/OnboardingFlow";
import { AuthProvider } from "./hooks/useAuth";
import AuthInsertListener from "./components/AuthInsertListener";
import ProtectedRoute from "./components/ProtectedRoute";

const queryClient = new QueryClient();

const App = () => (
  <QueryClientProvider client={queryClient}>
    <TooltipProvider>
      <BrowserRouter>
        <AuthProvider>
          <Toaster />
          <Sonner />
          <AuthInsertListener />
          <Routes>
            <Route path="/" element={<Index />} />
            <Route path="/signup" element={<Signup />} />
            <Route path="/login" element={<Login />} />
            <Route
              path="/dashboard"
              element={
                <ProtectedRoute>
                  <DashboardWrapper />
                </ProtectedRoute>
              }
            />
            <Route
              path="/onboarding"
              element={
                <ProtectedRoute>
                  <OnboardingFlow />
                </ProtectedRoute>
              }
            />
            <Route path="*" element={<NotFound />} />
          </Routes>
        </AuthProvider>
      </BrowserRouter>
    </TooltipProvider>
  </QueryClientProvider>
);

export default App;

```

### app/backend/main.py

```python
from typing import Union, List, Dict, Any, Optional
from pydantic import BaseModel
from fastapi import FastAPI, HTTPException, WebSocket, WebSocketDisconnect, Depends
from fastapi.responses import HTMLResponse
import json
import asyncio
from datetime import datetime

# Import dependencies and routers
from dependencies import get_letta_client, get_conflictsense_tools_available, LETTA_BASE_URL, LETTA_API_KEY
from routers import conflictsense

app = FastAPI(title="Market Shield - Letta Agent API", version="1.0.0")

# Include routers
app.include_router(conflictsense.router)

# Pydantic models for request/response
class MemoryBlock(BaseModel):
    value: str
    label: str

class CreateAgentRequest(BaseModel):
    memory_blocks: List[MemoryBlock]
    model: str = "anthropic/claude-3-5-sonnet"
    context_window_limit: int = 16000
    embedding: str = "letta/letta-free"
    name: Optional[str] = None
    description: Optional[str] = None

class MessageRequest(BaseModel):
    content: str
    role: str = "user"

class AgentResponse(BaseModel):
    id: str
    name: str
    created_at: str
    status: str
    message: Optional[str] = None

class AgentMessageResponse(BaseModel):
    agent_id: str
    response: str
    timestamp: str

class WebSocketMessage(BaseModel):
    type: str  # "user_message", "agent_response", "status", "error"
    content: str
    agent_id: Optional[str] = None
    timestamp: str = None

# Note: ConflictSense models moved to routers/conflictsense.py

# WebSocket Connection Manager
class ConnectionManager:
    def __init__(self):
        self.active_connections: Dict[str, List[WebSocket]] = {}
        self.agent_connections: Dict[str, List[WebSocket]] = {}
    
    async def connect(self, websocket: WebSocket, client_id: str, agent_id: Optional[str] = None):
        await websocket.accept()
        
        if client_id not in self.active_connections:
            self.active_connections[client_id] = []
        self.active_connections[client_id].append(websocket)
        
        if agent_id:
            if agent_id not in self.agent_connections:
                self.agent_connections[agent_id] = []
            self.agent_connections[agent_id].append(websocket)
    
    def disconnect(self, websocket: WebSocket, client_id: str, agent_id: Optional[str] = None):
        if client_id in self.active_connections:
            if websocket in self.active_connections[client_id]:
                self.active_connections[client_id].remove(websocket)
            if not self.active_connections[client_id]:
                del self.active_connections[client_id]
        
        if agent_id and agent_id in self.agent_connections:
            if websocket in self.agent_connections[agent_id]:
                self.agent_connections[agent_id].remove(websocket)
            if not self.agent_connections[agent_id]:
                del self.agent_connections[agent_id]
    
    async def send_personal_message(self, message: str, websocket: WebSocket):
        try:
            await websocket.send_text(message)
        except Exception as e:
            print(f"Error sending personal message: {e}")
    
    async def send_to_agent_connections(self, message: str, agent_id: str):
        if agent_id in self.agent_connections:
            disconnected = []
            for connection in self.agent_connections[agent_id]:
                try:
                    await connection.send_text(message)
                except Exception as e:
                    print(f"Error sending to agent connection: {e}")
                    disconnected.append(connection)
            
            # Remove disconnected connections
            for conn in disconnected:
                self.agent_connections[agent_id].remove(conn)
    
    async def broadcast_to_client(self, message: str, client_id: str):
        if client_id in self.active_connections:
            disconnected = []
            for connection in self.active_connections[client_id]:
                try:
                    await connection.send_text(message)
                except Exception as e:
                    print(f"Error broadcasting to client: {e}")
                    disconnected.append(connection)
            
            # Remove disconnected connections
            for conn in disconnected:
                self.active_connections[client_id].remove(conn)

manager = ConnectionManager()

@app.get("/")
def read_root():
    return {
        "service": "Market Shield Letta Agent API",
        "status": "running",
        "letta_connected": get_letta_client() is not None,
        "conflictsense_tools_available": get_conflictsense_tools_available(),
        "architecture": "Modular FastAPI with APIRouter",
        "endpoints": {
            "agent_management": "/agents/*",
            "websockets": "/ws/*",
            "conflictsense": "/conflictsense/*",
            "health": "/health",
            "docs": "/docs"
        }
    }

@app.post("/agents/create")
async def create_agent(request: CreateAgentRequest, letta_client=Depends(get_letta_client)):
    """Create a new Letta agent with specified memory blocks and configuration."""
    if not letta_client:
        raise HTTPException(status_code=503, detail="Letta client not available")
    
    try:
        # Convert memory blocks to the format expected by Letta
        memory_blocks = [
            {"value": block.value, "label": block.label} 
            for block in request.memory_blocks
        ]
        
        # Create agent
        agent = letta_client.agents.create(
            memory_blocks=memory_blocks,
            model=request.model,
            context_window_limit=request.context_window_limit,
            embedding=request.embedding,
            name=request.name,
            description=request.description
        )
        
        return {
            "success": True,
            "agent_id": agent.id,
            "agent_name": agent.name,
            "message": "Agent created success
[truncated — 22595 more characters]
```

### app/frontend/src/pages/Index.tsx

```typescript

import { useState } from "react";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { AlertTriangle, TrendingUp, Shield, Users, ArrowRight } from "lucide-react";
import { OnboardingFlow } from "@/components/OnboardingFlow";
import { Dashboard } from "@/components/Dashboard";
import { FaviconIcon } from "@/components/FaviconIcon";
import { useNavigate } from "react-router-dom";

const Index = () => {
  const navigate = useNavigate();
  const [currentView, setCurrentView] = useState<'landing' | 'onboarding' | 'dashboard'>('landing');
  const [userProfile, setUserProfile] = useState(null);

  const handleStartOnboarding = () => {
    navigate('/signup');
  };

  const handleOnboardingComplete = (profile: any) => {
    setUserProfile(profile);
    setCurrentView('dashboard');
  };

  const handleSkipDemo = () => {
    setCurrentView('dashboard');
  };

  const handleBackToHome = () => {
    setCurrentView('landing');
  };

  if (currentView === 'onboarding') {
    return (
      <OnboardingFlow 
        onComplete={handleOnboardingComplete}
        onSkip={handleSkipDemo}
      />
    );
  }

  if (currentView === 'dashboard') {
    return <Dashboard userProfile={userProfile} onBackToHome={handleBackToHome} />;
  }

  return (
    <div className="min-h-screen bg-gradient-to-br from-slate-900 via-blue-900 to-slate-800">
      {/* Header */}
      <header className="bg-white/10 backdrop-blur-md border-b border-white/20">
        <div className="container mx-auto px-6 py-4">
          <div className="flex items-center justify-between">
            <div className="flex items-center space-x-3">
              <div className="w-10 h-10 bg-gradient-to-r from-blue-500 to-blue-600 rounded-lg flex items-center justify-center">
                <FaviconIcon className="w-6 h-6 text-white" />
              </div>
              <div>
                <h1 className="text-2xl font-bold text-white">MarketShield</h1>
                <p className="text-sm text-blue-200">AI-Powered Financial Intelligence</p>
              </div>
            </div>
            <Button 
              onClick={() => navigate("/signup")}
              className="bg-blue-600 hover:bg-blue-700 text-white px-6 py-2"
            >
              Get Started
              <ArrowRight className="w-4 h-4 ml-2" />
            </Button>
          </div>
        </div>
      </header>

      {/* Hero Section */}
      <section className="container mx-auto px-6 py-20 text-center">
        <Badge className="mb-6 bg-blue-600/20 text-blue-200 border-blue-400" variant="outline">
          Live Global Intelligence • Updated Every 15 Minutes
        </Badge>
        <h2 className="text-5xl font-bold text-white mb-6 leading-tight">
          Make Smarter Financial Decisions<br />
          <span className="text-blue-400">Based on World Events</span>
        </h2>
        <p className="text-xl text-gray-300 mb-8 max-w-3xl mx-auto">
          Our AI analyzes live conflict data and market trends to give you personalized recommendations 
          for gas, groceries, travel, and investments - before prices change.
        </p>
        <div className="flex flex-col sm:flex-row gap-4 justify-center">
          <Button 
            size="lg" 
            onClick={handleStartOnboarding}
            className="bg-blue-600 hover:bg-blue-700 text-white px-8 py-4 text-lg"
          >
            Start Free Analysis
            <ArrowRight className="w-5 h-5 ml-2" />
          </Button>
          <Button 
            size="lg" 
            variant="outline" 
            onClick={handleSkipDemo}
            className="border-white/30 text-black hover:bg-white/10 px-8 py-4 text-lg bg-white"
          >
            View Demo Dashboard
          </Button>
        </div>
      </section>

      {/* Features Grid */}
      <section className="container mx-auto px-6 py-20">
        <div className="grid md:grid-cols-3 gap-8">
          <Card className="bg-white/10 backdrop-blur-md border-white/20 text-white">
            <CardHeader>
              <div className="w-12 h-12 bg-red-500/20 rounded-lg flex items-center justify-center mb-4">
                <AlertTriangle className="w-6 h-6 text-red-400" />
              </div>
              <CardTitle>Real-Time Conflict Analysis</CardTitle>
              <CardDescription className="text-gray-300">
                Monitor global conflicts from ACLED data and their immediate impact on your daily expenses
              </CardDescription>
            </CardHeader>
          </Card>

          <Card className="bg-white/10 backdrop-blur-md border-white/20 text-white">
            <CardHeader>
              <div className="w-12 h-12 bg-green-500/20 rounded-lg flex items-center justify-center mb-4">
                <TrendingUp className="w-6 h-6 text-green-400" />
              </div>
              <CardTitle>Market Intelligence</CardTitle>
              <CardDescription className="text-gray-300">
                AI-powered analysis of market data to predict price movements before they happen
              </CardDescription>
            </CardHeader>
          </Card>

          <Card className="bg-white/10 backdrop-blur-md border-white/20 text-white">
            <CardHeader>
              <div className="w-12 h-12 bg-blue-500/20 rounded-lg flex items-center justify-center mb-4">
                <Shield className="w-6 h-6 text-blue-400" />
              </div>
              <CardTitle>Personal Recommendations</CardTitle>
              <CardDescription className="text-gray-300">
                Get specific daily actions tailored to your location, lifestyle, and upcoming financial decisions
              </CardDescription>
            </CardHeader>
          </Card>
        </div>
      </section>

      {/* Preview Dashboard */}
      <section className="container mx-auto px-6 py-20">

[truncated — 4462 more characters]
```

### app/frontend/postcss.config.js

```javascript
export default {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
}

```

### app/frontend/vite.config.ts

```typescript
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react-swc";
import path from "path";
import { componentTagger } from "lovable-tagger";

// https://vitejs.dev/config/
export default defineConfig(({ mode }) => ({
  server: {
    host: "::",
    port: 8080,
    proxy: {
      '/api': {
        target: 'http://localhost:8000',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, '')
      }
    }
  },
  plugins: [
    react(),
    mode === 'development' &&
    componentTagger(),
  ].filter(Boolean),
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
    },
  },
}));

```

### app/frontend/eslint.config.js

```javascript
import js from "@eslint/js";
import globals from "globals";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import tseslint from "typescript-eslint";

export default tseslint.config(
  { ignores: ["dist"] },
  {
    extends: [js.configs.recommended, ...tseslint.configs.recommended],
    files: ["**/*.{ts,tsx}"],
    languageOptions: {
      ecmaVersion: 2020,
      globals: globals.browser,
    },
    plugins: {
      "react-hooks": reactHooks,
      "react-refresh": reactRefresh,
    },
    rules: {
      ...reactHooks.configs.recommended.rules,
      "react-refresh/only-export-components": [
        "warn",
        { allowConstantExport: true },
      ],
      "@typescript-eslint/no-unused-vars": "off",
    },
  }
);

```

### app/frontend/index.html

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Market Shield</title>
    <meta name="description" content="Make Smarter Financial Decisions
    Based on World Events" />
    <meta name="author" content="CalHacks" />

    <meta property="og:title" content="Market Shield" />
    <meta property="og:description" content="Make Smarter Financial Decisions
    Based on World Events" />
    <meta property="og:type" content="website" />
    <meta property="og:image" content="https://lovable.dev/opengraph-image-p98pqg.png" />

    <meta name="twitter:card" content="summary_large_image" />
    <meta name="twitter:site" content="@nothing" />
    <meta name="twitter:image" content="https://lovable.dev/opengraph-image-p98pqg.png" />
    
    <!-- Leaflet CSS -->
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
     integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
     crossorigin=""/>
  </head>

  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>

```

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