cleanup
This commit is contained in:
14
.env.example
14
.env.example
@@ -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
|
|
||||||
8
.github/copilot-instructions.md
vendored
8
.github/copilot-instructions.md
vendored
@@ -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
|
||||||
|
|||||||
@@ -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
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
296
docs/FIRESTORE_SETUP.md
Normal file
296
docs/FIRESTORE_SETUP.md
Normal 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)
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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'
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
45
start-dev.sh
45
start-dev.sh
@@ -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
|
|
||||||
Reference in New Issue
Block a user