cleanup
This commit is contained in:
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)
|
||||
Reference in New Issue
Block a user