diff --git a/.env.prod.example b/.env.prod.example new file mode 100644 index 0000000..6056a13 --- /dev/null +++ b/.env.prod.example @@ -0,0 +1,57 @@ +# =========================================== +# Produccion - Direccion de Admision 2026 +# =========================================== +# Copiar este archivo como .env.prod y completar los valores + +# --- App --- +APP_NAME="Direccion de Admision" +APP_ENV=production +APP_KEY= +APP_DEBUG=false +APP_URL=https://tu-dominio.com + +# Puerto donde se expone la app (default: 80) +APP_PORT=80 + +# --- Base de datos --- +DB_CONNECTION=mysql +DB_HOST=mysql +DB_PORT=3306 +DB_DATABASE=admision_2026 +DB_USERNAME=root +DB_PASSWORD=CAMBIAR_PASSWORD_SEGURA + +# --- Sessions --- +SESSION_DRIVER=database +SESSION_LIFETIME=120 +SESSION_ENCRYPT=true +SESSION_DOMAIN=tu-dominio.com + +# --- Cache & Queue --- +CACHE_STORE=database +QUEUE_CONNECTION=database + +# --- Sanctum --- +SANCTUM_STATEFUL_DOMAINS=tu-dominio.com + +# --- Frontend --- +VITE_API_URL=/api + +# --- Mail (configurar segun proveedor) --- +MAIL_MAILER=smtp +MAIL_HOST=smtp.ejemplo.com +MAIL_PORT=587 +MAIL_USERNAME= +MAIL_PASSWORD= +MAIL_ENCRYPTION=tls +MAIL_FROM_ADDRESS="admision@tu-dominio.com" +MAIL_FROM_NAME="${APP_NAME}" + +# --- Logging --- +LOG_CHANNEL=stack +LOG_STACK=single +LOG_LEVEL=error + +# --- Misc --- +BCRYPT_ROUNDS=12 +FILESYSTEM_DISK=local diff --git a/admision_2026_200.sql b/admision_2026_200.sql new file mode 100644 index 0000000..bbc7cd8 --- /dev/null +++ b/admision_2026_200.sql @@ -0,0 +1,687 @@ +-- -------------------------------------------------------- +-- Host: 127.0.0.1 +-- Versión del servidor: 8.0.30 - MySQL Community Server - GPL +-- SO del servidor: Win64 +-- HeidiSQL Versión: 12.1.0.6537 +-- -------------------------------------------------------- + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET NAMES utf8 */; +/*!50503 SET NAMES utf8mb4 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + + +-- Volcando estructura de base de datos para admision_2026 +DROP DATABASE IF EXISTS `admision_2026`; +CREATE DATABASE IF NOT EXISTS `admision_2026` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */; +USE `admision_2026`; + +-- Volcando estructura para tabla admision_2026.areas +DROP TABLE IF EXISTS `areas`; +CREATE TABLE IF NOT EXISTS `areas` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `nombre` varchar(100) NOT NULL, + `codigo` varchar(20) NOT NULL, + `descripcion` varchar(500) DEFAULT NULL, + `activo` tinyint(1) NOT NULL DEFAULT '1', + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `codigo` (`codigo`), + KEY `idx_areas_activo` (`activo`), + KEY `idx_areas_codigo` (`codigo`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- La exportación de datos fue deseleccionada. + +-- Volcando estructura para tabla admision_2026.areas_admision +DROP TABLE IF EXISTS `areas_admision`; +CREATE TABLE IF NOT EXISTS `areas_admision` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `nombre` varchar(150) NOT NULL, + `descripcion` text, + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- La exportación de datos fue deseleccionada. + +-- Volcando estructura para tabla admision_2026.area_curso +DROP TABLE IF EXISTS `area_curso`; +CREATE TABLE IF NOT EXISTS `area_curso` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `area_id` bigint unsigned NOT NULL, + `curso_id` bigint unsigned NOT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE, + KEY `fk_area_curso_area` (`area_id`) USING BTREE, + KEY `fk_area_curso_curso` (`curso_id`) USING BTREE, + CONSTRAINT `fk_area_curso_area` FOREIGN KEY (`area_id`) REFERENCES `areas` (`id`) ON DELETE CASCADE, + CONSTRAINT `fk_area_curso_curso` FOREIGN KEY (`curso_id`) REFERENCES `cursos` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- La exportación de datos fue deseleccionada. + +-- Volcando estructura para tabla admision_2026.area_proceso +DROP TABLE IF EXISTS `area_proceso`; +CREATE TABLE IF NOT EXISTS `area_proceso` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `area_id` bigint unsigned NOT NULL, + `proceso_id` bigint unsigned NOT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `area_proceso_unique` (`area_id`,`proceso_id`), + KEY `fk_area_proceso_proceso` (`proceso_id`), + CONSTRAINT `fk_area_proceso_area` FOREIGN KEY (`area_id`) REFERENCES `areas` (`id`) ON DELETE CASCADE, + CONSTRAINT `fk_area_proceso_proceso` FOREIGN KEY (`proceso_id`) REFERENCES `procesos` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- La exportación de datos fue deseleccionada. + +-- Volcando estructura para tabla admision_2026.cache +DROP TABLE IF EXISTS `cache`; +CREATE TABLE IF NOT EXISTS `cache` ( + `key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `value` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `expiration` int NOT NULL, + PRIMARY KEY (`key`), + KEY `cache_expiration_index` (`expiration`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- La exportación de datos fue deseleccionada. + +-- Volcando estructura para tabla admision_2026.cache_locks +DROP TABLE IF EXISTS `cache_locks`; +CREATE TABLE IF NOT EXISTS `cache_locks` ( + `key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `owner` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `expiration` int NOT NULL, + PRIMARY KEY (`key`), + KEY `cache_locks_expiration_index` (`expiration`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- La exportación de datos fue deseleccionada. + +-- Volcando estructura para tabla admision_2026.cursos +DROP TABLE IF EXISTS `cursos`; +CREATE TABLE IF NOT EXISTS `cursos` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `nombre` varchar(100) NOT NULL, + `codigo` varchar(20) NOT NULL, + `descripcion` varchar(500) DEFAULT NULL, + `activo` tinyint(1) NOT NULL DEFAULT '1', + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `codigo` (`codigo`), + KEY `idx_cursos_activo` (`activo`), + KEY `idx_cursos_codigo` (`codigo`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- La exportación de datos fue deseleccionada. + +-- Volcando estructura para tabla admision_2026.examenes +DROP TABLE IF EXISTS `examenes`; +CREATE TABLE IF NOT EXISTS `examenes` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `postulante_id` bigint unsigned NOT NULL, + `area_proceso_id` bigint unsigned NOT NULL, + `pagado` tinyint(1) NOT NULL DEFAULT '0', + `tipo_pago` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `pago_id` decimal(20,6) DEFAULT '0.000000', + `intentos` int NOT NULL DEFAULT '0', + `hora_inicio` timestamp NULL DEFAULT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE, + KEY `examenes_postulante_id_foreign` (`postulante_id`) USING BTREE, + KEY `examenes_area_proceso_id_foreign` (`area_proceso_id`) USING BTREE, + CONSTRAINT `examenes_area_proceso_id_foreign` FOREIGN KEY (`area_proceso_id`) REFERENCES `area_proceso` (`id`) ON DELETE CASCADE, + CONSTRAINT `examenes_postulante_id_foreign` FOREIGN KEY (`postulante_id`) REFERENCES `postulantes` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- La exportación de datos fue deseleccionada. + +-- Volcando estructura para tabla admision_2026.failed_jobs +DROP TABLE IF EXISTS `failed_jobs`; +CREATE TABLE IF NOT EXISTS `failed_jobs` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `uuid` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `connection` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `queue` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `payload` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `exception` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `failed_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `failed_jobs_uuid_unique` (`uuid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- La exportación de datos fue deseleccionada. + +-- Volcando estructura para tabla admision_2026.jobs +DROP TABLE IF EXISTS `jobs`; +CREATE TABLE IF NOT EXISTS `jobs` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `queue` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `payload` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `attempts` tinyint unsigned NOT NULL, + `reserved_at` int unsigned DEFAULT NULL, + `available_at` int unsigned NOT NULL, + `created_at` int unsigned NOT NULL, + PRIMARY KEY (`id`), + KEY `jobs_queue_index` (`queue`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- La exportación de datos fue deseleccionada. + +-- Volcando estructura para tabla admision_2026.job_batches +DROP TABLE IF EXISTS `job_batches`; +CREATE TABLE IF NOT EXISTS `job_batches` ( + `id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `total_jobs` int NOT NULL, + `pending_jobs` int NOT NULL, + `failed_jobs` int NOT NULL, + `failed_job_ids` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `options` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `cancelled_at` int DEFAULT NULL, + `created_at` int NOT NULL, + `finished_at` int DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- La exportación de datos fue deseleccionada. + +-- Volcando estructura para tabla admision_2026.migrations +DROP TABLE IF EXISTS `migrations`; +CREATE TABLE IF NOT EXISTS `migrations` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `migration` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `batch` int NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- La exportación de datos fue deseleccionada. + +-- Volcando estructura para tabla admision_2026.model_has_permissions +DROP TABLE IF EXISTS `model_has_permissions`; +CREATE TABLE IF NOT EXISTS `model_has_permissions` ( + `permission_id` bigint unsigned NOT NULL, + `model_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `model_id` bigint unsigned NOT NULL, + PRIMARY KEY (`permission_id`,`model_id`,`model_type`), + KEY `model_has_permissions_model_id_model_type_index` (`model_id`,`model_type`), + CONSTRAINT `model_has_permissions_permission_id_foreign` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- La exportación de datos fue deseleccionada. + +-- Volcando estructura para tabla admision_2026.model_has_roles +DROP TABLE IF EXISTS `model_has_roles`; +CREATE TABLE IF NOT EXISTS `model_has_roles` ( + `role_id` bigint unsigned NOT NULL, + `model_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `model_id` bigint unsigned NOT NULL, + PRIMARY KEY (`role_id`,`model_id`,`model_type`), + KEY `model_has_roles_model_id_model_type_index` (`model_id`,`model_type`), + CONSTRAINT `model_has_roles_role_id_foreign` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- La exportación de datos fue deseleccionada. + +-- Volcando estructura para tabla admision_2026.pagos +DROP TABLE IF EXISTS `pagos`; +CREATE TABLE IF NOT EXISTS `pagos` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `postulante_id` bigint unsigned NOT NULL, + `tipo_pago` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `codigo_pago` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `utilizado` tinyint(1) NOT NULL DEFAULT '0', + `monto` decimal(10,2) NOT NULL, + `original_date` timestamp NULL DEFAULT NULL, + `confirmed_date` timestamp NULL DEFAULT NULL, + `fecha_pago` timestamp NULL DEFAULT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE, + UNIQUE KEY `pagos_codigo_pago_unique` (`codigo_pago`) USING BTREE, + KEY `pagos_postulante_id_foreign` (`postulante_id`) USING BTREE, + CONSTRAINT `pagos_postulante_id_foreign` FOREIGN KEY (`postulante_id`) REFERENCES `postulantes` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- La exportación de datos fue deseleccionada. + +-- Volcando estructura para tabla admision_2026.password_reset_tokens +DROP TABLE IF EXISTS `password_reset_tokens`; +CREATE TABLE IF NOT EXISTS `password_reset_tokens` ( + `email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `token` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `created_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`email`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- La exportación de datos fue deseleccionada. + +-- Volcando estructura para tabla admision_2026.permissions +DROP TABLE IF EXISTS `permissions`; +CREATE TABLE IF NOT EXISTS `permissions` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `guard_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `permissions_name_guard_name_unique` (`name`,`guard_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- La exportación de datos fue deseleccionada. + +-- Volcando estructura para tabla admision_2026.personal_access_tokens +DROP TABLE IF EXISTS `personal_access_tokens`; +CREATE TABLE IF NOT EXISTS `personal_access_tokens` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `tokenable_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `tokenable_id` bigint unsigned NOT NULL, + `name` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `token` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `abilities` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `last_used_at` timestamp NULL DEFAULT NULL, + `expires_at` timestamp NULL DEFAULT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `personal_access_tokens_token_unique` (`token`), + KEY `personal_access_tokens_tokenable_type_tokenable_id_index` (`tokenable_type`,`tokenable_id`), + KEY `personal_access_tokens_expires_at_index` (`expires_at`) +) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- La exportación de datos fue deseleccionada. + +-- Volcando estructura para tabla admision_2026.postulantes +DROP TABLE IF EXISTS `postulantes`; +CREATE TABLE IF NOT EXISTS `postulantes` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `email` varchar(255) NOT NULL, + `password` varchar(255) NOT NULL, + `dni` varchar(20) NOT NULL, + `device_id` varchar(100) DEFAULT NULL, + `last_activity` timestamp NULL DEFAULT NULL, + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `email` (`email`), + UNIQUE KEY `dni` (`dni`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- La exportación de datos fue deseleccionada. + +-- Volcando estructura para tabla admision_2026.preguntas +DROP TABLE IF EXISTS `preguntas`; +CREATE TABLE IF NOT EXISTS `preguntas` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `curso_id` bigint unsigned NOT NULL, + `enunciado` longtext NOT NULL, + `enunciado_adicional` longtext, + `opciones` json DEFAULT NULL, + `respuesta_correcta` longtext, + `explicacion` longtext, + `imagenes_explicacion` json DEFAULT NULL, + `imagenes` json DEFAULT NULL, + `nivel_dificultad` varchar(20) DEFAULT NULL, + `activo` tinyint(1) NOT NULL DEFAULT '1', + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + KEY `idx_preguntas_curso` (`curso_id`), + KEY `idx_preguntas_activo` (`activo`), + CONSTRAINT `fk_preguntas_curso` FOREIGN KEY (`curso_id`) REFERENCES `cursos` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- La exportación de datos fue deseleccionada. + +-- Volcando estructura para tabla admision_2026.preguntas_asignadas +DROP TABLE IF EXISTS `preguntas_asignadas`; +CREATE TABLE IF NOT EXISTS `preguntas_asignadas` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `examen_id` bigint unsigned NOT NULL, + `pregunta_id` bigint unsigned NOT NULL, + `orden` int NOT NULL, + `respuesta_usuario` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'Clave elegida (A, B, C, D) o texto si es abierta', + `es_correcta` tinyint(1) DEFAULT NULL COMMENT '1 correcta, 0 incorrecta, NULL no respondida', + `estado` enum('pendiente','respondida','anulada') COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'pendiente', + `puntaje` decimal(5,2) NOT NULL DEFAULT '0.00', + `respondida_at` timestamp NULL DEFAULT NULL, + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) USING BTREE, + KEY `idx_preg_asig_examen` (`examen_id`) USING BTREE, + KEY `idx_preg_asig_pregunta` (`pregunta_id`) USING BTREE, + KEY `idx_preg_asig_estado` (`estado`) USING BTREE, + CONSTRAINT `fk_preg_asig_examen` FOREIGN KEY (`examen_id`) REFERENCES `examenes` (`id`) ON DELETE CASCADE, + CONSTRAINT `fk_preg_asig_pregunta` FOREIGN KEY (`pregunta_id`) REFERENCES `preguntas` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- La exportación de datos fue deseleccionada. + +-- Volcando estructura para tabla admision_2026.procesos +DROP TABLE IF EXISTS `procesos`; +CREATE TABLE IF NOT EXISTS `procesos` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `nombre` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `descripcion` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `estado` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'borrador', + `duracion` int NOT NULL COMMENT 'Duración total en minutos', + `intentos_maximos` int DEFAULT '1', + `requiere_pago` tinyint(1) NOT NULL DEFAULT '0', + `precio` decimal(8,2) DEFAULT NULL, + `calificacion_id` bigint unsigned DEFAULT NULL, + `slug` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `tipo_simulacro` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'simulacro | test | practica', + `tipo_proceso` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'admision | preuniversitario | universitario', + `activo` tinyint(1) NOT NULL DEFAULT '1', + `publico` tinyint(1) NOT NULL DEFAULT '0', + `fecha_inicio` datetime DEFAULT NULL, + `fecha_fin` datetime DEFAULT NULL, + `tiempo_por_pregunta` int DEFAULT NULL COMMENT 'Segundos por pregunta', + `cantidad_pregunta` int DEFAULT '10', + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `slug` (`slug`), + KEY `idx_examenes_estado` (`estado`), + KEY `idx_examenes_activo` (`activo`), + KEY `idx_examenes_publico` (`publico`), + KEY `idx_examenes_tipo_simulacro` (`tipo_simulacro`), + KEY `idx_examenes_tipo_proceso` (`tipo_proceso`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- La exportación de datos fue deseleccionada. + +-- Volcando estructura para tabla admision_2026.procesos_admision +DROP TABLE IF EXISTS `procesos_admision`; +CREATE TABLE IF NOT EXISTS `procesos_admision` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `titulo` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `subtitulo` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `descripcion` text COLLATE utf8mb4_unicode_ci, + `slug` varchar(120) COLLATE utf8mb4_unicode_ci NOT NULL, + `tipo_proceso` varchar(60) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `modalidad` varchar(50) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `publicado` tinyint(1) NOT NULL DEFAULT '0', + `fecha_publicacion` datetime DEFAULT NULL, + `fecha_inicio_preinscripcion` datetime DEFAULT NULL, + `fecha_fin_preinscripcion` datetime DEFAULT NULL, + `fecha_inicio_inscripcion` datetime DEFAULT NULL, + `fecha_fin_inscripcion` datetime DEFAULT NULL, + `fecha_examen1` datetime DEFAULT NULL, + `fecha_examen2` datetime DEFAULT NULL, + `fecha_resultados` datetime DEFAULT NULL, + `fecha_inicio_biometrico` datetime DEFAULT NULL, + `fecha_fin_biometrico` datetime DEFAULT NULL, + `imagen_path` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `banner_path` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `brochure_path` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `link_preinscripcion` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `link_inscripcion` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `link_resultados` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `link_reglamento` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `estado` enum('nuevo','publicado','en_proceso','finalizado','cancelado') COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'nuevo', + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `uq_procesos_slug` (`slug`), + KEY `idx_procesos_publico` (`publicado`,`estado`), + KEY `idx_procesos_fechas` (`fecha_inicio_inscripcion`,`fecha_examen1`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- La exportación de datos fue deseleccionada. + +-- Volcando estructura para tabla admision_2026.proceso_admision_detalles +DROP TABLE IF EXISTS `proceso_admision_detalles`; +CREATE TABLE IF NOT EXISTS `proceso_admision_detalles` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `proceso_admision_id` bigint unsigned NOT NULL, + `tipo` enum('requisitos','pagos','vacantes','cronograma') COLLATE utf8mb4_unicode_ci NOT NULL, + `titulo_detalle` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `descripcion` text COLLATE utf8mb4_unicode_ci, + `listas` json DEFAULT NULL, + `meta` json DEFAULT NULL, + `url` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `imagen_path` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `imagen_path_2` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `uq_proceso_modalidad_tipo` (`proceso_admision_id`), + KEY `idx_detalles_lookup` (`proceso_admision_id`,`tipo`), + CONSTRAINT `fk_detalles_proceso` FOREIGN KEY (`proceso_admision_id`) REFERENCES `procesos_admision` (`id`) ON DELETE CASCADE, + CONSTRAINT `proceso_admision_detalles_chk_1` CHECK (json_valid(`listas`)), + CONSTRAINT `proceso_admision_detalles_chk_2` CHECK (json_valid(`meta`)) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- La exportación de datos fue deseleccionada. + +-- Volcando estructura para tabla admision_2026.reglas_area_proceso +DROP TABLE IF EXISTS `reglas_area_proceso`; +CREATE TABLE IF NOT EXISTS `reglas_area_proceso` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `area_proceso_id` bigint unsigned NOT NULL, + `curso_id` bigint unsigned NOT NULL, + `cantidad_preguntas` int NOT NULL DEFAULT '0', + `orden` int NOT NULL DEFAULT '1', + `nivel_dificultad` varchar(50) DEFAULT 'medio', + `ponderacion` decimal(5,2) DEFAULT '0.00', + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + KEY `area_proceso_id` (`area_proceso_id`), + KEY `curso_id` (`curso_id`), + CONSTRAINT `reglas_area_proceso_ibfk_1` FOREIGN KEY (`area_proceso_id`) REFERENCES `area_proceso` (`id`), + CONSTRAINT `reglas_area_proceso_ibfk_2` FOREIGN KEY (`curso_id`) REFERENCES `cursos` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- La exportación de datos fue deseleccionada. + +-- Volcando estructura para tabla admision_2026.resultados_admision +DROP TABLE IF EXISTS `resultados_admision`; +CREATE TABLE IF NOT EXISTS `resultados_admision` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `dni` varchar(20) NOT NULL, + `paterno` varchar(100) NOT NULL, + `materno` varchar(100) NOT NULL, + `nombres` varchar(150) NOT NULL, + `puntaje` decimal(6,2) DEFAULT '0.00', + `vocacional` decimal(6,2) DEFAULT '0.00', + `apto` enum('SI','NO') DEFAULT 'NO', + `obs` text, + `desprograma` tinyint(1) DEFAULT '0', + `idproceso` bigint unsigned NOT NULL, + `idearea` bigint unsigned NOT NULL, + `litho` varchar(50) DEFAULT NULL, + `numlectura` varchar(50) DEFAULT NULL, + `tipo` varchar(50) DEFAULT NULL, + `calificar` tinyint(1) DEFAULT '1', + `aula` varchar(50) DEFAULT NULL, + `respuestas` json DEFAULT NULL, + `puesto` int DEFAULT NULL, + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + KEY `idx_dni` (`dni`), + KEY `idx_proceso` (`idproceso`), + KEY `idx_area` (`idearea`), + CONSTRAINT `fk_resultado_area_admision` FOREIGN KEY (`idearea`) REFERENCES `areas_admision` (`id`) ON DELETE CASCADE, + CONSTRAINT `fk_resultado_proceso_admision` FOREIGN KEY (`idproceso`) REFERENCES `procesos_admision` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- La exportación de datos fue deseleccionada. + +-- Volcando estructura para tabla admision_2026.resultados_admision_carga +DROP TABLE IF EXISTS `resultados_admision_carga`; +CREATE TABLE IF NOT EXISTS `resultados_admision_carga` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `dni` varchar(20) DEFAULT NULL, + `paterno` varchar(100) DEFAULT NULL, + `materno` varchar(100) DEFAULT NULL, + `nombres` varchar(150) DEFAULT NULL, + `idproceso` bigint unsigned NOT NULL, + `idearea` bigint unsigned NOT NULL, + `apto` char(20) DEFAULT NULL, + `puntaje_total` decimal(8,2) DEFAULT NULL, + `puesto` int DEFAULT NULL, + `correctas_aritmetica` int DEFAULT NULL, + `blancas_aritmetica` int DEFAULT NULL, + `puntaje_aritmetica` decimal(6,2) DEFAULT NULL, + `porcentaje_aritmetica` decimal(5,2) DEFAULT NULL, + `correctas_algebra` int DEFAULT NULL, + `blancas_algebra` int DEFAULT NULL, + `puntaje_algebra` decimal(6,2) DEFAULT NULL, + `porcentaje_algebra` decimal(5,2) DEFAULT NULL, + `correctas_geometria` int DEFAULT NULL, + `blancas_geometria` int DEFAULT NULL, + `puntaje_geometria` decimal(6,2) DEFAULT NULL, + `porcentaje_geometria` decimal(5,2) DEFAULT NULL, + `correctas_trigonometria` int DEFAULT NULL, + `blancas_trigonometria` int DEFAULT NULL, + `puntaje_trigonometria` decimal(6,2) DEFAULT NULL, + `porcentaje_trigonometria` decimal(5,2) DEFAULT NULL, + `correctas_fisica` int DEFAULT NULL, + `blancas_fisica` int DEFAULT NULL, + `puntaje_fisica` decimal(6,2) DEFAULT NULL, + `porcentaje_fisica` decimal(5,2) DEFAULT NULL, + `correctas_quimica` int DEFAULT NULL, + `blancas_quimica` int DEFAULT NULL, + `puntaje_quimica` decimal(6,2) DEFAULT NULL, + `porcentaje_quimica` decimal(5,2) DEFAULT NULL, + `correctas_biologia_anatomia` int DEFAULT NULL, + `blancas_biologia_anatomia` int DEFAULT NULL, + `puntaje_biologia_anatomia` decimal(6,2) DEFAULT NULL, + `porcentaje_biologia_anatomia` decimal(5,2) DEFAULT NULL, + `correctas_psicologia_filosofia` int DEFAULT NULL, + `blancas_psicologia_filosofia` int DEFAULT NULL, + `puntaje_psicologia_filosofia` decimal(6,2) DEFAULT NULL, + `porcentaje_psicologia_filosofia` decimal(5,2) DEFAULT NULL, + `correctas_geografia` int DEFAULT NULL, + `blancas_geografia` int DEFAULT NULL, + `puntaje_geografia` decimal(6,2) DEFAULT NULL, + `porcentaje_geografia` decimal(5,2) DEFAULT NULL, + `correctas_historia` int DEFAULT NULL, + `blancas_historia` int DEFAULT NULL, + `puntaje_historia` decimal(6,2) DEFAULT NULL, + `porcentaje_historia` decimal(5,2) DEFAULT NULL, + `correctas_educacion_civica` int DEFAULT NULL, + `blancas_educacion_civica` int DEFAULT NULL, + `puntaje_educacion_civica` decimal(6,2) DEFAULT NULL, + `porcentaje_educacion_civica` decimal(5,2) DEFAULT NULL, + `correctas_economia` int DEFAULT NULL, + `blancas_economia` int DEFAULT NULL, + `puntaje_economia` decimal(6,2) DEFAULT NULL, + `porcentaje_economia` decimal(5,2) DEFAULT NULL, + `correctas_comunicacion` int DEFAULT NULL, + `blancas_comunicacion` int DEFAULT NULL, + `puntaje_comunicacion` decimal(6,2) DEFAULT NULL, + `porcentaje_comunicacion` decimal(5,2) DEFAULT NULL, + `correctas_literatura` int DEFAULT NULL, + `blancas_literatura` int DEFAULT NULL, + `puntaje_literatura` decimal(6,2) DEFAULT NULL, + `porcentaje_literatura` decimal(5,2) DEFAULT NULL, + `correctas_razonamiento_matematico` int DEFAULT NULL, + `blancas_razonamiento_matematico` int DEFAULT NULL, + `puntaje_razonamiento_matematico` decimal(6,2) DEFAULT NULL, + `porcentaje_razonamiento_matematico` decimal(5,2) DEFAULT NULL, + `correctas_razonamiento_verbal` int DEFAULT NULL, + `blancas_razonamiento_verbal` int DEFAULT NULL, + `puntaje_razonamiento_verbal` decimal(6,2) DEFAULT NULL, + `porcentaje_razonamiento_verbal` decimal(5,2) DEFAULT NULL, + `correctas_ingles` int DEFAULT NULL, + `blancas_ingles` int DEFAULT NULL, + `puntaje_ingles` decimal(6,2) DEFAULT NULL, + `porcentaje_ingles` decimal(5,2) DEFAULT NULL, + `correctas_quechua_aimara` int DEFAULT NULL, + `blancas_quechua_aimara` int DEFAULT NULL, + `puntaje_quechua_aimara` decimal(6,2) DEFAULT NULL, + `porcentaje_quechua_aimara` decimal(5,2) DEFAULT NULL, + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + KEY `idx_dni` (`dni`), + KEY `idx_proceso_area` (`idproceso`,`idearea`), + KEY `fk_carga_area` (`idearea`), + CONSTRAINT `fk_carga_area` FOREIGN KEY (`idearea`) REFERENCES `areas_admision` (`id`) ON DELETE CASCADE, + CONSTRAINT `fk_carga_proceso` FOREIGN KEY (`idproceso`) REFERENCES `procesos_admision` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- La exportación de datos fue deseleccionada. + +-- Volcando estructura para tabla admision_2026.roles +DROP TABLE IF EXISTS `roles`; +CREATE TABLE IF NOT EXISTS `roles` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `guard_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `roles_name_guard_name_unique` (`name`,`guard_name`) +) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- La exportación de datos fue deseleccionada. + +-- Volcando estructura para tabla admision_2026.role_has_permissions +DROP TABLE IF EXISTS `role_has_permissions`; +CREATE TABLE IF NOT EXISTS `role_has_permissions` ( + `permission_id` bigint unsigned NOT NULL, + `role_id` bigint unsigned NOT NULL, + PRIMARY KEY (`permission_id`,`role_id`), + KEY `role_has_permissions_role_id_foreign` (`role_id`), + CONSTRAINT `role_has_permissions_permission_id_foreign` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`id`) ON DELETE CASCADE, + CONSTRAINT `role_has_permissions_role_id_foreign` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- La exportación de datos fue deseleccionada. + +-- Volcando estructura para tabla admision_2026.sessions +DROP TABLE IF EXISTS `sessions`; +CREATE TABLE IF NOT EXISTS `sessions` ( + `id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `user_id` bigint unsigned DEFAULT NULL, + `ip_address` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `user_agent` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `payload` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `last_activity` int NOT NULL, + PRIMARY KEY (`id`), + KEY `sessions_user_id_index` (`user_id`), + KEY `sessions_last_activity_index` (`last_activity`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- La exportación de datos fue deseleccionada. + +-- Volcando estructura para tabla admision_2026.users +DROP TABLE IF EXISTS `users`; +CREATE TABLE IF NOT EXISTS `users` ( + `id` bigint unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `email_verified_at` timestamp NULL DEFAULT NULL, + `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `remember_token` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `users_email_unique` (`email`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- La exportación de datos fue deseleccionada. + +/*!40103 SET TIME_ZONE=IFNULL(@OLD_TIME_ZONE, 'system') */; +/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */; +/*!40014 SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1) */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40111 SET SQL_NOTES=IFNULL(@OLD_SQL_NOTES, 1) */; diff --git a/back/.dockerignore b/back/.dockerignore new file mode 100644 index 0000000..b9c2153 --- /dev/null +++ b/back/.dockerignore @@ -0,0 +1,12 @@ +vendor +node_modules +.env +.env.backup +.env.production +storage/logs/* +storage/framework/cache/* +storage/framework/sessions/* +storage/framework/views/* +tests +.git +.phpunit.cache diff --git a/back/Dockerfile b/back/Dockerfile new file mode 100644 index 0000000..80ce693 --- /dev/null +++ b/back/Dockerfile @@ -0,0 +1,72 @@ +# Stage 1: Composer dependencies +FROM composer:2 AS vendor + +WORKDIR /app + +COPY composer.json composer.lock ./ + +RUN composer install \ + --no-dev \ + --no-interaction \ + --no-scripts \ + --prefer-dist \ + --optimize-autoloader + +# Stage 2: PHP-FPM production image +FROM php:8.4-fpm-alpine + +# Install system dependencies +RUN apk add --no-cache \ + libpng-dev \ + libjpeg-turbo-dev \ + freetype-dev \ + libzip-dev \ + libxml2-dev \ + curl-dev \ + oniguruma-dev \ + icu-dev + +# Install PHP extensions +RUN docker-php-ext-configure gd --with-freetype --with-jpeg \ + && docker-php-ext-install \ + pdo_mysql \ + bcmath \ + mbstring \ + gd \ + curl \ + zip \ + xml \ + intl \ + opcache + +# Configure OPcache for production +RUN echo "opcache.enable=1" >> /usr/local/etc/php/conf.d/opcache.ini \ + && echo "opcache.memory_consumption=128" >> /usr/local/etc/php/conf.d/opcache.ini \ + && echo "opcache.interned_strings_buffer=8" >> /usr/local/etc/php/conf.d/opcache.ini \ + && echo "opcache.max_accelerated_files=10000" >> /usr/local/etc/php/conf.d/opcache.ini \ + && echo "opcache.validate_timestamps=0" >> /usr/local/etc/php/conf.d/opcache.ini + +# PHP production settings +RUN echo "upload_max_filesize=20M" >> /usr/local/etc/php/conf.d/uploads.ini \ + && echo "post_max_size=25M" >> /usr/local/etc/php/conf.d/uploads.ini + +WORKDIR /var/www/html + +# Copy application code +COPY . . + +# Copy vendor from composer stage +COPY --from=vendor /app/vendor ./vendor + +# Set permissions +RUN chown -R www-data:www-data storage bootstrap/cache \ + && chmod -R 775 storage bootstrap/cache + +# Laravel optimizations +RUN php artisan config:cache \ + && php artisan route:cache \ + && php artisan view:cache + +EXPOSE 9000 + +CMD ["php-fpm"] diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 0000000..13bd4fa --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,67 @@ +services: + nginx: + image: nginx:alpine + container_name: admision_prod_nginx + restart: unless-stopped + ports: + - "${APP_PORT:-80}:80" + volumes: + - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro + - backend_storage:/var/www/html/storage/app/public:ro + depends_on: + - backend + - frontend + networks: + - admision_net + + backend: + build: + context: ./back + dockerfile: Dockerfile + container_name: admision_prod_backend + restart: unless-stopped + env_file: + - .env.prod + volumes: + - backend_storage:/var/www/html/storage + depends_on: + mysql: + condition: service_healthy + networks: + - admision_net + + frontend: + build: + context: ./front + dockerfile: Dockerfile + args: + VITE_API_URL: ${VITE_API_URL:-/api} + container_name: admision_prod_frontend + restart: unless-stopped + networks: + - admision_net + + mysql: + image: mysql:8.0 + container_name: admision_prod_db + restart: unless-stopped + environment: + MYSQL_ROOT_PASSWORD: ${DB_PASSWORD} + MYSQL_DATABASE: ${DB_DATABASE:-admision_2026} + volumes: + - mysql_data:/var/lib/mysql + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-p${DB_PASSWORD}"] + interval: 10s + timeout: 5s + retries: 5 + networks: + - admision_net + +volumes: + mysql_data: + backend_storage: + +networks: + admision_net: + driver: bridge diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..9e7ffbd --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,15 @@ +services: + db: + image: mysql:8.0 + container_name: admision_2026_db + restart: unless-stopped + ports: + - "3306:3306" + environment: + MYSQL_ROOT_PASSWORD: root + MYSQL_DATABASE: admision_2026 + volumes: + - mysql_data:/var/lib/mysql + +volumes: + mysql_data: diff --git a/front/.dockerignore b/front/.dockerignore new file mode 100644 index 0000000..f2ccdb4 --- /dev/null +++ b/front/.dockerignore @@ -0,0 +1,4 @@ +node_modules +dist +.env +.git diff --git a/front/Dockerfile b/front/Dockerfile new file mode 100644 index 0000000..a3ae709 --- /dev/null +++ b/front/Dockerfile @@ -0,0 +1,31 @@ +# Stage 1: Build Vue SPA +FROM node:20-alpine AS build + +WORKDIR /app + +COPY package.json package-lock.json ./ + +RUN npm ci + +COPY . . + +ARG VITE_API_URL +ENV VITE_API_URL=${VITE_API_URL} + +RUN npm run build + +# Stage 2: Serve with nginx +FROM nginx:alpine + +# Remove default nginx config +RUN rm /etc/nginx/conf.d/default.conf + +# Copy custom nginx config +COPY nginx.conf /etc/nginx/conf.d/default.conf + +# Copy built files +COPY --from=build /app/dist /usr/share/nginx/html + +EXPOSE 80 + +CMD ["nginx", "-g", "daemon off;"] diff --git a/front/nginx.conf b/front/nginx.conf new file mode 100644 index 0000000..9a330ab --- /dev/null +++ b/front/nginx.conf @@ -0,0 +1,33 @@ +server { + listen 80; + server_name _; + root /usr/share/nginx/html; + index index.html; + + # Gzip compression + gzip on; + gzip_vary on; + gzip_proxied any; + gzip_comp_level 6; + gzip_min_length 256; + gzip_types + text/plain + text/css + text/javascript + application/javascript + application/json + application/xml + image/svg+xml; + + # Cache static assets + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + try_files $uri =404; + } + + # SPA fallback - all routes to index.html + location / { + try_files $uri $uri/ /index.html; + } +} diff --git a/front/package-lock.json b/front/package-lock.json index 7158e86..8c0f97d 100644 --- a/front/package-lock.json +++ b/front/package-lock.json @@ -1188,7 +1188,6 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -1198,7 +1197,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "license": "MIT", - "peer": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -1344,7 +1342,6 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "license": "MIT", - "peer": true, "engines": { "node": ">=6" } @@ -1354,6 +1351,7 @@ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.1.tgz", "integrity": "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==", "license": "MIT", + "peer": true, "dependencies": { "@kurkle/color": "^0.3.0" }, @@ -1366,7 +1364,6 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", "license": "ISC", - "peer": true, "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", @@ -1387,7 +1384,6 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "license": "MIT", - "peer": true, "dependencies": { "color-name": "~1.1.4" }, @@ -1399,8 +1395,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/combined-stream": { "version": "1.0.8", @@ -1472,7 +1467,6 @@ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -1553,8 +1547,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz", "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/dom-align": { "version": "1.12.4", @@ -1586,8 +1579,7 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/entities": { "version": "7.0.1", @@ -1735,7 +1727,6 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "license": "MIT", - "peer": true, "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -1818,7 +1809,6 @@ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "license": "ISC", - "peer": true, "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -1966,7 +1956,6 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -2045,7 +2034,6 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "license": "MIT", - "peer": true, "dependencies": { "p-locate": "^4.1.0" }, @@ -2262,7 +2250,6 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "license": "MIT", - "peer": true, "dependencies": { "p-try": "^2.0.0" }, @@ -2278,7 +2265,6 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "license": "MIT", - "peer": true, "dependencies": { "p-limit": "^2.2.0" }, @@ -2291,7 +2277,6 @@ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=6" } @@ -2311,7 +2296,6 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -2334,6 +2318,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -2367,7 +2352,6 @@ "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", "license": "MIT", - "peer": true, "engines": { "node": ">=10.13.0" } @@ -2518,7 +2502,6 @@ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -2527,8 +2510,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/resize-observer-polyfill": { "version": "1.5.1", @@ -2600,8 +2582,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/set-function-length": { "version": "1.2.2", @@ -2664,7 +2645,6 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "license": "MIT", - "peer": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -2679,7 +2659,6 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "license": "MIT", - "peer": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -2749,6 +2728,7 @@ "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -2823,6 +2803,7 @@ "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.27.tgz", "integrity": "sha512-aJ/UtoEyFySPBGarREmN4z6qNKpbEguYHMmXSiOGk69czc+zhs0NF6tEFrY8TZKAl8N/LYAkd4JHVd5E/AsSmw==", "license": "MIT", + "peer": true, "dependencies": { "@vue/compiler-dom": "3.5.27", "@vue/compiler-sfc": "3.5.27", @@ -2914,15 +2895,13 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "license": "MIT", - "peer": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -2936,15 +2915,13 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/yargs": { "version": "15.4.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "license": "MIT", - "peer": true, "dependencies": { "cliui": "^6.0.0", "decamelize": "^1.2.0", @@ -2967,7 +2944,6 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "license": "ISC", - "peer": true, "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" diff --git a/install.md b/install.md new file mode 100644 index 0000000..597faf8 --- /dev/null +++ b/install.md @@ -0,0 +1,351 @@ +# Instalacion - Direccion de Admision 2026 + +## Requisitos previos + +| Herramienta | Version minima | Uso | +|---|---|---| +| Laragon | - | PHP + Composer (servidor local) | +| PHP | 8.4+ | Backend Laravel (Thread Safe, VS17 x64) | +| Composer | 2.x | Dependencias PHP | +| Node.js | 18+ | Frontend Vue | +| npm | 9+ | Dependencias JS | +| Docker | 20+ | Solo para MySQL | +| Docker Compose | 2+ | Solo para MySQL | + +### Descargar PHP 8.4 para Laragon + +Si Laragon no trae PHP 8.4, descargarlo manualmente: + +1. Descargar desde https://windows.php.net/download/ el archivo **VS17 x64 Thread Safe** (zip) +2. Extraer en `C:\laragon\bin\php\php-8.4.xx-Win32-vs17-x64\` +3. En Laragon: clic derecho > **PHP** > seleccionar la version 8.4 +4. Instalar Visual C++ 2022 si no lo tienes: https://aka.ms/vs/17/release/vc_redist.x64.exe +5. Agregar al PATH: clic derecho en Laragon > **Tools** > **Path** > **Add Laragon to Path** + +--- + +## Paso 1: Clonar el repositorio + +```bash +git clone direccion_de_admision_2026 +cd direccion_de_admision_2026 +``` + +--- + +## Paso 2: Levantar MySQL con Docker + +```bash +docker compose up -d +``` + +Esto levanta un contenedor MySQL 8.0 con: +- **Host:** 127.0.0.1 +- **Puerto:** 3306 +- **Usuario:** root +- **Password:** root +- **Base de datos:** admision_2026 + +Verificar que funcione: + +```bash +docker exec admision_2026_db mysql -uroot -proot -e "SELECT 'MySQL OK'" +``` + +--- + +## Paso 3: Importar la base de datos + +```bash +docker exec -i admision_2026_db mysql -uroot -proot admision_2026 < admision_2026_200.sql +``` + +Verificar tablas importadas: + +```bash +docker exec admision_2026_db mysql -uroot -proot admision_2026 -e "SHOW TABLES;" +``` + +Debe mostrar 32 tablas (users, postulantes, areas, cursos, examenes, procesos_admision, etc.) + +--- + +## Paso 4: Configurar el Backend (Laravel) + +```bash +cd back +``` + +### 4.1 Instalar dependencias + +```bash +composer install +``` + +### 4.2 Configurar variables de entorno + +```bash +copy .env.example .env +``` + +Editar `back/.env` y cambiar la password de la BD: + +``` +DB_PASSWORD=root +``` + +### 4.3 Generar clave de aplicacion + +```bash +php artisan key:generate +``` + +### 4.4 Crear enlace de storage (para imagenes) + +```bash +php artisan storage:link +``` + +--- + +## Paso 5: Configurar el Frontend (Vue 3) + +```bash +cd front +``` + +### 5.1 Instalar dependencias + +```bash +npm install +``` + +### 5.2 Configurar variables de entorno + +```bash +copy .env.example .env +``` + +El archivo debe contener: + +``` +VITE_API_URL=http://127.0.0.1:8000/api +``` + +--- + +## Levantar el proyecto + +Necesitas **3 cosas corriendo** al mismo tiempo: + +### 1. MySQL (Docker) - si no esta corriendo + +```bash +docker compose up -d +``` + +### 2. Backend (Terminal 1) + +```bash +cd back +php artisan serve +``` + +Estara disponible en: **http://localhost:8000** + +### 3. Frontend (Terminal 2) + +```bash +cd front +npm run dev +``` + +Estara disponible en: **http://localhost:5173** + +--- + +## Stack tecnologico + +| Capa | Tecnologia | +|---|---| +| Backend | Laravel 12 + PHP 8.4 | +| Frontend | Vue 3 + Vite 7 + Ant Design Vue + Pinia | +| Base de datos | MySQL 8.0 (Docker) | +| Autenticacion | Laravel Sanctum (Bearer tokens) | +| Permisos | Spatie Laravel Permission | +| QR | SimpleSoftwareIO QRCode | + +--- + +## Notas importantes + +- **No modificar** `composer.lock` a menos que todos los del equipo acuerden (requiere PHP 8.4+) +- El dump SQL (`admision_2026_200.sql`) ya incluye todas las tablas y datos necesarios, no se necesita `php artisan migrate` +- Si el puerto 3306 esta ocupado (por otro MySQL local), detener ese servicio primero o cambiar el puerto en `docker-compose.yml` +- Los archivos `.env` no se suben al repositorio (estan en `.gitignore`) + +--- + +# Deploy en Produccion (Docker) + +Todo el proyecto se dockeriza para correr en un VPS con Linux. Se usan 4 contenedores: **nginx** (reverse proxy), **backend** (PHP-FPM), **frontend** (Vue SPA + nginx) y **mysql**. + +## Requisitos del servidor + +| Herramienta | Version minima | +|---|---| +| Docker | 20+ | +| Docker Compose | 2+ | +| RAM | 2 GB minimo | +| Disco | 10 GB minimo | + +--- + +## Paso 1: Clonar el repositorio en el servidor + +```bash +git clone direccion_de_admision_2026 +cd direccion_de_admision_2026 +``` + +--- + +## Paso 2: Configurar variables de entorno + +```bash +cp .env.prod.example .env.prod +``` + +Editar `.env.prod` y configurar **obligatoriamente**: + +``` +APP_KEY= # Generar con: php artisan key:generate --show (o tras el build) +APP_URL=https://tu-dominio.com +DB_PASSWORD=UNA_PASSWORD_SEGURA +SESSION_DOMAIN=tu-dominio.com +SANCTUM_STATEFUL_DOMAINS=tu-dominio.com +VITE_API_URL=/api +``` + +Configurar tambien el correo SMTP si se usa envio de emails. + +--- + +## Paso 3: Importar la base de datos (primera vez) + +Construir y levantar solo MySQL primero: + +```bash +docker compose -f docker-compose.prod.yml up -d mysql +``` + +Esperar a que MySQL este listo y luego importar el dump: + +```bash +docker exec -i admision_prod_db mysql -uroot -pTU_PASSWORD admision_2026 < admision_2026_200.sql +``` + +Verificar: + +```bash +docker exec admision_prod_db mysql -uroot -pTU_PASSWORD admision_2026 -e "SHOW TABLES;" +``` + +--- + +## Paso 4: Construir y levantar todos los servicios + +```bash +docker compose -f docker-compose.prod.yml build +docker compose -f docker-compose.prod.yml up -d +``` + +Verificar que los 4 contenedores esten corriendo: + +```bash +docker compose -f docker-compose.prod.yml ps +``` + +--- + +## Paso 5: Generar APP_KEY (primera vez) + +```bash +docker exec admision_prod_backend php artisan key:generate --show +``` + +Copiar la clave generada al archivo `.env.prod` en `APP_KEY=` y reiniciar: + +```bash +docker compose -f docker-compose.prod.yml restart backend +``` + +--- + +## Paso 6: Crear enlace de storage + +```bash +docker exec admision_prod_backend php artisan storage:link +``` + +--- + +## Verificar el deploy + +- Abrir `http://tu-dominio.com` -> debe cargar el frontend Vue +- Abrir `http://tu-dominio.com/api/...` -> debe responder la API Laravel + +--- + +## Comandos utiles + +```bash +# Ver logs de todos los servicios +docker compose -f docker-compose.prod.yml logs -f + +# Ver logs de un servicio especifico +docker compose -f docker-compose.prod.yml logs -f backend + +# Reiniciar todo +docker compose -f docker-compose.prod.yml restart + +# Detener todo +docker compose -f docker-compose.prod.yml down + +# Reconstruir tras cambios de codigo +git pull +docker compose -f docker-compose.prod.yml build +docker compose -f docker-compose.prod.yml up -d + +# Ejecutar comandos artisan +docker exec admision_prod_backend php artisan migrate --force +docker exec admision_prod_backend php artisan cache:clear +``` + +--- + +## Arquitectura de contenedores + +``` + Puerto 80 + | + [nginx] (reverse proxy) + / \ + /api/* / \ /* + / \ + [backend] [frontend] + PHP-FPM nginx+SPA + :9000 :80 + | + [mysql] + :3306 +``` + +--- + +## Notas de produccion + +- Los datos de MySQL se persisten en un volumen Docker (`mysql_data`) +- El storage de Laravel se persiste en un volumen Docker (`backend_storage`) +- Para HTTPS, configurar un reverse proxy externo (Nginx/Caddy en el host) o usar Cloudflare +- El archivo `.env.prod` **nunca** debe subirse al repositorio diff --git a/nginx/nginx.conf b/nginx/nginx.conf new file mode 100644 index 0000000..ab361f5 --- /dev/null +++ b/nginx/nginx.conf @@ -0,0 +1,53 @@ +upstream php-fpm { + server backend:9000; +} + +upstream frontend-server { + server frontend:80; +} + +server { + listen 80; + server_name _; + + client_max_body_size 25M; + + # API requests -> PHP-FPM backend + location /api { + root /var/www/html/public; + + fastcgi_pass php-fpm; + fastcgi_index index.php; + fastcgi_param SCRIPT_FILENAME /var/www/html/public/index.php; + include fastcgi_params; + fastcgi_param PATH_INFO $fastcgi_path_info; + } + + # Sanctum CSRF cookie + location /sanctum { + root /var/www/html/public; + + fastcgi_pass php-fpm; + fastcgi_index index.php; + fastcgi_param SCRIPT_FILENAME /var/www/html/public/index.php; + include fastcgi_params; + fastcgi_param PATH_INFO $fastcgi_path_info; + } + + # Storage files (uploaded images, etc.) + location /storage { + alias /var/www/html/storage/app/public; + expires 7d; + add_header Cache-Control "public"; + try_files $uri =404; + } + + # Everything else -> Vue SPA frontend + location / { + proxy_pass http://frontend-server; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +}