From 45287f1dcdaae84756ba0b5d05237cb33c21db65 Mon Sep 17 00:00:00 2001 From: Jessica Orozco Date: Wed, 1 Jul 2026 07:12:26 -0400 Subject: [PATCH] feat: add Supabase connection, seed script with 69 future reservations for July 2026 --- backend/.env | 14 ++-- backend/package.json | 14 ++-- backend/prisma/schema.prisma | 5 +- backend/prisma/seed.ts | 128 +++++++++++++++++++++++++++++++++++ 4 files changed, 147 insertions(+), 14 deletions(-) create mode 100644 backend/prisma/seed.ts diff --git a/backend/.env b/backend/.env index ea34186..277d933 100644 --- a/backend/.env +++ b/backend/.env @@ -5,16 +5,15 @@ # ========================================== PORT=3000 NODE_ENV=development - -# Database Settings (PostgreSQL / Supabase) -DATABASE_URL="postgresql://admin:supersecretpassword123@localhost:5432/App_db?schema=public" -# SUPABASE_URL="https://your-project.supabase.co" -# SUPABASE_KEY="your-anon-key" +PASSWORD_DB=T4Y7c)j.L0Toq5 +# Database Settings (Supabase / PostgreSQL) +# Pooled connection - para queries de la app (PgBouncer, puerto 6543) +DATABASE_URL="postgresql://postgres.szfqeppzcyavmlmmvcwl:7LtH*QUUTfBcrYf@aws-0-us-east-1.pooler.supabase.com:6543/postgres?pgbouncer=true&connection_limit=1" +# Direct connection - para migraciones (bypasa PgBouncer, puerto 5432) +DIRECT_URL="postgresql://postgres.szfqeppzcyavmlmmvcwl:7LtH*QUUTfBcrYf@aws-0-us-east-1.pooler.supabase.com:5432/postgres" SUPABASE_PASSWORD=7LtH*QUUTfBcrYf NEXT_PUBLIC_SUPABASE_URL=https://szfqeppzcyavmlmmvcwl.supabase.co NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=sb_publishable_zmH4vijRiPtiwO_TUTleNg_R20kK235 - - # Active Directory / Azure AD SSO Config AD_TENANT_ID="your-azure-tenant-id" AD_CLIENT_ID="your-azure-client-id" @@ -29,4 +28,3 @@ NG_APP_API_URL="http://localhost:3000/api" NG_APP_AD_CLIENT_ID="your-azure-client-id" NG_APP_AD_TENANT_ID="your-azure-tenant-id" -PASSWORD_DB=T4Y7c)j.L0Toq5 diff --git a/backend/package.json b/backend/package.json index b86c268..3ba4247 100644 --- a/backend/package.json +++ b/backend/package.json @@ -8,7 +8,8 @@ "start:dev": "nest start --watch", "start:prod": "node dist/main", "db:migrate": "prisma migrate deploy", - "db:generate": "prisma generate" + "db:generate": "prisma generate", + "db:seed": "ts-node prisma/seed.ts" }, "dependencies": { "@nestjs/common": "^10.0.0", @@ -16,7 +17,7 @@ "@nestjs/jwt": "^10.0.0", "@nestjs/passport": "^10.0.0", "@nestjs/platform-express": "^10.0.0", - "@prisma/client": "^5.0.0", + "@prisma/client": "5.22.0", "passport": "^0.7.0", "passport-jwt": "^4.0.1", "reflect-metadata": "^0.1.13", @@ -27,7 +28,12 @@ "@nestjs/schematics": "^10.0.0", "@types/node": "^20.0.0", "@types/passport-jwt": "^4.0.0", - "prisma": "^5.0.0", + "dotenv": "^17.4.2", + "prisma": "5.22.0", + "ts-node": "^10.9.2", "typescript": "^5.0.0" + }, + "prisma": { + "seed": "ts-node prisma/seed.ts" } -} \ No newline at end of file +} diff --git a/backend/prisma/schema.prisma b/backend/prisma/schema.prisma index 479ba39..cbc298c 100644 --- a/backend/prisma/schema.prisma +++ b/backend/prisma/schema.prisma @@ -3,8 +3,9 @@ generator client { } datasource db { - provider = "postgresql" - url = env("DATABASE_URL") + provider = "postgresql" + url = env("DATABASE_URL") + directUrl = env("DIRECT_URL") } model Reserva { diff --git a/backend/prisma/seed.ts b/backend/prisma/seed.ts new file mode 100644 index 0000000..41fe59e --- /dev/null +++ b/backend/prisma/seed.ts @@ -0,0 +1,128 @@ +import { PrismaClient } from '@prisma/client'; + +const prisma = new PrismaClient(); + +// Recursos disponibles en la empresa +const resources = [ + { id: 'sala-A', name: 'Sala de Reuniones A' }, + { id: 'sala-B', name: 'Sala de Reuniones B' }, + { id: 'cowork-1', name: 'Espacio Coworking 1' }, + { id: 'cowork-2', name: 'Espacio Coworking 2' }, + { id: 'auditorio', name: 'Auditorio Principal' }, +]; + +// Autores del equipo +const authors = [ + 'Jessica Orozco', + 'Carlos Méndez', + 'Ana Torres', + 'Luis Herrera', + 'María López', +]; + +// Slots de horario (horas laborales) +const slots = [ + { start: '09:00', end: '10:00' }, + { start: '10:00', end: '11:00' }, + { start: '11:00', end: '12:00' }, + { start: '14:00', end: '15:00' }, + { start: '15:00', end: '16:00' }, + { start: '16:00', end: '17:00' }, + { start: '17:00', end: '18:00' }, +]; + +// Genera fechas futuras en julio 2026 (días hábiles: lunes a viernes) +function getFutureDates(): string[] { + const dates: string[] = []; + // Desde mañana (02/07) hasta fin de julio (31/07) + const start = new Date('2026-07-02'); + const end = new Date('2026-07-31'); + + for (let d = new Date(start); d <= end; d.setDate(d.getDate() + 1)) { + const dayOfWeek = d.getDay(); + if (dayOfWeek !== 0 && dayOfWeek !== 6) { + // excluir sábado y domingo + dates.push(d.toISOString().split('T')[0]); + } + } + return dates; +} + +function getRandom(arr: T[]): T { + return arr[Math.floor(Math.random() * arr.length)]; +} + +function getRandomNotes(): string | undefined { + const notes = [ + 'Reunión de planificación sprint', + 'Demo con cliente', + 'Sesión de diseño', + 'Revisión de métricas', + 'Workshop de onboarding', + 'Retrospectiva del equipo', + undefined, + undefined, // 2/8 chance de sin notas + ]; + return getRandom(notes); +} + +async function main() { + console.log('🌱 Iniciando seed de reservas futuras en Supabase...\n'); + + const dates = getFutureDates(); + console.log(`📅 Fechas a cubrir: ${dates[0]} → ${dates[dates.length - 1]} (${dates.length} días hábiles)`); + + let created = 0; + let skipped = 0; + + for (const date of dates) { + // 2-4 reservas por día para simular uso real + const reservasDelDia = Math.floor(Math.random() * 3) + 2; + + // Shuffle slots para no repetir + const shuffledSlots = [...slots].sort(() => Math.random() - 0.5); + + for (let i = 0; i < reservasDelDia; i++) { + const slot = shuffledSlots[i]; + const resource = getRandom(resources); + const author = getRandom(authors); + + try { + await prisma.reserva.create({ + data: { + resourceId: resource.id, + resourceName: resource.name, + date, + startTime: slot.start, + endTime: slot.end, + author, + notes: getRandomNotes(), + }, + }); + created++; + console.log(` ✅ ${date} ${slot.start}-${slot.end} | ${resource.name} | ${author}`); + } catch (e: any) { + // Conflicto de unique constraint: mismo recurso + fecha + hora + if (e.code === 'P2002') { + skipped++; + } else { + console.error(` ❌ Error inesperado: ${e.message}`); + } + } + } + } + + console.log(`\n📊 Resultado:`); + console.log(` ✅ Creadas: ${created} reservas`); + console.log(` ⏭️ Omitidas por conflicto: ${skipped}`); + console.log(`\n🎉 Seed completado. Datos disponibles en Supabase.`); +} + +main() + .catch((e) => { + console.error('❌ Error en el seed:', e); + process.exit(1); + }) + .finally(async () => { + await prisma.$disconnect(); + });