Skip to content

Repository files navigation

STAGEFRONT

Plataforma de eventos y conciertos. Venta de boletos, reventas, reseñas y panel administrativo.


Stack

CapaTecnología
FrontendReact 18 + TypeScript + Vite + Tailwind CSS + GSAP
BackendNode.js + Express + TypeScript
ORM relacionalPrisma 5
Base de datos relacionalPostgreSQL 16
Base de datos documentalMongoDB 7 + Mongoose
ContenedoresDocker Compose

Requisitos previos

  • Node.js 20+
  • Docker Desktop (para las bases de datos)
  • pnpm / npm / yarn

Levantamiento local

1. Bases de datos (Docker)

docker compose up -d

Esto levanta:

  • PostgreSQL en localhost:5432
  • MongoDB en localhost:27017

Ambos servicios persisten datos en volúmenes Docker (stagefront_pg_data, stagefront_mongo_data).


2. Backend

cd backend
cp .env.example .env # copiar variables de entorno
npm install
npm run db:setup # prisma db push + seed
npm run dev # servidor en http://localhost:3001

El comando db:setup aplica el schema de Prisma y carga todos los datos de ejemplo (6 eventos, venues, zonas, asientos, órdenes, perfiles de artistas, reseñas, notificaciones).


3. Frontend

cd frontend
cp .env.example .env # copiar variables de entorno
npm install
npm run dev # app en http://localhost:5173

URLs del frontend

URLPáginaAcceso
http://localhost:5173/Home — listado de eventos destacadosPúblico
http://localhost:5173/eventsCatálogo de eventosPúblico
http://localhost:5173/events/:idDetalle de evento + compraPúblico
http://localhost:5173/resalesMercado de reventasPúblico
http://localhost:5173/checkoutFinalizar compraPúblico (usa usuario demo)
http://localhost:5173/admin/loginLogin del panel adminCredenciales requeridas
http://localhost:5173/adminDashboard administrativoSolo admin autenticado

Autenticación

Panel de administración

La app usa autenticación basada en contexto (React AdminAuthContext). Para acceder al dashboard:

  1. Ir a /admin/login
  2. Ingresar las credenciales del usuario admin creado por el seed:
Email: admin@stagefront.mx
Password: (definida en JWT_SECRET — en dev cualquier contraseña funciona con el seed)

El guard AdminGuard redirige a /admin/login si no hay sesión activa.

Compra pública (checkout)

El flujo de compra no requiere login. Se usa automáticamente el usuario demo creado por el seed. Su ID se configura en las variables de entorno:

# backend/.env
DEMO_USER_ID=seed-user-demo
# frontend/.env
VITE_DEMO_USER_ID=seed-user-demo

Endpoints de API

Los endpoints de /api/v1/admin/*no tienen middleware de auth en la implementación actual (ver comentario en backend/src/routes/index.ts). Deben protegerse antes de ir a producción con un middleware JWT.


Variables de entorno

backend/.env

DATABASE_URL="postgresql://stagefront:stagefront@localhost:5432/stagefront"MONGODB_URI="mongodb://localhost:27017/stagefront"PORT=3001NODE_ENV=developmentJWT_SECRET=change_me_before_productionDEMO_USER_ID=seed-user-demo

frontend/.env

VITE_DEMO_USER_ID=seed-user-demo

API REST — Endpoints

Base URL: http://localhost:3001/api/v1

Estadísticas públicas

MétodoRutaDescripción
GET/statsConteos generales (eventos, órdenes, reventas)

Eventos

MétodoRutaDescripción
GET/eventsLista todos los eventos con venues y zonas
GET/events/:idDetalle de un evento + zonas + asientos
POST/eventsCrear nuevo evento

POST /events — body:

{
"title": "Nombre del evento",
"artist_name": "Artista",
"venue_id": "id-del-venue",
"date": "2026-12-01T21:00:00-06:00",
"status": "draft",
"total_capacity": 20000,
"genre": "Pop",
"description": "Descripción del evento",
"image_url": "/images/mi-evento.jpg"
}

Órdenes

MétodoRutaDescripción
POST/ordersCrear una orden de compra
GET/users/:userId/ordersÓrdenes de un usuario

POST /orders — body:

{
"user_id": "seed-user-demo",
"event_id": "id-del-evento",
"seat_ids": ["seat-zone-ro-general-A-1", "seat-zone-ro-general-A-2"]
}

Reventas

MétodoRutaDescripción
GET/resalesLista reventas activas con info de asiento y evento
POST/resalesPublicar una reventa

POST /resales — body:

{
"seat_id": "id-del-asiento",
"seller_id": "id-del-vendedor",
"price": 2100
}

Regla de negocio: el precio de reventa no puede superar el 30% sobre el precio original.

Reseñas (MongoDB)

MétodoRutaDescripción
GET/events/:eventId/reviewsReseñas de un evento
POST/reviewsCrear reseña

POST /reviews — body:

{
"user_id": "seed-user-demo",
"event_id": "id-del-evento",
"rating": 5,
"comment": "Texto de la reseña"
}

Admin

MétodoRutaDescripción
GET/admin/statsKPIs: eventos activos, revenue, ticket promedio, sold out
GET/admin/ordersÚltimas órdenes (param: ?limit=10, máx 50)
GET/admin/eventsEventos con métricas de venta por zona

Arquitectura de base de datos

PostgreSQL — Prisma (transaccional)

users
id String (cuid) PK
name String
email String UNIQUE
password_hash String
role UserRole admin | buyer | seller
created_at DateTime
venues
id String (cuid) PK
name String
city String
address String
capacity Int
events
id String (cuid) PK
title String
artist_name String
venue_id String FK → venues
date DateTime
status EventStatus draft | published | cancelled | completed
total_capacity Int
genre String
description Text
image_url String
zones
id String (cuid) PK
event_id String FK → events
name String
price Decimal(10,2)
total_seats Int
available_seats Int
seats
id String (cuid) PK
zone_id String FK → zones
row String
number Int
status SeatStatus available | reserved | sold
orders
id String (cuid) PK
user_id String FK → users
event_id String FK → events
total Decimal(10,2)
status OrderStatus pending | confirmed | cancelled | refunded
created_at DateTime
order_items
id String (cuid) PK
order_id String FK → orders
seat_id String FK → seats
price Decimal(10,2)
resales
id String (cuid) PK
seat_id String FK → seats
seller_id String FK → users
price Decimal(10,2)
status ResaleStatus active | sold | cancelled

MongoDB — Mongoose (documental)

reviews
user_id String (ref a users de Postgres)
event_id String (ref a events de Postgres)
rating Number (1–5)
comment String
created_at Date
activity_logs
user_id String
action String (order_placed | review_created | resale_listed | ...)
metadata Object (datos arbitrarios del evento)
timestamp Date
notifications
user_id String
type String (order_confirmed | event_reminder | resale_alert | system)
message String
read Boolean
created_at Date
artist_profiles
name String
bio String
genres String[]
social_links Object { instagram, spotify, youtube, twitter }
media String[] (URLs de imágenes)

Agregar registros nuevos

Nuevo evento (vía API)

curl -X POST http://localhost:3001/api/v1/events \
-H "Content-Type: application/json" \
-d '{ "title": "Bad Bunny — DeBÍ TiRAR MáS FOToS Tour", "artist_name": "Bad Bunny", "venue_id": "seed-venue-gnp", "date": "2026-11-15T21:00:00-06:00", "status": "published", "total_capacity": 65000, "genre": "Reggaetón / Latin Trap", "description": "Bad Bunny regresa a México.", "image_url": "/images/badbunny.jpg" }'

Los IDs de venues del seed son:

  • seed-venue-gnp — Estadio GNP Seguros, CDMX (65,000)
  • seed-venue-palacio — Palacio de los Deportes, CDMX (20,000)
  • seed-venue-arena-vfg — Arena VFG, Guadalajara (16,000)
  • seed-venue-foro-sol — Foro Sol, CDMX (65,000)

Nuevo venue (vía Prisma)

import{PrismaClient}from"@prisma/client";constprisma=newPrismaClient();awaitprisma.venue.create({data: {name: "Arena CDMX",city: "Ciudad de México",address: "Av. de los Insurgentes 1",capacity: 22000,},});

O directamente en psql:

INSERT INTO venues (id, name, city, address, capacity)
VALUES (gen_random_uuid(), 'Arena CDMX', 'Ciudad de México', 'Av. de los Insurgentes 1', 22000);

Nueva zona para un evento

awaitprisma.zone.create({data: {event_id: "id-del-evento",name: "Pista General",price: 1800,total_seats: 200,available_seats: 200,},});

Nuevo usuario

importbcryptfrom"bcrypt";awaitprisma.user.create({data: {name: "María López",email: "maria@ejemplo.mx",password_hash: awaitbcrypt.hash("mi-contraseña",10),role: "buyer",// "admin" | "buyer" | "seller"},});

Nueva reseña (MongoDB)

import{Review}from"./src/models/mongoose/Review.js";awaitReview.create({user_id: "seed-user-demo",event_id: "seed-event-weeknd",rating: 5,comment: "Increíble producción.",created_at: newDate(),});

O vía API:

curl -X POST http://localhost:3001/api/v1/reviews \
-H "Content-Type: application/json" \
-d '{ "user_id": "seed-user-demo", "event_id": "seed-event-weeknd", "rating": 5, "comment": "Increíble producción." }'

Datos del seed

El seed (npm run db:seed) crea:

Usuarios de prueba

IDEmailRol
seed-user-demoana.garcia@ejemplo.mxbuyer
seed-user-adminadmin@stagefront.mxadmin
seed-user-sellercarlos.mendoza@ejemplo.mxseller

Eventos publicados

IDEventoVenueFecha
seed-event-rosaliaRosalía — Motomami World TourPalacio de los Deportes22 ago 2026
seed-event-fka-twigsFKA Twigs — Body High TourArena VFG05 sep 2026
seed-event-ctanganaC. Tangana — Sin Cantar ni AfinarForo Sol26 sep 2026
seed-event-weekndThe Weeknd — After Hours Til DawnEstadio GNP17 oct 2026
seed-event-axe-ceremoniaAxe Ceremonia 2027Foro Sol17 abr 2027
seed-event-kanyeKanye West: Ye Live in MexicoEstadio GNP20 feb 2027

Scripts disponibles

Backend

ScriptAcción
npm run devDesarrollo con hot-reload (tsx watch)
npm run buildCompilar a JS
npm run startEjecutar build compilado
npm run db:pushAplicar schema Prisma sin migraciones
npm run db:migrateCrear y aplicar migración Prisma
npm run db:generateRegenerar Prisma Client
npm run db:seedEjecutar seed (borra y recrea datos)
npm run db:setupdb:push + db:seed en un solo comando

Frontend

ScriptAcción
npm run devServidor de desarrollo Vite
npm run buildBuild de producción
npm run previewPreview del build
npm run lintESLint

Estructura del proyecto

stagefront/
├── docker-compose.yml # PostgreSQL 16 + MongoDB 7
├── frontend/
│ ├── src/
│ │ ├── App.tsx # Router principal
│ │ ├── components/
│ │ │ ├── Navbar.tsx
│ │ │ └── AdminGuard.tsx # Protección de rutas admin
│ │ ├── context/
│ │ │ └── AdminAuthContext.tsx
│ │ ├── hooks/
│ │ ├── pages/
│ │ │ ├── HomePage.tsx
│ │ │ ├── EventsPage.tsx
│ │ │ ├── EventDetailPage.tsx
│ │ │ ├── ResalesPage.tsx
│ │ │ ├── CheckoutPage.tsx
│ │ │ ├── AdminLoginPage.tsx
│ │ │ └── AdminDashboardPage.tsx
│ │ ├── lib/ # Clientes HTTP / utilidades
│ │ └── types/
│ └── vite.config.ts
└── backend/
├── prisma/
│ ├── schema.prisma # Schema PostgreSQL
│ └── seed.ts # Datos de prueba
└── src/
├── index.ts # Entry point Express
├── routes/index.ts # Todas las rutas
├── controllers/ # Handlers HTTP
│ ├── eventsController.ts
│ ├── ordersController.ts
│ ├── resalesController.ts
│ ├── reviewsController.ts
│ ├── statsController.ts
│ └── adminController.ts
├── services/ # Lógica de negocio pura
│ ├── eventService.ts
│ ├── orderService.ts
│ ├── purchaseService.ts
│ ├── resaleService.ts
│ └── promoService.ts
├── models/
│ ├── prisma/ # Tipos derivados de Prisma
│ └── mongoose/ # Modelos MongoDB
│ ├── Review.ts
│ ├── ActivityLog.ts
│ ├── Notification.ts
│ └── ArtistProfile.ts
├── lib/
│ ├── prisma.ts # Singleton PrismaClient
│ └── mongoose.ts # Conexión MongoDB
└── types/ # Tipos compartidos

Lógica de negocio (services)

Todas las funciones en backend/src/services/ son puras, sin side effects, y están listas para unit tests.

FunciónDescripción
isEventSoldOut(zones)true si todas las zonas tienen available_seats === 0
getAvailableSeats(zone)Asientos con status === "available" en una zona
getEventsByCity(events, city)Filtra eventos por ciudad del venue
calculateOrderTotal(items)Suma de precios de los items
canUserPurchase(user, event, qty)Valida que el usuario pueda comprar
validateResalePrice(original, resale)Máximo 30% de markup permitido
applyPromoCode(total, code, validCodes)Aplica descuento por código promo

Imágenes de eventos

Las imágenes se sirven como estáticos desde el frontend. Para usar imágenes reales:

  1. Colocar el archivo en frontend/public/images/<nombre>.jpg
  2. En el seed o al crear el evento usar image_url: "/images/<nombre>.jpg"

Los eventos del seed apuntan a /images/rosalia.jpg, /images/theweeknd.jpg, etc. Si los archivos no existen, el frontend renderizará sin imagen o usará el fallback definido en el componente.


Healthcheck

curl http://localhost:3001/health
# { "status": "ok" }

About

Plataforma de eventos y conciertos. Venta de boletos, reventas, reseñas y panel administrativo.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages