🔥 Firebase Desde Cero - Guía Completa

Aprende Firebase desde los fundamentos hasta conceptos avanzados

"Firebase is Google's mobile platform that helps you quickly develop high-quality apps and grow your business."
Explorar Temas

📖 Temas del Curso

Haz clic en cualquier tema para ver el contenido detallado

📌 Introducción a Firebase

¿Qué es Firebase? Firebase es una plataforma de desarrollo de aplicaciones móviles y web desarrollada por Google. Ofrece una amplia gama de herramientas y servicios que ayudan a los desarrolladores a crear aplicaciones de alta calidad sin necesidad de gestionar infraestructura compleja.

Servicios principales de Firebase:

  • Authentication: Gestión de usuarios segura y sencilla
  • Firestore/Realtime Database: Bases de datos NoSQL en tiempo real
  • Cloud Functions: Backend sin servidor
  • Hosting: Alojamiento web rápido y seguro
  • Cloud Messaging: Notificaciones push
  • Analytics: Análisis de uso de la aplicación

Historia de Firebase:

Año Evento
2011 Firebase fundado como empresa independiente
2014 Adquirido por Google
2016 Firebase 2.0 - Expansión a web y juegos
2024 Firebase con más de 2 millones de apps
💡 Dato curioso: Firebase comenzó como un servicio de base de datos en tiempo real y ahora es una plataforma completa de desarrollo con más de 20 servicios.
← Volver a temas

🔧 Crear Proyecto en Firebase Console

Pasos para crear un proyecto:

  1. Ve a Firebase Console
  2. Haz clic en "Agregar proyecto" o "Create a project"
  3. Ingresa el nombre del proyecto
  4. Configura Google Analytics (opcional)
  5. Haz clic en "Crear proyecto"

Configurar aplicación web:

// 1. En Firebase Console, ve a Configuración del proyecto
// 2. Agrega una aplicación web
// 3. Copia la configuración

const firebaseConfig = {
  apiKey: "AIzaSyXXXXXXXXXXXXXXXXXXXXXXXX",
  authDomain: "tu-proyecto.firebaseapp.com",
  projectId: "tu-proyecto",
  storageBucket: "tu-proyecto.appspot.com",
  messagingSenderId: "123456789012",
  appId: "1:123456789012:web:abcdef123456",
  measurementId: "G-XXXXXXXXXX"
};

Instalar Firebase SDK:

# Con npm
npm install firebase

# Con yarn
yarn add firebase

# Con CDN (HTML)
<script src="https://www.gstatic.com/firebasejs/10.7.1/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/10.7.1/firebase-auth-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/10.7.1/firebase-firestore-compat.js"></script>

Inicializar Firebase:

// Firebase v9+ (Modular)
import { initializeApp } from 'firebase/app';
import { getAuth } from 'firebase/auth';
import { getFirestore } from 'firebase/firestore';

const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const db = getFirestore(app);

// Firebase v8 (Compat - más sencillo para principiantes)
import firebase from 'firebase/compat/app';
import 'firebase/compat/auth';
import 'firebase/compat/firestore';

firebase.initializeApp(firebaseConfig);
const auth = firebase.auth();
const db = firebase.firestore();
💡 Tip: Usa variables de entorno para almacenar tu configuración de Firebase. Nunca subas las claves API a repositorios públicos.
← Volver a temas

🔐 Firebase Authentication

¿Qué es Firebase Auth?

Firebase Authentication proporciona funciones de autenticación completas para tu aplicación. Soporta múltiples métodos de autenticación incluyendo email/password, proveedores de identidad (Google, Facebook, Twitter), y autenticación anónima.

Métodos de autenticación soportados:

Método Descripción
Email/Password Autenticación tradicional con credenciales
Google Login con cuenta de Google
Facebook Login con cuenta de Facebook
GitHub Login con cuenta de GitHub
Teléfono Verificación por SMS
Anónimo Usuario temporal sin credenciales

Objeto User:

// Estructura del objeto usuario
{
  uid: "abc123",              // ID único del usuario
  email: "usuario@email.com", // Email verificado
  displayName: "Juan",        // Nombre visible
  photoURL: "https://...",    // URL de foto de perfil
  emailVerified: true,        // Email verificado
  isAnonymous: false,         // Si es anónimo
  providerData: [...],        // Proveedores vinculados
  metadata: {
    creationTime: 1234567890,
    lastSignInTime: 1234567890
  }
}

Estado de autenticación:

import { onAuthStateChanged } from 'firebase/auth';

// Escuchar cambios en el estado de autenticación
onAuthStateChanged(auth, (user) => {
  if (user) {
    // Usuario está logueado
    console.log('Usuario:', user.email);
  } else {
    // Usuario no está logueado
    console.log('No hay usuario');
  }
});
⚠️ Seguridad: Las reglas de seguridad de Firebase son tu primera línea de defensa. Nunca confíes únicamente en la validación del cliente.
← Volver a temas

📊 Cloud Firestore y Realtime Database

Comparación entre bases de datos:

Característica Cloud Firestore Realtime Database
Modelo de datos Documentos y colecciones Árbol JSON único
Consultas Avanzadas y flexibles Básicas
Escalabilidad Automática Manual (sharding)
Precios Por operación Por ancho de banda
Offline Sí (avanzado) Sí (básico)

Estructura de Firestore:

// Colecciones y Documentos
/usuarios                    // Colección
  /usuario123               // Documento
    /nombre: "Juan"         // Campo
    /edad: 30               // Campo
    /posts                  // Subcolección
      /post1
        /titulo: "Mi post"
        /contenido: "..."

// Jerarquía: Colección → Documento → Colección → Documento

Tipos de datos en Firestore:

// Tipos soportados
{
  string: "texto",
  number: 42,
  boolean: true,
  null: null,
  array: [1, 2, 3],
  object: { nested: "value" },
  timestamp: new Date(),
  geopoint: new GeoPoint(51.5074, -0.1278),
  reference: docRef,
  blob: new Uint8Array(...)
}

Escuchar cambios en tiempo real:

import { onSnapshot, collection } from 'firebase/firestore';

// Escuchar una colección
const unsubscribe = onSnapshot(collection(db, 'usuarios'), (snapshot) => {
  snapshot.docChanges().forEach((change) => {
    if (change.type === 'added') {
      console.log('Nuevo usuario:', change.doc.data());
    }
    if (change.type === 'modified') {
      console.log('Usuario modificado:', change.doc.data());
    }
    if (change.type === 'removed') {
      console.log('Usuario eliminado');
    }
  });
});

// Dejar de escuchar
unsubscribe();
← Volver a temas

📧 Auth con Email/Password

Registro de usuario:

import { 
  createUserWithEmailAndPassword,
  updateProfile 
} from 'firebase/auth';

async function registrarUsuario(email, password, nombre) {
  try {
    const userCredential = await createUserWithEmailAndPassword(
      auth, 
      email, 
      password
    );
    
    // Actualizar perfil con nombre
    await updateProfile(userCredential.user, {
      displayName: nombre
    });
    
    console.log('Usuario registrado:', userCredential.user.uid);
    return userCredential.user;
  } catch (error) {
    console.error('Error en registro:', error.code);
    
    // Manejo de errores comunes
    switch (error.code) {
      case 'auth/email-already-in-use':
        return { error: 'El email ya está registrado' };
      case 'auth/weak-password':
        return { error: 'Contraseña muy débil (mínimo 6 caracteres)' };
      case 'auth/invalid-email':
        return { error: 'Email inválido' };
      default:
        return { error: error.message };
    }
  }
}

Inicio de sesión:

import { signInWithEmailAndPassword } from 'firebase/auth';

async function iniciarSesion(email, password) {
  try {
    const userCredential = await signInWithEmailAndPassword(
      auth, 
      email, 
      password
    );
    
    console.log('Usuario logueado:', userCredential.user.email);
    return userCredential.user;
  } catch (error) {
    console.error('Error en login:', error.code);
    
    switch (error.code) {
      case 'auth/user-not-found':
        return { error: 'No existe usuario con este email' };
      case 'auth/wrong-password':
        return { error: 'Contraseña incorrecta' };
      case 'auth/too-many-requests':
        return { error: 'Demasiados intentos. Intenta más tarde' };
      default:
        return { error: error.message };
    }
  }
}

Restablecer contraseña:

import { sendPasswordResetEmail } from 'firebase/auth';

async function resetearPassword(email) {
  try {
    await sendPasswordResetEmail(auth, email);
    console.log('Email de recuperación enviado');
    return { success: true };
  } catch (error) {
    console.error('Error:', error.code);
    return { error: error.message };
  }
}

Cerrar sesión:

import { signOut } from 'firebase/auth';

async function cerrarSesion() {
  try {
    await signOut(auth);
    console.log('Sesión cerrada');
  } catch (error) {
    console.error('Error al cerrar sesión:', error);
  }
}
💡 Tip: Implementa validación del lado del cliente antes de enviar datos a Firebase para mejor experiencia de usuario.
← Volver a temas

🔗 Auth con Google, Facebook

Configurar proveedores de identidad:

  1. En Firebase Console, ve a Authentication → Sign-in method
  2. Selecciona el proveedor (Google, Facebook, etc.)
  3. Habilita el proveedor
  4. Configura las credenciales necesarias
  5. Guarda los cambios

Login con Google:

import { 
  GoogleAuthProvider, 
  signInWithPopup,
  signInWithRedirect,
  getRedirectResult
} from 'firebase/auth';

const provider = new GoogleAuthProvider();

// Método 1: Popup
async function loginConGoogle() {
  try {
    const result = await signInWithPopup(auth, provider);
    const user = result.user;
    
    // Obtener token de acceso
    const credential = GoogleAuthProvider.credentialFromResult(result);
    const token = credential.accessToken;
    
    console.log('Usuario logueado:', user.email);
    return user;
  } catch (error) {
    console.error('Error:', error.code);
  }
}

// Método 2: Redirect (mejor para móviles)
async function loginConGoogleRedirect() {
  await signInWithRedirect(auth, provider);
}

// Obtener resultado después del redirect
getRedirectResult(auth).then((result) => {
  const user = result.user;
  console.log('Usuario:', user.email);
});

Login con Facebook:

import { FacebookAuthProvider } from 'firebase/auth';

const provider = new FacebookAuthProvider();

// Agregar scopes (permisos adicionales)
provider.addScope('email');
provider.addScope('public_profile');

// Configurar idioma
provider.setCustomParameters({ lang: 'es' });

async function loginConFacebook() {
  try {
    const result = await signInWithPopup(auth, provider);
    const user = result.user;
    
    // Obtener token de acceso de Facebook
    const credential = FacebookAuthProvider.credentialFromResult(result);
    const accessToken = credential.accessToken;
    
    return user;
  } catch (error) {
    console.error('Error:', error);
  }
}

Vincular múltiples proveedores:

import { 
  linkWithPopup,
  unlink,
  getProviders 
} from 'firebase/auth';

// Vincular Google a cuenta existente
async function vincularGoogle(user) {
  const provider = new GoogleAuthProvider();
  try {
    await linkWithPopup(user, provider);
    console.log('Google vinculado');
  } catch (error) {
    console.error('Error al vincular:', error);
  }
}

// Obtener proveedores vinculados
const providers = getProviders(user);
console.log('Proveedores:', providers);

// Desvincular proveedor
await unlink(user, 'google.com');
⚠️ Importante: Para Facebook, necesitas crear una app en developers.facebook.com y agregar las credenciales en Firebase Console.
← Volver a temas

📝 CRUD en Firestore

Crear documentos:

import { 
  collection, 
  addDoc, 
  doc, 
  setDoc 
} from 'firebase/firestore';

// Opción 1: Auto-ID (recomendado)
async function crearUsuario(nombre, email) {
  const docRef = await addDoc(collection(db, 'usuarios'), {
    nombre: nombre,
    email: email,
    createdAt: new Date(),
    activo: true
  });
  console.log('Documento creado con ID:', docRef.id);
  return docRef.id;
}

// Opción 2: ID personalizado
async function crearUsuarioConId(userId, datos) {
  await setDoc(doc(db, 'usuarios', userId), {
    ...datos,
    createdAt: new Date()
  });
}

Leer documentos:

import { 
  doc, 
  getDoc, 
  collection, 
  getDocs,
  query,
  where
} from 'firebase/firestore';

// Leer un documento
async function obtenerUsuario(userId) {
  const docRef = doc(db, 'usuarios', userId);
  const docSnap = await getDoc(docRef);
  
  if (docSnap.exists()) {
    console.log('Datos:', docSnap.data());
    return { id: docSnap.id, ...docSnap.data() };
  } else {
    console.log('Documento no encontrado');
    return null;
  }
}

// Leer colección completa
async function obtenerTodosUsuarios() {
  const querySnapshot = await getDocs(collection(db, 'usuarios'));
  const usuarios = [];
  querySnapshot.forEach((doc) => {
    usuarios.push({ id: doc.id, ...doc.data() });
  });
  return usuarios;
}

// Leer con filtro
async function obtenerUsuariosActivos() {
  const q = query(
    collection(db, 'usuarios'), 
    where('activo', '==', true)
  );
  const querySnapshot = await getDocs(q);
  // ...
}

Actualizar documentos:

import { 
  doc, 
  updateDoc, 
  increment,
  arrayUnion,
  arrayRemove
} from 'firebase/firestore';

// Actualizar campos específicos
async function actualizarUsuario(userId, datos) {
  const userRef = doc(db, 'usuarios', userId);
  await updateDoc(userRef, {
    ...datos,
    updatedAt: new Date()
  });
}

// Operaciones atómicas
async function incrementarVisitas(postId) {
  const postRef = doc(db, 'posts', postId);
  await updateDoc(postRef, {
    visitas: increment(1)
  });
}

// Arrays
async function agregarTag(postId, tag) {
  const postRef = doc(db, 'posts', postId);
  await updateDoc(postRef, {
    tags: arrayUnion(tag)  // Agrega si no existe
  });
}

async function removerTag(postId, tag) {
  const postRef = doc(db, 'posts', postId);
  await updateDoc(postRef, {
    tags: arrayRemove(tag)  // Remueve si existe
  });
}

Eliminar documentos:

import { doc, deleteDoc } from 'firebase/firestore';

async function eliminarUsuario(userId) {
  await deleteDoc(doc(db, 'usuarios', userId));
  console.log('Usuario eliminado');
}

// Eliminar con confirmación
async function eliminarConConfirmacion(userId) {
  const userRef = doc(db, 'usuarios', userId);
  
  // Primero verificar que existe
  const docSnap = await getDoc(userRef);
  if (docSnap.exists()) {
    await deleteDoc(userRef);
    return true;
  }
  return false;
}
💡 Tip: Usa transacciones para operaciones que requieren consistencia, como transferencias de saldo.
← Volver a temas

🔒 Reglas de Seguridad

Estructura de reglas:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    
    // Regla para toda la base de datos
    match /{document=**} {
      allow read, write: if false;  // Denegar todo por defecto
    }
    
    // Reglas específicas por colección
    match /usuarios/{userId} {
      allow read: if true;  // Público leer
      allow write: if request.auth != null 
                   && request.auth.uid == userId;  // Solo el dueño
    }
  }
}

Variables disponibles:

Variable Descripción
request.auth Datos del usuario autenticado
request.auth.uid ID del usuario
request.time Timestamp del servidor
resource.data Datos existentes del documento
request.resource.data Datos que se están escribiendo

Ejemplos de reglas:

// Solo usuarios autenticados
match /posts/{postId} {
  allow read: if request.auth != null;
  allow write: if request.auth != null;
}

// Validar datos de entrada
match /usuarios/{userId} {
  allow create: if request.auth.uid == userId
                && request.resource.data.keys().hasAll(['nombre', 'email'])
                && request.resource.data.nombre is string
                && request.resource.data.email is string;
  
  allow update: if request.auth.uid == userId
                && request.resource.data.keys().hasOnly(['nombre', 'fotoURL']);
}

// Limitar tamaño de datos
match /mensajes/{mensajeId} {
  allow create: if request.resource.data.texto.size() <= 500;
}

// Validar formato de email
function isValidEmail(email) {
  return email.matches('^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$');
}

match /usuarios/{userId} {
  allow create: if isValidEmail(request.resource.data.email);
}

Reglas para subcolecciones:

match /usuarios/{userId} {
  allow read, write: if request.auth.uid == userId;
  
  // Subcolección posts
  match /posts/{postId} {
    allow read: if true;  // Posts públicos
    allow create: if request.auth.uid == userId;
    allow update, delete: if request.auth.uid == userId;
  }
  
  // Subcolección configuracion
  match /configuracion/{configId} {
    allow read, write: if request.auth.uid == userId;
  }
}
⚠️ Importante: Las reglas de seguridad no son validadores de datos. Siempre valida en el cliente y en Cloud Functions para mayor seguridad.
← Volver a temas

⚡ Cloud Functions

¿Qué son Cloud Functions?

Cloud Functions for Firebase es un entorno de ejecución sin servidor que te permite ejecutar código backend automáticamente en respuesta a eventos activados por funciones de Firebase y HTTPS.

Tipos de funciones:

Tipo Descripción
HTTP Funciones callable desde HTTP
Firestore Se activan con cambios en Firestore
Auth Se activan con eventos de autenticación
Scheduled Se ejecutan en un cron programado
Storage Se activan con cambios en Cloud Storage

Configuración inicial:

# Instalar Firebase CLI
npm install -g firebase-tools

# Inicializar funciones
firebase init functions

# Estructura creada
/functions
  /index.js
  package.json
  .gitignore

Función HTTP:

const functions = require('firebase-functions');
const admin = require('firebase-admin');

admin.initializeApp();

// Función HTTP tradicional
exports.saludar = functions.https.onRequest((req, res) => {
  const nombre = req.query.nombre || 'Mundo';
  res.send(`Hola ${nombre}!`);
});

// Función callable (recomendada para clientes Firebase)
exports.saludarCallable = functions.https.onCall(async (data, context) => {
  // Verificar autenticación
  if (!context.auth) {
    throw new functions.https.HttpsError(
      'unauthenticated',
      'Usuario debe estar autenticado'
    );
  }
  
  const nombre = data.nombre || 'Mundo';
  return { mensaje: `Hola ${nombre}!` };
});

Función Firestore trigger:

// Se activa cuando se crea un documento
exports.onUsuarioCreado = functions.firestore
  .document('usuarios/{userId}')
  .onCreate(async (snap, context) => {
    const usuario = snap.data();
    const userId = context.params.userId;
    
    // Enviar email de bienvenida
    await enviarEmailBienvenida(usuario.email, usuario.nombre);
    
    // Crear documento de perfil
    await snap.ref.parent.parent()
      .doc('perfiles')
      .collection(userId)
      .add({ createdAt: admin.firestore.FieldValue.serverTimestamp() });
    
    return null;
  });

// Se activa cuando se actualiza un documento
exports.onUsuarioActualizado = functions.firestore
  .document('usuarios/{userId}')
  .onUpdate(async (change, context) => {
    const antes = change.before.data();
    const despues = change.after.data();
    
    if (antes.email !== despues.email) {
      // Email cambió, enviar notificación
      await notificarCambioEmail(despues.email);
    }
    
    return null;
  });

Función programada (Cron):

// Ejecutar todos los días a medianoche
exports.limpiezaDiaria = functions.pubsub
  .schedule('0 0 * * *')
  .timeZone('America/New_York')
  .onRun(async (context) => {
    // Eliminar usuarios inactivos
    const hace30Dias = new Date();
    hace30Dias.setDate(hace30Dias.getDate() - 30);
    
    const db = admin.firestore();
    const snapshot = await db.collection('usuarios')
      .where('ultimaActividad', '<', hace30Dias)
      .get();
    
    const batch = db.batch();
    snapshot.docs.forEach(doc => batch.delete(doc.ref));
    await batch.commit();
    
    console.log(`${snapshot.size} usuarios eliminados`);
    return null;
  });
💡 Tip: Usa funciones callable en lugar de HTTP para mejor seguridad y manejo automático de tokens de autenticación.
← Volver a temas

🌐 Firebase Hosting

¿Qué es Firebase Hosting?

Firebase Hosting es un servicio de alojamiento web diseñado para desarrolladores. Ofrece hosting seguro, rápido y confiable para tu aplicación web con SSL gratuito y CDN global.

Características principales:

  • SSL gratuito: HTTPS automático
  • CDN global: Contenido entregado desde el edge más cercano
  • Rollback instantáneo: Revierte a versiones anteriores
  • Preview channels: URLs de preview para cada PR
  • Integración con Functions: Hosting dinámico

Configuración inicial:

# Inicializar hosting
firebase init hosting

# Estructura creada
/public
  index.html
  css/
  js/
  images/
/firebase.json
.hostingrc

# firebase.json configuración básica
{
  "hosting": {
    "public": "public",
    "ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ]
  }
}

Deploy:

# Deploy a producción
firebase deploy --only hosting

# Deploy solo de hosting (más rápido)
firebase deploy hosting

# Deploy a canal de preview
firebase hosting:channel:deploy preview-pr-123

# Listar canales
firebase hosting:channel:list

# Eliminar canal
firebase hosting:channel:delete preview-pr-123

Configuración avanzada:

{
  "hosting": {
    "public": "dist",
    "ignore": ["firebase.json"],
    
    // Rewrites para SPA
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ],
    
    // Headers personalizados
    "headers": [
      {
        "source": "**/*.@(js|css)",
        "headers": [
          {
            "key": "Cache-Control",
            "value": "max-age=31536000"
          }
        ]
      },
      {
        "source": "**/*.@(jpg|jpeg|gif|png|webp)",
        "headers": [
          {
            "key": "Cache-Control",
            "value": "max-age=31536000, immutable"
          }
        ]
      }
    ],
    
    // Redirecciones
    "redirects": [
      {
        "source": "/old-page",
        "destination": "/new-page",
        "type": 301
      }
    ],
    
    // Integración con Cloud Functions
    "functions": "functions"
  }
}

Hosting con Functions (SSR):

// functions/index.js
const express = require('express');
const app = express();

app.get('/', (req, res) => {
  res.send('Hola desde SSR!');
});

app.get('/api/usuarios', async (req, res) => {
  const usuarios = await obtenerUsuarios();
  res.json(usuarios);
});

exports.app = functions.https.onRequest(app);

// firebase.json
{
  "hosting": {
    "public": "public",
    "rewrites": [
      {
        "source": "**",
        "function": "app"
      }
    ]
  }
}
💡 Tip: Usa preview channels para revisar cambios antes de hacer deploy a producción. Ideal para CI/CD.
← Volver a temas

📱 Cloud Messaging (FCM)

¿Qué es Firebase Cloud Messaging?

FCM es una solución de mensajería multiplataforma que permite enviar mensajes y notificaciones push de manera confiable y sin costo a Android, iOS y web.

Tipos de mensajes:

Tipo Descripción
Notification Mensaje con payload predefinido (app en background)
Data Mensaje personalizado (app en foreground o background)
Topic Enviar a múltiples dispositivos suscritos a un tema

Configurar en cliente web:

import { 
  getMessaging, 
  getToken,
  onMessage
} from 'firebase/messaging';

const messaging = getMessaging(app);

// Solicitar permiso y obtener token
async function solicitarPermisoNotificaciones() {
  try {
    const permission = await Notification.requestPermission();
    
    if (permission === 'granted') {
      const token = await getToken(messaging, {
        vapidKey: 'TU_VAPID_KEY'
      });
      
      console.log('Token FCM:', token);
      
      // Guardar token en Firestore
      await guardarTokenEnBD(token);
      return token;
    }
  } catch (error) {
    console.error('Error:', error);
  }
}

// Escuchar mensajes en foreground
onMessage(messaging, (payload) => {
  console.log('Mensaje recibido:', payload);
  
  const { title, body } = payload.notification;
  
  // Mostrar notificación personalizada
  new Notification(title, {
    body: body,
    icon: '/icon.png'
  });
});

Enviar mensaje desde Cloud Functions:

const admin = require('firebase-admin');
admin.initializeApp();

async function enviarNotificacion(userId, titulo, cuerpo) {
  // Obtener token del usuario
  const userDoc = await admin.firestore()
    .collection('usuarios')
    .doc(userId)
    .get();
  
  const token = userDoc.data()?.fcmToken;
  
  if (!token) {
    console.log('Usuario sin token FCM');
    return;
  }
  
  const message = {
    notification: {
      title: titulo,
      body: cuerpo
    },
    data: {
      tipo: 'mensaje_personal',
      userId: userId
    },
    token: token
  };
  
  try {
    const response = await admin.messaging().send(message);
    console.log('Mensaje enviado:', response);
  } catch (error) {
    console.error('Error al enviar:', error);
  }
}

Enviar a topic:

// Suscribirse a topic (cliente)
import { subscribeToTopic, unsubscribeFromTopic } from 'firebase/messaging';

await subscribeToTopic(messaging, 'noticias');
await unsubscribeFromTopic(messaging, 'noticias');

// Enviar a topic (Functions)
const message = {
  notification: {
    title: 'Nueva noticia!',
    body: 'Hay una nueva noticia disponible'
  },
  topic: 'noticias'
};

await admin.messaging().send(message);
💡 Tip: Para producción, implementa un sistema de gestión de tokens inválidos para limpiar tokens expirados de tu base de datos.
← Volver a temas

📊 Analytics y Crashlytics

Firebase Analytics:

Firebase Analytics es una solución de análisis de aplicaciones gratuita e ilimitada que proporciona información sobre el uso de la aplicación y la participación de los usuarios.

Eventos automáticos:

Evento Descripción
first_open Primera apertura de la app
session_start Inicio de sesión
screen_view Vista de pantalla
user_engagement Tiempo de uso

Eventos personalizados:

import { getAnalytics, logEvent } from 'firebase/analytics';

const analytics = getAnalytics(app);

// Loguear evento personalizado
logEvent(analytics, 'compra_realizada', {
  producto_id: 'prod_123',
  producto_nombre: 'Premium Plan',
  precio: 9.99,
  moneda: 'USD',
  metodo_pago: 'tarjeta_credito'
});

// Eventos recomendados por Firebase
logEvent(analytics, 'add_to_cart', {
  items: [{
    item_id: 'SKU_123',
    item_name: 'Producto X',
    price: 29.99,
    quantity: 2
  }]
});

logEvent(analytics, 'begin_checkout', {
  currency: 'USD',
  value: 59.98,
  items: [...]
});

Parámetros de usuario:

import { setUserProperties } from 'firebase/analytics';

// Establecer propiedades del usuario
setUserProperties(analytics, {
  nivel: 'premium',
  tipo_usuario: 'registrado',
  fecha_registro: '2024-01-15'
});

// Establecer ID de usuario (para cross-device)
import { setUserId } from 'firebase/analytics';
setUserId(analytics, usuario.uid);

Firebase Crashlytics:

Crashlytics es una solución de seguimiento de fallos ligera y en tiempo real que te ayuda a priorizar y estabilizar la calidad de tu aplicación.

// Web (a través de Firebase Console)
// Los crashes se reportan automáticamente

// Personalizar reporte
import { getCrashlytics } from 'firebase/crashlytics';

const crashlytics = getCrashlytics(app);

// Agregar logs personalizados
crashlytics.log('Usuario inició sesión');
crashlytics.log('Intentando cargar datos...');

// Establecer claves personalizadas
crashlytics.setCustomKey('usuario_id', usuario.uid);
crashlytics.setCustomKey('nivel_app', 'premium');

// Registrar usuario (sin PII)
crashlytics.setUserId(usuario.uid);

// Forzar crash para testing (solo desarrollo)
if (process.env.NODE_ENV === 'development') {
  crashlytics.crash();
}

Dashboard de Analytics:

  • Retención: Usuarios que regresan
  • Funnels: Conversión por pasos
  • Audiencias: Segmentos de usuarios
  • Eventos: Todos los eventos registrados
  • DebugView: Ver eventos en tiempo real
💡 Tip: Usa DebugView durante el desarrollo para verificar que los eventos se están registrando correctamente antes de lanzar a producción.
← Volver a temas

📚 Contenido del Curso

Módulo 1: Fundamentos

  • Introducción a Firebase
  • Crear proyecto en Firebase Console
  • Firebase Authentication
  • Cloud Firestore y Realtime Database
Ir a temas →

Módulo 2: Intermedio

  • Auth con email/password
  • Auth con Google, Facebook
  • CRUD en Firestore
  • Reglas de seguridad
Ir a temas →

Módulo 3: Avanzado

  • Cloud Functions
  • Firebase Hosting
  • Cloud Messaging (FCM)
  • Analytics y Crashlytics
Ir a temas →

📝 Ejemplos Rápidos

Inicialización

import { initializeApp } from 'firebase/app';
import { getAuth } from 'firebase/auth';
import { getFirestore } from 'firebase/firestore';

const firebaseConfig = {
  apiKey: "TU_API_KEY",
  authDomain: "tu-proyecto.firebaseapp.com",
  projectId: "tu-proyecto",
  storageBucket: "tu-proyecto.appspot.com",
  messagingSenderId: "123456789",
  appId: "1:123456789:web:abcdef"
};

const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const db = getFirestore(app);

Authentication

import {
  createUserWithEmailAndPassword,
  signInWithEmailAndPassword,
  signOut,
  onAuthStateChanged
} from 'firebase/auth';

// Registro
await createUserWithEmailAndPassword(auth, email, password);

// Login
await signInWithEmailAndPassword(auth, email, password);

// Logout
await signOut(auth);

// Escuchar cambios
onAuthStateChanged(auth, (user) => {
  if (user) {
    console.log('Usuario logueado:', user.uid);
  }
});

Firestore CRUD

import {
  collection,
  addDoc,
  getDocs,
  doc,
  updateDoc,
  deleteDoc,
  query,
  where
} from 'firebase/firestore';

// Crear
await addDoc(collection(db, 'usuarios'), {
  nombre: 'Juan',
  email: 'juan@email.com'
});

// Leer
const snapshot = await getDocs(collection(db, 'usuarios'));
snapshot.forEach(doc => console.log(doc.data()));

// Actualizar
await updateDoc(doc(db, 'usuarios', 'id'), {
  edad: 31
});

// Eliminar
await deleteDoc(doc(db, 'usuarios', 'id'));

Cloud Functions

const functions = require('firebase-functions');
const admin = require('firebase-admin');

admin.initializeApp();

exports.onUserCreate = functions.firestore
  .document('usuarios/{userId}')
  .onCreate((snap, context) => {
    const userData = snap.data();
    console.log('Nuevo usuario:', userData);
    return null;
  });

Firebase CLI

# Instalar Firebase CLI
npm install -g firebase-tools

# Login
firebase login

# Inicializar proyecto
firebase init

# Deploy functions
firebase deploy --only functions

# Deploy hosting
firebase deploy --only hosting

# Emuladores locales
firebase emulators:start

📖 Recursos Adicionales

Herramientas

  • Firebase Console - Panel de control
  • Firebase Emulator Suite
  • Firestore Rules Playground

Comunidades

👨‍💻 Desarrollado por Isaac Esteban Haro Torres

Ingeniero en Sistemas · Full Stack · Automatización · Data

📧 Email: zackharo1@gmail.com

📱 WhatsApp: 098805517

💻 GitHub: github.com/ieharo1

🌐 Portafolio: ieharo1.github.io/portafolio-isaac.haro/