Files
prosapp-migration/docs.html
T

528 lines
32 KiB
HTML

<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ProsApp — Documentación del Sistema</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
* { font-family: 'Inter', sans-serif; }
html { scroll-behavior: smooth; }
.card-hover { transition: transform 0.15s, box-shadow 0.15s; }
.card-hover:hover { transform: translateY(-2px); box-shadow: 0 8px 24px rgba(0,0,0,0.08); }
pre { overflow-x: auto; }
</style>
</head>
<body class="bg-gray-50 text-gray-900">
<nav class="fixed top-0 left-0 right-0 z-50 bg-white/80 backdrop-blur border-b">
<div class="max-w-6xl mx-auto px-4 h-14 flex items-center gap-6 text-sm">
<span class="font-bold text-base">ProsApp</span>
<a href="#backend" class="text-gray-600 hover:text-gray-900">Backend</a>
<a href="#admin" class="text-gray-600 hover:text-gray-900">Admin</a>
<a href="#apps" class="text-gray-600 hover:text-gray-900">Apps</a>
<a href="#db" class="text-gray-600 hover:text-gray-900">BD</a>
<a href="#issues" class="text-gray-600 hover:text-gray-900">Issues</a>
<a href="#plan" class="text-gray-600 hover:text-gray-900">Plan</a>
</div>
</nav>
<div class="max-w-6xl mx-auto px-4 pt-20 pb-20 space-y-16">
<!-- Header -->
<div class="text-center space-y-3">
<h1 class="text-4xl font-bold">ProsApp Migration</h1>
<p class="text-lg text-gray-500">Arquitectura completa del ecosistema ProsApp · Firebase → NestJS + PostgreSQL</p>
<div class="flex gap-3 justify-center text-sm">
<span class="px-3 py-1 bg-blue-100 text-blue-700 rounded-full">Backend NestJS</span>
<span class="px-3 py-1 bg-green-100 text-green-700 rounded-full">Admin Next.js</span>
<span class="px-3 py-1 bg-purple-100 text-purple-700 rounded-full">Flutter Mobile</span>
<span class="px-3 py-1 bg-orange-100 text-orange-700 rounded-full">Flutter Web</span>
</div>
</div>
<!-- Architecture Diagram -->
<section class="bg-white rounded-2xl p-8 shadow-sm border card-hover">
<h2 class="text-2xl font-bold mb-6">Arquitectura</h2>
<div class="grid md:grid-cols-3 gap-6 text-center">
<div class="space-y-2 p-4 bg-blue-50 rounded-xl">
<div class="font-semibold text-blue-700">Clientes</div>
<div class="text-sm text-gray-600 space-y-1">
<div class="bg-white rounded-lg p-2 shadow-sm">prosappco (Flutter/Bloc)</div>
<div class="bg-white rounded-lg p-2 shadow-sm">prosapp_web_app (Flutter/Provider)</div>
</div>
</div>
<div class="space-y-2 p-4 bg-green-50 rounded-xl">
<div class="font-semibold text-green-700">API</div>
<div class="text-sm text-gray-600 space-y-1">
<div class="bg-white rounded-lg p-2 shadow-sm">NestJS · api/v1 · JWT</div>
<div class="bg-white rounded-lg p-2 shadow-sm">WebSocket Socket.IO</div>
<div class="bg-white rounded-lg p-2 shadow-sm">Swagger /docs</div>
</div>
</div>
<div class="space-y-2 p-4 bg-purple-50 rounded-xl">
<div class="font-semibold text-purple-700">Admin</div>
<div class="text-sm text-gray-600 space-y-1">
<div class="bg-white rounded-lg p-2 shadow-sm">Next.js + shadcn/ui (NUEVO)</div>
<div class="bg-white rounded-lg p-2 shadow-sm border border-red-200 text-red-500 line-through">dashpro (Laravel · LEGACY)</div>
</div>
</div>
</div>
<div class="mt-4 text-center text-sm text-gray-400">
Base de datos: PostgreSQL 16 en Coolify · 15 tablas · Prisma ORM
</div>
</section>
<!-- Backend -->
<section id="backend" class="scroll-mt-20 space-y-4">
<h2 class="text-2xl font-bold border-b pb-2">Backend NestJS</h2>
<div class="grid md:grid-cols-2 gap-4 text-sm">
<div class="bg-white rounded-xl p-5 shadow-sm border card-hover">
<h3 class="font-semibold mb-3">Módulos y Endpoints</h3>
<table class="w-full text-left">
<thead><tr class="text-gray-500 border-b"><th class="pb-1">Módulo</th><th class="pb-1">Endpoints</th><th class="pb-1">Auth</th></tr></thead>
<tbody class="divide-y">
<tr><td class="py-1.5 font-medium">Auth</td><td class="py-1.5 text-gray-600">register, login, phone, me</td><td class="py-1.5"><span class="text-green-600">3 público</span> · <span class="text-orange-600">3 JWT</span></td></tr>
<tr><td class="py-1.5 font-medium">Users</td><td class="py-1.5 text-gray-600">me, update, fcm-token</td><td class="py-1.5"><span class="text-orange-600">3 JWT</span></td></tr>
<tr><td class="py-1.5 font-medium">Professionals</td><td class="py-1.5 text-gray-600">list, pending, approve, deny, request, schedules</td><td class="py-1.5"><span class="text-green-600">2 público</span> · <span class="text-orange-600">7 JWT</span></td></tr>
<tr><td class="py-1.5 font-medium">Services</td><td class="py-1.5 text-gray-600">create, list, history, calendar, status</td><td class="py-1.5"><span class="text-green-600">1 público</span> · <span class="text-orange-600">9 JWT</span></td></tr>
<tr><td class="py-1.5 font-medium">Comments</td><td class="py-1.5 text-gray-600">create, scores, reputation</td><td class="py-1.5"><span class="text-green-600">3 público</span> · <span class="text-orange-600">1 JWT</span></td></tr>
<tr><td class="py-1.5 font-medium">Chat</td><td class="py-1.5 text-gray-600">start, message, list + WebSocket</td><td class="py-1.5"><span class="text-orange-600">4 JWT</span></td></tr>
<tr><td class="py-1.5 font-medium">Locations</td><td class="py-1.5 text-gray-600">countries, regions, cities</td><td class="py-1.5"><span class="text-green-600">3 público</span></td></tr>
<tr><td class="py-1.5 font-medium">Professions</td><td class="py-1.5 text-gray-600">list</td><td class="py-1.5"><span class="text-green-600">1 público</span></td></tr>
<tr><td class="py-1.5 font-medium">Settings</td><td class="py-1.5 text-gray-600">global settings</td><td class="py-1.5"><span class="text-green-600">1 público</span></td></tr>
<tr><td class="py-1.5 font-medium">Storage</td><td class="py-1.5 text-gray-600">upload (multer)</td><td class="py-1.5"><span class="text-orange-600">JWT</span></td></tr>
</tbody>
</table>
</div>
<div class="space-y-4">
<div class="bg-white rounded-xl p-5 shadow-sm border card-hover">
<h3 class="font-semibold mb-2">Stack</h3>
<div class="space-y-1 text-sm text-gray-600">
<div><span class="text-gray-400 w-24 inline-block">Framework</span> NestJS 11.1.24</div>
<div><span class="text-gray-400 w-24 inline-block">ORM</span> Prisma 7.8.0</div>
<div><span class="text-gray-400 w-24 inline-block">Auth</span> Passport + JWT (7d)</div>
<div><span class="text-gray-400 w-24 inline-block">WS</span> Socket.IO</div>
<div><span class="text-gray-400 w-24 inline-block">Docs</span> Swagger /docs</div>
<div><span class="text-gray-400 w-24 inline-block">Puerto</span> 3000 · prefijo /api/v1</div>
</div>
</div>
<div class="bg-white rounded-xl p-5 shadow-sm border card-hover">
<h3 class="font-semibold mb-2">WebSocket Gateway</h3>
<div class="text-sm text-gray-600 space-y-1">
<div><code class="bg-gray-100 px-1.5 py-0.5 rounded">connection</code> Auth JWT → sala user:{id}</div>
<div><code class="bg-gray-100 px-1.5 py-0.5 rounded">sendMessage</code> { chatId, content }</div>
<div><code class="bg-gray-100 px-1.5 py-0.5 rounded">joinChat</code> Sala chat:{id}</div>
<div><code class="bg-gray-100 px-1.5 py-0.5 rounded">newMessage</code> Emitido a ambos participantes</div>
</div>
</div>
</div>
</div>
</section>
<!-- Admin Panel -->
<section id="admin" class="scroll-mt-20 space-y-4">
<h2 class="text-2xl font-bold border-b pb-2">Admin Panel Next.js</h2>
<div class="grid md:grid-cols-2 gap-4">
<div class="bg-white rounded-xl p-5 shadow-sm border card-hover">
<h3 class="font-semibold mb-3">Rutas</h3>
<table class="w-full text-sm text-left">
<thead><tr class="text-gray-500 border-b"><th class="pb-1">Ruta</th><th class="pb-1">Función</th></tr></thead>
<tbody class="divide-y">
<tr><td class="py-1 font-medium">/login</td><td class="py-1 text-gray-600">Login JWT (email + password)</td></tr>
<tr><td class="py-1 font-medium">/</td><td class="py-1 text-gray-600">Dashboard con stats en vivo</td></tr>
<tr><td class="py-1 font-medium">/users</td><td class="py-1 text-gray-600">Tabla de usuarios con búsqueda</td></tr>
<tr><td class="py-1 font-medium">/professionals</td><td class="py-1 text-gray-600">Activos / Pendientes · aprobar/rechazar</td></tr>
<tr><td class="py-1 font-medium">/services</td><td class="py-1 text-gray-600">Lista con filtro por estado</td></tr>
<tr><td class="py-1 font-medium">/professions</td><td class="py-1 text-gray-600">CRUD (agregar, eliminar)</td></tr>
<tr><td class="py-1 font-medium">/cities</td><td class="py-1 text-gray-600">País → Región → Ciudad</td></tr>
<tr><td class="py-1 font-medium">/settings</td><td class="py-1 text-gray-600">Ver JSON configuración global</td></tr>
</tbody>
</table>
</div>
<div class="bg-white rounded-xl p-5 shadow-sm border card-hover">
<h3 class="font-semibold mb-2">Stack</h3>
<div class="space-y-1 text-sm text-gray-600">
<div><span class="text-gray-400 w-24 inline-block">Framework</span> Next.js 16.2.7</div>
<div><span class="text-gray-400 w-24 inline-block">Estilos</span> Tailwind v4 + shadcn/ui</div>
<div><span class="text-gray-400 w-24 inline-block">Iconos</span> Lucide React</div>
<div><span class="text-gray-400 w-24 inline-block">Toast</span> Sonner</div>
<div><span class="text-gray-400 w-24 inline-block">Auth</span> JWT vía localStorage</div>
<div><span class="text-gray-400 w-24 inline-block">API URL</span> NEXT_PUBLIC_API_URL</div>
</div>
<h3 class="font-semibold mt-4 mb-2">Componentes UI instalados</h3>
<div class="flex flex-wrap gap-1.5">
<span class="px-2 py-0.5 bg-gray-100 rounded text-xs">button</span>
<span class="px-2 py-0.5 bg-gray-100 rounded text-xs">card</span>
<span class="px-2 py-0.5 bg-gray-100 rounded text-xs">table</span>
<span class="px-2 py-0.5 bg-gray-100 rounded text-xs">tabs</span>
<span class="px-2 py-0.5 bg-gray-100 rounded text-xs">select</span>
<span class="px-2 py-0.5 bg-gray-100 rounded text-xs">input</span>
<span class="px-2 py-0.5 bg-gray-100 rounded text-xs">badge</span>
<span class="px-2 py-0.5 bg-gray-100 rounded text-xs">avatar</span>
<span class="px-2 py-0.5 bg-gray-100 rounded text-xs">dropdown-menu</span>
<span class="px-2 py-0.5 bg-gray-100 rounded text-xs">sheet</span>
<span class="px-2 py-0.5 bg-gray-100 rounded text-xs">sonner</span>
</div>
</div>
</div>
</section>
<!-- Flutter Apps -->
<section id="apps" class="scroll-mt-20 space-y-4">
<h2 class="text-2xl font-bold border-b pb-2">Apps Flutter</h2>
<div class="grid md:grid-cols-2 gap-4">
<div class="bg-white rounded-xl p-5 shadow-sm border card-hover">
<div class="flex items-center gap-2 mb-3">
<span class="px-2 py-0.5 bg-purple-100 text-purple-700 rounded text-xs font-medium">MÓVIL</span>
<h3 class="font-semibold">prosappco</h3>
</div>
<div class="text-sm text-gray-600 space-y-1">
<div><span class="text-gray-400 w-28 inline-block">Versión</span> 1.0.14+14</div>
<div><span class="text-gray-400 w-28 inline-block">SDK</span> Dart &gt;=2.19.3</div>
<div><span class="text-gray-400 w-28 inline-block">State</span> Bloc 8.1.4</div>
<div><span class="text-gray-400 w-28 inline-block">DI</span> Injector</div>
<div><span class="text-gray-400 w-28 inline-block">Routing</span> BlocBuilder implícito</div>
<div><span class="text-gray-400 w-28 inline-block">Archivos</span> ~167 Dart · ~18,923 LOC</div>
<div><span class="text-gray-400 w-28 inline-block">Firebase</span> Auth, Firestore, Storage, Messaging, Functions</div>
</div>
<h4 class="font-medium mt-4 mb-1 text-xs uppercase tracking-wider text-gray-400">8 Repositorios Locales</h4>
<div class="flex flex-wrap gap-1.5">
<span class="px-2 py-0.5 bg-purple-50 rounded text-xs">user</span>
<span class="px-2 py-0.5 bg-purple-50 rounded text-xs">professional</span>
<span class="px-2 py-0.5 bg-purple-50 rounded text-xs">service</span>
<span class="px-2 py-0.5 bg-purple-50 rounded text-xs">chat</span>
<span class="px-2 py-0.5 bg-purple-50 rounded text-xs">score</span>
<span class="px-2 py-0.5 bg-purple-50 rounded text-xs">city</span>
<span class="px-2 py-0.5 bg-purple-50 rounded text-xs">profession</span>
<span class="px-2 py-0.5 bg-purple-50 rounded text-xs">setting</span>
</div>
<h4 class="font-medium mt-4 mb-1 text-xs uppercase tracking-wider text-gray-400">14 BLoCs</h4>
<div class="flex flex-wrap gap-1.5">
<span class="px-2 py-0.5 bg-purple-50 rounded text-xs">authentication</span>
<span class="px-2 py-0.5 bg-purple-50 rounded text-xs">my_user</span>
<span class="px-2 py-0.5 bg-purple-50 rounded text-xs">profile</span>
<span class="px-2 py-0.5 bg-purple-50 rounded text-xs">professional</span>
<span class="px-2 py-0.5 bg-purple-50 rounded text-xs">professional_profile</span>
<span class="px-2 py-0.5 bg-purple-50 rounded text-xs">professional_list</span>
<span class="px-2 py-0.5 bg-purple-50 rounded text-xs">chat</span>
<span class="px-2 py-0.5 bg-purple-50 rounded text-xs">notification</span>
<span class="px-2 py-0.5 bg-purple-50 rounded text-xs">score</span>
<span class="px-2 py-0.5 bg-purple-50 rounded text-xs">service</span>
<span class="px-2 py-0.5 bg-purple-50 rounded text-xs">setting</span>
<span class="px-2 py-0.5 bg-purple-50 rounded text-xs">sign_up / sign_in</span>
<span class="px-2 py-0.5 bg-purple-50 rounded text-xs">auth</span>
</div>
</div>
<div class="bg-white rounded-xl p-5 shadow-sm border card-hover">
<div class="flex items-center gap-2 mb-3">
<span class="px-2 py-0.5 bg-orange-100 text-orange-700 rounded text-xs font-medium">WEB</span>
<h3 class="font-semibold">prosapp_web_app</h3>
</div>
<div class="text-sm text-gray-600 space-y-1">
<div><span class="text-gray-400 w-28 inline-block">Versión</span> 1.0.0+1</div>
<div><span class="text-gray-400 w-28 inline-block">SDK</span> Dart &gt;=3.4.1</div>
<div><span class="text-gray-400 w-28 inline-block">State</span> Provider (ChangeNotifier)</div>
<div><span class="text-gray-400 w-28 inline-block">Routing</span> Fluro (28 rutas)</div>
<div><span class="text-gray-400 w-28 inline-block">Archivos</span> ~95 Dart · ~11,164 LOC</div>
<div><span class="text-gray-400 w-28 inline-block">Firebase</span> Auth, Firestore, Storage</div>
</div>
<h4 class="font-medium mt-4 mb-1 text-xs uppercase tracking-wider text-gray-400">18 Providers</h4>
<div class="flex flex-wrap gap-1.5">
<span class="px-2 py-0.5 bg-orange-50 rounded text-xs">auth</span>
<span class="px-2 py-0.5 bg-orange-50 rounded text-xs">professional</span>
<span class="px-2 py-0.5 bg-orange-50 rounded text-xs">professionals</span>
<span class="px-2 py-0.5 bg-orange-50 rounded text-xs">services</span>
<span class="px-2 py-0.5 bg-orange-50 rounded text-xs">calendar_services</span>
<span class="px-2 py-0.5 bg-orange-50 rounded text-xs">chat</span>
<span class="px-2 py-0.5 bg-orange-50 rounded text-xs">cities</span>
<span class="px-2 py-0.5 bg-orange-50 rounded text-xs">professions</span>
<span class="px-2 py-0.5 bg-orange-50 rounded text-xs">professional_detail</span>
<span class="px-2 py-0.5 bg-orange-50 rounded text-xs">professional_form</span>
<span class="px-2 py-0.5 bg-orange-50 rounded text-xs">profile_form</span>
<span class="px-2 py-0.5 bg-orange-50 rounded text-xs">settings</span>
<span class="px-2 py-0.5 bg-orange-50 rounded text-xs">score</span>
<span class="px-2 py-0.5 bg-orange-50 rounded text-xs">sidemenu</span>
<span class="px-2 py-0.5 bg-orange-50 rounded text-xs">login_form / register_form / phone_form / email_form</span>
</div>
</div>
</div>
</section>
<!-- Landing Page -->
<section class="space-y-2">
<h2 class="text-xl font-bold">prosapp/ (Landing Page)</h2>
<div class="bg-white rounded-xl p-5 shadow-sm border">
<p class="text-sm text-gray-600">HTML estático + Tailwind CDN + Alpine.js. Sin backend. Sin cambios necesarios.</p>
<p class="text-sm text-gray-600 mt-1">1 archivo (398 líneas) · 7 imágenes · Sin dependencias npm</p>
</div>
</section>
<!-- Database -->
<section id="db" class="scroll-mt-20 space-y-4">
<h2 class="text-2xl font-bold border-b pb-2">Base de Datos PostgreSQL</h2>
<div class="grid md:grid-cols-2 gap-4">
<div class="bg-white rounded-xl p-5 shadow-sm border card-hover">
<h3 class="font-semibold mb-3">Conexión</h3>
<pre class="bg-gray-50 rounded-lg p-3 text-xs">Host: 46.202.93.92:5432
Database: prosapp
User: prosapp_user</pre>
<h3 class="font-semibold mt-4 mb-2">15 Tablas</h3>
<div class="grid grid-cols-2 gap-1 text-sm">
<div class="flex items-center gap-2"><span class="w-2 h-2 rounded-full bg-blue-500"></span>users</div>
<div class="flex items-center gap-2"><span class="w-2 h-2 rounded-full bg-green-500"></span>professionals</div>
<div class="flex items-center gap-2"><span class="w-2 h-2 rounded-full bg-purple-500"></span>services</div>
<div class="flex items-center gap-2"><span class="w-2 h-2 rounded-full bg-orange-500"></span>comments</div>
<div class="flex items-center gap-2"><span class="w-2 h-2 rounded-full bg-pink-500"></span>chats</div>
<div class="flex items-center gap-2"><span class="w-2 h-2 rounded-full bg-red-500"></span>messages</div>
<div class="flex items-center gap-2"><span class="w-2 h-2 rounded-full bg-teal-500"></span>professions</div>
<div class="flex items-center gap-2"><span class="w-2 h-2 rounded-full bg-indigo-500"></span>specializations</div>
<div class="flex items-center gap-2"><span class="w-2 h-2 rounded-full bg-yellow-500"></span>schedules</div>
<div class="flex items-center gap-2"><span class="w-2 h-2 rounded-full bg-cyan-500"></span>payment_methods</div>
<div class="flex items-center gap-2"><span class="w-2 h-2 rounded-full bg-gray-500"></span>reputations</div>
<div class="flex items-center gap-2"><span class="w-2 h-2 rounded-full bg-lime-500"></span>countries</div>
<div class="flex items-center gap-2"><span class="w-2 h-2 rounded-full bg-emerald-500"></span>regions</div>
<div class="flex items-center gap-2"><span class="w-2 h-2 rounded-full bg-sky-500"></span>cities</div>
<div class="flex items-center gap-2"><span class="w-2 h-2 rounded-full bg-violet-500"></span>settings</div>
</div>
</div>
<div class="bg-white rounded-xl p-5 shadow-sm border card-hover">
<h3 class="font-semibold mb-3">Relaciones Clave</h3>
<div class="text-sm space-y-2">
<div class="bg-gray-50 rounded-lg p-3">
<div class="font-medium">users 1:1 professionals</div>
<div class="text-gray-500 text-xs">Un usuario puede ser profesional</div>
</div>
<div class="bg-gray-50 rounded-lg p-3">
<div class="font-medium">professional 1:N services</div>
<div class="text-gray-500 text-xs">Un profesional tiene muchos servicios</div>
</div>
<div class="bg-gray-50 rounded-lg p-3">
<div class="font-medium">users 1:N services (como cliente)</div>
<div class="text-gray-500 text-xs">Un usuario puede solicitar servicios</div>
</div>
<div class="bg-gray-50 rounded-lg p-3">
<div class="font-medium">chats 1:N messages (cascade)</div>
<div class="text-gray-500 text-xs">Un chat tiene muchos mensajes</div>
</div>
</div>
<h3 class="font-semibold mt-4 mb-1">Enums</h3>
<div class="text-sm"><span class="font-medium">service_status:</span> pending, accepted, denied, active, cancelled, completed, self_booked</div>
<div class="text-sm"><span class="font-medium">service_location:</span> office, delivery</div>
<h3 class="font-semibold mt-3 mb-1">Triggers</h3>
<div class="text-sm">update_reputation() — actualiza reputación al insertar/actualizar comments</div>
</div>
</div>
</section>
<!-- Issues -->
<section id="issues" class="scroll-mt-20 space-y-4">
<h2 class="text-2xl font-bold border-b pb-2">Issues Críticos (11)</h2>
<div class="space-y-2">
<div class="bg-red-50 border border-red-200 rounded-xl p-4">
<div class="flex items-start gap-3">
<span class="text-lg shrink-0 mt-0.5">🔴</span>
<div>
<div class="font-semibold">C-1 · Chat FK violation</div>
<div class="text-sm text-red-700">chat.service.ts usa prof.id (PK professionals) en vez del userId. Causa violación de FK en runtime.</div>
</div>
</div>
</div>
<div class="bg-red-50 border border-red-200 rounded-xl p-4">
<div class="flex items-start gap-3">
<span class="text-lg shrink-0 mt-0.5">🔴</span>
<div>
<div class="font-semibold">C-2 · .env commiteado</div>
<div class="text-sm text-red-700">Credenciales de BD en .env dentro del repo. Mover a Coolify y agregar a .gitignore.</div>
</div>
</div>
</div>
<div class="bg-red-50 border border-red-200 rounded-xl p-4">
<div class="flex items-start gap-3">
<span class="text-lg shrink-0 mt-0.5">🔴</span>
<div>
<div class="font-semibold">C-3 · Storage no-op</div>
<div class="text-sm text-red-700">POST /storage/upload no persiste archivos. Solo devuelve una URL construida.</div>
</div>
</div>
</div>
<div class="bg-red-50 border border-red-200 rounded-xl p-4">
<div class="flex items-start gap-3">
<span class="text-lg shrink-0 mt-0.5">🔴</span>
<div>
<div class="font-semibold">C-4 · Sin migraciones Prisma</div>
<div class="text-sm text-red-700">No existe prisma/migrations/. Los cambios de schema no tienen tracking.</div>
</div>
</div>
</div>
<div class="bg-orange-50 border border-orange-200 rounded-xl p-4">
<div class="flex items-start gap-3">
<span class="text-lg shrink-0 mt-0.5">🟠</span>
<div>
<div class="font-semibold">C-5 · Sin paginación</div>
<div class="text-sm text-orange-700">Todos los findMany sin skip/take. Performance issues con datos reales.</div>
</div>
</div>
</div>
<div class="bg-red-50 border border-red-200 rounded-xl p-4">
<div class="flex items-start gap-3">
<span class="text-lg shrink-0 mt-0.5">🔴</span>
<div>
<div class="font-semibold">C-6 · Admin sin auth guard</div>
<div class="text-sm text-red-700">AuthGuard definido pero no conectado. Todas las rutas del admin son públicas.</div>
</div>
</div>
</div>
<div class="bg-red-50 border border-red-200 rounded-xl p-4">
<div class="flex items-start gap-3">
<span class="text-lg shrink-0 mt-0.5">🔴</span>
<div>
<div class="font-semibold">C-7 / C-8 · FCM Key hardcodeada</div>
<div class="text-sm text-red-700">prosappco y prosapp_web_app tienen la server key de Firebase Cloud Messaging en texto plano en el cliente.</div>
</div>
</div>
</div>
<div class="bg-red-50 border border-red-200 rounded-xl p-4">
<div class="flex items-start gap-3">
<span class="text-lg shrink-0 mt-0.5">🔴</span>
<div>
<div class="font-semibold">C-9 · dd() kills execution</div>
<div class="text-sm text-red-700">dashpro: ShowSettings.php:223 y MenuController.php:106 tienen dd() que detienen la ejecución.</div>
</div>
</div>
</div>
<div class="bg-red-50 border border-red-200 rounded-xl p-4">
<div class="flex items-start gap-3">
<span class="text-lg shrink-0 mt-0.5">🔴</span>
<div>
<div class="font-semibold">C-10 · /confirmar sin auth</div>
<div class="text-sm text-red-700">dashpro: ruta de aprobación de servicios accesible sin autenticación.</div>
</div>
</div>
</div>
<div class="bg-orange-50 border border-orange-200 rounded-xl p-4">
<div class="flex items-start gap-3">
<span class="text-lg shrink-0 mt-0.5">🟠</span>
<div>
<div class="font-semibold">C-11 · MongoDB creds hardcodeadas</div>
<div class="text-sm text-orange-700">dashpro/config/database.php contiene usuario y password de MongoDB Atlas en texto plano.</div>
</div>
</div>
</div>
</div>
</section>
<!-- Task Board -->
<section class="space-y-4">
<h2 class="text-2xl font-bold border-b pb-2">Estado de Tareas (utasker)</h2>
<div class="bg-white rounded-xl p-5 shadow-sm border">
<h3 class="font-semibold mb-3 text-green-700">✅ Completadas (10)</h3>
<div class="grid md:grid-cols-2 gap-2 text-sm">
<div class="bg-green-50 rounded-lg p-2">#1 Corregir pubspec.yaml prosappco (3 null versions)</div>
<div class="bg-green-50 rounded-lg p-2">#2 Agregar http a prosapp_web_app pubspec.yaml</div>
<div class="bg-green-50 rounded-lg p-2">#3 Eliminar propsapp_web_app (duplicado)</div>
<div class="bg-green-50 rounded-lg p-2">#4 Eliminar comment_entity copy.dart</div>
<div class="bg-green-50 rounded-lg p-2">#5 Verificar http en prosappco (ya estaba)</div>
<div class="bg-green-50 rounded-lg p-2">#6 Fix Firebase credentials filename en dashpro</div>
<div class="bg-green-50 rounded-lg p-2">#7-11 Plan de migración creado</div>
<div class="bg-green-50 rounded-lg p-2">#12-15 Fases de migración registradas</div>
</div>
<h3 class="font-semibold mt-5 mb-3 text-red-700">🔴 Críticas Pendientes (6)</h3>
<div class="space-y-1 text-sm">
<div class="bg-red-50 rounded-lg p-2 flex items-center gap-2">
<span class="w-5 h-5 rounded-full bg-red-500 text-white text-xs flex items-center justify-center shrink-0">16</span>
Fix chat FK: usar professionalUserId en vez de prof.id
</div>
<div class="bg-red-50 rounded-lg p-2 flex items-center gap-2">
<span class="w-5 h-5 rounded-full bg-red-500 text-white text-xs flex items-center justify-center shrink-0">17</span>
Agregar .env a .gitignore y mover credenciales a Coolify
</div>
<div class="bg-red-50 rounded-lg p-2 flex items-center gap-2">
<span class="w-5 h-5 rounded-full bg-red-500 text-white text-xs flex items-center justify-center shrink-0">18</span>
Implementar storage real en lugar de no-op
</div>
<div class="bg-red-50 rounded-lg p-2 flex items-center gap-2">
<span class="w-5 h-5 rounded-full bg-red-500 text-white text-xs flex items-center justify-center shrink-0">19</span>
Crear migraciones Prisma (prisma migrate dev)
</div>
<div class="bg-red-50 rounded-lg p-2 flex items-center gap-2">
<span class="w-5 h-5 rounded-full bg-red-500 text-white text-xs flex items-center justify-center shrink-0">20</span>
Agregar paginación a todos los findMany
</div>
<div class="bg-red-50 rounded-lg p-2 flex items-center gap-2">
<span class="w-5 h-5 rounded-full bg-red-500 text-white text-xs flex items-center justify-center shrink-0">21</span>
Conectar AuthGuard en layout del admin panel
</div>
</div>
<h3 class="font-semibold mt-5 mb-3 text-gray-500">⏳ Pendientes (5)</h3>
<div class="space-y-1 text-sm">
<div class="bg-gray-50 rounded-lg p-2">#7 MongoDB creds hardcodeadas en config/database.php</div>
<div class="bg-gray-50 rounded-lg p-2">#8 dd() en MenuController rompe ruta /noti</div>
<div class="bg-gray-50 rounded-lg p-2">#9 Migrar prosapp_web_app (Provider → API)</div>
<div class="bg-gray-50 rounded-lg p-2">#10 Migrar prosappco (Bloc + 8 repos → API)</div>
<div class="bg-gray-50 rounded-lg p-2">#11 Migrar dashpro a PostgreSQL + NestJS</div>
</div>
</div>
</section>
<!-- Plan -->
<section id="plan" class="scroll-mt-20 space-y-4">
<h2 class="text-2xl font-bold border-b pb-2">Plan de Migración</h2>
<div class="space-y-3">
<div class="bg-white rounded-xl p-5 shadow-sm border border-blue-200 card-hover">
<div class="flex items-center gap-2 mb-2">
<span class="px-2 py-0.5 bg-blue-100 text-blue-700 rounded text-xs font-medium">FASE 1</span>
<h3 class="font-semibold">Completar Backend</h3>
</div>
<div class="text-sm text-gray-600 space-y-1">
<div>✅ Fix C-1 (chat FK) · C-4 (migraciones) · C-5 (paginación)</div>
<div>✅ Implementar storage real · Health check · Rate limiting</div>
<div>⬜ Deploy en Coolify</div>
</div>
</div>
<div class="bg-white rounded-xl p-5 shadow-sm border border-green-200 card-hover">
<div class="flex items-center gap-2 mb-2">
<span class="px-2 py-0.5 bg-green-100 text-green-700 rounded text-xs font-medium">FASE 2</span>
<h3 class="font-semibold">Asegurar Admin Panel</h3>
</div>
<div class="text-sm text-gray-600 space-y-1">
<div>✅ Conectar AuthGuard (C-6) · `.env.example`</div>
<div>✅ Estados de carga/error · Páginas de detalle</div>
<div>⬜ Deploy en Coolify</div>
</div>
</div>
<div class="bg-white rounded-xl p-5 shadow-sm border border-orange-200 card-hover">
<div class="flex items-center gap-2 mb-2">
<span class="px-2 py-0.5 bg-orange-100 text-orange-700 rounded text-xs font-medium">FASE 3</span>
<h3 class="font-semibold">Migrar prosapp_web_app</h3>
</div>
<div class="text-sm text-gray-600">API service layer → Migrar 18 providers → JWT → Storage → WebSockets</div>
</div>
<div class="bg-white rounded-xl p-5 shadow-sm border border-purple-200 card-hover">
<div class="flex items-center gap-2 mb-2">
<span class="px-2 py-0.5 bg-purple-100 text-purple-700 rounded text-xs font-medium">FASE 4</span>
<h3 class="font-semibold">Migrar prosappco</h3>
</div>
<div class="text-sm text-gray-600">Reescribir 8 repositorios → Migrar auth + storage + push → Reemplazar snapshots</div>
</div>
<div class="bg-white rounded-xl p-5 shadow-sm border border-red-200 card-hover">
<div class="flex items-center gap-2 mb-2">
<span class="px-2 py-0.5 bg-red-100 text-red-700 rounded text-xs font-medium">FASE 5</span>
<h3 class="font-semibold">Retirar dashpro</h3>
</div>
<div class="text-sm text-gray-600">Verificar paridad → Crear módulos faltantes en admin nuevo → Dar de baja → Eliminar Firebase</div>
</div>
</div>
</section>
<!-- Footer -->
<div class="text-center text-sm text-gray-400 border-t pt-8">
ProsApp Migration · 2026-06-02 · Backend NestJS + PostgreSQL · Admin Next.js + shadcn/ui
</div>
</div>
</body>
</html>