Skip to content
luxznff-wqPublic

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

2 Commits

Folders and files

Repository files navigation

EventQR — Sistema de Gestión de Entradas

Sistema completo de venta y validación de entradas para eventos con códigos QR, similar a Eventbrite.

Stack Tecnológico

Capa Tecnología
Frontend React 18 + TypeScript + Vite + TailwindCSS
Backend Node.js + Express + TypeScript
Base de datos PostgreSQL vía Prisma ORM
Autenticación JWT (access + refresh token rotation)
QR qrcode (generación) + html5-qrcode (escaneo)
Estado del servidor TanStack Query v5
Formularios React Hook Form + Zod
Deploy Docker Compose + Nginx

¿Por qué PostgreSQL?

  • Datos relacionales: User → Ticket ← Event son relaciones fuertes
  • Transacciones ACID: críticas para evitar double-booking (2 usuarios comprando el último ticket simultáneamente)
  • Unicidad garantizada: constraint @@unique([userId, eventId]) a nivel de BD
  • Escalabilidad: índices eficientes en status, eventId, userId

Arranque rápido

Prerrequisitos

  • Node.js 20+
  • Docker Desktop (para PostgreSQL)
  • npm

1. Clonar y configurar entorno

# Backend
cp backend/.env.example backend/.env
# Edita backend/.env con tus secretos JWT (mínimo 32 caracteres)

# Frontend
cp frontend/.env.example frontend/.env

2. Levantar PostgreSQL

docker compose up postgres -d

3. Instalar dependencias e inicializar BD

# Backend
cd backend
npm install
npm run db:migrate     # crea tablas
npm run db:generate    # genera Prisma Client
npm run db:seed        # datos de prueba

4. Instalar dependencias frontend

cd ../frontend
npm install

5. Ejecutar en modo desarrollo

# Terminal 1 — Backend (puerto 4000)
cd backend && npm run dev

# Terminal 2 — Frontend (puerto 5173)
cd frontend && npm run dev

Abre: http://localhost:5173


Credenciales de prueba (seed)

Rol Email Contraseña
Admin admin@eventqr.com Admin@1234
Usuario user@eventqr.com User@1234

Arquitectura del Sistema

┌─────────────────────────────────────────────────────┐
│                     Frontend (React)                  │
│  ┌──────────┐  ┌──────────┐  ┌────────────────────┐  │
│  │  /events │  │/my-tickets│  │  /admin/*          │  │
│  │ EventCard│  │ QRTicket  │  │  Dashboard         │  │
│  │ EventForm│  │ (QR Image)│  │  CRUD de eventos   │  │
│  └──────────┘  └──────────┘  │  QRScanner (cámara)│  │
│                               └────────────────────┘  │
│  AuthContext → JWT en localStorage + auto-refresh     │
└───────────────────────┬─────────────────────────────┘
                        │ HTTP / Axios
┌───────────────────────▼─────────────────────────────┐
│                     Backend (Express)                 │
│  ┌─────────────────────────────────────────────────┐ │
│  │  Middlewares: helmet, cors, rate-limit, JWT auth│ │
│  └──────────┬──────────────────────────────────────┘ │
│  ┌──────────▼──────────────────────────────────────┐ │
│  │  Routes:  /api/auth  /api/events  /api/tickets  │ │
│  └──────────┬──────────────────────────────────────┘ │
│  ┌──────────▼──────────────────────────────────────┐ │
│  │  Services: AuthService EventService TicketService│ │
│  │  QrService: jwt.sign(ticketId) → qrcode.toDataURL│ │
│  └──────────┬──────────────────────────────────────┘ │
└─────────────┼───────────────────────────────────────┘
              │ Prisma ORM
┌─────────────▼───────────────────────────────────────┐
│                  PostgreSQL                           │
│   User ←──── Ticket ────→ Event                      │
│                RefreshToken                           │
└─────────────────────────────────────────────────────┘

Flujo del QR

1. Usuario se registra en evento
2. Backend crea Ticket en BD
3. QrService.createQrPayload(ticketId):
   jwt.sign({ ticketId, eventId, userId }, QR_SECRET)  ← sin expiración
4. QrService.generateQrImage(payload):
   qrcode.toDataURL(payload) → base64 PNG
5. Usuario ve QR en la app / lo descarga

6. Admin escanea con html5-qrcode (cámara)
7. POST /api/tickets/validate { qrPayload }
8. Backend: jwt.verify(payload, QR_SECRET) → extrae ticketId
9. Busca ticket en BD → verifica status === ACTIVE
10. UPDATE ticket SET status = 'USED', usedAt = NOW()
11. Responde: { valid: true, message: "¡Acceso permitido!" }

API Reference

Auth

Método Ruta Descripción
POST /api/auth/register Registro de usuario
POST /api/auth/login Inicio de sesión
POST /api/auth/refresh Renovar access token
POST /api/auth/logout Cerrar sesión
GET /api/auth/me Perfil del usuario autenticado

Events

Método Ruta Auth Descripción
GET /api/events Público Listar eventos activos
GET /api/events/:id Público Detalle de evento
GET /api/events/admin/all Admin Todos los eventos
POST /api/events Admin Crear evento
PATCH /api/events/:id Admin Actualizar evento
DELETE /api/events/:id Admin Eliminar evento
GET /api/events/:id/attendees Admin Lista de asistentes

Tickets

Método Ruta Auth Descripción
POST /api/tickets Usuario Obtener entrada
GET /api/tickets/mine Usuario Mis tickets con QR
GET /api/tickets/mine/:id Usuario Un ticket
PATCH /api/tickets/mine/:id/cancel Usuario Cancelar ticket
POST /api/tickets/validate Admin Validar QR escaneado

Despliegue completo con Docker

# Crea archivo .env con los secretos de producción
cp backend/.env.example backend/.env
# edita con secretos reales

docker compose up -d

Servicios:

Seguridad implementada

  • ✅ Contraseñas con bcrypt (12 rounds)
  • ✅ JWT de corta vida (15min) + refresh token rotation
  • ✅ Detección de robo de refresh token (revocación en cascada)
  • ✅ QR firmado criptográficamente (JWT, no falsificable)
  • ✅ Rate limiting en login/register (20 req/15min)
  • ✅ Helmet (headers de seguridad)
  • ✅ CORS restringido al origen del frontend
  • ✅ Validación con Zod en ambos extremos
  • ✅ Timing-safe login (evita timing attacks en email lookup)
  • ✅ Un ticket solo puede ser usado una vez (ACID transaction)
  • ✅ Usuario no puede comprar dos tickets para el mismo evento

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages