This commit is contained in:
2026-03-04 12:34:12 +05:30
parent a9eaa7599c
commit eabf295f2e
17 changed files with 306 additions and 505 deletions

View File

@@ -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

View File

@@ -58,7 +58,8 @@ src/ # Frontend
components/ # BottomNav, LoginCard, GoogleSignInButton, ProtectedRoute components/ # BottomNav, LoginCard, GoogleSignInButton, ProtectedRoute
contexts/ # AuthContext (Firebase Google Auth) contexts/ # AuthContext (Firebase Google Auth)
lib/ 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) backend/ # FastAPI backend (Port 8001)
main.py # FastAPI app, CORS, routes, lifespan main.py # FastAPI app, CORS, routes, lifespan
@@ -90,9 +91,8 @@ backend/ # FastAPI backend (Port 8001)
✅ Pydantic models for User, JournalEntry, UserSettings ✅ Pydantic models for User, JournalEntry, UserSettings
✅ Route structure: `/api/users/*` and `/api/entries/*` ✅ Route structure: `/api/users/*` and `/api/entries/*`
✅ CORS enabled for frontend (localhost:8000) ✅ CORS enabled for frontend (localhost:8000)
✅ Firestore database files removed (`firestoreService.ts`, `firestoreConfig.ts`) ✅ Firebase Google Auth kept (Firestore completely removed)
Firebase authentication kept (Google sign-in only) MongoDB as single source of truth
### API Ready ### API Ready
- User registration, profile updates, deletion - User registration, profile updates, deletion

View File

@@ -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

View File

@@ -1,4 +1,4 @@
from pydantic_settings import BaseSettings from pydantic_settings import BaseSettings # type: ignore
from functools import lru_cache from functools import lru_cache

View File

@@ -1,4 +1,4 @@
from pydantic import BaseModel, Field from pydantic import BaseModel, Field # type: ignore
from datetime import datetime from datetime import datetime
from typing import Optional, List from typing import Optional, List
from enum import Enum from enum import Enum

296
docs/FIRESTORE_SETUP.md Normal file
View File

@@ -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<JournalEntry>(COLLECTIONS.ENTRIES, entryId)
// Get all entries
const entries = await getDocuments<JournalEntry>(COLLECTIONS.ENTRIES)
// Query entries with conditions
import { where, orderBy } from 'firebase/firestore'
const userEntries = await queryDocuments<JournalEntry>(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)

View File

@@ -62,7 +62,8 @@ src/ # Frontend
components/ # BottomNav, LoginCard, GoogleSignInButton, ProtectedRoute components/ # BottomNav, LoginCard, GoogleSignInButton, ProtectedRoute
contexts/ # AuthContext (Firebase Google Auth) contexts/ # AuthContext (Firebase Google Auth)
lib/ 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) backend/ # FastAPI backend (Port 8001)
main.py # FastAPI app, CORS, routes, lifespan main.py # FastAPI app, CORS, routes, lifespan
@@ -96,9 +97,8 @@ _Last updated: 2026-03-04_
✅ Pydantic models for User, JournalEntry, UserSettings ✅ Pydantic models for User, JournalEntry, UserSettings
✅ Route structure: `/api/users/*` and `/api/entries/*` ✅ Route structure: `/api/users/*` and `/api/entries/*`
✅ CORS enabled for frontend (localhost:8000) ✅ CORS enabled for frontend (localhost:8000)
✅ Firestore database files removed (`firestoreService.ts`, `firestoreConfig.ts`) ✅ Firebase Google Auth kept (Firestore completely removed)
Firebase authentication kept (Google sign-in only) MongoDB as single source of truth
### API Ready ### API Ready
- User registration, profile updates, deletion - User registration, profile updates, deletion

View File

@@ -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'
}

View File

@@ -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<string, any>
/**
* Generic function to add or update a document
*/
export async function setDocument<T extends FirestoreData>(
collectionName: string,
docId: string,
data: T,
merge = true
): Promise<void> {
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<T extends FirestoreData>(
collectionName: string,
docId: string
): Promise<T | null> {
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<T extends FirestoreData>(
collectionName: string
): Promise<T[]> {
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<T extends FirestoreData>(
collectionName: string,
constraints: any[]
): Promise<T[]> {
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<T extends Partial<FirestoreData>>(
collectionName: string,
docId: string,
data: T
): Promise<void> {
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<void> {
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<void> {
try {
await batch.commit()
} catch (error) {
console.error('Error committing batch write:', error)
throw error
}
}

View File

@@ -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