Skip to main content

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

Last Updated: January 2024
Version: 2.0.0
Status: Production Ready