Files

18 KiB

Auditoría Completa — ProsApp Migration

Fecha: 2026-06-02 Proyecto: Migración de Firebase a NestJS + PostgreSQL + Coolify


Índice

  1. Resumen Ejecutivo
  2. Arquitectura General
  3. Backend NestJS
  4. Admin Panel Next.js
  5. prosappco (App Móvil Flutter)
  6. prosapp_web_app (Web Flutter)
  7. dashpro (Admin Laravel)
  8. prosapp (Landing Page)
  9. Base de Datos PostgreSQL
  10. Issues Críticos
  11. Plan de Migración por Fases

1. Resumen Ejecutivo

El ecosistema ProsApp consta de 5 proyectos que operaban sobre una arquitectura 100% Firebase (Auth + Firestore + Storage + Messaging + Functions). Actualmente se migra a un backend NestJS con PostgreSQL y un nuevo admin panel Next.js, manteniendo las apps Flutter como clientes.

Proyecto Tipo Stack Actual Estado Migración
backend/ API REST NestJS + Prisma + PostgreSQL Completado
admin/ Panel Admin Next.js 16 + shadcn/ui Construido
prosappco/ App Móvil Flutter + Bloc + Firebase Pendiente
prosapp_web_app/ Web App Flutter + Provider + Firebase Pendiente
dashpro/ Admin Legacy Laravel 8 + Firebase + MongoDB 🔄 Reemplazado
prosapp/ Landing Page HTML + Tailwind CDN Sin cambios

Total código fuente: ~69 archivos backend, ~31 admin, ~167 prosappco, ~95 web_app, ~40 dashpro


2. Arquitectura General

2.1 Antes (Firebase-centric)

prosappco ──→ Firebase Auth + Firestore (SDK cliente)
prosapp_web ──→ Firebase Auth + Firestore (SDK cliente)
dashpro ────→ Firebase Admin SDK + Firestore (Laravel servidor)
Functions ──→ Firebase Cloud Functions (notificaciones)

2.2 Después (NestJS API)

prosappco ──→ NestJS API (HTTP/JSON) ──→ PostgreSQL
prosapp_web ──→ NestJS API (HTTP/JSON) ──→ PostgreSQL
admin ──────→ NestJS API (HTTP/JSON) ──→ PostgreSQL
prosapp ────→ (sin cambios - HTML estático)

2.3 Servicios compartidos

Servicio Antes Después
Auth Firebase Auth (email, phone, Google) JWT (passport-jwt, 7 días exp)
DB Usuarios Firestore users + professional_info PostgreSQL + Prisma ORM
DB Admin MongoDB Atlas PostgreSQL (misma)
Archivos Firebase Storage Pendiente (MinIO/S3)
Notificaciones FCM directo desde cliente Pendiente (endpoint NestJS)
WebSockets Firestore snapshots Socket.IO con JWT
API Docs No existía Swagger en /docs

3. Backend NestJS

3.1 Ficha técnica

Atributo Valor
Framework NestJS 11.1.24
ORM Prisma 7.8.0 (@prisma/client)
Base de datos PostgreSQL 16 en Coolify
Host 46.202.93.92:5432
DB prosapp / User: prosapp_user
Puerto 3000
Prefijo API /api/v1
Auth Passport + JWT (7 días expiración)
Validación class-validator + ValidationPipe global
WebSocket Socket.IO (@nestjs/platform-socket.io)
Documentación Swagger en /docs

3.2 Módulos y Endpoints

Módulo Endpoints Auth Archivos
Auth POST /register, /login, /phone, /verify-phone, /link-email; GET /me 3 públicos, 3 JWT 6 archivos
Users GET /me, PATCH /me, PATCH /me/fcm-token, GET /:id 3 JWT, 1 público 3 archivos
Professionals GET /, /pending, /me, /:id; POST /request, /:id/approve, /:id/deny; PATCH /me, /me/schedules 7 JWT, 2 públicos 7 archivos
Services POST /; GET /me, /professional, /professional/requests, /professional/history, /me/history, /professional/calendar, /public-calendar/:id, /:id; PATCH /:id/status 9 JWT, 1 público 10 archivos
Comments POST /; GET /user/:id, /professional/:id, /reputation/:id 1 JWT, 3 públicos 4 archivos
Chat POST /start/:id, /:id/message; GET /my, /:id/messages Todos JWT 4 archivos REST + Gateway WS
Locations GET /countries, /countries/:id/regions, /regions/:id/cities Todos públicos 3 archivos
Professions GET / Público 1 archivo
Settings GET / Público 1 archivo
Storage POST /upload JWT 1 archivo

Total: ~37 endpoints + WebSocket Gateway

3.3 Modelos Prisma (15 tablas)

users ──→ professionals (1:1)
users ──→ reputations (1:1)
users ──→ services (1:N)
users ──→ messages (1:N)
users ──→ chats (1:N como user_id y professional_id)
users ──→ comments (1:N como author_id y destination_id)
professionals ──→ schedules (1:N)
professionals ──→ specializations (1:N)
professionals ──→ payment_methods (1:1)
professionals ──→ services (1:N)
services ──→ comments (1:N)
chats ──→ messages (1:N, cascade)
countries ──→ regions ──→ cities

3.4 WebSocket Gateway

Evento Dirección Payload Descripción
connection Cliente→Server auth.token o query.token Auth JWT, join a user:{id}
disconnect Cliente→Server - Limpieza de socket
sendMessage Cliente→Server { chatId, content } Guarda y emite a ambos participantes
joinChat Cliente→Server chatId Join a sala chat:{id}
newMessage Server→Client message Notifica a ambos users

3.5 Issues del Backend

# Severidad Archivo Problema
1 🔴 Crítico chat/chat.service.ts getOrCreateChat() usa prof.id (PK de professionals) en vez de professionalUserId (FK users). Causa violación FK en runtime
2 🔴 Crítico .env Credenciales de BD hardcodeadas y commiteadas
3 🟠 Alto storage/ Upload no persiste archivos — es un no-op
4 🟠 Alto prisma/ No existe prisma/migrations — los cambios de esquema no tienen tracking
5 🟠 Alto Todos los findMany Sin paginación (skip/take) — rompe con datos reales
6 🟡 Medio auth.service.ts verifyOtpAndLinkPhone no hace verificación OTP real
7 🟡 Medio common/roles.guard.ts RolesGuard y OwnershipGuard definidos pero no usados
8 🟡 Medio users.service.ts findAll() existe sin ruta HTTP — código muerto
9 🟢 Bajo auth/dto/auth.dto.ts PhoneDto.phone sin validación de formato
10 🟢 Bajo Chat Gateway Usa jsonwebtoken raw duplicando lógica JWT
11 🟢 Bajo professionals.controller.ts Orden de rutas frágil (/me antes de /:id

4. Admin Panel Next.js

4.1 Ficha técnica

Atributo Valor
Framework Next.js 16.2.7 (App Router)
UI shadcn/ui (base-nova) + Tailwind v4
Iconos Lucide React
Notificaciones Sonner
Auth JWT con localStorage
Build Compila sin errores

4.2 Rutas y Funcionalidad

Ruta Función Estado
/login Login email + password → JWT
/ Dashboard con stats (usuarios, profesionales, servicios)
/users Tabla con búsqueda por nombre/email/teléfono
/professionals Tabs: Activos / Pendientes (aprobar/rechazar)
/services Lista con filtro por estado + badges coloridos
/professions CRUD completo (agregar, eliminar profesiones)
/cities Vista jerárquica país → región → ciudad
/settings JSON de configuración global (solo lectura)

4.3 Issues del Admin

# Severidad Archivo Problema
1 🔴 Crítico layout.tsx AuthGuard está definido pero no se usa. Todas las rutas son públicas si se navega directo
2 🟠 Alto environ No hay .env.example — la URL base del API está hardcodeada a localhost
3 🟠 Alto Varios Sin estados de carga ni error para fallos de API (todo se traga con .catch(() => []))
4 🟡 Medio Todos Sin paginación en tablas
5 🟡 Medio settings/ Solo lectura — no hay formulario para editar configuración
6 🟡 Medio profession/ Solo add/delete — no se puede renombrar
7 🟢 Bajo General Sin modo oscuro (next-themes instalado pero sin toggle)

5. prosappco (App Móvil Flutter)

5.1 Ficha técnica

Atributo Valor
Tipo App móvil multiplataforma
Versión 1.0.14+14
SDK Dart >=2.19.3 <3.0.0
State Bloc (flutter_bloc 8.1.4)
DI Injector
Routing BlocBuilder (implícito)
Firebase Auth + Firestore + Storage + Messaging + Functions
Paquetes locales 8 repositorios (user, chat, professional, service, score, city, profession, setting)
Archivos Dart ~167
LOC estimado ~18,923

5.2 Firebase Collections usadas

Colección Uso
users Perfiles de usuario (cliente + profesional)
professional_info Datos profesionales (cédula, certificados, etc.)
services Solicitudes de servicio
countries v2 / Colombia Ciudades y departamentos
settings / global Configuración de la app
professions / professions Lista de profesiones
reputations Reputación acumulada
comments Calificaciones
chats Conversaciones

5.3 Issues

# Severidad Problema
1 🔴 Crítico FCM Server Key hardcodeada en local_notifications.dart — clave expuesta en cliente
2 🟠 Alto diacritic, flutter_animate, table_calendar estaban en null (ya corregido)
3 🟠 Alto firebase_storage nativo no declarado en pubspec principal (solo _web)
4 🟡 Medio SDK constraint >=2.19.3 incompatible con Firebase Messaging Web moderno
5 🟡 Medio google_sign_in declarado pero nunca usado
6 🟢 Bajo app.dart no usado (código muerto)
7 🟢 Bajo Typo en nombre de directorio sing_in_bloc/

5.4 Migración a NestJS

Esfuerzo estimado: 4-5 semanas

Cambios necesarios:

  1. Reescribir los 8 repositorios Firebase → HTTP API
  2. Reemplazar FirebaseAuth → JWT (register, login, OTP)
  3. Reemplazar FirebaseStorage → multipart upload a NestJS
  4. Reemplazar Firestore snapshots → polling o WebSocket
  5. Reemplazar FCM directo → endpoint NestJS de notificaciones
  6. Los BLoCs y UI pueden quedar igual (solo cambia capa de datos)

6. prosapp_web_app (Web Flutter)

6.1 Ficha técnica

Atributo Valor
Tipo Web app Flutter
Versión 1.0.0+1
SDK Dart >=3.4.1 <4.0.0
State Provider (ChangeNotifier)
DI get_it (declarado pero no usado)
Routing Fluro (28 rutas)
Firebase Auth + Firestore + Storage
Archivos Dart ~95
LOC estimado ~11,164

6.2 Issues

# Severidad Problema
1 🔴 Crítico FCM Server Key hardcodeada en local_notifications.dart
2 🟠 Alto http no estaba en pubspec.yaml (ya corregido)
3 🟡 Medio get_it declarado pero sin registros — código muerto
4 🟢 Bajo Sin firebase_messaging package (usa HTTP directo a FCM)

6.3 Migración a NestJS

Esfuerzo estimado: 3-4 semanas

Cambios necesarios:

  1. Refactorizar los 18 providers que llaman Firebase directo
  2. Crear capa de repositorio (hoy no existe)
  3. Reemplazar FirebaseAuth → JWT
  4. Reemplazar FirebaseStorage → upload a NestJS
  5. Reemplazar Firestore snapshots → polling o WebSocket
  6. UI y rutas Fluro pueden quedar igual

7. dashpro (Admin Laravel)

7.1 Ficha técnica

Atributo Valor
Framework Laravel 8.75
PHP ^7.3 / ^8.0
DB Admins MongoDB Atlas (vía jenssegers/mongodb)
DB App Firebase Firestore
Frontend Livewire 2.12 + Alpine.js + Tailwind CDN
Auth Admin Laravel Breeze (session-based, MongoDB)
Firebase SDK google/cloud-firestore, kreait/firebase-php
Storage Firebase Cloud Storage
Componentes 13 Livewire

7.2 Issues

# Severidad Problema
1 🔴 Crítico dd() en ShowSettings.php:223 — mata ejecución, notificaciones no se envían
2 🔴 Crítico dd() en MenuController.php:106 — ruta /noti rota
3 🔴 Crítico Route /confirmar/{id} sin auth — cualquiera puede aprobar servicios
4 🔴 Crítico MongoDB Atlas credenciales hardcodeadas en config/database.php
5 🔴 Crítico Firebase credentials filename mal en 2 Livewire components (ya corregido)
6 🟠 Alto Contraseña débil '123456' hardcodeada en 4 componentes
7 🟠 Alto Google Maps API key hardcodeada en MenuController.php
8 🟠 Alto config/firebase.php no existe — paquete kreait/laravel-firebase sin config
9 🟡 Medio FirebaseDataExport usa campos incorrectos (phoneNumber vs phone)
10 🟡 Medio Notificación solicitud.php referencia $name que nunca se pasa

7.3 Reemplazo

dashpro no se migrará — será reemplazado por el nuevo admin panel Next.js que ya consume directamente la API NestJS.


8. prosapp (Landing Page)

8.1 Ficha técnica

Atributo Valor
Tipo HTML estático
CSS Tailwind CDN
JS Alpine.js 3.x CDN
Archivos 1 HTML (398 lines) + 7 imágenes

8.2 Issues

Ninguno. No requiere migración.


9. Base de Datos PostgreSQL

9.1 Conexión

Host: 46.202.93.92
Puerto: 5432
Base de datos: prosapp
Usuario: prosapp_user
Password: DateTGNpxQfoPkE6OA2fOl9M10

9.2 Modelos (15 tablas)

Tabla Columnas PK FKs
users 17 id (uuid) -
professionals 18 id (uuid) user_id → users
services 19 id (uuid) professional_id → professionals, user_id → users
comments 8 id (uuid) author_id → users, destination_id → users, service_id → services
chats 4 id (uuid) user_id → users, professional_id → users
messages 5 id (uuid) chat_id → chats (cascade), sender_id → users
professions 2 id (uuid) -
specializations 4 id (uuid) professional_id → professionals (cascade)
schedules 9 id (uuid) professional_id → professionals (cascade)
payment_methods 5 id (uuid) professional_id → professionals (cascade)
reputations 6 user_id (uuid) user_id → users (cascade)
countries 2 id (uuid) -
regions 3 id (uuid) country_id → countries (cascade)
cities 5 id (uuid) region_id → regions (cascade)
settings 3 key (varchar) -

9.3 Enums

  • service_status: pending, accepted, denied, active, cancelled, completed, self_booked
  • service_location: office, delivery

9.4 Triggers

  • update_reputation() — actualiza reputación automáticamente al insertar/actualizar comments

10. Issues Críticos

🔴 Deben resolverse antes del deploy a producción

ID Proyecto Issue Solución
C-1 Backend chat.service.ts usa prof.id en vez de professionalUserId Cambiar a professionalUserId
C-2 Backend .env con credenciales commiteadas Agregar .env a .gitignore, usar variables de entorno en Coolify
C-3 Backend Storage upload es no-op Implementar subida a disco/S3/MinIO
C-4 Backend Sin migraciones Prisma Ejecutar prisma migrate dev para crear historial
C-5 Backend Sin paginación en listados Agregar skip/take con defaults
C-6 Admin Sin auth guard en rutas Conectar AuthGuard en layout o middleware
C-7 prosappco FCM key hardcodeada Mover a servidor, usar endpoint NestJS
C-8 prosapp_web FCM key hardcodeada Mover a servidor, usar endpoint NestJS
C-9 dashpro 2x dd() matan funcionalidad Reemplazar con logs, eliminar dd()
C-10 dashpro /confirmar sin auth Agregar middleware auth
C-11 dashpro MongoDB creds hardcodeadas Usar env vars

11. Plan de Migración por Fases

Fase 1: Completar Backend (en progreso)

  • Corregir issue C-1 (chat FK)
  • Corregir issue C-4 (migraciones Prisma)
  • Corregir issue C-5 (paginación)
  • Implementar storage real (C-3)
  • Agregar health check endpoint
  • Agregar rate limiting
  • Desplegar en Coolify

Fase 2: Asegurar Admin Panel

  • Conectar AuthGuard (C-6)
  • Agregar .env.example
  • Agregar estados de carga/error
  • Implementar páginas de detalle (profesionales, servicios, usuarios)
  • Deploy en Coolify

Fase 3: Migrar prosapp_web_app

  • Crear API service layer
  • Migrar auth (JWT reemplaza FirebaseAuth)
  • Migrar 18 providers uno por uno
  • Reemplazar Storage
  • WebSockets para chat

Fase 4: Migrar prosappco

  • Reescribir 8 repositorios locales
  • Migrar auth
  • Migrar storage
  • Migrar notificaciones push
  • [ ) Reemplazar Firestore snapshots

Fase 5: Retirar dashpro

  • Verificar paridad funcional con admin nuevo
  • Crear módulos faltantes en admin (CRUD ciudades, editor settings)
  • Dar de baja dashpro
  • Eliminar Firebase project

Fin del documento de auditoría