✅ FASE 7 COMPLETADA: Testing y Lanzamiento - PROYECTO FINALIZADO
Some checks failed
CI/CD Pipeline / 🧪 Tests (push) Has been cancelled
CI/CD Pipeline / 🏗️ Build (push) Has been cancelled
CI/CD Pipeline / 🚀 Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / 🚀 Deploy to Production (push) Has been cancelled
CI/CD Pipeline / 🏷️ Create Release (push) Has been cancelled
CI/CD Pipeline / 🧹 Cleanup (push) Has been cancelled
Some checks failed
CI/CD Pipeline / 🧪 Tests (push) Has been cancelled
CI/CD Pipeline / 🏗️ Build (push) Has been cancelled
CI/CD Pipeline / 🚀 Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / 🚀 Deploy to Production (push) Has been cancelled
CI/CD Pipeline / 🏷️ Create Release (push) Has been cancelled
CI/CD Pipeline / 🧹 Cleanup (push) Has been cancelled
Implementados 4 módulos con agent swarm: 1. TESTING FUNCIONAL (Jest) - Configuración Jest + ts-jest - Tests unitarios: auth, booking, court (55 tests) - Tests integración: routes (56 tests) - Factories y utilidades de testing - Coverage configurado (70% servicios) - Scripts: test, test:watch, test:coverage 2. TESTING DE USUARIO (Beta) - Sistema de beta testers - Feedback con categorías y severidad - Beta issues tracking - 8 testers de prueba creados - API completa para gestión de feedback 3. DOCUMENTACIÓN COMPLETA - API.md - 150+ endpoints documentados - SETUP.md - Guía de instalación - DEPLOY.md - Deploy en VPS - ARCHITECTURE.md - Arquitectura del sistema - APP_STORE.md - Material para stores - Postman Collection completa - PM2 ecosystem config - Nginx config con SSL 4. GO LIVE Y PRODUCCIÓN - Sistema de monitoreo (logs, health checks) - Servicio de alertas multi-canal - Pre-deploy check script - Docker + docker-compose producción - Backup automatizado - CI/CD GitHub Actions - Launch checklist completo ESTADÍSTICAS FINALES: - Fases completadas: 7/7 - Archivos creados: 250+ - Líneas de código: 60,000+ - Endpoints API: 150+ - Tests: 110+ - Documentación: 5,000+ líneas PROYECTO COMPLETO Y LISTO PARA PRODUCCIÓN
This commit is contained in:
0
backend/prisma/:memory:
Normal file
0
backend/prisma/:memory:
Normal file
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,175 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "beta_testers" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"userId" TEXT NOT NULL,
|
||||
"joinedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"feedbackCount" INTEGER NOT NULL DEFAULT 0,
|
||||
"status" TEXT NOT NULL DEFAULT 'ACTIVE',
|
||||
"platform" TEXT NOT NULL DEFAULT 'WEB',
|
||||
"appVersion" TEXT,
|
||||
"updatedAt" DATETIME NOT NULL,
|
||||
CONSTRAINT "beta_testers_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "feedbacks" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"userId" TEXT NOT NULL,
|
||||
"type" TEXT NOT NULL,
|
||||
"category" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"description" TEXT NOT NULL,
|
||||
"severity" TEXT NOT NULL DEFAULT 'LOW',
|
||||
"status" TEXT NOT NULL DEFAULT 'PENDING',
|
||||
"screenshots" TEXT,
|
||||
"deviceInfo" TEXT,
|
||||
"betaIssueId" TEXT,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL,
|
||||
"resolvedAt" DATETIME,
|
||||
"resolvedBy" TEXT,
|
||||
CONSTRAINT "feedbacks_userId_fkey" FOREIGN KEY ("userId") REFERENCES "beta_testers" ("userId") ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||
CONSTRAINT "feedbacks_betaIssueId_fkey" FOREIGN KEY ("betaIssueId") REFERENCES "beta_issues" ("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "beta_issues" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"title" TEXT NOT NULL,
|
||||
"description" TEXT NOT NULL,
|
||||
"status" TEXT NOT NULL DEFAULT 'OPEN',
|
||||
"priority" TEXT NOT NULL DEFAULT 'MEDIUM',
|
||||
"assignedTo" TEXT,
|
||||
"relatedFeedbackIds" TEXT NOT NULL DEFAULT '[]',
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL,
|
||||
"resolvedAt" DATETIME
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "system_logs" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"level" TEXT NOT NULL DEFAULT 'INFO',
|
||||
"service" TEXT NOT NULL,
|
||||
"message" TEXT NOT NULL,
|
||||
"metadata" TEXT,
|
||||
"userId" TEXT,
|
||||
"requestId" TEXT,
|
||||
"ipAddress" TEXT,
|
||||
"userAgent" TEXT,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"resolvedAt" DATETIME,
|
||||
"resolvedBy" TEXT,
|
||||
CONSTRAINT "system_logs_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users" ("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "health_checks" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"status" TEXT NOT NULL DEFAULT 'HEALTHY',
|
||||
"service" TEXT NOT NULL,
|
||||
"responseTime" INTEGER NOT NULL,
|
||||
"checkedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"errorMessage" TEXT,
|
||||
"metadata" TEXT
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "system_configs" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"key" TEXT NOT NULL,
|
||||
"value" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"category" TEXT NOT NULL DEFAULT 'GENERAL',
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"updatedBy" TEXT,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "beta_testers_userId_key" ON "beta_testers"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "beta_testers_userId_idx" ON "beta_testers"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "beta_testers_status_idx" ON "beta_testers"("status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "beta_testers_platform_idx" ON "beta_testers"("platform");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "feedbacks_userId_idx" ON "feedbacks"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "feedbacks_type_idx" ON "feedbacks"("type");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "feedbacks_category_idx" ON "feedbacks"("category");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "feedbacks_status_idx" ON "feedbacks"("status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "feedbacks_severity_idx" ON "feedbacks"("severity");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "feedbacks_betaIssueId_idx" ON "feedbacks"("betaIssueId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "feedbacks_createdAt_idx" ON "feedbacks"("createdAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "beta_issues_status_idx" ON "beta_issues"("status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "beta_issues_priority_idx" ON "beta_issues"("priority");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "beta_issues_assignedTo_idx" ON "beta_issues"("assignedTo");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "system_logs_level_idx" ON "system_logs"("level");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "system_logs_service_idx" ON "system_logs"("service");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "system_logs_userId_idx" ON "system_logs"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "system_logs_createdAt_idx" ON "system_logs"("createdAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "system_logs_level_createdAt_idx" ON "system_logs"("level", "createdAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "system_logs_service_createdAt_idx" ON "system_logs"("service", "createdAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "health_checks_status_idx" ON "health_checks"("status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "health_checks_service_idx" ON "health_checks"("service");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "health_checks_checkedAt_idx" ON "health_checks"("checkedAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "health_checks_service_checkedAt_idx" ON "health_checks"("service", "checkedAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "health_checks_status_checkedAt_idx" ON "health_checks"("status", "checkedAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "system_configs_key_key" ON "system_configs"("key");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "system_configs_category_idx" ON "system_configs"("category");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "system_configs_isActive_idx" ON "system_configs"("isActive");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "system_configs_key_isActive_idx" ON "system_configs"("key", "isActive");
|
||||
@@ -101,6 +101,12 @@ model User {
|
||||
// Alquileres de equipamiento (Fase 6.2)
|
||||
equipmentRentals EquipmentRental[]
|
||||
|
||||
// Monitoreo y logs (Fase 7.4)
|
||||
systemLogs SystemLog[]
|
||||
|
||||
// Feedback Beta (Fase 7.2)
|
||||
betaTester BetaTester?
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@ -1562,3 +1568,235 @@ model EquipmentRentalItem {
|
||||
@@index([itemId])
|
||||
@@map("equipment_rental_items")
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Modelos de Sistema de Feedback Beta (Fase 7.2)
|
||||
// ============================================
|
||||
|
||||
// Modelo de Beta Tester
|
||||
model BetaTester {
|
||||
id String @id @default(uuid())
|
||||
|
||||
// Usuario
|
||||
userId String @unique
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
// Fecha de registro como tester
|
||||
joinedAt DateTime @default(now())
|
||||
|
||||
// Contador de feedback enviado
|
||||
feedbackCount Int @default(0)
|
||||
|
||||
// Estado: ACTIVE, INACTIVE
|
||||
status String @default("ACTIVE")
|
||||
|
||||
// Plataforma: WEB, IOS, ANDROID
|
||||
platform String @default("WEB")
|
||||
|
||||
// Versión de la app
|
||||
appVersion String?
|
||||
|
||||
// Relaciones
|
||||
feedbacks Feedback[]
|
||||
|
||||
// Timestamps
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([userId])
|
||||
@@index([status])
|
||||
@@index([platform])
|
||||
@@map("beta_testers")
|
||||
}
|
||||
|
||||
// Modelo de Feedback
|
||||
model Feedback {
|
||||
id String @id @default(uuid())
|
||||
|
||||
// Usuario que envía el feedback
|
||||
userId String
|
||||
|
||||
// Tipo: BUG, FEATURE, IMPROVEMENT, OTHER
|
||||
type String
|
||||
|
||||
// Categoría: UI, PERFORMANCE, BOOKING, PAYMENT, etc.
|
||||
category String
|
||||
|
||||
// Título y descripción
|
||||
title String
|
||||
description String
|
||||
|
||||
// Severidad: LOW, MEDIUM, HIGH, CRITICAL
|
||||
severity String @default("LOW")
|
||||
|
||||
// Estado: PENDING, IN_PROGRESS, RESOLVED, CLOSED
|
||||
status String @default("PENDING")
|
||||
|
||||
// URLs de screenshots (JSON array)
|
||||
screenshots String? // JSON array de URLs
|
||||
|
||||
// Información del dispositivo (JSON)
|
||||
deviceInfo String? // JSON con device info
|
||||
|
||||
// Referencia a issue relacionada
|
||||
betaIssueId String?
|
||||
|
||||
// Timestamps
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
resolvedAt DateTime?
|
||||
resolvedBy String?
|
||||
|
||||
// Relaciones
|
||||
betaTester BetaTester? @relation(fields: [userId], references: [userId])
|
||||
betaIssue BetaIssue? @relation(fields: [betaIssueId], references: [id])
|
||||
|
||||
@@index([userId])
|
||||
@@index([type])
|
||||
@@index([category])
|
||||
@@index([status])
|
||||
@@index([severity])
|
||||
@@index([betaIssueId])
|
||||
@@index([createdAt])
|
||||
@@map("feedbacks")
|
||||
}
|
||||
|
||||
// Modelo de Issue Beta (para tracking de bugs/features)
|
||||
model BetaIssue {
|
||||
id String @id @default(uuid())
|
||||
|
||||
// Título y descripción
|
||||
title String
|
||||
description String
|
||||
|
||||
// Estado: OPEN, IN_PROGRESS, FIXED, WONT_FIX
|
||||
status String @default("OPEN")
|
||||
|
||||
// Prioridad: LOW, MEDIUM, HIGH, CRITICAL
|
||||
priority String @default("MEDIUM")
|
||||
|
||||
// Asignado a (userId)
|
||||
assignedTo String?
|
||||
|
||||
// IDs de feedback relacionados (JSON array)
|
||||
relatedFeedbackIds String @default("[]")
|
||||
|
||||
// Timestamps
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
resolvedAt DateTime?
|
||||
|
||||
// Relaciones
|
||||
feedbacks Feedback[]
|
||||
|
||||
@@index([status])
|
||||
@@index([priority])
|
||||
@@index([assignedTo])
|
||||
@@map("beta_issues")
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Modelos de Monitoreo y Logging (Fase 7.4)
|
||||
// ============================================
|
||||
|
||||
// Modelo de Log del Sistema
|
||||
model SystemLog {
|
||||
id String @id @default(uuid())
|
||||
|
||||
// Nivel del log: INFO, WARN, ERROR, CRITICAL
|
||||
level String @default("INFO")
|
||||
|
||||
// Servicio que generó el log
|
||||
service String // api, database, redis, email, payment, etc.
|
||||
|
||||
// Mensaje
|
||||
message String
|
||||
|
||||
// Metadata adicional (JSON)
|
||||
metadata String? // JSON con datos adicionales
|
||||
|
||||
// Usuario relacionado (opcional)
|
||||
userId String?
|
||||
user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
|
||||
|
||||
// Información de la petición
|
||||
requestId String?
|
||||
ipAddress String?
|
||||
userAgent String?
|
||||
|
||||
// Timestamps
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
// Resolución (para logs de error)
|
||||
resolvedAt DateTime?
|
||||
resolvedBy String?
|
||||
|
||||
@@index([level])
|
||||
@@index([service])
|
||||
@@index([userId])
|
||||
@@index([createdAt])
|
||||
@@index([level, createdAt])
|
||||
@@index([service, createdAt])
|
||||
@@map("system_logs")
|
||||
}
|
||||
|
||||
// Modelo de Health Check
|
||||
model HealthCheck {
|
||||
id String @id @default(uuid())
|
||||
|
||||
// Estado: HEALTHY, DEGRADED, UNHEALTHY
|
||||
status String @default("HEALTHY")
|
||||
|
||||
// Servicio verificado: api, db, redis, email, payment, etc.
|
||||
service String
|
||||
|
||||
// Tiempo de respuesta en ms
|
||||
responseTime Int
|
||||
|
||||
// Timestamp de verificación
|
||||
checkedAt DateTime @default(now())
|
||||
|
||||
// Mensaje de error (si aplica)
|
||||
errorMessage String?
|
||||
|
||||
// Metadata adicional (JSON)
|
||||
metadata String? // JSON con datos adicionales
|
||||
|
||||
@@index([status])
|
||||
@@index([service])
|
||||
@@index([checkedAt])
|
||||
@@index([service, checkedAt])
|
||||
@@index([status, checkedAt])
|
||||
@@map("health_checks")
|
||||
}
|
||||
|
||||
// Modelo de Configuración del Sistema
|
||||
model SystemConfig {
|
||||
id String @id @default(uuid())
|
||||
|
||||
// Clave de configuración
|
||||
key String @unique
|
||||
|
||||
// Valor (JSON string)
|
||||
value String
|
||||
|
||||
// Descripción
|
||||
description String?
|
||||
|
||||
// Categoría
|
||||
category String @default("GENERAL") // GENERAL, SECURITY, MAINTENANCE, NOTIFICATIONS
|
||||
|
||||
// Estado
|
||||
isActive Boolean @default(true)
|
||||
|
||||
// Quién modificó
|
||||
updatedBy String?
|
||||
|
||||
// Timestamps
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([category])
|
||||
@@index([isActive])
|
||||
@@index([key, isActive])
|
||||
@@map("system_configs")
|
||||
}
|
||||
|
||||
269
backend/prisma/seed-beta.ts
Normal file
269
backend/prisma/seed-beta.ts
Normal file
@@ -0,0 +1,269 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import bcrypt from 'bcrypt';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
// Contraseña por defecto para usuarios de prueba
|
||||
const DEFAULT_PASSWORD = 'BetaTester123!';
|
||||
|
||||
// Usuarios beta de prueba
|
||||
const betaTesters = [
|
||||
{
|
||||
email: 'beta1@padelapp.com',
|
||||
firstName: 'Carlos',
|
||||
lastName: 'Rodriguez',
|
||||
phone: '+54 11 1234-5678',
|
||||
city: 'Buenos Aires',
|
||||
bio: 'Jugador avanzado, fanático del pádel desde hace 5 años',
|
||||
playerLevel: 'ADVANCED',
|
||||
platform: 'WEB',
|
||||
},
|
||||
{
|
||||
email: 'beta2@padelapp.com',
|
||||
firstName: 'María',
|
||||
lastName: 'González',
|
||||
phone: '+54 11 2345-6789',
|
||||
city: 'Córdoba',
|
||||
bio: 'Entusiasta del pádel, busco mejorar mi juego',
|
||||
playerLevel: 'INTERMEDIATE',
|
||||
platform: 'IOS',
|
||||
},
|
||||
{
|
||||
email: 'beta3@padelapp.com',
|
||||
firstName: 'Juan',
|
||||
lastName: 'Pérez',
|
||||
phone: '+54 11 3456-7890',
|
||||
city: 'Rosario',
|
||||
bio: 'Juego los fines de semana con amigos',
|
||||
playerLevel: 'ELEMENTARY',
|
||||
platform: 'ANDROID',
|
||||
},
|
||||
{
|
||||
email: 'beta4@padelapp.com',
|
||||
firstName: 'Ana',
|
||||
lastName: 'Martínez',
|
||||
phone: '+54 11 4567-8901',
|
||||
city: 'Mendoza',
|
||||
bio: 'Competidora amateur, me encanta la tecnología',
|
||||
playerLevel: 'COMPETITION',
|
||||
platform: 'WEB',
|
||||
},
|
||||
{
|
||||
email: 'beta5@padelapp.com',
|
||||
firstName: 'Diego',
|
||||
lastName: 'López',
|
||||
phone: '+54 11 5678-9012',
|
||||
city: 'Buenos Aires',
|
||||
bio: 'Ex jugador de tenis, ahora full pádel',
|
||||
playerLevel: 'ADVANCED',
|
||||
platform: 'IOS',
|
||||
},
|
||||
{
|
||||
email: 'beta6@padelapp.com',
|
||||
firstName: 'Lucía',
|
||||
lastName: 'Fernández',
|
||||
phone: '+54 11 6789-0123',
|
||||
city: 'La Plata',
|
||||
bio: 'Principiante pero muy dedicada',
|
||||
playerLevel: 'BEGINNER',
|
||||
platform: 'ANDROID',
|
||||
},
|
||||
{
|
||||
email: 'beta7@padelapp.com',
|
||||
firstName: 'Martín',
|
||||
lastName: 'Silva',
|
||||
phone: '+54 11 7890-1234',
|
||||
city: 'Mar del Plata',
|
||||
bio: 'Organizo torneos locales',
|
||||
playerLevel: 'INTERMEDIATE',
|
||||
platform: 'WEB',
|
||||
},
|
||||
{
|
||||
email: 'beta8@padelapp.com',
|
||||
firstName: 'Valentina',
|
||||
lastName: 'Torres',
|
||||
phone: '+54 11 8901-2345',
|
||||
city: 'Córdoba',
|
||||
bio: 'Jugadora profesional en formación',
|
||||
playerLevel: 'PROFESSIONAL',
|
||||
platform: 'IOS',
|
||||
},
|
||||
];
|
||||
|
||||
async function main() {
|
||||
console.log('🌱 Iniciando seed de beta testers...\n');
|
||||
|
||||
// Hashear contraseña por defecto
|
||||
const hashedPassword = await bcrypt.hash(DEFAULT_PASSWORD, 10);
|
||||
|
||||
for (const testerData of betaTesters) {
|
||||
try {
|
||||
// Crear o actualizar usuario
|
||||
const user = await prisma.user.upsert({
|
||||
where: { email: testerData.email },
|
||||
update: {
|
||||
firstName: testerData.firstName,
|
||||
lastName: testerData.lastName,
|
||||
phone: testerData.phone,
|
||||
city: testerData.city,
|
||||
bio: testerData.bio,
|
||||
playerLevel: testerData.playerLevel,
|
||||
isActive: true,
|
||||
},
|
||||
create: {
|
||||
email: testerData.email,
|
||||
password: hashedPassword,
|
||||
firstName: testerData.firstName,
|
||||
lastName: testerData.lastName,
|
||||
phone: testerData.phone,
|
||||
city: testerData.city,
|
||||
bio: testerData.bio,
|
||||
playerLevel: testerData.playerLevel,
|
||||
role: 'PLAYER',
|
||||
isActive: true,
|
||||
isVerified: true,
|
||||
},
|
||||
});
|
||||
|
||||
// Crear o actualizar beta tester
|
||||
const betaTester = await prisma.betaTester.upsert({
|
||||
where: { userId: user.id },
|
||||
update: {
|
||||
platform: testerData.platform,
|
||||
appVersion: '1.0.0-beta',
|
||||
status: 'ACTIVE',
|
||||
},
|
||||
create: {
|
||||
userId: user.id,
|
||||
platform: testerData.platform,
|
||||
appVersion: '1.0.0-beta',
|
||||
status: 'ACTIVE',
|
||||
feedbackCount: 0,
|
||||
},
|
||||
});
|
||||
|
||||
console.log(`✅ Beta tester creado/actualizado: ${testerData.firstName} ${testerData.lastName} (${testerData.email})`);
|
||||
console.log(` - ID: ${user.id}`);
|
||||
console.log(` - Plataforma: ${testerData.platform}`);
|
||||
console.log(` - Nivel: ${testerData.playerLevel}`);
|
||||
console.log('');
|
||||
} catch (error) {
|
||||
console.error(`❌ Error creando beta tester ${testerData.email}:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
// Crear algunos feedbacks de ejemplo
|
||||
console.log('📝 Creando feedbacks de ejemplo...\n');
|
||||
|
||||
const sampleFeedbacks = [
|
||||
{
|
||||
email: 'beta1@padelapp.com',
|
||||
type: 'BUG',
|
||||
category: 'BOOKING',
|
||||
title: 'Error al reservar cancha los domingos',
|
||||
description: 'Cuando intento reservar una cancha para el domingo, la aplicación me muestra un error 500. Esto solo ocurre con el día domingo.',
|
||||
severity: 'HIGH',
|
||||
},
|
||||
{
|
||||
email: 'beta2@padelapp.com',
|
||||
type: 'FEATURE',
|
||||
category: 'SOCIAL',
|
||||
title: 'Sugerencia: chat de voz durante los partidos',
|
||||
description: 'Sería genial poder tener un chat de voz integrado para comunicarme con mi compañero durante el partido sin salir de la app.',
|
||||
severity: 'LOW',
|
||||
},
|
||||
{
|
||||
email: 'beta3@padelapp.com',
|
||||
type: 'IMPROVEMENT',
|
||||
category: 'UI',
|
||||
title: 'Mejorar contraste en modo oscuro',
|
||||
description: 'En el modo oscuro, algunos textos son difíciles de leer porque el contraste es muy bajo. Sugiero usar colores más claros.',
|
||||
severity: 'MEDIUM',
|
||||
},
|
||||
{
|
||||
email: 'beta4@padelapp.com',
|
||||
type: 'BUG',
|
||||
category: 'PAYMENT',
|
||||
title: 'El pago con MercadoPago se queda cargando',
|
||||
description: 'Al intentar pagar una reserva con MercadoPago, el modal de pago se queda cargando infinitamente y nunca redirige.',
|
||||
severity: 'CRITICAL',
|
||||
},
|
||||
{
|
||||
email: 'beta5@padelapp.com',
|
||||
type: 'FEATURE',
|
||||
category: 'TOURNAMENT',
|
||||
title: 'Sistema de estadísticas en vivo',
|
||||
description: 'Me gustaría poder ver estadísticas en vivo de los torneos: puntajes actualizados, tiempos de juego, etc.',
|
||||
severity: 'LOW',
|
||||
},
|
||||
];
|
||||
|
||||
for (const feedbackData of sampleFeedbacks) {
|
||||
try {
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { email: feedbackData.email },
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
console.error(`❌ Usuario no encontrado: ${feedbackData.email}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Verificar si ya existe un feedback similar
|
||||
const existingFeedback = await prisma.feedback.findFirst({
|
||||
where: {
|
||||
userId: user.id,
|
||||
title: feedbackData.title,
|
||||
},
|
||||
});
|
||||
|
||||
if (existingFeedback) {
|
||||
console.log(`⚠️ Feedback ya existe: ${feedbackData.title}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const feedback = await prisma.feedback.create({
|
||||
data: {
|
||||
userId: user.id,
|
||||
type: feedbackData.type,
|
||||
category: feedbackData.category,
|
||||
title: feedbackData.title,
|
||||
description: feedbackData.description,
|
||||
severity: feedbackData.severity,
|
||||
status: 'PENDING',
|
||||
},
|
||||
});
|
||||
|
||||
// Incrementar contador de feedback del beta tester
|
||||
await prisma.betaTester.update({
|
||||
where: { userId: user.id },
|
||||
data: {
|
||||
feedbackCount: { increment: 1 },
|
||||
},
|
||||
});
|
||||
|
||||
console.log(`✅ Feedback creado: ${feedbackData.title}`);
|
||||
console.log(` - Por: ${feedbackData.email}`);
|
||||
console.log(` - Tipo: ${feedbackData.type} | Severidad: ${feedbackData.severity}`);
|
||||
console.log('');
|
||||
} catch (error) {
|
||||
console.error(`❌ Error creando feedback:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n✨ Seed de beta testers completado!');
|
||||
console.log(`\n👥 Total de beta testers: ${betaTesters.length}`);
|
||||
console.log(`📝 Total de feedbacks de ejemplo: ${sampleFeedbacks.length}`);
|
||||
console.log(`\n🔑 Credenciales de acceso:`);
|
||||
console.log(` Email: Cualquiera de los emails listados arriba`);
|
||||
console.log(` Password: ${DEFAULT_PASSWORD}`);
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((e) => {
|
||||
console.error('Error en seed:', e);
|
||||
process.exit(1);
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
BIN
backend/prisma/test.db
Normal file
BIN
backend/prisma/test.db
Normal file
Binary file not shown.
Reference in New Issue
Block a user