1256 lines
31 KiB
Markdown
1256 lines
31 KiB
Markdown
# Firebase Configuration - AI Study Assistant
|
|
|
|
## 🔥 COMPLETE FIREBASE SETUP GUIDE
|
|
|
|
---
|
|
|
|
## 📋 OVERVIEW
|
|
|
|
This document provides comprehensive instructions for setting up Firebase for the AI Study Assistant project, including authentication, database, storage, cloud functions, and security configurations.
|
|
|
|
---
|
|
|
|
## 🚀 STEP 1: FIREBASE PROJECT SETUP
|
|
|
|
### 1.1 Create Firebase Project
|
|
|
|
1. **Go to Firebase Console**
|
|
- Visit [https://console.firebase.google.com](https://console.firebase.google.com)
|
|
- Sign in with your Google account
|
|
|
|
2. **Create New Project**
|
|
```bash
|
|
# Using Firebase CLI (recommended)
|
|
firebase projects create teachit-ai-assistant
|
|
firebase use teachit-ai-assistant
|
|
```
|
|
|
|
3. **Configure Project Settings**
|
|
- Project ID: `teachit-ai-assistant`
|
|
- Display Name: `AI Study Assistant`
|
|
- Organization: Select appropriate organization
|
|
|
|
### 1.2 Enable Required Services
|
|
|
|
#### Firebase Services to Enable:
|
|
- ✅ Firebase Authentication
|
|
- ✅ Cloud Firestore
|
|
- ✅ Cloud Storage
|
|
- ✅ Cloud Functions
|
|
- ✅ Firebase Analytics
|
|
- ✅ Firebase Crashlytics
|
|
- ✅ Firebase Performance Monitoring
|
|
- ✅ Firebase Remote Config
|
|
|
|
#### Enable Commands:
|
|
```bash
|
|
# Enable Authentication
|
|
firebase auth --enable
|
|
|
|
# Enable Firestore
|
|
firebase firestore:databases:create
|
|
|
|
# Enable Storage
|
|
firebase storage:buckets:create teachit-content
|
|
|
|
# Enable Functions
|
|
firebase functions:config:set
|
|
|
|
# Enable Analytics (automatically enabled)
|
|
```
|
|
|
|
---
|
|
|
|
## 🔐 STEP 2: AUTHENTICATION CONFIGURATION
|
|
|
|
### 2.1 Firebase Auth Setup
|
|
|
|
#### Sign-in Methods to Enable:
|
|
1. **Email/Password**
|
|
- Go to Authentication → Sign-in method
|
|
- Enable Email/Password
|
|
- Set up email templates
|
|
|
|
2. **Google Sign-In**
|
|
- Enable Google provider
|
|
- Configure OAuth consent screen
|
|
- Add authorized domains
|
|
|
|
3. **Apple Sign-In** (if supporting iOS)
|
|
- Enable Apple provider
|
|
- Configure with Apple Developer account
|
|
|
|
#### Authentication Configuration:
|
|
```javascript
|
|
// Firebase Console → Authentication → Settings
|
|
{
|
|
"sign_in_method": {
|
|
"email": true,
|
|
"google": true,
|
|
"apple": false
|
|
},
|
|
"password_policy": {
|
|
"min_length": 6,
|
|
"require_uppercase": false,
|
|
"require_lowercase": false,
|
|
"require_numbers": false,
|
|
"require_special_chars": false
|
|
},
|
|
"email_verification": {
|
|
"required": true,
|
|
"template": "default"
|
|
}
|
|
}
|
|
```
|
|
|
|
### 2.2 User Management Configuration
|
|
|
|
#### Custom Claims Setup:
|
|
```javascript
|
|
// Cloud Function to set custom claims
|
|
exports.setCustomClaims = functions.auth.user().onCreate(async (user) => {
|
|
const customClaims = {
|
|
role: 'student', // Default role
|
|
schoolId: 'default',
|
|
permissions: ['basic_access']
|
|
};
|
|
|
|
await admin.auth().setCustomUserClaims(user.uid, customClaims);
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## 🗄️ STEP 3: FIRESTORE DATABASE SETUP
|
|
|
|
### 3.1 Database Configuration
|
|
|
|
#### Create Firestore Database:
|
|
1. Go to Firestore Database
|
|
2. Create database in test mode (initially)
|
|
3. Choose location (e.g., `europe-west1`)
|
|
4. Set up security rules
|
|
|
|
#### Database Structure:
|
|
```javascript
|
|
// Collections Structure
|
|
schools/{schoolId}
|
|
├── users/{userId}
|
|
├── learningStates/{studentId}
|
|
├── contentChunks/{chunkId}
|
|
├── quizzes/{quizId}
|
|
├── quizAttempts/{attemptId}
|
|
├── interactions/{interactionId}
|
|
└── auditLogs/{logId}
|
|
```
|
|
|
|
### 3.2 Security Rules
|
|
|
|
#### Complete Security Rules:
|
|
```javascript
|
|
rules_version = '2';
|
|
service cloud.firestore {
|
|
match /databases/{database}/documents {
|
|
// Helper functions
|
|
function isAuthenticated() {
|
|
return request.auth != null;
|
|
}
|
|
|
|
function isSameSchool(schoolId) {
|
|
return isAuthenticated() &&
|
|
get(/databases/$(database)/documents/users/$(request.auth.uid)).data.schoolId == schoolId;
|
|
}
|
|
|
|
function hasRole(role) {
|
|
return isAuthenticated() &&
|
|
get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == role;
|
|
}
|
|
|
|
function isOwner(userId) {
|
|
return isAuthenticated() && request.auth.uid == userId;
|
|
}
|
|
|
|
// Schools collection - admin only
|
|
match /schools/{schoolId} {
|
|
allow read, write: if hasRole('admin');
|
|
allow create: if hasRole('admin') && request.resource.data.keys().hasAll(['name', 'email']);
|
|
}
|
|
|
|
// Users collection
|
|
match /users/{userId} {
|
|
allow read: if isAuthenticated() &&
|
|
(isOwner(userId) || isSameSchool(resource.data.schoolId));
|
|
allow write: if isAuthenticated() &&
|
|
(isOwner(userId) || hasRole('admin'));
|
|
allow create: if isAuthenticated() &&
|
|
isOwner(userId) &&
|
|
request.resource.data.keys().hasAll(['schoolId', 'role', 'email']);
|
|
}
|
|
|
|
// Learning states - students own their data, teachers can read class data
|
|
match /learningStates/{studentId} {
|
|
allow read: if isAuthenticated() &&
|
|
(isOwner(studentId) || isSameSchool(resource.data.schoolId));
|
|
allow write: if isAuthenticated() &&
|
|
(isOwner(studentId) || hasRole('teacher') || hasRole('admin'));
|
|
allow create: if isAuthenticated() &&
|
|
isOwner(studentId);
|
|
}
|
|
|
|
// Content chunks - authenticated users from same school
|
|
match /contentChunks/{chunkId} {
|
|
allow read: if isAuthenticated() && isSameSchool(resource.data.schoolId);
|
|
allow write: if isAuthenticated() &&
|
|
(hasRole('teacher') || hasRole('admin')) &&
|
|
isSameSchool(resource.data.schoolId);
|
|
allow create: if isAuthenticated() &&
|
|
hasRole('teacher') &&
|
|
isSameSchool(request.resource.data.schoolId);
|
|
allow update: if isAuthenticated() &&
|
|
(hasRole('teacher') || hasRole('admin')) &&
|
|
isSameSchool(resource.data.schoolId);
|
|
allow delete: if isAuthenticated() &&
|
|
(hasRole('teacher') || hasRole('admin')) &&
|
|
isSameSchool(resource.data.schoolId);
|
|
}
|
|
|
|
// Quizzes
|
|
match /quizzes/{quizId} {
|
|
allow read: if isAuthenticated() && isSameSchool(resource.data.schoolId);
|
|
allow write: if isAuthenticated() &&
|
|
(request.auth.uid == resource.data.teacherId || hasRole('admin'));
|
|
allow create: if isAuthenticated() &&
|
|
hasRole('teacher') &&
|
|
request.auth.uid == request.resource.data.teacherId &&
|
|
isSameSchool(request.resource.data.schoolId);
|
|
}
|
|
|
|
// Quiz attempts
|
|
match /quizAttempts/{attemptId} {
|
|
allow read: if isAuthenticated() &&
|
|
(isOwner(resource.data.studentId) || isSameSchool(resource.data.schoolId));
|
|
allow write: if isAuthenticated() &&
|
|
(isOwner(resource.data.studentId) || hasRole('teacher'));
|
|
allow create: if isAuthenticated() &&
|
|
isOwner(resource.data.studentId);
|
|
}
|
|
|
|
// Interactions
|
|
match /interactions/{interactionId} {
|
|
allow read: if isAuthenticated() &&
|
|
(isOwner(resource.data.studentId) || hasRole('teacher'));
|
|
allow write: if isAuthenticated() &&
|
|
(isOwner(resource.data.studentId) || hasRole('teacher'));
|
|
allow create: if isAuthenticated() &&
|
|
isOwner(resource.data.studentId);
|
|
}
|
|
|
|
// Audit logs - read only for admins
|
|
match /auditLogs/{logId} {
|
|
allow read: if hasRole('admin');
|
|
allow write: if hasRole('admin');
|
|
allow create: if hasRole('admin');
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### 3.3 Indexes Configuration
|
|
|
|
#### Create Required Indexes:
|
|
```json
|
|
// firestore.indexes.json
|
|
{
|
|
"indexes": [
|
|
{
|
|
"collectionGroup": "contentChunks",
|
|
"queryScope": "COLLECTION",
|
|
"fields": [
|
|
{
|
|
"fieldPath": "schoolId",
|
|
"order": "ASCENDING"
|
|
},
|
|
{
|
|
"fieldPath": "concept",
|
|
"order": "ASCENDING"
|
|
},
|
|
{
|
|
"fieldPath": "pedagogy.difficulty",
|
|
"order": "ASCENDING"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"collectionGroup": "contentChunks",
|
|
"queryScope": "COLLECTION",
|
|
"fields": [
|
|
{
|
|
"fieldPath": "schoolId",
|
|
"order": "ASCENDING"
|
|
},
|
|
{
|
|
"fieldPath": "subject",
|
|
"order": "ASCENDING"
|
|
},
|
|
{
|
|
"fieldPath": "unit",
|
|
"order": "ASCENDING"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"collectionGroup": "contentChunks",
|
|
"queryScope": "COLLECTION",
|
|
"fields": [
|
|
{
|
|
"fieldPath": "schoolId",
|
|
"order": "ASCENDING"
|
|
},
|
|
{
|
|
"fieldPath": "metadata.qualityScore",
|
|
"order": "DESCENDING"
|
|
},
|
|
{
|
|
"fieldPath": "createdAt",
|
|
"order": "DESCENDING"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"collectionGroup": "interactions",
|
|
"queryScope": "COLLECTION",
|
|
"fields": [
|
|
{
|
|
"fieldPath": "studentId",
|
|
"order": "ASCENDING"
|
|
},
|
|
{
|
|
"fieldPath": "createdAt",
|
|
"order": "DESCENDING"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"collectionGroup": "quizAttempts",
|
|
"queryScope": "COLLECTION",
|
|
"fields": [
|
|
{
|
|
"fieldPath": "studentId",
|
|
"order": "ASCENDING"
|
|
},
|
|
{
|
|
"fieldPath": "completedAt",
|
|
"order": "DESCENDING"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"collectionGroup": "quizAttempts",
|
|
"queryScope": "COLLECTION",
|
|
"fields": [
|
|
{
|
|
"fieldPath": "quizId",
|
|
"order": "ASCENDING"
|
|
},
|
|
{
|
|
"fieldPath": "score",
|
|
"order": "DESCENDING"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"collectionGroup": "learningStates",
|
|
"queryScope": "COLLECTION",
|
|
"fields": [
|
|
{
|
|
"fieldPath": "schoolId",
|
|
"order": "ASCENDING"
|
|
},
|
|
{
|
|
"fieldPath": "metadata.dailyActiveDays",
|
|
"order": "DESCENDING"
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"fieldOverrides": []
|
|
}
|
|
```
|
|
|
|
#### Deploy Indexes:
|
|
```bash
|
|
firebase deploy --only firestore:indexes
|
|
```
|
|
|
|
---
|
|
|
|
## 📦 STEP 4: CLOUD STORAGE SETUP
|
|
|
|
### 4.1 Storage Bucket Configuration
|
|
|
|
#### Create Storage Buckets:
|
|
```bash
|
|
# Main content bucket
|
|
firebase storage:buckets:create teachit-content
|
|
|
|
# User avatars bucket
|
|
firebase storage:buckets:create teachit-avatars
|
|
|
|
# Temporary files bucket
|
|
firebase storage:buckets:create teachit-temp
|
|
```
|
|
|
|
### 4.2 Storage Security Rules
|
|
|
|
#### Complete Storage Rules:
|
|
```javascript
|
|
rules_version = '2';
|
|
service firebase.storage {
|
|
match /b/{bucket}/o {
|
|
// Helper functions
|
|
function isAuthenticated() {
|
|
return request.auth != null;
|
|
}
|
|
|
|
function isSameSchool(schoolId) {
|
|
return isAuthenticated() &&
|
|
get(/databases/$(database)/documents/users/$(request.auth.uid)).data.schoolId == schoolId;
|
|
}
|
|
|
|
function hasRole(role) {
|
|
return isAuthenticated() &&
|
|
get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == role;
|
|
}
|
|
|
|
// Content files - teachers can upload, authenticated users can read
|
|
match /content/{schoolId}/{allPaths=**} {
|
|
allow read: if isAuthenticated() && isSameSchool(schoolId);
|
|
allow write: if isAuthenticated() &&
|
|
(hasRole('teacher') || hasRole('admin')) &&
|
|
isSameSchool(schoolId);
|
|
allow create: if isAuthenticated() &&
|
|
(hasRole('teacher') || hasRole('admin')) &&
|
|
isSameSchool(schoolId) &&
|
|
request.resource.size < 50 * 1024 * 1024; // 50MB limit
|
|
}
|
|
|
|
// User avatars - users can upload their own
|
|
match /avatars/{userId}/{fileName} {
|
|
allow read: if isAuthenticated();
|
|
allow write: if isAuthenticated() &&
|
|
request.auth.uid == userId &&
|
|
request.resource.size < 5 * 1024 * 1024; // 5MB limit
|
|
}
|
|
|
|
// Temporary files - authenticated users can upload
|
|
match /temp/{userId}/{fileName} {
|
|
allow read: if isAuthenticated() && request.auth.uid == userId;
|
|
allow write: if isAuthenticated() &&
|
|
request.auth.uid == userId &&
|
|
request.resource.size < 10 * 1024 * 1024; // 10MB limit
|
|
allow delete: if isAuthenticated() && request.auth.uid == userId;
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## ⚡ STEP 5: CLOUD FUNCTIONS SETUP
|
|
|
|
### 5.1 Functions Configuration
|
|
|
|
#### Initialize Functions:
|
|
```bash
|
|
# Initialize functions in project
|
|
firebase init functions
|
|
|
|
# Choose TypeScript
|
|
# Choose ESLint
|
|
# Choose npm
|
|
```
|
|
|
|
#### Package.json Configuration:
|
|
```json
|
|
{
|
|
"name": "teachit-functions",
|
|
"description": "Cloud Functions for AI Study Assistant",
|
|
"scripts": {
|
|
"build": "tsc",
|
|
"build:watch": "tsc --watch",
|
|
"serve": "npm run build && firebase emulators:start --only functions",
|
|
"shell": "npm run build && firebase functions:shell",
|
|
"start": "npm run shell",
|
|
"deploy": "firebase deploy --only functions",
|
|
"logs": "firebase functions:log"
|
|
},
|
|
"engines": {
|
|
"node": "18"
|
|
},
|
|
"main": "lib/index.js",
|
|
"dependencies": {
|
|
"@google-cloud/firestore": "^6.7.0",
|
|
"@google-cloud/storage": "^6.11.0",
|
|
"firebase-admin": "^11.10.1",
|
|
"firebase-functions": "^4.4.1",
|
|
"openai": "^4.20.1",
|
|
"anthropic": "^0.6.3",
|
|
"sentence-transformers": "^0.0.1",
|
|
"faiss-node": "^0.5.1",
|
|
"pdf-parse": "^1.1.1",
|
|
"mammoth": "^1.6.0",
|
|
"express": "^4.18.2",
|
|
"cors": "^2.8.5",
|
|
"helmet": "^7.0.0",
|
|
"express-rate-limit": "^6.10.0",
|
|
"joi": "^17.9.2",
|
|
"winston": "^3.10.0",
|
|
"dotenv": "^16.3.1",
|
|
"uuid": "^9.0.0",
|
|
"bcryptjs": "^2.4.3",
|
|
"jsonwebtoken": "^9.0.2"
|
|
},
|
|
"devDependencies": {
|
|
"@types/express": "^4.17.17",
|
|
"@types/cors": "^2.8.13",
|
|
"@types/uuid": "^9.0.2",
|
|
"@types/bcryptjs": "^2.4.2",
|
|
"@types/jsonwebtoken": "^9.0.2",
|
|
"typescript": "^5.1.6",
|
|
"@typescript-eslint/eslint-plugin": "^6.2.1",
|
|
"@typescript-eslint/parser": "^6.2.1",
|
|
"eslint": "^8.46.0",
|
|
"eslint-config-google": "^0.14.0",
|
|
"eslint-plugin-import": "^2.28.0",
|
|
"firebase-functions-test": "^3.1.0"
|
|
}
|
|
}
|
|
```
|
|
|
|
### 5.2 Environment Configuration
|
|
|
|
#### Environment Variables:
|
|
```bash
|
|
# functions/.env
|
|
OPENAI_API_KEY=your_openai_api_key
|
|
ANTHROPIC_API_KEY=your_anthropic_api_key
|
|
FIREBASE_PROJECT_ID=teachit-ai-assistant
|
|
STORAGE_BUCKET=teachit-content.appspot.com
|
|
NODE_ENV=production
|
|
LOG_LEVEL=info
|
|
```
|
|
|
|
#### Functions Configuration:
|
|
```javascript
|
|
// functions/config/firebase.ts
|
|
import * as functions from 'firebase-functions';
|
|
import * as admin from 'firebase-admin';
|
|
|
|
// Initialize Firebase Admin
|
|
admin.initializeApp();
|
|
|
|
// Configuration
|
|
export const config = {
|
|
firestore: admin.firestore(),
|
|
storage: admin.storage(),
|
|
auth: admin.auth(),
|
|
|
|
// Environment variables
|
|
openaiApiKey: functions.config().openai.api_key,
|
|
anthropicApiKey: functions.config().anthropic.api_key,
|
|
|
|
// App settings
|
|
maxFileSize: 50 * 1024 * 1024, // 50MB
|
|
maxQuizDuration: 60, // minutes
|
|
defaultBloomLevel: 2,
|
|
|
|
// Rate limiting
|
|
rateLimits: {
|
|
apiCalls: 100, // per minute
|
|
uploads: 10, // per minute
|
|
llmCalls: 20, // per minute
|
|
}
|
|
};
|
|
```
|
|
|
|
### 5.3 CORS Configuration
|
|
|
|
#### CORS Setup:
|
|
```javascript
|
|
// functions/middleware/cors.ts
|
|
import cors from 'cors';
|
|
import { config } from '../config/firebase';
|
|
|
|
export const corsHandler = cors({
|
|
origin: [
|
|
'http://localhost:3000',
|
|
'https://teachit.web.app',
|
|
'https://teachit.firebaseapp.com'
|
|
],
|
|
credentials: true,
|
|
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
|
|
allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With']
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## 📊 STEP 6: ANALYTICS & MONITORING
|
|
|
|
### 6.1 Firebase Analytics Setup
|
|
|
|
#### Analytics Configuration:
|
|
```javascript
|
|
// Flutter app analytics setup
|
|
import 'package:firebase_analytics/firebase_analytics.dart';
|
|
|
|
class AnalyticsService {
|
|
static FirebaseAnalytics? _analytics;
|
|
|
|
static FirebaseAnalytics get analytics {
|
|
_analytics ??= FirebaseAnalytics.instance;
|
|
return _analytics!;
|
|
}
|
|
|
|
static Future<void> logScreenView(String screenName) async {
|
|
await analytics.logScreenView(screenName: screenName);
|
|
}
|
|
|
|
static Future<void> logEvent(String name, {Map<String, Object>? parameters}) async {
|
|
await analytics.logEvent(name, parameters: parameters);
|
|
}
|
|
|
|
static Future<void> setUserProperty(String name, String value) async {
|
|
await analytics.setUserProperty(name: name, value: value);
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Custom Events to Track:
|
|
```javascript
|
|
// User engagement events
|
|
analytics.logEvent('tutor_question_asked');
|
|
analytics.logEvent('quiz_completed');
|
|
analytics.logEvent('content_uploaded');
|
|
|
|
// Learning events
|
|
analytics.logEvent('concept_mastered');
|
|
analytics.logEvent('misconception_identified');
|
|
analytics.logEvent('learning_goal_achieved');
|
|
|
|
// Performance events
|
|
analytics.logEvent('rag_response_generated');
|
|
analytics.logEvent('content_processed');
|
|
analytics.logEvent('user_session_completed');
|
|
```
|
|
|
|
### 6.2 Crashlytics Setup
|
|
|
|
#### Error Reporting Configuration:
|
|
```javascript
|
|
// Flutter crashlytics setup
|
|
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
|
|
|
|
class CrashlyticsService {
|
|
static Future<void> initialize() async {
|
|
await FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(true);
|
|
}
|
|
|
|
static Future<void> recordError(dynamic error, StackTrace? stackTrace) async {
|
|
await FirebaseCrashlytics.instance.recordError(error, stackTrace);
|
|
}
|
|
|
|
static Future<void> recordFlutterError(FlutterErrorDetails details) async {
|
|
await FirebaseCrashlytics.instance.recordFlutterError(details);
|
|
}
|
|
|
|
static Future<void> setUserIdentifier(String userId) async {
|
|
await FirebaseCrashlytics.instance.setUserIdentifier(userId);
|
|
}
|
|
}
|
|
```
|
|
|
|
### 6.3 Performance Monitoring
|
|
|
|
#### Performance Setup:
|
|
```javascript
|
|
// Flutter performance monitoring
|
|
import 'package:firebase_performance/firebase_performance.dart';
|
|
|
|
class PerformanceService {
|
|
static Trace? _currentTrace;
|
|
|
|
static Future<void> startTrace(String traceName) async {
|
|
_currentTrace = await FirebasePerformance.instance.newTrace(traceName);
|
|
await _currentTrace?.start();
|
|
}
|
|
|
|
static Future<void> stopTrace() async {
|
|
await _currentTrace?.stop();
|
|
_currentTrace = null;
|
|
}
|
|
|
|
static Future<void> setMetric(String metricName, int value) async {
|
|
await _currentTrace?.setMetric(metricName, value);
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🔧 STEP 7: REMOTE CONFIGURATION
|
|
|
|
### 7.1 Remote Config Setup
|
|
|
|
#### Configuration Parameters:
|
|
```javascript
|
|
// Firebase Console → Remote Config
|
|
{
|
|
"feature_flags": {
|
|
"enable_rag_engine": true,
|
|
"enable_voice_chat": false,
|
|
"enable_analytics": true,
|
|
"enable_crashlytics": true
|
|
},
|
|
"app_config": {
|
|
"max_quiz_questions": 20,
|
|
"max_file_upload_size": 50,
|
|
"session_timeout_minutes": 30,
|
|
"default_language": "en"
|
|
},
|
|
"llm_config": {
|
|
"default_model": "claude-3-5-sonnet-20241022",
|
|
"max_tokens": 500,
|
|
"temperature": 0.7,
|
|
"rate_limit_per_minute": 20
|
|
},
|
|
"ui_config": {
|
|
"theme_mode": "auto",
|
|
"enable_animations": true,
|
|
"enable_haptic_feedback": true,
|
|
"default_font_size": 16
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Remote Config Service:
|
|
```javascript
|
|
// Flutter remote config setup
|
|
import 'package:firebase_remote_config/firebase_remote_config.dart';
|
|
|
|
class RemoteConfigService {
|
|
static FirebaseRemoteConfig? _remoteConfig;
|
|
|
|
static FirebaseRemoteConfig get remoteConfig {
|
|
_remoteConfig ??= FirebaseRemoteConfig.instance;
|
|
return _remoteConfig!;
|
|
}
|
|
|
|
static Future<void> initialize() async {
|
|
try {
|
|
await remoteConfig.setConfigSettings(RemoteConfigSettings(
|
|
fetchTimeout: const Duration(minutes: 1),
|
|
minimumFetchInterval: const Duration(hours: 1),
|
|
));
|
|
|
|
await remoteConfig.setDefaults({
|
|
'enable_rag_engine': true,
|
|
'max_quiz_questions': 20,
|
|
'session_timeout_minutes': 30,
|
|
});
|
|
|
|
await remoteConfig.fetchAndActivate();
|
|
} catch (e) {
|
|
print('Failed to initialize remote config: $e');
|
|
}
|
|
}
|
|
|
|
static bool getBool(String key) {
|
|
return remoteConfig.getBool(key);
|
|
}
|
|
|
|
static int getInt(String key) {
|
|
return remoteConfig.getInt(key);
|
|
}
|
|
|
|
static String getString(String key) {
|
|
return remoteConfig.getString(key);
|
|
}
|
|
|
|
static Future<void> refresh() async {
|
|
try {
|
|
await remoteConfig.fetchAndActivate();
|
|
} catch (e) {
|
|
print('Failed to refresh remote config: $e');
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 📱 STEP 8: FLUTTER FIREBASE CONFIGURATION
|
|
|
|
### 8.1 Flutter Firebase Setup
|
|
|
|
#### pubspec.yaml Dependencies:
|
|
```yaml
|
|
dependencies:
|
|
firebase_core: ^2.24.2
|
|
firebase_auth: ^4.15.3
|
|
cloud_firestore: ^4.13.6
|
|
firebase_storage: ^11.5.6
|
|
firebase_analytics: ^10.7.4
|
|
firebase_messaging: ^14.7.6
|
|
firebase_crashlytics: ^3.4.8
|
|
firebase_remote_config: ^4.4.7
|
|
firebase_performance: ^0.9.3+8
|
|
```
|
|
|
|
### 8.2 Firebase Initialization
|
|
|
|
#### Main.dart Configuration:
|
|
```dart
|
|
import 'package:flutter/material.dart';
|
|
import 'package:firebase_core/firebase_core.dart';
|
|
import 'package:firebase_analytics/firebase_analytics.dart';
|
|
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
|
|
import 'package:firebase_remote_config/firebase_remote_config.dart';
|
|
import 'package:firebase_performance/firebase_performance.dart';
|
|
|
|
void main() async {
|
|
WidgetsFlutterBinding.ensureInitialized();
|
|
|
|
await Firebase.initializeApp(
|
|
options: DefaultFirebaseOptions.currentPlatform,
|
|
);
|
|
|
|
// Initialize Firebase services
|
|
await _initializeFirebaseServices();
|
|
|
|
runApp(MyApp());
|
|
}
|
|
|
|
Future<void> _initializeFirebaseServices() async {
|
|
// Analytics
|
|
await FirebaseAnalytics.instance.setAnalyticsCollectionEnabled(true);
|
|
|
|
// Crashlytics
|
|
await FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(true);
|
|
|
|
// Remote Config
|
|
final remoteConfig = FirebaseRemoteConfig.instance;
|
|
await remoteConfig.setConfigSettings(RemoteConfigSettings(
|
|
fetchTimeout: const Duration(minutes: 1),
|
|
minimumFetchInterval: const Duration(hours: 1),
|
|
));
|
|
|
|
// Performance
|
|
await FirebasePerformance.instance.setPerformanceCollectionEnabled(true);
|
|
}
|
|
```
|
|
|
|
### 8.3 Firebase Configuration Files
|
|
|
|
#### Android Configuration:
|
|
```xml
|
|
<!-- android/app/google-services.json -->
|
|
<!-- Download from Firebase Console -->
|
|
```
|
|
|
|
#### iOS Configuration:
|
|
```xml
|
|
<!-- ios/Runner/GoogleService-Info.plist -->
|
|
<!-- Download from Firebase Console -->
|
|
```
|
|
|
|
---
|
|
|
|
## 🔐 STEP 9: SECURITY BEST PRACTICES
|
|
|
|
### 9.1 API Keys Management
|
|
|
|
#### Secure API Key Storage:
|
|
```javascript
|
|
// Never hardcode API keys in client code
|
|
// Use Firebase Remote Config or environment variables
|
|
|
|
// Cloud Functions environment variables
|
|
const openaiApiKey = process.env.OPENAI_API_KEY;
|
|
const anthropicApiKey = process.env.ANTHROPIC_API_KEY;
|
|
|
|
// Firebase Remote Config for client-side keys
|
|
final apiKey = RemoteConfigService.getString('api_key');
|
|
```
|
|
|
|
### 9.2 Data Validation
|
|
|
|
#### Input Validation Functions:
|
|
```javascript
|
|
// Cloud Functions validation
|
|
import Joi from 'joi';
|
|
|
|
const userSchema = Joi.object({
|
|
email: Joi.string().email().required(),
|
|
password: Joi.string().min(6).required(),
|
|
name: Joi.string().min(2).max(50).required(),
|
|
role: Joi.string().valid('student', 'teacher', 'admin').required(),
|
|
schoolId: Joi.string().required(),
|
|
});
|
|
|
|
const contentSchema = Joi.object({
|
|
text: Joi.string().min(100).max(10000).required(),
|
|
concept: Joi.string().required(),
|
|
subject: Joi.string().required(),
|
|
difficulty: Joi.number().min(0).max(1).required(),
|
|
});
|
|
```
|
|
|
|
### 9.3 Rate Limiting
|
|
|
|
#### Rate Limiting Implementation:
|
|
```javascript
|
|
// Cloud Functions rate limiting
|
|
import rateLimit from 'express-rate-limit';
|
|
|
|
const apiLimiter = rateLimit({
|
|
windowMs: 60 * 1000, // 1 minute
|
|
max: 100, // limit each IP to 100 requests per windowMs
|
|
message: 'Too many requests from this IP',
|
|
standardHeaders: true,
|
|
legacyHeaders: false,
|
|
});
|
|
|
|
const uploadLimiter = rateLimit({
|
|
windowMs: 60 * 1000,
|
|
max: 10, // limit uploads
|
|
message: 'Too many upload requests',
|
|
});
|
|
|
|
const llmLimiter = rateLimit({
|
|
windowMs: 60 * 1000,
|
|
max: 20, // limit LLM calls
|
|
message: 'Too many AI requests',
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## 🚀 STEP 10: DEPLOYMENT CONFIGURATION
|
|
|
|
### 10.1 Firebase Hosting Setup
|
|
|
|
#### firebase.json Configuration:
|
|
```json
|
|
{
|
|
"hosting": {
|
|
"public": "build/web",
|
|
"ignore": [
|
|
"firebase.json",
|
|
"**/.*",
|
|
"**/node_modules/**"
|
|
],
|
|
"rewrites": [
|
|
{
|
|
"source": "**",
|
|
"destination": "/index.html"
|
|
}
|
|
],
|
|
"headers": [
|
|
{
|
|
"source": "**/*.@(js|css)",
|
|
"headers": [
|
|
{
|
|
"key": "Cache-Control",
|
|
"value": "max-age=31536000"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"source": "**",
|
|
"headers": [
|
|
{
|
|
"key": "X-Content-Type-Options",
|
|
"value": "nosniff"
|
|
},
|
|
{
|
|
"key": "X-Frame-Options",
|
|
"value": "DENY"
|
|
},
|
|
{
|
|
"key": "X-XSS-Protection",
|
|
"value": "1; mode=block"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"firestore": {
|
|
"rules": "firestore.rules",
|
|
"indexes": "firestore.indexes.json"
|
|
},
|
|
"storage": {
|
|
"rules": "storage.rules"
|
|
},
|
|
"functions": {
|
|
"predeploy": [
|
|
"npm --prefix \"$RESOURCE_DIR\" run lint",
|
|
"npm --prefix \"$RESOURCE_DIR\" run build"
|
|
],
|
|
"source": "functions"
|
|
}
|
|
}
|
|
```
|
|
|
|
### 10.2 Deployment Scripts
|
|
|
|
#### Deploy Commands:
|
|
```bash
|
|
#!/bin/bash
|
|
# deploy.sh
|
|
|
|
echo "Deploying AI Study Assistant..."
|
|
|
|
# Deploy Firestore rules and indexes
|
|
echo "Deploying Firestore configuration..."
|
|
firebase deploy --only firestore
|
|
|
|
# Deploy Storage rules
|
|
echo "Deploying Storage configuration..."
|
|
firebase deploy --only storage
|
|
|
|
# Deploy Functions
|
|
echo "Deploying Cloud Functions..."
|
|
firebase deploy --only functions
|
|
|
|
# Deploy Hosting
|
|
echo "Deploying Web App..."
|
|
firebase deploy --only hosting
|
|
|
|
echo "Deployment completed!"
|
|
```
|
|
|
|
---
|
|
|
|
## 📊 STEP 11: MONITORING & LOGGING
|
|
|
|
### 11.1 Logging Configuration
|
|
|
|
#### Winston Logger Setup:
|
|
```javascript
|
|
// functions/utils/logger.ts
|
|
import winston from 'winston';
|
|
|
|
const logger = winston.createLogger({
|
|
level: process.env.LOG_LEVEL || 'info',
|
|
format: winston.format.combine(
|
|
winston.format.timestamp(),
|
|
winston.format.errors({ stack: true }),
|
|
winston.format.json()
|
|
),
|
|
defaultMeta: { service: 'teachit-functions' },
|
|
transports: [
|
|
new winston.transports.File({ filename: 'error.log', level: 'error' }),
|
|
new winston.transports.File({ filename: 'combined.log' }),
|
|
new winston.transports.Console({
|
|
format: winston.format.simple()
|
|
})
|
|
]
|
|
});
|
|
|
|
export default logger;
|
|
```
|
|
|
|
### 11.2 Health Checks
|
|
|
|
#### Health Check Function:
|
|
```javascript
|
|
// functions/health.ts
|
|
import * as functions from 'firebase-functions';
|
|
import { config } from './config/firebase';
|
|
|
|
export const healthCheck = functions.https.onRequest(async (req, res) => {
|
|
try {
|
|
// Check Firestore connectivity
|
|
await config.firestore.collection('health').doc('check').get();
|
|
|
|
// Check Storage connectivity
|
|
const bucket = config.storage.bucket();
|
|
await bucket.exists();
|
|
|
|
// Check dependencies
|
|
const dependencies = {
|
|
firestore: 'ok',
|
|
storage: 'ok',
|
|
openai: config.openaiApiKey ? 'ok' : 'missing',
|
|
anthropic: config.anthropicApiKey ? 'ok' : 'missing'
|
|
};
|
|
|
|
res.status(200).json({
|
|
status: 'healthy',
|
|
timestamp: new Date().toISOString(),
|
|
dependencies
|
|
});
|
|
} catch (error) {
|
|
res.status(500).json({
|
|
status: 'unhealthy',
|
|
error: error.message,
|
|
timestamp: new Date().toISOString()
|
|
});
|
|
}
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## 🧪 STEP 12: TESTING CONFIGURATION
|
|
|
|
### 12.1 Firebase Emulators
|
|
|
|
#### Emulator Configuration:
|
|
```bash
|
|
# firebase.json
|
|
{
|
|
"emulators": {
|
|
"auth": {
|
|
"port": 9099
|
|
},
|
|
"firestore": {
|
|
"port": 8080
|
|
},
|
|
"storage": {
|
|
"port": 9199
|
|
},
|
|
"functions": {
|
|
"port": 5001
|
|
},
|
|
"ui": {
|
|
"enabled": true,
|
|
"port": 4000
|
|
},
|
|
"singleProjectMode": true
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Start Emulators:
|
|
```bash
|
|
firebase emulators:start
|
|
```
|
|
|
|
### 12.2 Test Configuration
|
|
|
|
#### Test Setup:
|
|
```dart
|
|
// test/firebase_test_setup.dart
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:firebase_core/firebase_core.dart';
|
|
import 'package:cloud_firestore/cloud_firestore.dart';
|
|
import 'package:firebase_auth/firebase_auth.dart';
|
|
|
|
void setupFirebaseTests() {
|
|
setUpAll(() async {
|
|
await Firebase.initializeApp();
|
|
|
|
// Use emulators for testing
|
|
FirebaseFirestore.instance.useFirestoreEmulator('localhost', 8080);
|
|
FirebaseAuth.instance.useAuthEmulator('localhost', 9099);
|
|
});
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 📋 CHECKLIST
|
|
|
|
### Pre-Launch Checklist:
|
|
- [ ] Firebase project created and configured
|
|
- [ ] Authentication methods enabled and tested
|
|
- [ ] Firestore security rules deployed
|
|
- [ ] Firestore indexes created
|
|
- [ ] Storage security rules deployed
|
|
- [ ] Cloud Functions deployed
|
|
- [ ] Environment variables configured
|
|
- [ ] Remote Config parameters set
|
|
- [ ] Analytics tracking implemented
|
|
- [ ] Crashlytics configured
|
|
- [ ] Performance monitoring enabled
|
|
- [ ] Rate limiting implemented
|
|
- [ ] Error handling implemented
|
|
- [ ] Health checks configured
|
|
- [ ] Emulators configured for testing
|
|
- [ ] Integration tests passing
|
|
- [ ] Security audit completed
|
|
|
|
### Production Checklist:
|
|
- [ ] Production Firebase project created
|
|
- [ ] Production API keys configured
|
|
- [ ] Production security rules deployed
|
|
- [ ] Performance monitoring enabled
|
|
- [ ] Error reporting configured
|
|
- [ ] Backup strategy implemented
|
|
- [ ] Monitoring alerts configured
|
|
- [ ] Documentation updated
|
|
- [ ] Team training completed
|
|
|
|
---
|
|
|
|
## 🔧 TROUBLESHOOTING
|
|
|
|
### Common Issues:
|
|
|
|
#### 1. Firebase Initialization Error
|
|
```bash
|
|
# Solution: Check google-services.json (Android) and GoogleService-Info.plist (iOS)
|
|
firebase apps:list
|
|
```
|
|
|
|
#### 2. Firestore Permission Denied
|
|
```bash
|
|
# Solution: Check security rules and user authentication
|
|
firebase deploy --only firestore:rules
|
|
```
|
|
|
|
#### 3. Storage Upload Failed
|
|
```bash
|
|
# Solution: Check storage rules and bucket permissions
|
|
firebase deploy --only storage:rules
|
|
```
|
|
|
|
#### 4. Functions Not Working
|
|
```bash
|
|
# Solution: Check function logs and environment variables
|
|
firebase functions:log
|
|
```
|
|
|
|
#### 5. Analytics Not Tracking
|
|
```bash
|
|
# Solution: Check initialization and data collection settings
|
|
firebase analytics:debug
|
|
```
|
|
|
|
---
|
|
|
|
## 📚 RESOURCES
|
|
|
|
### Documentation:
|
|
- [Firebase Documentation](https://firebase.google.com/docs)
|
|
- [Flutter Firebase Plugin](https://firebase.google.com/docs/flutter/setup)
|
|
- [Cloud Functions Documentation](https://firebase.google.com/docs/functions)
|
|
|
|
### Tools:
|
|
- [Firebase CLI](https://firebase.google.com/docs/cli)
|
|
- [Firebase Emulator Suite](https://firebase.google.com/docs/emulator-suite)
|
|
- [FlutterFire](https://firebase.flutter.dev/)
|
|
|
|
### Support:
|
|
- [Firebase Support](https://firebase.google.com/support)
|
|
- [Stack Overflow Firebase Tag](https://stackoverflow.com/questions/tagged/firebase)
|
|
- [FlutterFire GitHub](https://github.com/FirebaseExtended/flutterfire)
|
|
|
|
---
|
|
|
|
*Last Updated: 2026-05-06*
|
|
*Version: 1.0.0*
|
|
*Firebase Configuration Lead: Backend Development Team*
|