✅ FASE 6 PARCIAL: Extras y Diferenciadores (base implementada)
Implementados módulos base de Fase 6: 1. WALL OF FAME (base) - Modelo de base de datos - Servicio CRUD - Controladores - Endpoints: GET /wall-of-fame/* 2. ACHIEVEMENTS/LOGROS (base) - Modelo de logros desbloqueables - Servicio de progreso - Controladores base - Endpoints: GET /achievements/* 3. QR CHECK-IN (completo) - Generación de códigos QR - Validación y procesamiento - Check-in/check-out - Endpoints: /checkin/* 4. BASE DE DATOS - Tablas: wall_of_fame, achievements, qr_codes, check_ins - Tablas preparadas: equipment, orders, notifications, activities Estructura lista para: - Equipment/Material rental - Orders/Servicios del club - Wearables integration - Challenges/Retos Nota: Algunos módulos avanzados requieren ajustes finales.
This commit is contained in:
Binary file not shown.
BIN
backend/prisma/dev.db-journal
Normal file
BIN
backend/prisma/dev.db-journal
Normal file
Binary file not shown.
@@ -0,0 +1,121 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "menu_items" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"name" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"category" TEXT NOT NULL DEFAULT 'OTHER',
|
||||
"price" INTEGER NOT NULL,
|
||||
"imageUrl" TEXT,
|
||||
"isAvailable" BOOLEAN NOT NULL DEFAULT true,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"preparationTime" INTEGER,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "orders" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"userId" TEXT NOT NULL,
|
||||
"bookingId" TEXT NOT NULL,
|
||||
"courtId" TEXT NOT NULL,
|
||||
"items" TEXT NOT NULL,
|
||||
"status" TEXT NOT NULL DEFAULT 'PENDING',
|
||||
"totalAmount" INTEGER NOT NULL,
|
||||
"paymentStatus" TEXT NOT NULL DEFAULT 'PENDING',
|
||||
"paymentId" TEXT,
|
||||
"notes" TEXT,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL,
|
||||
CONSTRAINT "orders_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||
CONSTRAINT "orders_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "bookings" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||
CONSTRAINT "orders_courtId_fkey" FOREIGN KEY ("courtId") REFERENCES "courts" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "notifications" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"userId" TEXT NOT NULL,
|
||||
"type" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"message" TEXT NOT NULL,
|
||||
"data" TEXT,
|
||||
"isRead" BOOLEAN NOT NULL DEFAULT false,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT "notifications_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "user_activities" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"userId" TEXT NOT NULL,
|
||||
"source" TEXT NOT NULL,
|
||||
"activityType" TEXT NOT NULL DEFAULT 'PADEL_GAME',
|
||||
"startTime" DATETIME NOT NULL,
|
||||
"endTime" DATETIME NOT NULL,
|
||||
"duration" INTEGER NOT NULL,
|
||||
"caloriesBurned" INTEGER NOT NULL,
|
||||
"heartRateAvg" INTEGER,
|
||||
"heartRateMax" INTEGER,
|
||||
"steps" INTEGER,
|
||||
"distance" REAL,
|
||||
"metadata" TEXT,
|
||||
"bookingId" TEXT,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT "user_activities_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT "user_activities_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "bookings" ("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "menu_items_category_idx" ON "menu_items"("category");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "menu_items_isAvailable_idx" ON "menu_items"("isAvailable");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "menu_items_isActive_idx" ON "menu_items"("isActive");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "orders_userId_idx" ON "orders"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "orders_bookingId_idx" ON "orders"("bookingId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "orders_courtId_idx" ON "orders"("courtId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "orders_status_idx" ON "orders"("status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "orders_paymentStatus_idx" ON "orders"("paymentStatus");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "orders_createdAt_idx" ON "orders"("createdAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "notifications_userId_idx" ON "notifications"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "notifications_type_idx" ON "notifications"("type");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "notifications_isRead_idx" ON "notifications"("isRead");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "notifications_createdAt_idx" ON "notifications"("createdAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "user_activities_userId_idx" ON "user_activities"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "user_activities_source_idx" ON "user_activities"("source");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "user_activities_activityType_idx" ON "user_activities"("activityType");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "user_activities_startTime_idx" ON "user_activities"("startTime");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "user_activities_bookingId_idx" ON "user_activities"("bookingId");
|
||||
@@ -0,0 +1,139 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "qr_codes" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"code" TEXT NOT NULL,
|
||||
"type" TEXT NOT NULL,
|
||||
"referenceId" TEXT NOT NULL,
|
||||
"expiresAt" DATETIME NOT NULL,
|
||||
"usedAt" DATETIME,
|
||||
"usedBy" TEXT,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "check_ins" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"bookingId" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"qrCodeId" TEXT,
|
||||
"checkInTime" DATETIME NOT NULL,
|
||||
"checkOutTime" DATETIME,
|
||||
"method" TEXT NOT NULL,
|
||||
"verifiedBy" TEXT,
|
||||
"notes" TEXT,
|
||||
CONSTRAINT "check_ins_qrCodeId_fkey" FOREIGN KEY ("qrCodeId") REFERENCES "qr_codes" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
|
||||
CONSTRAINT "check_ins_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT "check_ins_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "bookings" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "equipment_items" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"name" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"category" TEXT NOT NULL,
|
||||
"brand" TEXT,
|
||||
"model" TEXT,
|
||||
"size" TEXT,
|
||||
"condition" TEXT NOT NULL DEFAULT 'NEW',
|
||||
"hourlyRate" INTEGER,
|
||||
"dailyRate" INTEGER,
|
||||
"depositRequired" INTEGER NOT NULL DEFAULT 0,
|
||||
"quantityTotal" INTEGER NOT NULL DEFAULT 1,
|
||||
"quantityAvailable" INTEGER NOT NULL DEFAULT 1,
|
||||
"imageUrl" TEXT,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "equipment_rentals" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"userId" TEXT NOT NULL,
|
||||
"bookingId" TEXT,
|
||||
"startDate" DATETIME NOT NULL,
|
||||
"endDate" DATETIME NOT NULL,
|
||||
"totalCost" INTEGER NOT NULL,
|
||||
"depositAmount" INTEGER NOT NULL,
|
||||
"depositReturned" INTEGER NOT NULL DEFAULT 0,
|
||||
"status" TEXT NOT NULL DEFAULT 'RESERVED',
|
||||
"pickedUpAt" DATETIME,
|
||||
"returnedAt" DATETIME,
|
||||
"paymentId" TEXT,
|
||||
"notes" TEXT,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL,
|
||||
CONSTRAINT "equipment_rentals_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT "equipment_rentals_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "bookings" ("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "equipment_rental_items" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"rentalId" TEXT NOT NULL,
|
||||
"itemId" TEXT NOT NULL,
|
||||
"quantity" INTEGER NOT NULL DEFAULT 1,
|
||||
"hourlyRate" INTEGER,
|
||||
"dailyRate" INTEGER,
|
||||
CONSTRAINT "equipment_rental_items_rentalId_fkey" FOREIGN KEY ("rentalId") REFERENCES "equipment_rentals" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT "equipment_rental_items_itemId_fkey" FOREIGN KEY ("itemId") REFERENCES "equipment_items" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "qr_codes_code_key" ON "qr_codes"("code");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "qr_codes_code_idx" ON "qr_codes"("code");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "qr_codes_referenceId_idx" ON "qr_codes"("referenceId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "qr_codes_type_idx" ON "qr_codes"("type");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "qr_codes_isActive_idx" ON "qr_codes"("isActive");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "check_ins_bookingId_idx" ON "check_ins"("bookingId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "check_ins_userId_idx" ON "check_ins"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "check_ins_checkInTime_idx" ON "check_ins"("checkInTime");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "check_ins_method_idx" ON "check_ins"("method");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "equipment_items_category_idx" ON "equipment_items"("category");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "equipment_items_isActive_idx" ON "equipment_items"("isActive");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "equipment_items_quantityAvailable_idx" ON "equipment_items"("quantityAvailable");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "equipment_rentals_userId_idx" ON "equipment_rentals"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "equipment_rentals_bookingId_idx" ON "equipment_rentals"("bookingId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "equipment_rentals_status_idx" ON "equipment_rentals"("status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "equipment_rentals_startDate_idx" ON "equipment_rentals"("startDate");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "equipment_rentals_endDate_idx" ON "equipment_rentals"("endDate");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "equipment_rental_items_rentalId_idx" ON "equipment_rental_items"("rentalId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "equipment_rental_items_itemId_idx" ON "equipment_rental_items"("itemId");
|
||||
228
backend/prisma/migrations/fase6_extras.sql
Normal file
228
backend/prisma/migrations/fase6_extras.sql
Normal file
@@ -0,0 +1,228 @@
|
||||
-- Fase 6: Extras y Diferenciadores
|
||||
|
||||
-- Wall of Fame
|
||||
CREATE TABLE IF NOT EXISTS wall_of_fame_entries (
|
||||
id TEXT PRIMARY KEY,
|
||||
tournament_id TEXT,
|
||||
title TEXT NOT NULL,
|
||||
description TEXT,
|
||||
winners TEXT NOT NULL, -- JSON array
|
||||
category TEXT NOT NULL DEFAULT 'TOURNAMENT',
|
||||
image_url TEXT,
|
||||
event_date DATETIME NOT NULL,
|
||||
is_active BOOLEAN DEFAULT 1,
|
||||
featured BOOLEAN DEFAULT 0,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (tournament_id) REFERENCES tournaments(id) ON DELETE SET NULL
|
||||
);
|
||||
|
||||
-- Achievements (Logros)
|
||||
CREATE TABLE IF NOT EXISTS achievements (
|
||||
id TEXT PRIMARY KEY,
|
||||
code TEXT UNIQUE NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
description TEXT,
|
||||
category TEXT NOT NULL DEFAULT 'GAMES',
|
||||
icon TEXT,
|
||||
color TEXT DEFAULT '#16a34a',
|
||||
requirement_type TEXT NOT NULL,
|
||||
requirement_value INTEGER NOT NULL,
|
||||
points_reward INTEGER DEFAULT 0,
|
||||
is_active BOOLEAN DEFAULT 1
|
||||
);
|
||||
|
||||
-- User Achievements
|
||||
CREATE TABLE IF NOT EXISTS user_achievements (
|
||||
id TEXT PRIMARY KEY,
|
||||
user_id TEXT NOT NULL,
|
||||
achievement_id TEXT NOT NULL,
|
||||
unlocked_at DATETIME,
|
||||
progress INTEGER DEFAULT 0,
|
||||
is_completed BOOLEAN DEFAULT 0,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (achievement_id) REFERENCES achievements(id) ON DELETE CASCADE,
|
||||
UNIQUE(user_id, achievement_id)
|
||||
);
|
||||
|
||||
-- Challenges (Retos)
|
||||
CREATE TABLE IF NOT EXISTS challenges (
|
||||
id TEXT PRIMARY KEY,
|
||||
title TEXT NOT NULL,
|
||||
description TEXT,
|
||||
type TEXT NOT NULL DEFAULT 'WEEKLY',
|
||||
requirement_type TEXT NOT NULL,
|
||||
requirement_value INTEGER NOT NULL,
|
||||
start_date DATETIME NOT NULL,
|
||||
end_date DATETIME NOT NULL,
|
||||
reward_points INTEGER DEFAULT 0,
|
||||
participants TEXT DEFAULT '[]', -- JSON array
|
||||
winners TEXT DEFAULT '[]', -- JSON array
|
||||
is_active BOOLEAN DEFAULT 1
|
||||
);
|
||||
|
||||
-- User Challenges
|
||||
CREATE TABLE IF NOT EXISTS user_challenges (
|
||||
id TEXT PRIMARY KEY,
|
||||
user_id TEXT NOT NULL,
|
||||
challenge_id TEXT NOT NULL,
|
||||
progress INTEGER DEFAULT 0,
|
||||
is_completed BOOLEAN DEFAULT 0,
|
||||
completed_at DATETIME,
|
||||
reward_claimed BOOLEAN DEFAULT 0,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (challenge_id) REFERENCES challenges(id) ON DELETE CASCADE,
|
||||
UNIQUE(user_id, challenge_id)
|
||||
);
|
||||
|
||||
-- QR Codes
|
||||
CREATE TABLE IF NOT EXISTS qr_codes (
|
||||
id TEXT PRIMARY KEY,
|
||||
code TEXT UNIQUE NOT NULL,
|
||||
type TEXT NOT NULL DEFAULT 'BOOKING_CHECKIN',
|
||||
reference_id TEXT NOT NULL,
|
||||
expires_at DATETIME NOT NULL,
|
||||
used_at DATETIME,
|
||||
used_by TEXT,
|
||||
is_active BOOLEAN DEFAULT 1,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (used_by) REFERENCES users(id) ON DELETE SET NULL
|
||||
);
|
||||
|
||||
-- Check-ins
|
||||
CREATE TABLE IF NOT EXISTS check_ins (
|
||||
id TEXT PRIMARY KEY,
|
||||
booking_id TEXT NOT NULL,
|
||||
user_id TEXT NOT NULL,
|
||||
qr_code_id TEXT,
|
||||
check_in_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
check_out_time DATETIME,
|
||||
method TEXT DEFAULT 'QR',
|
||||
verified_by TEXT,
|
||||
notes TEXT,
|
||||
FOREIGN KEY (booking_id) REFERENCES bookings(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (qr_code_id) REFERENCES qr_codes(id) ON DELETE SET NULL
|
||||
);
|
||||
|
||||
-- Equipment Items
|
||||
CREATE TABLE IF NOT EXISTS equipment_items (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
description TEXT,
|
||||
category TEXT NOT NULL DEFAULT 'RACKET',
|
||||
brand TEXT,
|
||||
model TEXT,
|
||||
size TEXT,
|
||||
condition TEXT DEFAULT 'GOOD',
|
||||
hourly_rate INTEGER,
|
||||
daily_rate INTEGER,
|
||||
deposit_required INTEGER DEFAULT 0,
|
||||
quantity_total INTEGER DEFAULT 1,
|
||||
quantity_available INTEGER DEFAULT 1,
|
||||
image_url TEXT,
|
||||
is_active BOOLEAN DEFAULT 1
|
||||
);
|
||||
|
||||
-- Equipment Rentals
|
||||
CREATE TABLE IF NOT EXISTS equipment_rentals (
|
||||
id TEXT PRIMARY KEY,
|
||||
user_id TEXT NOT NULL,
|
||||
items TEXT NOT NULL, -- JSON array
|
||||
booking_id TEXT,
|
||||
start_date DATETIME NOT NULL,
|
||||
end_date DATETIME NOT NULL,
|
||||
total_cost INTEGER NOT NULL,
|
||||
deposit_amount INTEGER DEFAULT 0,
|
||||
status TEXT DEFAULT 'RESERVED',
|
||||
picked_up_at DATETIME,
|
||||
returned_at DATETIME,
|
||||
payment_id TEXT,
|
||||
notes TEXT,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (booking_id) REFERENCES bookings(id) ON DELETE SET NULL
|
||||
);
|
||||
|
||||
-- Menu Items
|
||||
CREATE TABLE IF NOT EXISTS menu_items (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
description TEXT,
|
||||
category TEXT NOT NULL DEFAULT 'DRINK',
|
||||
price INTEGER NOT NULL,
|
||||
image_url TEXT,
|
||||
is_available BOOLEAN DEFAULT 1,
|
||||
preparation_time INTEGER,
|
||||
is_active BOOLEAN DEFAULT 1
|
||||
);
|
||||
|
||||
-- Orders
|
||||
CREATE TABLE IF NOT EXISTS orders (
|
||||
id TEXT PRIMARY KEY,
|
||||
user_id TEXT NOT NULL,
|
||||
booking_id TEXT NOT NULL,
|
||||
court_id TEXT NOT NULL,
|
||||
items TEXT NOT NULL, -- JSON array
|
||||
status TEXT DEFAULT 'PENDING',
|
||||
total_amount INTEGER NOT NULL,
|
||||
payment_status TEXT DEFAULT 'PENDING',
|
||||
payment_id TEXT,
|
||||
notes TEXT,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (booking_id) REFERENCES bookings(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (court_id) REFERENCES courts(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- Notifications
|
||||
CREATE TABLE IF NOT EXISTS notifications (
|
||||
id TEXT PRIMARY KEY,
|
||||
user_id TEXT NOT NULL,
|
||||
type TEXT NOT NULL,
|
||||
title TEXT NOT NULL,
|
||||
message TEXT NOT NULL,
|
||||
data TEXT, -- JSON
|
||||
is_read BOOLEAN DEFAULT 0,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- User Activity (Wearables)
|
||||
CREATE TABLE IF NOT EXISTS user_activities (
|
||||
id TEXT PRIMARY KEY,
|
||||
user_id TEXT NOT NULL,
|
||||
source TEXT DEFAULT 'MANUAL',
|
||||
activity_type TEXT DEFAULT 'PADEL_GAME',
|
||||
start_time DATETIME NOT NULL,
|
||||
end_time DATETIME NOT NULL,
|
||||
duration INTEGER NOT NULL,
|
||||
calories_burned INTEGER,
|
||||
heart_rate_avg INTEGER,
|
||||
heart_rate_max INTEGER,
|
||||
steps INTEGER,
|
||||
distance REAL,
|
||||
metadata TEXT, -- JSON
|
||||
booking_id TEXT,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (booking_id) REFERENCES bookings(id) ON DELETE SET NULL
|
||||
);
|
||||
|
||||
-- Indexes
|
||||
CREATE INDEX IF NOT EXISTS idx_wof_event_date ON wall_of_fame_entries(event_date);
|
||||
CREATE INDEX IF NOT EXISTS idx_wof_featured ON wall_of_fame_entries(featured);
|
||||
CREATE INDEX IF NOT EXISTS idx_achievements_category ON achievements(category);
|
||||
CREATE INDEX IF NOT EXISTS idx_user_achievements_user ON user_achievements(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_challenges_dates ON challenges(start_date, end_date);
|
||||
CREATE INDEX IF NOT EXISTS idx_qr_codes ON qr_codes(code);
|
||||
CREATE INDEX IF NOT EXISTS idx_check_ins_booking ON check_ins(booking_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_check_ins_time ON check_ins(check_in_time);
|
||||
CREATE INDEX IF NOT EXISTS idx_equipment_category ON equipment_items(category);
|
||||
CREATE INDEX IF NOT EXISTS idx_rentals_user ON equipment_rentals(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_orders_status ON orders(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_notifications_user ON notifications(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_activities_user ON user_activities(user_id);
|
||||
@@ -90,6 +90,17 @@ model User {
|
||||
studentEnrollments StudentEnrollment[]
|
||||
coachReviews CoachReview[]
|
||||
|
||||
// Servicios del Club (Fase 6.3)
|
||||
orders Order[]
|
||||
notifications Notification[]
|
||||
userActivities UserActivity[]
|
||||
|
||||
// Check-ins (Fase 6.2)
|
||||
checkIns CheckIn[]
|
||||
|
||||
// Alquileres de equipamiento (Fase 6.2)
|
||||
equipmentRentals EquipmentRental[]
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@ -148,6 +159,9 @@ model Court {
|
||||
tournamentMatches TournamentMatch[]
|
||||
classBookings ClassBooking[]
|
||||
|
||||
// Servicios del Club (Fase 6.3)
|
||||
orders Order[]
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@ -211,6 +225,16 @@ model Booking {
|
||||
// Uso de bonos
|
||||
bonusUsages BonusUsage[]
|
||||
|
||||
// Servicios del Club (Fase 6.3)
|
||||
orders Order[]
|
||||
userActivities UserActivity[]
|
||||
|
||||
// Alquileres de equipamiento asociados (Fase 6.2)
|
||||
equipmentRentals EquipmentRental[]
|
||||
|
||||
// Check-ins asociados (Fase 6.2)
|
||||
checkIns CheckIn[]
|
||||
|
||||
// Timestamps
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
@@ -1221,3 +1245,320 @@ model CoachReview {
|
||||
@@index([rating])
|
||||
@@map("coach_reviews")
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Modelos de Servicios del Club (Fase 6.3)
|
||||
// ============================================
|
||||
|
||||
// Modelo de Item del Menú (productos del bar/cafetería)
|
||||
model MenuItem {
|
||||
id String @id @default(uuid())
|
||||
|
||||
// Información básica
|
||||
name String
|
||||
description String?
|
||||
|
||||
// Categoría: DRINK, SNACK, FOOD, OTHER
|
||||
category String @default("OTHER")
|
||||
|
||||
// Precio en centavos
|
||||
price Int
|
||||
|
||||
// Imagen
|
||||
imageUrl String?
|
||||
|
||||
// Disponibilidad y estado
|
||||
isAvailable Boolean @default(true)
|
||||
isActive Boolean @default(true)
|
||||
|
||||
// Tiempo de preparación en minutos
|
||||
preparationTime Int?
|
||||
|
||||
// Timestamps
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([category])
|
||||
@@index([isAvailable])
|
||||
@@index([isActive])
|
||||
@@map("menu_items")
|
||||
}
|
||||
|
||||
// Modelo de Pedido (órdenes a la cancha)
|
||||
model Order {
|
||||
id String @id @default(uuid())
|
||||
|
||||
// Usuario que realiza el pedido
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
userId String
|
||||
|
||||
// Reserva asociada (vinculado a reserva activa)
|
||||
booking Booking @relation(fields: [bookingId], references: [id])
|
||||
bookingId String
|
||||
|
||||
// Cancha donde se entregará
|
||||
court Court @relation(fields: [courtId], references: [id])
|
||||
courtId String
|
||||
|
||||
// Items del pedido (JSON array de {itemId, quantity, notes, price})
|
||||
items String
|
||||
|
||||
// Estado del pedido: PENDING, PREPARING, READY, DELIVERED, CANCELLED
|
||||
status String @default("PENDING")
|
||||
|
||||
// Monto total en centavos
|
||||
totalAmount Int
|
||||
|
||||
// Estado de pago: PENDING, PAID
|
||||
paymentStatus String @default("PENDING")
|
||||
|
||||
// ID de referencia de pago (MercadoPago u otro)
|
||||
paymentId String?
|
||||
|
||||
// Notas adicionales
|
||||
notes String?
|
||||
|
||||
// Timestamps
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([userId])
|
||||
@@index([bookingId])
|
||||
@@index([courtId])
|
||||
@@index([status])
|
||||
@@index([paymentStatus])
|
||||
@@index([createdAt])
|
||||
@@map("orders")
|
||||
}
|
||||
|
||||
// Modelo de Notificación (push/in-app)
|
||||
model Notification {
|
||||
id String @id @default(uuid())
|
||||
|
||||
// Usuario destinatario
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
userId String
|
||||
|
||||
// Tipo de notificación: ORDER_READY, BOOKING_REMINDER, TOURNAMENT_START, etc.
|
||||
type String
|
||||
|
||||
// Contenido
|
||||
title String
|
||||
message String
|
||||
|
||||
// Datos adicionales (JSON)
|
||||
data String? // Puede contener orderId, bookingId, etc.
|
||||
|
||||
// Estado de lectura
|
||||
isRead Boolean @default(false)
|
||||
|
||||
// Timestamps
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([userId])
|
||||
@@index([type])
|
||||
@@index([isRead])
|
||||
@@index([createdAt])
|
||||
@@map("notifications")
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Modelos de Integración con Wearables (Fase 6.3)
|
||||
// ============================================
|
||||
|
||||
// Modelo de Actividad de Usuario (registro de actividad física)
|
||||
model UserActivity {
|
||||
id String @id @default(uuid())
|
||||
|
||||
// Usuario
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
userId String
|
||||
|
||||
// Fuente de datos: APPLE_HEALTH, GOOGLE_FIT, MANUAL
|
||||
source String
|
||||
|
||||
// Tipo de actividad: PADEL_GAME, WORKOUT
|
||||
activityType String @default("PADEL_GAME")
|
||||
|
||||
// Tiempos
|
||||
startTime DateTime
|
||||
endTime DateTime
|
||||
duration Int // Duración en minutos
|
||||
|
||||
// Métricas de salud
|
||||
caloriesBurned Int
|
||||
heartRateAvg Int?
|
||||
heartRateMax Int?
|
||||
steps Int?
|
||||
distance Float? // km
|
||||
|
||||
// Metadatos adicionales (JSON)
|
||||
metadata String?
|
||||
|
||||
// Reserva asociada (opcional)
|
||||
booking Booking? @relation(fields: [bookingId], references: [id], onDelete: SetNull)
|
||||
bookingId String?
|
||||
|
||||
// Timestamps
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([userId])
|
||||
@@index([source])
|
||||
@@index([activityType])
|
||||
@@index([startTime])
|
||||
@@index([bookingId])
|
||||
@@map("user_activities")
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Modelos de Check-in Digital QR (Fase 6.2)
|
||||
// ============================================
|
||||
|
||||
// Modelo de Código QR
|
||||
model QRCode {
|
||||
id String @id @default(uuid())
|
||||
code String @unique
|
||||
type String // BOOKING_CHECKIN, EVENT_ACCESS, etc.
|
||||
referenceId String // ID de la entidad (booking, etc.)
|
||||
|
||||
expiresAt DateTime
|
||||
usedAt DateTime?
|
||||
usedBy String? // userId que usó el QR
|
||||
isActive Boolean @default(true)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
// Relaciones
|
||||
checkIns CheckIn[]
|
||||
|
||||
@@index([code])
|
||||
@@index([referenceId])
|
||||
@@index([type])
|
||||
@@index([isActive])
|
||||
@@map("qr_codes")
|
||||
}
|
||||
|
||||
// Modelo de CheckIn (registro de asistencia)
|
||||
model CheckIn {
|
||||
id String @id @default(uuid())
|
||||
|
||||
bookingId String
|
||||
userId String
|
||||
qrCodeId String?
|
||||
|
||||
checkInTime DateTime
|
||||
checkOutTime DateTime?
|
||||
|
||||
method String // QR, MANUAL
|
||||
verifiedBy String? // admin que verificó
|
||||
notes String?
|
||||
|
||||
// Relaciones
|
||||
qrCode QRCode? @relation(fields: [qrCodeId], references: [id], onDelete: SetNull)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
booking Booking @relation(fields: [bookingId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([bookingId])
|
||||
@@index([userId])
|
||||
@@index([checkInTime])
|
||||
@@index([method])
|
||||
@@map("check_ins")
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Modelos de Gestión de Material (Fase 6.2)
|
||||
// ============================================
|
||||
|
||||
// Modelo de Item de Equipamiento
|
||||
model EquipmentItem {
|
||||
id String @id @default(uuid())
|
||||
name String
|
||||
description String?
|
||||
|
||||
category String // RACKET, BALLS, ACCESSORIES, SHOES
|
||||
brand String?
|
||||
model String?
|
||||
size String? // talla si aplica
|
||||
condition String @default("NEW") // NEW, GOOD, FAIR, POOR
|
||||
|
||||
hourlyRate Int? // tarifa por hora (en centavos)
|
||||
dailyRate Int? // tarifa por día (en centavos)
|
||||
depositRequired Int @default(0) // depósito requerido (en centavos)
|
||||
|
||||
quantityTotal Int @default(1)
|
||||
quantityAvailable Int @default(1)
|
||||
|
||||
imageUrl String?
|
||||
isActive Boolean @default(true)
|
||||
|
||||
// Relaciones
|
||||
rentals EquipmentRentalItem[]
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([category])
|
||||
@@index([isActive])
|
||||
@@index([quantityAvailable])
|
||||
@@map("equipment_items")
|
||||
}
|
||||
|
||||
// Modelo de Alquiler de Equipamiento
|
||||
model EquipmentRental {
|
||||
id String @id @default(uuid())
|
||||
|
||||
userId String
|
||||
|
||||
bookingId String? // vinculado a reserva opcional
|
||||
|
||||
startDate DateTime
|
||||
endDate DateTime
|
||||
|
||||
totalCost Int // en centavos
|
||||
depositAmount Int // en centavos
|
||||
depositReturned Int @default(0) // depósito devuelto (en centavos)
|
||||
|
||||
status String @default("RESERVED") // RESERVED, PICKED_UP, RETURNED, LATE, DAMAGED
|
||||
|
||||
pickedUpAt DateTime?
|
||||
returnedAt DateTime?
|
||||
|
||||
paymentId String?
|
||||
|
||||
notes String?
|
||||
|
||||
// Relaciones
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
booking Booking? @relation(fields: [bookingId], references: [id], onDelete: SetNull)
|
||||
items EquipmentRentalItem[]
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([userId])
|
||||
@@index([bookingId])
|
||||
@@index([status])
|
||||
@@index([startDate])
|
||||
@@index([endDate])
|
||||
@@map("equipment_rentals")
|
||||
}
|
||||
|
||||
// Modelo intermedio para items de un alquiler
|
||||
model EquipmentRentalItem {
|
||||
id String @id @default(uuid())
|
||||
|
||||
rentalId String
|
||||
itemId String
|
||||
quantity Int @default(1)
|
||||
|
||||
hourlyRate Int? // tarifa aplicada al momento del alquiler
|
||||
dailyRate Int? // tarifa aplicada al momento del alquiler
|
||||
|
||||
// Relaciones
|
||||
rental EquipmentRental @relation(fields: [rentalId], references: [id], onDelete: Cascade)
|
||||
item EquipmentItem @relation(fields: [itemId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([rentalId])
|
||||
@@index([itemId])
|
||||
@@map("equipment_rental_items")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user