From eabf295f2e25ecf5cb2a22fefe1c6cc0fa477241 Mon Sep 17 00:00:00 2001 From: Jeet Debnath Date: Wed, 4 Mar 2026 12:34:12 +0530 Subject: [PATCH] cleanup --- .env.example | 14 - .github/copilot-instructions.md | 8 +- BACKEND_QUICKSTART.md | 241 -------------- backend/__pycache__/config.cpython-312.pyc | Bin 1136 -> 0 bytes backend/__pycache__/db.cpython-312.pyc | Bin 1757 -> 0 bytes backend/__pycache__/main.cpython-312.pyc | Bin 2400 -> 0 bytes backend/__pycache__/models.cpython-312.pyc | Bin 3681 -> 0 bytes backend/config.py | 2 +- backend/models.py | 2 +- .../__pycache__/__init__.cpython-312.pyc | Bin 165 -> 0 bytes .../__pycache__/entries.cpython-312.pyc | Bin 6779 -> 0 bytes .../routers/__pycache__/users.cpython-312.pyc | Bin 4582 -> 0 bytes docs/FIRESTORE_SETUP.md | 296 ++++++++++++++++++ project-context.md | 8 +- src/lib/firestoreConfig.ts | 65 ---- src/lib/firestoreService.ts | 130 -------- start-dev.sh | 45 --- 17 files changed, 306 insertions(+), 505 deletions(-) delete mode 100644 .env.example delete mode 100644 BACKEND_QUICKSTART.md delete mode 100644 backend/__pycache__/config.cpython-312.pyc delete mode 100644 backend/__pycache__/db.cpython-312.pyc delete mode 100644 backend/__pycache__/main.cpython-312.pyc delete mode 100644 backend/__pycache__/models.cpython-312.pyc delete mode 100644 backend/routers/__pycache__/__init__.cpython-312.pyc delete mode 100644 backend/routers/__pycache__/entries.cpython-312.pyc delete mode 100644 backend/routers/__pycache__/users.cpython-312.pyc create mode 100644 docs/FIRESTORE_SETUP.md delete mode 100644 src/lib/firestoreConfig.ts delete mode 100644 src/lib/firestoreService.ts delete mode 100644 start-dev.sh 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 57ecd89b7a93872dbeacce8b3e04199fbb80ae14..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1136 zcmZ8g&1(}u6rb7MB%80MwO=VkBiPFd>Be3vp%nZ;MN2%CUiLC63fu8i@&6-Y;+Gz2AE??`yG`17eMbpS&*+ zfbWtdD>X63Tf#U6E^wg_I?#ep+KR7qR7-_G0ndS}9syUw@Jx-*SegQ`dNv8*rj9^j zTd989$o!NZ1M%iLFWb0@?!H1{xO=2IN*v!H9f^a3+!Om)&2bJuqE zMHQwK=~(Udc{-LvOCnG~{6YywU^KgQtdExNe3+sO;tyID&@c*gT9O$Fwyz!FRvpci2QQADp;jI(uEgGzQP~`9o!lF0<{wQ-Rel2jacCL!#%0NuCZ}aA zGoJ#MT;9J)*%kxRFkr0brbb?9VJ3PX&kemTBFH|3vcv)Sk)Qoo|EA4Hi5o_m&vg5) zO_=9gACZ}Pw%H>N3j#l+a>C+FGT47Dxzab{=deld3a?ZeRt5Z0A%y4P{yC^zrn9he b{Pq%v?V=2n{JZ4~1;T}~3Y21GMQZ*6orD&F diff --git a/backend/__pycache__/db.cpython-312.pyc b/backend/__pycache__/db.cpython-312.pyc deleted file mode 100644 index 0ceae744f077539155f42ca9a9047b93d7012b9d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1757 zcmah}&u<$=6rNdo*IRp?p9Dx!h$*S4Q&ICnLbM7#B%zIvFcMV}GE!G-&&1fZcg^lt z!VyS01gSxl0_q_LK)g(}s`NLAs&&5!1(*<=W16WJL_3ky|H43)`l$~cyW*_ZtK1f_G%8$}9v7l&S3FqjA2mhQv8{R; z^P>?9oxvyI91u>5l#!xx15g!XJkHg5h;xl8t1v?>!F3kfC5Pd$;u%;2vf(-jYxUGR z)uvg^Pe^DRYXx5`OMGJ(kP*Z&=zuvOf`-M1Rlg=8!b!d&wTQte4d%n}jL@Q>Im{Zx zYI?LgnxUTT)hL1<-gpLy|`9-qJ5J%9OV{>q)ior&Ju*@K(k-@LbZyu8|l z&)jKIqpYsu9)aQ=_0>*PKyWR(E30SDaY(2SsJ_*?+ci3n)0egU#P%m@1fEVzBKQhKRYEUx10?ruY7=3C) zO1n;6Br)Rt8CMFPYGw(mWPys7Ap2$bdMKeC(nEFZ<&RQ}o%o^zR>7fK6rSe6cp3v9rnkShMRu zTvZAM38Y@&()7?nZ>0*{IriQQE>y9mAX>GD_7)n{pPc$;{ga5KYwg>4^WMz+-ka}@ zzmG;c5IlcB`Nr5(5c*Xptw(JRHirWUts;U5Hj#yM*b3wVmXwpQm7xH!43|k$!4u7neomM0lv7))CuLsST70<;n3Lx6C)(n;FqH&^9Tnv!VExA40 z4L+EJNeAhq-47yba>G5BpoxXIT5z|&RH0o9!`pgmM4}{Cl1Q9%m9Tgpbgx0q;=u@Z zI@%cTlr*|eQOl(EoRJWY5(-q<7b9ZI3AFHQbE1?-pv;Vjm#g%e$}b z-M_=TkM@&+MW_XvfU_Dj2XX^Y%YlVcd&GN#?1#Ed?zX_})b3d_B=&ufX`Kc}%Y(~< z*#mzF*Q~_V_jK1gbNK@vegEp!%jd5bXxTFyo2%z&ncBq7Vjg?d4^qbg(I~+W>A+a6_+xxSyFeG?Lxt^J$l`< zbXzY`#wER6E;P&NrvOw&5{S(r3})cqSCQAYF9_>vPpj~Pv=8Mk@G8bTS2U@(bJ6yS zW%N+GhO>A!D>2bcyaV9bv;djS@le5ZTneKsW>GM@0!C)*l=iVmNL!%P)6P+M(R0e$ zMZ?ibO!sK9Vjf>`D$LeRZB8#NLLoIvH|){!G7p(Xk-BBwW(nA-Q*3z%#P8^z74#~I zl*qc=Ta$aA%KM(l;os!Wbvad&Q$NbR|GFZJ&$My8mAcT3lDXK3l7SPfo<7?MC6r9j zVVPZC$1`PSECIkw6CE5=25P^hjE#wHa6Ct9-lZlItIUSfBGuNBd}{!H%;eS-eE?`uwCBWPz#I_;D@1` zZp*`>-n>KF>O9p6#IAN|dfCu?3NcYJU{lv#-2)(eHf#h@GW{$)w4Od% zOCPPL_rFx-NN@wmO0da=o;2oI+dIQv*rt`C$brc1ER`=kwFs9L)R##DjW|pu{u+3?IX`N( zZ>iCO!(0{=)&QCF`7KG+58YLDMiprdd2MqHm<5SCTesMRM#vF@)4?8S`=vBY} zc}yoHza581ig5BCba=kPOdd1rf>|Ln-`E(i`vJHF7o~s1e&IwdY~7;yJXb4A20*pB z#40uq3G#@feYU(-`K{2D<&cU=r`Z{RBQ7F$3gm`_F@Awg)X<6NXyOGr{2UFvKnI_r zkzYE~pHHuZfJlL!jevsFU#fp1_-sn8iI*{?#_AoJde=-nlB`F2UWFAkup(`AAuO+> zL=7eCa-yCbSWgbulEd}n$m3)0LcrvC{Bv)AJ=uHrh%Yvx2q#}56$ds_?Ui@mS)IB! zbwBdx!lToVQQ|2&Uq@17)4L~Er|(VQAN?-;=o8;GBS0#*(>Kz0`kvtAOF$bGFjE3| z5a2Y8$(w_1TdZM=AvtoV`h(Q>6Cjo2D;I9h+?c6{67^^=B(xsgUyJUq$J6WaL$&y! VuRpED-~KDCD8UT{$^A_5`afa?L74ym diff --git a/backend/__pycache__/models.cpython-312.pyc b/backend/__pycache__/models.cpython-312.pyc deleted file mode 100644 index adb245bc9d0590f220fb967736a7fa142f55b1bf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3681 zcmb_fOOM-B6t?5*#Cc7o)5lDwk9lN9)Ib>l1zIQ-^f6QV2neWzEJ5VPw=-^?2iK0& ztO#mB(_Ok^*s(*XKZOldx`?h+b-{`q(gYS=an5lv_N1XI5|Mm-?st9f_5IFwj&FX= z=Q9fY{_g(lmQsrHJ2r;D#PgYQjpW*iLv_RkJkmHIG$wORpxa zB(<5Bsv4G|DhXvxarC>2ljQ0HEu7Oz6Pg0lh@lxm(|~4TXqM0{pgEr7#sfB(BTsl9 z@QK*d6NDB3os6LcLiYeV6+kjv% zzUp$%F;!_ecEAI-%Aw!*xDmMZn(aw;#q|T|WfyAAY9)O0&W-)lsa( zHHB-OIqGRZorI{iLH za%nU+>OuY5r&mlv8s%~guyR>u%H?X^X?p1A%H^+{wm0a}{6NS;xop>J^}xpc_~o+5 z!FmFvA@X2;QMSPXP7UAEjiy4b$BxzX|ORUffM zv2QqPJgJwUJ5H*jT0kq;iOQstASzWW6~jV$Rm+HBA-(F5-fImEaw#MM_b>HegG0#E zVglc%fMya+MAIH@PNBg8Vg}7#G_-^L=uHm|j`v>$0}TAz=DTdMcWADCVe@3?+`ac7 zvAJ*}oMSu{0(#<9MEW8xq(a-JG}^YK0X>oWbfk;}IZkrNOA(ERm5x1^My#co8Ocx+ zGT}NR3s9W3bcJ;4d>F`dlQ>0J_uTc3fEY3}ql88@M${6aI?O$m)miL7gB<&3!2qj9 z_RiY##fAJ9rn_uzsU;IoxH%-ux0ZPi$%TPd&^)^TL4^xxSAkr{vtivE^n|plRt|dd1B_C-rGhkf(LStq$Kag=?p_dmL>lsC zPK**wPtxZhqC6Tnk5lZXTpUMiM6)Z1p?MuHzXS#tkBVNG&Gn8fwAVJj=v3}~*<}ka z5`$tCgJKv1Twr_*zK5Q8491mA!swepUdT6`fI!Sc=@YAv^v_CvSU58f8|F~SgtHBE zGE`d8%TgKD&791|6G31C%VZNO>qm~*iAyO8%ql5a9ERt_5in+cG)7Tmo|_C|WT?E3 zga@M{(42y67#^yuxx$^xVR?PQ)Yv}@VR5=_cBke(V$)%GaDnmR`3idC;rSm@WSBOT z9FPb}IfY-Z&v+2HwRL}x2r>^xA@_z`36Dc^Dm-V!G5Qoq!?SDaO?#c2*-`f2f|m~q z5GkKd25%!qCj*MjJJ=lI`~+fX*5LBr0|P0sbgX@~b8_qa{WD#5tY;qojUCuBe%klr zM3)^O$(J#wC!B3O!4~wy36AtXIFb$zql}IS%o&z)gPt6!8_NBTx}gq*>TYFG({Xae z8?fBx0*P4_M8#2XLn0HrCWsD{a_Lz%i7(=icqK|BHfiKI1*32U8muio4gfYuyt7Av z(i2^F6sk7T$*_R$nSnFFn_V{3+cyJxt)N$!-cc$|WbTC%cFVDAfm;z8&X0do1gxkkaKcOH?(Q{!}af)^T0|Uf{fQ*ve<^UIB>o3?HSXE~ 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 68d3a17e9046e9ab765047253eaab340f7940c6f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 165 zcmX@j%ge<81m7<&&lCdEk3k%C@R(dQGRI&NJo5pW?p7V le7s&kIV&v1k!|5iqpzkcE;|SeONQI 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 diff --git a/backend/routers/__pycache__/users.cpython-312.pyc b/backend/routers/__pycache__/users.cpython-312.pyc deleted file mode 100644 index 43d44e3656115d12818506b0886c74e91496ccb8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4582 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 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