feat: add Supabase connection, seed script with 69 future reservations for July 2026

This commit is contained in:
Jessica Orozco 2026-07-01 07:12:26 -04:00
parent 08eddc1d9a
commit 45287f1dcd
4 changed files with 147 additions and 14 deletions

View File

@ -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

View File

@ -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"
}
}

View File

@ -5,6 +5,7 @@ generator client {
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
directUrl = env("DIRECT_URL")
}
model Reserva {

128
backend/prisma/seed.ts Normal file
View File

@ -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<T>(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();
});