diff --git a/one.md b/one.md
deleted file mode 100644
index 3fede61..0000000
--- a/one.md
+++ /dev/null
@@ -1,390 +0,0 @@
-# Plan: Conectar Convocatorias Vigentes con la API de Procesos de Admisión
-
-## Contexto
-La sección "Convocatorias Vigentes" en la página pública (`ConvocatoriasSection.vue`) mostraba datos hardcodeados. El backend ya tenía todo listo (modelo `ProcesoAdmision`, controlador, endpoints CRUD). Solo faltaba conectar el frontend público con la API para que cuando un admin cree un proceso de admisión desde el panel, aparezca dinámicamente en la web pública.
-
-## Problemas que se resolvieron
-- `ConvocatoriasSection.vue` tenía cards estáticas ("Admisión Ordinaria 2026-I", "CEPREUNA", "Extraordinario")
-- Los botones de Requisitos/Pagos/Vacantes/Cronograma emitían eventos pero `showModal()` en `WebPage.vue` solo hacía `console.log`
-- No existía endpoint público (sin auth) para consultar procesos publicados
-- `ProcessSection.vue` tenía fechas y steps hardcodeados
-- El formulario admin no permitía borrar campos nullable (subtítulo, fechas, etc.)
-- Constraint único incorrecto en `proceso_admision_detalles` impedía crear más de un detalle por proceso
-
----
-
-## Implementación completada
-
-### 1. Backend: Endpoint público (sin auth)
-
-**Archivo:** `back/routes/api.php`
-- Se agregó ruta `GET /procesos-admision/publicados` fuera del middleware `auth:sanctum`
-- Esta ruta devuelve solo procesos con `publicado=true`, incluyendo sus detalles
-
-```php
-// Ruta pública (sin auth) - procesos publicados para la web
-Route::get('/procesos-admision/publicados', [ProcesoAdmisionController::class, 'publicados']);
-```
-
-**Archivo:** `back/app/Http/Controllers/Administracion/ProcesoAdmisionController.php`
-- Se agregó método `publicados()` que retorna procesos publicados con sus detalles, ordenados por fecha
-
-```php
-public function publicados()
-{
- $procesos = ProcesoAdmision::where('publicado', true)
- ->with(['detalles' => fn($d) => $d->orderBy('id', 'asc')])
- ->orderByDesc('id')
- ->get();
-
- return response()->json($procesos);
-}
-```
-
----
-
-### 2. Frontend: Store - action pública
-
-**Archivo:** `front/src/store/procesosAdmisionStore.js`
-- Se agregó estado `procesosPublicados: []`
-- Se agregó action `fetchProcesosPublicados()` que usa `axios` directo (sin token de auth) para llamar al endpoint público
-
-```js
-import axios from 'axios'
-
-// En state:
-procesosPublicados: [],
-
-// Nueva action:
-async fetchProcesosPublicados() {
- this.loading = true
- this.error = null
- try {
- const baseURL = import.meta.env.VITE_API_URL
- const { data } = await axios.get(`${baseURL}/procesos-admision/publicados`)
- this.procesosPublicados = Array.isArray(data) ? data : []
- return true
- } catch (err) {
- this._setError(err)
- return false
- } finally {
- this.loading = false
- }
-},
-```
-
-**Nota importante:** Se usa `axios` directo en lugar de la instancia `api` porque esta última inyecta automáticamente el token Bearer. Al ser un endpoint público, no necesita autenticación.
-
----
-
-### 3. Frontend: ConvocatoriasSection dinámico
-
-**Archivo:** `front/src/components/WebPageSections/ConvocatoriasSection.vue`
-
-Cambios principales:
-- Recibe `procesos` como prop (array de procesos desde la API)
-- El primer proceso se renderiza como **card principal**
-- Los demás se renderizan como **cards secundarias**
-- Mapeo de `estado` del proceso al tag visual:
-
-```js
-const estadoMap = {
- publicado: { label: 'Abierto', color: 'success' },
- en_proceso: { label: 'En Proceso', color: 'processing' },
- nuevo: { label: 'PRÓXIMAMENTE', color: 'orange' },
- finalizado: { label: 'FINALIZADO', color: 'default' },
- cancelado: { label: 'CANCELADO', color: 'red' },
-}
-```
-
-- Las fechas de inscripción se muestran dinámicamente desde `fecha_inicio_inscripcion` / `fecha_fin_inscripcion`
-- La imagen usa `imagen_url` del proceso (o fallback a `/images/extra.jpg`)
-- Botones Requisitos/Pagos/Vacantes/Cronograma emiten evento con `{ procesoId, tipo }`
-- Botón "Iniciar Preinscripción" abre `link_preinscripcion` en nueva pestaña directamente
-- Estado vacío: si no hay procesos publicados, muestra mensaje "No hay convocatorias vigentes"
-
----
-
-### 4. Frontend: WebPage.vue conectado con data y modal
-
-**Archivo:** `front/src/components/WebPage.vue`
-
-Cambios principales:
-- Importa el store y llama `fetchProcesosPublicados()` en `onMounted`
-- Pasa los procesos como prop a `ConvocatoriasSection`
-- Pasa el proceso principal como prop a `ProcessSection`
-
-```js
-const procesoStore = useProcesoAdmisionStore()
-const procesosPublicados = computed(() => procesoStore.procesosPublicados)
-const procesoPrincipal = computed(() => procesoStore.procesosPublicados[0] || null)
-
-onMounted(() => {
- procesoStore.fetchProcesosPublicados()
-})
-```
-
-```html
-
-
-
-```
-
-- Implementa `showModal({ procesoId, tipo })`:
- - Busca el proceso por ID en `procesosPublicados`
- - Busca el detalle cuyo `tipo` coincida (requisitos, pagos, vacantes, cronograma)
- - Abre un `a-modal` con: imagen + título + descripción + lista del detalle
- - Si no encuentra detalle, muestra `` con mensaje informativo
-
-```js
-const showModal = ({ procesoId, tipo }) => {
- const proceso = procesosPublicados.value.find(p => p.id === procesoId)
- if (!proceso) return
-
- const detalle = proceso.detalles?.find(d => d.tipo === tipo)
-
- if (detalle) {
- detalleModal.value = {
- titulo: detalle.titulo_detalle || tipoLabels[tipo] || tipo,
- descripcion: detalle.descripcion || '',
- imagen_url: detalle.imagen_url || null,
- imagen_url_2: detalle.imagen_url_2 || null,
- listas: detalle.listas || [],
- }
- } else {
- detalleModal.value = {
- titulo: `${tipoLabels[tipo] || tipo} - ${proceso.titulo}`,
- descripcion: '',
- imagen_url: null,
- imagen_url_2: null,
- listas: [],
- }
- }
-
- detalleModalVisible.value = true
-}
-```
-
----
-
-### 5. Frontend: ProcessSection dinámico (timeline de fechas)
-
-**Archivo:** `front/src/components/WebPageSections/ProcessSection.vue`
-
-Antes tenía steps hardcodeados ("Preinscripción Virtual: 20 Oct - 30 Nov", etc.). Ahora:
-
-- Recibe `proceso` como prop (el proceso principal/más reciente publicado)
-- Genera los steps dinámicamente solo para las fechas que existan en el proceso:
-
-```js
-const steps = computed(() => {
- const p = props.proceso
- if (!p) return []
- const list = []
-
- const preinscripcion = formatRango(p.fecha_inicio_preinscripcion, p.fecha_fin_preinscripcion)
- if (preinscripcion) list.push({ title: 'Preinscripción Virtual', description: preinscripcion })
-
- const inscripcion = formatRango(p.fecha_inicio_inscripcion, p.fecha_fin_inscripcion)
- if (inscripcion) list.push({ title: 'Inscripción Presencial', description: inscripcion })
-
- const examen = formatRango(p.fecha_examen1, p.fecha_examen2)
- if (examen) list.push({ title: 'Examen', description: examen })
-
- const resultados = formatFecha(p.fecha_resultados)
- if (resultados) list.push({ title: 'Resultados', description: resultados })
-
- const biometrico = formatRango(p.fecha_inicio_biometrico, p.fecha_fin_biometrico)
- if (biometrico) list.push({ title: 'Control Biométrico', description: biometrico })
-
- return list
-})
-```
-
-- El **currentStep** se calcula automáticamente comparando `new Date()` con las fechas del proceso
-- Muestra **título** y **subtítulo** del proceso dinámicamente
-- Si no hay proceso publicado, la sección **no se muestra** (`v-if="proceso"`)
-- Si un paso no tiene fechas, simplemente no aparece en el timeline
-
-Mapeo de campos DB → Steps:
-
-| Campo en DB | Step |
-|---|---|
-| `fecha_inicio_preinscripcion` / `fecha_fin_preinscripcion` | Preinscripción Virtual |
-| `fecha_inicio_inscripcion` / `fecha_fin_inscripcion` | Inscripción Presencial |
-| `fecha_examen1` / `fecha_examen2` | Examen |
-| `fecha_resultados` | Resultados |
-| `fecha_inicio_biometrico` / `fecha_fin_biometrico` | Control Biométrico |
-
----
-
-### 6. Fix: Unique constraint en detalles
-
-**Problema:** La tabla `proceso_admision_detalles` tenía un unique constraint `uq_proceso_modalidad_tipo` solo sobre `proceso_admision_id`, impidiendo crear más de un detalle por proceso.
-
-**Solución:** Migración `2026_02_15_051618_fix_unique_constraint_proceso_admision_detalles.php`
-
-```php
-// Eliminar el unique incorrecto (solo proceso_admision_id)
-$table->dropUnique('uq_proceso_modalidad_tipo');
-
-// Crear el unique correcto: un detalle por tipo por proceso
-$table->unique(['proceso_admision_id', 'tipo'], 'uq_proceso_tipo');
-```
-
-Ahora permite un detalle por cada tipo (requisitos, pagos, vacantes, cronograma) por proceso.
-
----
-
-### 7. Fix: Campos nullable no se borraban al editar
-
-**Problema:** Cuando el admin borraba un campo (subtítulo, fechas, links) en el formulario de edición, el valor viejo persistía en la DB.
-
-**Causa raíz (doble):**
-
-1. **Frontend** (`ProcesosAdmisionList.vue` → `buildFormData()`): Los campos usaban `|| null` que convertía strings vacíos a `null`, y luego el forEach filtraba `null`. Resultado: campos vacíos nunca se enviaban al backend.
-
-2. **Backend** (`ProcesoAdmisionController@update`): Laravel `validate()` con regla `sometimes` + `nullable` no siempre incluye campos con valor `null` en el array `$data` validado. Resultado: `$proceso->update($data)` no recibía el campo y el valor viejo quedaba.
-
-**Solución Frontend** (`front/src/views/administrador/procesoadmision/ProcesosAdmisionList.vue`):
-
-```js
-// ANTES (no funcionaba):
-subtitulo: formState.subtitulo || null, // "" → null → filtrado → no se envía
-
-// DESPUÉS:
-subtitulo: formState.subtitulo ?? '', // "" → "" → se envía
-
-// ANTES:
-if (v === null || v === undefined || v === '') return // filtraba todo
-
-// DESPUÉS:
-if (v === undefined) return // solo filtra undefined
-```
-
-**Solución Backend** (`back/app/Http/Controllers/Administracion/ProcesoAdmisionController.php`):
-
-Se agregó un bloque en `update()` que fuerza la inclusión de campos nullable cuando vienen en el request pero no quedaron en `$data` después de la validación:
-
-```php
-$nullableFields = [
- 'subtitulo','descripcion','tipo_proceso','modalidad',
- 'fecha_publicacion',
- 'fecha_inicio_preinscripcion','fecha_fin_preinscripcion',
- 'fecha_inicio_inscripcion','fecha_fin_inscripcion',
- 'fecha_examen1','fecha_examen2','fecha_resultados',
- 'fecha_inicio_biometrico','fecha_fin_biometrico',
- 'link_preinscripcion','link_inscripcion','link_resultados','link_reglamento',
-];
-
-foreach ($nullableFields as $field) {
- if ($request->has($field) && !array_key_exists($field, $data)) {
- $data[$field] = null;
- }
-}
-```
-
----
-
-## Archivos modificados (resumen)
-
-| # | Archivo | Cambio |
-|---|---------|--------|
-| 1 | `back/routes/api.php` | Nueva ruta pública `GET /procesos-admision/publicados` |
-| 2 | `back/app/Http/Controllers/Administracion/ProcesoAdmisionController.php` | Nuevo método `publicados()` + fix nullable en `update()` |
-| 3 | `front/src/store/procesosAdmisionStore.js` | Nuevo estado `procesosPublicados` + action `fetchProcesosPublicados()` |
-| 4 | `front/src/components/WebPageSections/ConvocatoriasSection.vue` | Componente dinámico con props en lugar de datos hardcodeados |
-| 5 | `front/src/components/WebPageSections/ProcessSection.vue` | Timeline dinámico con fechas del proceso principal |
-| 6 | `front/src/components/WebPage.vue` | Conexión con store, props a ProcessSection y ConvocatoriasSection, modal de detalles |
-| 7 | `front/src/views/administrador/procesoadmision/ProcesosAdmisionList.vue` | Fix `buildFormData()` para enviar campos vacíos |
-| 8 | `back/database/migrations/2026_02_15_051618_fix_unique_constraint_proceso_admision_detalles.php` | Fix unique constraint `(proceso_admision_id, tipo)` |
-
----
-
-## Flujo completo
-
-```
-Admin Panel Backend Web Pública
-───────────── ─────── ───────────
-Crear proceso con
-publicado=true ──────► Se guarda en DB
-+ fechas + detalles (procesos_admision +
- proceso_admision_detalles)
-
- GET /procesos-admision/publicados
- (sin auth) ◄──── fetchProcesosPublicados()
- en onMounted()
-
- Retorna JSON con ────► procesosPublicados (store)
- procesos + detalles │
- ├── ProcessSection
- │ (timeline con fechas)
- │
- ├── ConvocatoriasSection
- │ (cards dinámicas)
- │
- └── showModal()
- (abre modal con detalle)
-```
-
----
-
-## Verificación
-
-1. Crear un proceso de admisión desde el panel admin con `publicado=true`, agregar fechas y detalles de tipo `requisitos`, `pagos`, `vacantes`, `cronograma`
-2. Ir a la página pública y verificar que aparece en "Convocatorias Vigentes"
-3. Verificar que el timeline de "Proceso de Admisión" muestra las fechas correctas y el step actual
-4. Verificar que los botones de Requisitos/Pagos/Vacantes/Cronograma muestran la info correcta en el modal
-5. Verificar que si el proceso tiene `publicado=false`, no aparece en la web pública
-6. Verificar que "Iniciar Preinscripción" abre el `link_preinscripcion` en nueva pestaña
-7. Verificar que se pueden crear múltiples detalles por proceso (uno por tipo)
-8. Verificar que al editar y borrar un campo nullable (subtítulo, fechas), se limpia correctamente en la DB
-
----
-
-## Modelos de referencia
-
-### ProcesoAdmision (campos clave)
-- `titulo`, `subtitulo`, `descripcion`, `slug`
-- `tipo_proceso`, `modalidad`
-- `publicado` (boolean), `estado` (nuevo/publicado/en_proceso/finalizado/cancelado)
-- `fecha_inicio_preinscripcion`, `fecha_fin_preinscripcion`
-- `fecha_inicio_inscripcion`, `fecha_fin_inscripcion`
-- `fecha_examen1`, `fecha_examen2`
-- `fecha_resultados`
-- `fecha_inicio_biometrico`, `fecha_fin_biometrico`
-- `imagen_path` → accessor `imagen_url`
-- `link_preinscripcion`, `link_inscripcion`, `link_resultados`
-- Relación: `detalles` (hasMany ProcesoAdmisionDetalle)
-
-### ProcesoAdmisionDetalle (campos clave)
-- `proceso_admision_id`
-- `tipo` (requisitos/pagos/vacantes/cronograma)
-- `titulo_detalle`, `descripcion`
-- `listas` (JSON array), `meta` (JSON object)
-- `imagen_path` → accessor `imagen_url`
-- `imagen_path_2` → accessor `imagen_url_2`
-- **Unique constraint:** `(proceso_admision_id, tipo)` — un detalle por tipo por proceso
-
----
-
-### 8. Fix menor: Segunda imagen del modal no estaba centrada
-
-**Archivo:** `front/src/components/WebPage.vue`
-
-El div de la segunda imagen (`imagen_url_2`) no tenía la clase `detalle-modal-imagen`, por lo que aparecía alineada a la izquierda. Se agregó la clase para que ambas imágenes se muestren centradas con el mismo estilo.
-
----
-
-## Lecciones aprendidas
-
-1. **Laravel 12 no usa `Kernel.php`** — la configuración de middleware está en `bootstrap/app.php`. El `Kernel.php` que existía era legacy y no se ejecutaba.
-
-2. **`|| null` vs `?? ''` en JS** — `formState.value || null` convierte `""` (string vacío) a `null`. Usar `?? ''` solo convierte `null`/`undefined` a `""`, preservando strings vacíos.
-
-3. **Laravel `sometimes` + `nullable` en validate()** — Cuando un campo llega como `null` (después de `ConvertEmptyStringsToNull`), la validación `sometimes` + `nullable` no siempre lo incluye en `$data`. Se necesita un manejo explícito para forzar `null` en campos que el usuario quiere borrar.
-
-4. **Unique constraints** — Verificar siempre que columnas incluye un unique index. El nombre `uq_proceso_modalidad_tipo` sugería que era compuesto, pero solo era sobre `proceso_admision_id`.