diff --git a/.env.example b/.env.example deleted file mode 100644 index 8268420..0000000 --- a/.env.example +++ /dev/null @@ -1,14 +0,0 @@ -# Firebase – copy to .env and fill with your Firebase project config -# Get these from Firebase Console → Project settings → General → Your apps - -VITE_FIREBASE_API_KEY= -VITE_FIREBASE_AUTH_DOMAIN= -VITE_FIREBASE_DATABASE_URL= -VITE_FIREBASE_PROJECT_ID= -VITE_FIREBASE_STORAGE_BUCKET= -VITE_FIREBASE_MESSAGING_SENDER_ID= -VITE_FIREBASE_APP_ID= -# Optional: Firestore Emulator (for local development) -# Uncomment and set these if running Firebase emulator locally -# VITE_FIRESTORE_EMULATOR_HOST=localhost:8080 -# VITE_FIREBASE_EMULATOR_ENABLED=true \ No newline at end of file diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index ffa1071..882ee71 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -58,7 +58,8 @@ src/ # Frontend components/ # BottomNav, LoginCard, GoogleSignInButton, ProtectedRoute contexts/ # AuthContext (Firebase Google Auth) lib/ - firebase.ts # Firebase auth config (Firestore removed) + firebase.ts # Firebase auth config (Google sign-in only) + api.ts # API client for backend calls backend/ # FastAPI backend (Port 8001) main.py # FastAPI app, CORS, routes, lifespan @@ -90,9 +91,8 @@ backend/ # FastAPI backend (Port 8001) ✅ Pydantic models for User, JournalEntry, UserSettings ✅ Route structure: `/api/users/*` and `/api/entries/*` ✅ CORS enabled for frontend (localhost:8000) -✅ Firestore database files removed (`firestoreService.ts`, `firestoreConfig.ts`) -✅ Firebase authentication kept (Google sign-in only) - +✅ Firebase Google Auth kept (Firestore completely removed) +✅ MongoDB as single source of truth ### API Ready - User registration, profile updates, deletion diff --git a/BACKEND_QUICKSTART.md b/BACKEND_QUICKSTART.md deleted file mode 100644 index abf7e8b..0000000 --- a/BACKEND_QUICKSTART.md +++ /dev/null @@ -1,241 +0,0 @@ -# MongoDB & FastAPI Backend Setup - Quick Start - -## What's Been Set Up - -✅ **Backend directory structure** (`/backend`) -✅ **FastAPI application** (main.py with routes, CORS, lifecycle) -✅ **MongoDB connection** (config.py, db.py) -✅ **Pydantic models** (User, JournalEntry, UserSettings) -✅ **API routes** (users.py, entries.py) -✅ **Environment configuration** (.env.example) -✅ **Documentation** (README.md, MONGODB_SETUP.md) -✅ **Firebase auth preserved** (Google sign-in, no Firestore) - ---- - -## How to Start MongoDB - -### 1. Install MongoDB (if not already installed) - -```bash -# macOS -brew tap mongodb/brew -brew install mongodb-community - -# Linux (Ubuntu) -curl -fsSL https://www.mongodb.org/static/pgp/server-6.0.asc | sudo apt-key add - -echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/6.0 multiverse" \ - | sudo tee /etc/apt/sources.list.d/mongodb-org-6.0.list -sudo apt-get update -sudo apt-get install -y mongodb-org - -# Windows: Download from https://www.mongodb.com/try/download/community -``` - -### 2. Start MongoDB Service - -```bash -# macOS -brew services start mongodb-community - -# Linux -sudo systemctl start mongod - -# Windows -net start MongoDB - -# Verify it's running -mongosh # Should connect successfully -``` - ---- - -## How to Start FastAPI Backend - -### 1. Navigate to backend directory - -```bash -cd backend -``` - -### 2. Create Python virtual environment - -```bash -python3 -m venv venv - -# Activate it -source venv/bin/activate # macOS/Linux -# or -venv\Scripts\activate # Windows -``` - -### 3. Install dependencies - -```bash -pip install -r requirements.txt -``` - -### 4. Configure environment (optional) - -```bash -cp .env.example .env -# Edit .env if you need to change defaults -``` - -### 5. Start the API server - -```bash -python main.py -``` - -You should see: - -``` -✓ Connected to MongoDB: grateful_journal -INFO: Uvicorn running on http://0.0.0.0:8001 -``` - -### 6. Access API Documentation - -Open in browser: - -- **Interactive API Docs**: http://localhost:8001/docs -- **Alternative Docs**: http://localhost:8001/redoc -- **Health Check**: http://localhost:8001/health - ---- - -## Complete Startup (All Services) - -### Terminal 1: Start MongoDB - -```bash -brew services start mongodb-community -mongosh # Verify connection -``` - -### Terminal 2: Start Frontend - -```bash -npm run dev -- --port 8000 -``` - -### Terminal 3: Start Backend - -```bash -cd backend -source venv/bin/activate -python main.py -``` - -Now you have: - -- **Frontend**: http://localhost:8000 -- **Backend**: http://localhost:8001 -- **MongoDB**: localhost:27017 - ---- - -## API Endpoints Ready to Use - -### User Management - -- `POST /api/users/register` — Register user after Firebase auth -- `GET /api/users/by-email/{email}` — Fetch user profile -- `PUT /api/users/update/{user_id}` — Update profile -- `DELETE /api/users/{user_id}` — Delete account & data - -### Journal Entries - -- `POST /api/entries/{user_id}` — Create entry -- `GET /api/entries/{user_id}` — List entries (paginated) -- `GET /api/entries/{user_id}/{entry_id}` — Get entry -- `PUT /api/entries/{user_id}/{entry_id}` — Update entry -- `DELETE /api/entries/{user_id}/{entry_id}` — Delete entry -- `GET /api/entries/{user_id}/date/{YYYY-MM-DD}` — Entries by date - ---- - -## Authentication Flow - -1. **Frontend**: User clicks "Sign in with Google" -2. **Firebase**: Returns auth token + user info (email, displayName, photoURL) -3. **Frontend**: Calls `POST /api/users/register` with user data -4. **Backend**: Stores user in MongoDB, returns user ID -5. **Frontend**: Uses user ID for all subsequent API calls - ---- - -## File Structure - -``` -grateful-journal/ -├── backend/ # NEW: FastAPI backend -│ ├── main.py # FastAPI app -│ ├── config.py # Settings -│ ├── db.py # MongoDB connection -│ ├── models.py # Pydantic models -│ ├── requirements.txt # Python dependencies -│ ├── .env.example # Environment template -│ ├── README.md # Backend docs -│ └── routers/ # API routes -│ ├── users.py -│ └── entries.py -├── src/ # Frontend (existing) -│ └── lib/ -│ └── firebase.ts # Auth only (Firestore removed) -├── docs/ -│ ├── FIRESTORE_SETUP.md # (old, keep for reference) -│ └── MONGODB_SETUP.md # NEW: MongoDB setup guide -└── project-context.md # Updated with backend info -``` - ---- - -## Removed Files (Firestore) - -- ❌ `src/lib/firestoreService.ts` (removed — use MongoDB API instead) -- ❌ `src/lib/firestoreConfig.ts` (removed — use MongoDB API instead) - ---- - -## Next Steps - -1. **Start MongoDB** (see above) -2. **Start FastAPI** (see above) -3. **Connect Frontend to Backend** - - Update `src/contexts/AuthContext.tsx` to call `/api/users/register` - - Create hooks to fetch/save entries from `/api/entries/*` - - Pass Firebase user ID to all API calls - -4. **Test in API Docs** (http://localhost:8001/docs) - - Try creating a user - - Try creating an entry - - Try fetching entries - ---- - -## Troubleshooting - -**"MongoDB connection refused"** - -- Is the service running? `brew services list` (macOS) or `systemctl status mongod` (Linux) -- Check port 27017 is free: `lsof -i :27017` - -**"ModuleNotFoundError: pymongo"** - -- Is venv activated? Run `. venv/bin/activate` again -- Did you run `pip install -r requirements.txt`? - -**"CORS error in browser console"** - -- Backend running on 8001? Check `http://localhost:8001/docs` -- Frontend URL in `.env`? Should be `http://localhost:8000` - ---- - -For detailed setup instructions, see: - -- [MONGODB_SETUP.md](./docs/MONGODB_SETUP.md) — Full MongoDB installation & configuration -- [backend/README.md](./backend/README.md) — Backend architecture & endpoints -- [project-context.md](./project-context.md) — Implementation rules & conventions diff --git a/backend/__pycache__/config.cpython-312.pyc b/backend/__pycache__/config.cpython-312.pyc deleted file mode 100644 index 57ecd89..0000000 Binary files a/backend/__pycache__/config.cpython-312.pyc and /dev/null differ diff --git a/backend/__pycache__/db.cpython-312.pyc b/backend/__pycache__/db.cpython-312.pyc deleted file mode 100644 index 0ceae74..0000000 Binary files a/backend/__pycache__/db.cpython-312.pyc and /dev/null differ diff --git a/backend/__pycache__/main.cpython-312.pyc b/backend/__pycache__/main.cpython-312.pyc deleted file mode 100644 index c599152..0000000 Binary files a/backend/__pycache__/main.cpython-312.pyc and /dev/null differ diff --git a/backend/__pycache__/models.cpython-312.pyc b/backend/__pycache__/models.cpython-312.pyc deleted file mode 100644 index adb245b..0000000 Binary files a/backend/__pycache__/models.cpython-312.pyc and /dev/null differ diff --git a/backend/config.py b/backend/config.py index 063c0c8..b6af407 100644 --- a/backend/config.py +++ b/backend/config.py @@ -1,4 +1,4 @@ -from pydantic_settings import BaseSettings +from pydantic_settings import BaseSettings # type: ignore from functools import lru_cache diff --git a/backend/models.py b/backend/models.py index 79d356e..64c389d 100644 --- a/backend/models.py +++ b/backend/models.py @@ -1,4 +1,4 @@ -from pydantic import BaseModel, Field +from pydantic import BaseModel, Field # type: ignore from datetime import datetime from typing import Optional, List from enum import Enum diff --git a/backend/routers/__pycache__/__init__.cpython-312.pyc b/backend/routers/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index 68d3a17..0000000 Binary files a/backend/routers/__pycache__/__init__.cpython-312.pyc and /dev/null differ diff --git a/backend/routers/__pycache__/entries.cpython-312.pyc b/backend/routers/__pycache__/entries.cpython-312.pyc deleted file mode 100644 index 20f04bf..0000000 Binary files a/backend/routers/__pycache__/entries.cpython-312.pyc and /dev/null differ diff --git a/backend/routers/__pycache__/users.cpython-312.pyc b/backend/routers/__pycache__/users.cpython-312.pyc deleted file mode 100644 index 43d44e3..0000000 Binary files a/backend/routers/__pycache__/users.cpython-312.pyc and /dev/null differ diff --git a/docs/FIRESTORE_SETUP.md b/docs/FIRESTORE_SETUP.md new file mode 100644 index 0000000..aca172a --- /dev/null +++ b/docs/FIRESTORE_SETUP.md @@ -0,0 +1,296 @@ +# Firebase Firestore Setup Guide + +This document explains how to set up and use Firebase Firestore in the grateful-journal project. + +## Prerequisites + +- Firebase project created at [console.firebase.google.com](https://console.firebase.google.com) +- Node.js and npm installed + +## Installation + +Firebase is already installed in this project. To verify, check the `package.json`: + +```json +{ + "dependencies": { + "firebase": "^12.9.0", + ... + } +} +``` + +## Configuration + +### 1. Set Environment Variables + +Copy the existing `.env.example` to `.env`: + +```bash +cp .env.example .env +``` + +### 2. Add Firebase Project Credentials + +1. Go to [Firebase Console](https://console.firebase.google.com) +2. Select your project +3. Go to **Project Settings** (gear icon) +4. Under "Your apps", find your web app +5. Copy the Firebase config object +6. Fill in the following variables in `.env`: + +```env +VITE_FIREBASE_API_KEY=your-api-key +VITE_FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com +VITE_FIREBASE_DATABASE_URL=https://your-project.firebaseio.com +VITE_FIREBASE_PROJECT_ID=your-project-id +VITE_FIREBASE_STORAGE_BUCKET=your-project.appspot.com +VITE_FIREBASE_MESSAGING_SENDER_ID=your-sender-id +VITE_FIREBASE_APP_ID=your-app-id +``` + +### 3. Enable Firestore in Firebase Console + +1. In Firebase Console, go to **Firestore Database** +2. Click **Create Database** +3. Choose **Start in test mode** (for development) or set up security rules +4. Select your region +5. Click **Create** + +## Project Structure + +``` +src/lib/ +├── firebase.ts # Main Firebase initialization +├── firestoreService.ts # Generic Firestore CRUD operations +└── firestoreConfig.ts # Collection names and data interfaces +``` + +## Usage + +### Import the Firestore instance + +```typescript +import { db } from "@/lib/firebase"; +``` + +### Use the Firestore service + +The `firestoreService.ts` file provides generic CRUD operations: + +```typescript +import { + setDocument, + getDocument, + getDocuments, + queryDocuments, + updateDocument, + deleteDocument, +} from '@/lib/firestoreService' +import { COLLECTIONS, JournalEntry } from '@/lib/firestoreConfig' + +// Create or update a journal entry +await setDocument(COLLECTIONS.ENTRIES, entryId, { + title: 'Today's thoughts', + content: 'I am grateful for...', + mood: 'grateful', + userId: userId, + createdAt: Date.now(), + updatedAt: Date.now(), +}) + +// Get a single entry +const entry = await getDocument(COLLECTIONS.ENTRIES, entryId) + +// Get all entries +const entries = await getDocuments(COLLECTIONS.ENTRIES) + +// Query entries with conditions +import { where, orderBy } from 'firebase/firestore' + +const userEntries = await queryDocuments(COLLECTIONS.ENTRIES, [ + where('userId', '==', userId), + orderBy('createdAt', 'desc'), +]) + +// Update an entry +await updateDocument(COLLECTIONS.ENTRIES, entryId, { + updatedAt: Date.now(), +}) + +// Delete an entry +await deleteDocument(COLLECTIONS.ENTRIES, entryId) +``` + +### Batch Operations + +```typescript +import { createWriteBatch, commitBatch } from "@/lib/firestoreService"; + +const batch = createWriteBatch(); + +// Add operations to batch +batch.set(doc(db, COLLECTIONS.ENTRIES, entryId1), entryData1); +batch.update(doc(db, COLLECTIONS.ENTRIES, entryId2), { mood: "happy" }); +batch.delete(doc(db, COLLECTIONS.ENTRIES, entryId3)); + +// Commit all at once +await commitBatch(batch); +``` + +## Firestore Collections Schema + +### users + +Document ID: User's auth UID + +```typescript +{ + email: string + displayName?: string + photoURL?: string + createdAt: number (timestamp) + updatedAt: number (timestamp) + theme?: 'light' | 'dark' +} +``` + +### entries + +Document ID: Auto-generated or custom ID + +```typescript +{ + userId: string (reference to user) + title: string + content: string + mood?: 'happy' | 'sad' | 'neutral' | 'anxious' | 'grateful' + tags?: string[] + isPublic?: boolean + createdAt: number (timestamp) + updatedAt: number (timestamp) +} +``` + +### settings + +Document ID: User's auth UID + +```typescript +{ + userId: string + notifications?: boolean + emailNotifications?: boolean + theme?: 'light' | 'dark' | 'system' + language?: string + updatedAt: number (timestamp) +} +``` + +### tags + +Document ID: Auto-generated or custom ID + +```typescript +{ + userId: string + name: string + color?: string + createdAt: number (timestamp) + updatedAt: number (timestamp) +} +``` + +## Security Rules (Production) + +For production, update Firestore security rules in the Firebase Console: + +```firestore-rules +rules_version = '2'; +service cloud.firestore { + match /databases/{database}/documents { + // Users can only read/write their own user document + match /users/{userId} { + allow read, write: if request.auth.uid == userId; + } + + // Users can only read/write their own entries + match /entries/{document=**} { + allow read, write: if request.auth.uid == resource.data.userId; + allow create: if request.auth.uid == request.resource.data.userId; + } + + // Users can only read/write their own settings + match /settings/{userId} { + allow read, write: if request.auth.uid == userId; + } + + // Users can only read/write their own tags + match /tags/{document=**} { + allow read, write: if request.auth.uid == resource.data.userId; + allow create: if request.auth.uid == request.resource.data.userId; + } + } +} +``` + +## Local Emulator (Optional) + +To test locally without hitting your Firebase backend: + +### 1. Install Firebase CLI + +```bash +npm install -g firebase-tools +``` + +### 2. Initialize Firebase Emulator + +```bash +firebase init emulators +``` + +Select Firestore and Authentication emulators. + +### 3. Start the Emulator + +```bash +firebase emulators:start +``` + +### 4. Enable Emulator in Your App (Optional) + +Update `.env`: + +```env +VITE_FIREBASE_EMULATOR_ENABLED=true +VITE_FIRESTORE_EMULATOR_HOST=localhost:8080 +``` + +The emulator connection is already commented in `src/lib/firebase.ts` - uncomment it when needed. + +## Troubleshooting + +### Permission Denied Error + +- Check your Firestore security rules in Firebase Console +- Ensure your `.env` variables are correct +- Make sure you're authenticated before writing to Firestore + +### Document Not Found + +- Verify the collection name and document ID +- Check if the document exists in Firestore Console +- Ensure the user has read permissions + +### Emulator Not Connecting + +- Ensure Firebase emulator is running: `firebase emulators:start` +- Check that the emulator host matches your `.env` configuration +- Verify port 8080 is available + +## Resources + +- [Firebase Firestore Documentation](https://firebase.google.com/docs/firestore) +- [Firestore Best Practices](https://firebase.google.com/docs/firestore/best-practices) +- [Firebase Security Rules](https://firebase.google.com/docs/firestore/security/start) diff --git a/project-context.md b/project-context.md index 8a8eb60..6ee5784 100644 --- a/project-context.md +++ b/project-context.md @@ -62,7 +62,8 @@ src/ # Frontend components/ # BottomNav, LoginCard, GoogleSignInButton, ProtectedRoute contexts/ # AuthContext (Firebase Google Auth) lib/ - firebase.ts # Firebase auth config (Firestore removed) + firebase.ts # Firebase auth config (Google sign-in only) + api.ts # API client for backend calls backend/ # FastAPI backend (Port 8001) main.py # FastAPI app, CORS, routes, lifespan @@ -96,9 +97,8 @@ _Last updated: 2026-03-04_ ✅ Pydantic models for User, JournalEntry, UserSettings ✅ Route structure: `/api/users/*` and `/api/entries/*` ✅ CORS enabled for frontend (localhost:8000) -✅ Firestore database files removed (`firestoreService.ts`, `firestoreConfig.ts`) -✅ Firebase authentication kept (Google sign-in only) - +✅ Firebase Google Auth kept (Firestore completely removed) +✅ MongoDB as single source of truth ### API Ready - User registration, profile updates, deletion diff --git a/src/lib/firestoreConfig.ts b/src/lib/firestoreConfig.ts deleted file mode 100644 index 15bf19c..0000000 --- a/src/lib/firestoreConfig.ts +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Firestore Collections Configuration - * Define all collection names and common data structure interfaces here - */ - -// Collection names -export const COLLECTIONS = { - USERS: 'users', - ENTRIES: 'entries', - SETTINGS: 'settings', - TAGS: 'tags', -} as const - -// User document interface -export interface FirestoreUser { - id: string - email: string - displayName?: string - photoURL?: string - createdAt: number - updatedAt: number - theme?: 'light' | 'dark' -} - -// Entry (Journal Entry) document interface -export interface JournalEntry { - id: string - userId: string - title: string - content: string - mood?: 'happy' | 'sad' | 'neutral' | 'anxious' | 'grateful' - tags?: string[] - isPublic?: boolean - createdAt: number - updatedAt: number -} - -// Settings document interface -export interface UserSettings { - userId: string - notifications?: boolean - emailNotifications?: boolean - theme?: 'light' | 'dark' | 'system' - language?: string - updatedAt: number -} - -// Tags document interface -export interface Tag { - id: string - userId: string - name: string - color?: string - createdAt: number - updatedAt: number -} - -// Firestore emulator configuration -export function isEmulatorEnabled(): boolean { - return import.meta.env.VITE_FIREBASE_EMULATOR_ENABLED === 'true' -} - -export function getEmulatorHost(): string { - return import.meta.env.VITE_FIRESTORE_EMULATOR_HOST || 'localhost:8080' -} diff --git a/src/lib/firestoreService.ts b/src/lib/firestoreService.ts deleted file mode 100644 index f41586e..0000000 --- a/src/lib/firestoreService.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { - collection, - doc, - getDoc, - getDocs, - setDoc, - updateDoc, - deleteDoc, - query, - where, - orderBy, - WriteBatch, - writeBatch, -} from 'firebase/firestore' -import { db } from './firebase' - -type FirestoreData = Record - -/** - * Generic function to add or update a document - */ -export async function setDocument( - collectionName: string, - docId: string, - data: T, - merge = true -): Promise { - try { - await setDoc(doc(db, collectionName, docId), data, { merge }) - } catch (error) { - console.error(`Error setting document in ${collectionName}:`, error) - throw error - } -} - -/** - * Generic function to get a single document - */ -export async function getDocument( - collectionName: string, - docId: string -): Promise { - try { - const docRef = doc(db, collectionName, docId) - const docSnapshot = await getDoc(docRef) - return (docSnapshot.exists() ? docSnapshot.data() : null) as T | null - } catch (error) { - console.error(`Error getting document from ${collectionName}:`, error) - throw error - } -} - -/** - * Generic function to get all documents from a collection - */ -export async function getDocuments( - collectionName: string -): Promise { - try { - const querySnapshot = await getDocs(collection(db, collectionName)) - return querySnapshot.docs.map((doc) => ({ id: doc.id, ...doc.data() } as T)) - } catch (error) { - console.error(`Error getting documents from ${collectionName}:`, error) - throw error - } -} - -/** - * Generic function to query documents with conditions - */ -export async function queryDocuments( - collectionName: string, - constraints: any[] -): Promise { - try { - const q = query(collection(db, collectionName), ...constraints) - const querySnapshot = await getDocs(q) - return querySnapshot.docs.map((doc) => ({ id: doc.id, ...doc.data() } as T)) - } catch (error) { - console.error(`Error querying ${collectionName}:`, error) - throw error - } -} - -/** - * Generic function to update a document - */ -export async function updateDocument>( - collectionName: string, - docId: string, - data: T -): Promise { - try { - await updateDoc(doc(db, collectionName, docId), data) - } catch (error) { - console.error(`Error updating document in ${collectionName}:`, error) - throw error - } -} - -/** - * Generic function to delete a document - */ -export async function deleteDocument( - collectionName: string, - docId: string -): Promise { - try { - await deleteDoc(doc(db, collectionName, docId)) - } catch (error) { - console.error(`Error deleting document from ${collectionName}:`, error) - throw error - } -} - -/** - * Batch write operations - */ -export function createWriteBatch(): WriteBatch { - return writeBatch(db) -} - -export async function commitBatch(batch: WriteBatch): Promise { - try { - await batch.commit() - } catch (error) { - console.error('Error committing batch write:', error) - throw error - } -} diff --git a/start-dev.sh b/start-dev.sh deleted file mode 100644 index 91bc743..0000000 --- a/start-dev.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash -# grateful-journal startup script - -echo "🚀 Starting Grateful Journal (Development)" -echo "==========================================" -echo "" - -# Check if MongoDB is running -echo "Checking MongoDB..." -if mongosh --eval "db.adminCommand('ping')" &>/dev/null; then - echo "✅ MongoDB is running" -else - echo "❌ MongoDB not running. Start it with:" - echo " brew services start mongodb-community (macOS)" - echo " sudo systemctl start mongod (Linux)" - exit 1 -fi - -echo "" -echo "Starting Frontend..." -cd "$(dirname "$0")" -npm run dev -- --port 8000 & -FRONTEND_PID=$! -echo "✅ Frontend: http://localhost:8000 (PID: $FRONTEND_PID)" - -echo "" -echo "Starting Backend..." -cd backend -source venv/bin/activate 2>/dev/null || . venv/Scripts/activate 2>/dev/null -python main.py & -BACKEND_PID=$! -echo "✅ Backend: http://localhost:8001 (PID: $BACKEND_PID)" -echo " API Docs: http://localhost:8001/docs" - -echo "" -echo "==========================================" -echo "Services running:" -echo " • Frontend (React): 8000" -echo " • Backend (FastAPI): 8001" -echo " • MongoDB: 27017" -echo "" -echo "Press Ctrl+C to stop all services" -echo "==========================================" - -wait