Comprehensive Deployment Guide
Complete guide for deploying the Toto ecosystem to production, including Firebase configuration, project separation, and production readiness.
π Firebase Project Architectureβ
Project Separation Strategyβ
The Toto ecosystem uses multiple Firebase projects for security, scalability, and maintenance:
Current Project Structure:
toto-f9d2f/ # Main application
βββ Authentication
βββ Firestore Database
βββ Storage
βββ Functions
toto-bo/ # Backoffice system
βββ Authentication
βββ Firestore Database
βββ Storage
βββ Functions
toto-ai-hub/ # AI system (App Hosting)
βββ Backend Service
βββ Monitoring
toto-landing/ # Landing pages
βββ Hosting
βββ Analytics
toto-investors/ # Investor pages
βββ Hosting
βββ Analytics
Benefits of Project Separationβ
Security:
- Isolated access controls per project
- Granular permission management
- Reduced attack surface
- Independent security rules
Scalability:
- Independent scaling per component
- Resource allocation optimization
- Performance isolation
- Separate quotas and limits
Maintenance:
- Easier project management
- Independent deployments
- Simplified troubleshooting
- Clear ownership boundaries
Cost Control:
- Separate billing and quotas
- Resource usage tracking
- Budget allocation per component
- Independent cost optimization
π Service Account Configurationβ
1. Create Service Accountsβ
For Each Project:
# Navigate to Firebase Console
# https://console.firebase.google.com/project/<project-id>
# Go to Project Settings > Service Accounts
# Click "Generate New Private Key"
# Download the JSON file
Required Service Accounts:
- toto-main: Main application service account
- toto-bo: Backoffice service account
- toto-ai-hub: AI system service account
- toto-landing: Landing pages service account
- toto-investors: Investor pages service account
2. Environment Configurationβ
Development (.env.local):
# Main App
NEXT_PUBLIC_FIREBASE_API_KEY=your_main_app_api_key
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=toto-f9d2f.firebaseapp.com
NEXT_PUBLIC_FIREBASE_PROJECT_ID=toto-f9d2f
# Backoffice
FIREBASE_PROJECT_ID=toto-bo
FIREBASE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"
FIREBASE_CLIENT_EMAIL=firebase-adminsdk-xxxxx@toto-bo.iam.gserviceaccount.com
# AI System
AI_FIREBASE_PROJECT_ID=toto-ai-hub
AI_FIREBASE_PRIVATE_KEY=your_ai_private_key
AI_FIREBASE_CLIENT_EMAIL=your_ai_client_email
Production (.env.production):
# Main App
NEXT_PUBLIC_FIREBASE_API_KEY=your_prod_main_app_api_key
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=toto-production.firebaseapp.com
NEXT_PUBLIC_FIREBASE_PROJECT_ID=toto-production
# Backoffice
FIREBASE_PROJECT_ID=toto-bo-prod
FIREBASE_PRIVATE_KEY=your_prod_private_key
FIREBASE_CLIENT_EMAIL=your_prod_client_email
# AI System
AI_FIREBASE_PROJECT_ID=toto-ai-hub-prod
AI_FIREBASE_PRIVATE_KEY=your_prod_ai_private_key
AI_FIREBASE_CLIENT_EMAIL=your_prod_ai_client_email
3. Firebase Admin Initializationβ
Main App:
// lib/firebase-admin.ts
import { initializeApp, getApps, cert } from 'firebase-admin/app';
import { getFirestore } from 'firebase-admin/firestore';
const serviceAccount = {
projectId: process.env.FIREBASE_PROJECT_ID,
privateKey: process.env.FIREBASE_PRIVATE_KEY?.replace(/\\n/g, '\n'),
clientEmail: process.env.FIREBASE_CLIENT_EMAIL,
};
if (!getApps().length) {
initializeApp({
credential: cert(serviceAccount),
databaseURL: `https://${process.env.FIREBASE_PROJECT_ID}.firebaseio.com`,
});
}
export const adminDb = getFirestore();
Backoffice:
// lib/firebase-admin.ts
import { initializeApp, getApps, cert } from 'firebase-admin/app';
import { getFirestore } from 'firebase-admin/firestore';
const serviceAccount = {
projectId: process.env.FIREBASE_PROJECT_ID,
privateKey: process.env.FIREBASE_PRIVATE_KEY?.replace(/\\n/g, '\n'),
clientEmail: process.env.FIREBASE_CLIENT_EMAIL,
};
if (!getApps().length) {
initializeApp({
credential: cert(serviceAccount),
databaseURL: `https://${process.env.FIREBASE_PROJECT_ID}.firebaseio.com`,
});
}
export const adminDb = getFirestore();
AI System:
// lib/firebase-admin.ts
import { initializeApp, getApps, cert } from 'firebase-admin/app';
import { getFirestore } from 'firebase-admin/firestore';
const serviceAccount = {
projectId: process.env.AI_FIREBASE_PROJECT_ID,
privateKey: process.env.AI_FIREBASE_PRIVATE_KEY?.replace(/\\n/g, '\n'),
clientEmail: process.env.AI_FIREBASE_CLIENT_EMAIL,
};
if (!getApps().length) {
initializeApp({
credential: cert(serviceAccount),
databaseURL: `https://${process.env.AI_FIREBASE_PROJECT_ID}.firebaseio.com`,
});
}
export const adminDb = getFirestore();
π Deployment Processβ
1. Pre-Deployment Checklistβ
Environment Variables:
- All required environment variables set
- Service account keys configured
- API keys and secrets updated
- Database URLs configured
- Authentication domains set
Firebase Configuration:
- Projects created and configured
- Service accounts generated
- Security rules updated
- Indexes created
- Functions deployed
Code Quality:
- All tests passing
- Linting clean
- Type checking successful
- Build successful
- Performance optimized
2. Deployment Commandsβ
Development Deployment:
# Set development project
firebase use toto-dev
# Deploy functions
firebase deploy --only functions
# Deploy hosting
firebase deploy --only hosting
# Deploy Firestore rules
firebase deploy --only firestore:rules
# Deploy storage rules
firebase deploy --only storage
Staging Deployment:
# Set staging project
firebase use toto-staging
# Deploy all services
firebase deploy
# Verify deployment
firebase functions:list
firebase hosting:sites:list
Production Deployment:
# Set production project
firebase use toto-production
# Deploy with confirmation
firebase deploy --force
# Verify production deployment
firebase functions:list
firebase hosting:sites:list
3. Multi-Project Deploymentβ
Deploy All Projects:
#!/bin/bash
# deploy-all.sh
echo "π Deploying Toto Ecosystem..."
# Deploy main app
echo "π± Deploying main app..."
cd toto-app
firebase use toto-main
firebase deploy --only hosting,functions,firestore:rules
# Deploy backoffice
echo "π’ Deploying backoffice..."
cd ../toto-bo
firebase use toto-bo
firebase deploy --only hosting,functions,firestore:rules
# Deploy AI system
echo "π€ Deploying AI system..."
cd ../toto-ai-hub
# Note: toto-ai-hub uses Firebase App Hosting, not Functions
# Deployment is handled via Firebase App Hosting (see apphosting.yaml)
firebase apphosting:backends:deploy toto-ai-hub-backend
# Deploy landing pages
echo "π Deploying landing pages..."
cd ../toto-landing
firebase use toto-landing
firebase deploy --only hosting
# Deploy investor pages
echo "π° Deploying investor pages..."
cd ../toto-investors
firebase use toto-investors
firebase deploy --only hosting
echo "β
All projects deployed successfully!"
π Security Configurationβ
1. Firestore Security Rulesβ
Main App Rules:
// firestore.rules
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Cases collection
match /cases/{caseId} {
allow read: if request.auth != null;
allow write: if request.auth != null &&
(request.auth.token.role == 'admin' ||
request.auth.token.role == 'staff' ||
request.auth.uid == resource.data.guardianId);
}
// Users collection
match /users/{userId} {
allow read, write: if request.auth != null &&
(request.auth.uid == userId ||
request.auth.token.role == 'admin');
}
// Donations collection
match /donations/{donationId} {
allow read: if request.auth != null;
allow create: if request.auth != null;
allow update, delete: if request.auth != null &&
request.auth.token.role == 'admin';
}
}
}
Backoffice Rules:
// firestore.rules
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Investors collection
match /investors/{investorId} {
allow read, write: if request.auth != null &&
(request.auth.token.role == 'admin' ||
request.auth.token.role == 'staff');
}
// Case updates collection
match /caseUpdates/{updateId} {
allow read, write: if request.auth != null &&
(request.auth.token.role == 'admin' ||
request.auth.token.role == 'staff');
}
// System settings
match /settings/{settingId} {
allow read: if request.auth != null;
allow write: if request.auth != null &&
request.auth.token.role == 'admin';
}
}
}
2. Storage Security Rulesβ
Main App Storage:
// storage.rules
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
// Case images
match /cases/{caseId}/{imageId} {
allow read: if request.auth != null;
allow write: if request.auth != null &&
(request.auth.token.role == 'admin' ||
request.auth.token.role == 'staff' ||
request.auth.uid == getCaseGuardianId(caseId));
}
// User avatars
match /users/{userId}/avatar.jpg {
allow read: if request.auth != null;
allow write: if request.auth != null &&
request.auth.uid == userId;
}
}
}
Backoffice Storage:
// storage.rules
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
// Admin documents
match /admin/{documentType}/{documentId} {
allow read, write: if request.auth != null &&
(request.auth.token.role == 'admin' ||
request.auth.token.role == 'staff');
}
// Reports and exports
match /reports/{reportId} {
allow read, write: if request.auth != null &&
request.auth.token.role == 'admin';
}
}
}
3. Authentication Configurationβ
User Roles and Permissions:
// lib/auth/roles.ts
export enum UserRole {
ADMIN = 'admin',
STAFF = 'staff',
GUARDIAN = 'guardian',
VIEWER = 'viewer',
}
export enum Permission {
READ_CASES = 'read:cases',
WRITE_CASES = 'write:cases',
DELETE_CASES = 'delete:cases',
MANAGE_USERS = 'manage:users',
VIEW_ANALYTICS = 'view:analytics',
ADMIN_ACCESS = 'admin:access',
}
export const rolePermissions: Record<UserRole, Permission[]> = {
[UserRole.ADMIN]: Object.values(Permission),
[UserRole.STAFF]: [
Permission.READ_CASES,
Permission.WRITE_CASES,
Permission.VIEW_ANALYTICS,
],
[UserRole.GUARDIAN]: [
Permission.READ_CASES,
Permission.WRITE_CASES,
],
[UserRole.VIEWER]: [
Permission.READ_CASES,
Permission.VIEW_ANALYTICS,
],
};
π Production Readinessβ
1. Performance Optimizationβ
Function Configuration:
// functions/index.ts
export const runtimeOpts = {
timeoutSeconds: 540,
memory: '256MiB',
minInstances: 0,
maxInstances: 10,
concurrency: 80,
};
export const processUserInput = functions
.runWith(runtimeOpts)
.https.onCall(async (data, context) => {
// Function implementation
});
Database Indexes:
# Create required indexes
firebase firestore:indexes --project toto-main
firebase firestore:indexes --project toto-bo
# Common indexes needed:
# - cases: status + createdAt (composite)
# - cases: category + urgency + createdAt (composite)
# - users: role + status (composite)
# - donations: caseId + createdAt (composite)
# - investors: status + type + createdAt (composite)
2. Monitoring and Loggingβ
Function Monitoring:
// functions/monitoring.ts
import * as functions from 'firebase-functions';
export const logFunctionCall = (functionName: string, data: any) => {
functions.logger.info(`Function ${functionName} called`, {
functionName,
timestamp: new Date().toISOString(),
data,
});
};
export const logError = (functionName: string, error: Error, context: any) => {
functions.logger.error(`Error in ${functionName}`, {
functionName,
error: error.message,
stack: error.stack,
context,
timestamp: new Date().toISOString(),
});
};
Performance Monitoring:
// functions/performance.ts
export const measurePerformance = <T>(
operation: string,
fn: () => Promise<T>
): Promise<T> => {
const start = Date.now();
return fn().finally(() => {
const duration = Date.now() - start;
functions.logger.info(`Performance: ${operation}`, {
operation,
duration,
timestamp: new Date().toISOString(),
});
});
};
3. Error Handlingβ
Global Error Handler:
// functions/errorHandler.ts
export const handleError = (error: Error, context: string) => {
// Log error
functions.logger.error(`Error in ${context}`, {
context,
error: error.message,
stack: error.stack,
timestamp: new Date().toISOString(),
});
// Send to error tracking service
sendToErrorService(error, context);
// Return user-friendly error
return {
success: false,
error: process.env.NODE_ENV === 'production'
? 'An error occurred. Please try again.'
: error.message,
};
};
π CI/CD Pipelineβ
1. GitHub Actions Workflowβ
Main Workflow:
# .github/workflows/deploy.yml
name: Deploy Toto Ecosystem
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: |
cd toto-app && npm ci
cd ../toto-bo && npm ci
cd ../toto-ai-hub && npm ci
- name: Run tests
run: |
cd toto-app && npm test
cd ../toto-bo && npm test
cd ../toto-ai-hub && npm test
build:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Build applications
run: |
cd toto-app && npm run build
cd ../toto-bo && npm run build
cd ../toto-ai-hub && npm run build
deploy-staging:
needs: build
if: github.ref == 'refs/heads/develop'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: w9jds/firebase-action@master
with:
args: deploy --only hosting,functions --project toto-staging
- name: Deploy to staging
run: |
firebase use toto-staging
firebase deploy --only hosting,functions
deploy-production:
needs: build
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: w9jds/firebase-action@master
with:
args: deploy --only hosting,functions --project toto-production
- name: Deploy to production
run: |
firebase use toto-production
firebase deploy --only hosting,functions
2. Environment-Specific Deploymentsβ
Staging Environment:
# Staging configuration
export NODE_ENV=staging
export FIREBASE_PROJECT=toto-staging
export API_URL=https://stg.app.betoto.pet
# Deploy to staging
firebase use toto-staging
firebase deploy --only hosting,functions,firestore:rules
Production Environment:
# Production configuration
export NODE_ENV=production
export FIREBASE_PROJECT=toto-production
export API_URL=https://betoto.pet
# Deploy to production
firebase use toto-production
firebase deploy --only hosting,functions,firestore:rules
π Troubleshootingβ
Common Deployment Scenariosβ
1. Service Account Configuration:
# Check service account permissions
gcloud projects get-iam-policy <project-id>
# Verify service account exists
gcloud iam service-accounts list --project=<project-id>
# Check Firebase project access
firebase projects:list
firebase use <project-id>
2. Function Deployment Configuration:
# Check function logs
firebase functions:log --only <function-name>
# Verify function configuration
firebase functions:config:get
# Check function status
firebase functions:list
3. Database Connection Configuration:
# Verify Firestore rules
firebase deploy --only firestore:rules
# Check database indexes
firebase firestore:indexes
# Verify security rules
firebase deploy --only storage
Monitoring Commandsβ
App Hosting Debugging:
# Check App Hosting logs
firebase apphosting:backends:get BACKEND_NAME --project=PROJECT_ID
# See [App Hosting Debugging Guide](./app-hosting-debugging.md) for details
# Monitor function performance
firebase functions:config:get
# Test function locally
firebase emulators:start --only functions
Database Debugging:
# Check Firestore rules
firebase deploy --only firestore:rules
# Verify indexes
firebase firestore:indexes
# Test security rules
firebase emulators:start --only firestore
π Related Resourcesβ
- Firebase Documentation: Firebase Docs
- Next.js Deployment: Next.js Deployment
- GitHub Actions: GitHub Actions
- Firebase CLI: Firebase CLI
Last Updated: January 2024
Version: 2.0.0
Status: Production Ready