- Backend NestJS con módulos de autenticación, inventario, créditos - Frontend React con dashboard y componentes UI - Base de datos PostgreSQL con migraciones - Tests E2E configurados - Configuración de Docker y deployment Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
281 lines
5.8 KiB
Markdown
281 lines
5.8 KiB
Markdown
# INT-004: Integracion Firebase FCM
|
|
|
|
---
|
|
id: INT-004
|
|
type: Integration
|
|
status: Pendiente
|
|
version: "1.0.0"
|
|
created_date: 2026-01-10
|
|
updated_date: 2026-01-10
|
|
simco_version: "4.0.0"
|
|
---
|
|
|
|
## Metadata
|
|
|
|
| Campo | Valor |
|
|
|-------|-------|
|
|
| **ID** | INT-004 |
|
|
| **Servicio** | Firebase Cloud Messaging |
|
|
| **Proposito** | Notificaciones push |
|
|
| **Criticidad** | P1 |
|
|
| **Estado** | Pendiente |
|
|
|
|
---
|
|
|
|
## 1. Descripcion
|
|
|
|
Integracion con Firebase Cloud Messaging (FCM) para enviar notificaciones push a los usuarios sobre resultados de inventario, pagos y otros eventos.
|
|
|
|
---
|
|
|
|
## 2. Informacion del Servicio
|
|
|
|
| Campo | Valor |
|
|
|-------|-------|
|
|
| Proveedor | Google Firebase |
|
|
| Documentacion | https://firebase.google.com/docs/cloud-messaging |
|
|
| Consola | https://console.firebase.google.com |
|
|
| SDK | firebase-admin (node), @react-native-firebase/messaging |
|
|
|
|
---
|
|
|
|
## 3. Configuracion
|
|
|
|
### Variables de Entorno
|
|
|
|
```env
|
|
FIREBASE_PROJECT_ID=miinventario-xxx
|
|
FIREBASE_CLIENT_EMAIL=firebase-adminsdk@...
|
|
FIREBASE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n..."
|
|
```
|
|
|
|
### Instalacion Backend
|
|
|
|
```bash
|
|
npm install firebase-admin
|
|
```
|
|
|
|
### Instalacion Mobile
|
|
|
|
```bash
|
|
npm install @react-native-firebase/app @react-native-firebase/messaging
|
|
```
|
|
|
|
---
|
|
|
|
## 4. Tipos de Notificaciones
|
|
|
|
| Tipo | Evento | Prioridad |
|
|
|------|--------|-----------|
|
|
| INVENTORY_READY | Inventario procesado | Alta |
|
|
| PAYMENT_CONFIRMED | Pago confirmado | Alta |
|
|
| PAYMENT_PENDING | Voucher por vencer | Media |
|
|
| REFERRAL_ACTIVATED | Referido activado | Media |
|
|
| LOW_CREDITS | Creditos bajos | Baja |
|
|
| PROMO_ACTIVE | Promocion activa | Baja |
|
|
|
|
---
|
|
|
|
## 5. Implementacion Backend
|
|
|
|
### Inicializacion
|
|
|
|
```typescript
|
|
import * as admin from 'firebase-admin';
|
|
|
|
@Module({})
|
|
export class FirebaseModule {
|
|
static forRoot(): DynamicModule {
|
|
admin.initializeApp({
|
|
credential: admin.credential.cert({
|
|
projectId: process.env.FIREBASE_PROJECT_ID,
|
|
clientEmail: process.env.FIREBASE_CLIENT_EMAIL,
|
|
privateKey: process.env.FIREBASE_PRIVATE_KEY.replace(/\\n/g, '\n'),
|
|
}),
|
|
});
|
|
|
|
return {
|
|
module: FirebaseModule,
|
|
global: true,
|
|
};
|
|
}
|
|
}
|
|
```
|
|
|
|
### Servicio de Notificaciones
|
|
|
|
```typescript
|
|
@Injectable()
|
|
export class NotificationsService {
|
|
async sendToUser(
|
|
userId: string,
|
|
notification: { title: string; body: string; data?: Record<string, string> }
|
|
) {
|
|
const user = await this.usersService.findOne(userId);
|
|
if (!user.fcmToken) return;
|
|
|
|
await admin.messaging().send({
|
|
token: user.fcmToken,
|
|
notification: {
|
|
title: notification.title,
|
|
body: notification.body,
|
|
},
|
|
data: notification.data,
|
|
android: {
|
|
priority: 'high',
|
|
notification: {
|
|
channelId: 'default',
|
|
sound: 'default',
|
|
},
|
|
},
|
|
apns: {
|
|
payload: {
|
|
aps: {
|
|
sound: 'default',
|
|
badge: 1,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
}
|
|
|
|
async sendToTopic(
|
|
topic: string,
|
|
notification: { title: string; body: string }
|
|
) {
|
|
await admin.messaging().sendToTopic(topic, {
|
|
notification,
|
|
});
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 6. Implementacion Mobile
|
|
|
|
### Configuracion
|
|
|
|
```typescript
|
|
// App.tsx
|
|
import messaging from '@react-native-firebase/messaging';
|
|
|
|
const requestPermission = async () => {
|
|
const authStatus = await messaging().requestPermission();
|
|
const enabled =
|
|
authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
|
|
authStatus === messaging.AuthorizationStatus.PROVISIONAL;
|
|
|
|
if (enabled) {
|
|
const token = await messaging().getToken();
|
|
await api.updateFcmToken(token);
|
|
}
|
|
};
|
|
```
|
|
|
|
### Handlers
|
|
|
|
```typescript
|
|
// Foreground
|
|
messaging().onMessage(async remoteMessage => {
|
|
// Mostrar notificacion in-app
|
|
showLocalNotification(remoteMessage);
|
|
});
|
|
|
|
// Background/Quit
|
|
messaging().setBackgroundMessageHandler(async remoteMessage => {
|
|
// Procesar datos
|
|
console.log('Background message:', remoteMessage);
|
|
});
|
|
|
|
// Tap en notificacion
|
|
messaging().onNotificationOpenedApp(remoteMessage => {
|
|
// Navegar a pantalla
|
|
navigateToScreen(remoteMessage.data.screen);
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## 7. Modelo de Datos
|
|
|
|
### Tabla: notification_tokens
|
|
```sql
|
|
CREATE TABLE notification_tokens (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id UUID REFERENCES users(id),
|
|
token VARCHAR(255) NOT NULL,
|
|
platform VARCHAR(20), -- 'ios', 'android'
|
|
device_info JSONB,
|
|
is_active BOOLEAN DEFAULT true,
|
|
created_at TIMESTAMP DEFAULT NOW(),
|
|
updated_at TIMESTAMP DEFAULT NOW()
|
|
);
|
|
```
|
|
|
|
### Tabla: notification_logs
|
|
```sql
|
|
CREATE TABLE notification_logs (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id UUID REFERENCES users(id),
|
|
type VARCHAR(50),
|
|
title VARCHAR(255),
|
|
body TEXT,
|
|
data JSONB,
|
|
sent_at TIMESTAMP DEFAULT NOW(),
|
|
delivered_at TIMESTAMP,
|
|
opened_at TIMESTAMP
|
|
);
|
|
```
|
|
|
|
---
|
|
|
|
## 8. Templates de Notificacion
|
|
|
|
```typescript
|
|
const NOTIFICATION_TEMPLATES = {
|
|
INVENTORY_READY: {
|
|
title: 'Inventario listo',
|
|
body: 'Tu inventario de {{storeName}} esta listo. {{totalItems}} productos detectados.',
|
|
},
|
|
PAYMENT_CONFIRMED: {
|
|
title: 'Pago confirmado',
|
|
body: 'Tu pago de ${{amount}} MXN fue confirmado. +{{credits}} creditos.',
|
|
},
|
|
REFERRAL_ACTIVATED: {
|
|
title: 'Referido activado',
|
|
body: '{{referredName}} activo su cuenta. +{{reward}} creditos.',
|
|
},
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
## 9. Testing
|
|
|
|
### Enviar Notificacion de Prueba
|
|
|
|
```bash
|
|
# Usando Firebase CLI
|
|
firebase messaging:send \
|
|
--token "device_token" \
|
|
--notification-title "Test" \
|
|
--notification-body "This is a test"
|
|
```
|
|
|
|
### Simulador iOS
|
|
|
|
FCM no funciona en simulador iOS. Usar dispositivo fisico o Expo Go.
|
|
|
|
---
|
|
|
|
## 10. Referencias
|
|
|
|
- [Firebase FCM Docs](https://firebase.google.com/docs/cloud-messaging)
|
|
- [React Native Firebase](https://rnfirebase.io/messaging/usage)
|
|
- [MII-005](../01-epicas/MII-005-procesamiento-ia.md) - Notificacion de resultado
|
|
|
|
---
|
|
|
|
**Ultima Actualizacion:** 2026-01-10
|