Necesito implementar una nueva funcionalidad para la carga manual y sincronización del archivo `grupos.csv`.

## Contexto

Actualmente el sistema utiliza el archivo ubicado en:

`files/data/csv/grupos.csv`

Este archivo se utiliza posteriormente en el proceso ejecutado desde:

`@app/controllers/SincronizacionController.php`

específicamente mediante la acción:

`actionprogramacion`

El cliente debe actualizar este archivo todos los días.

Actualmente existe un proceso externo por FTP que copia el archivo directamente al servidor. Sin embargo, ese proceso todavía no está completamente automatizado/modificado por parte del cliente.

Como solución alternativa, nosotros como proveedores vamos a habilitar una vista dentro del sistema para que el usuario pueda cargar manualmente el archivo `grupos.csv`.

Antes de realizar cambios, revisa la arquitectura actual del proyecto, especialmente:

- `@app/controllers/SincronizacionController.php`
- La implementación de `actionprogramacion`.
- La carpeta `files/data/csv/`.
- La forma actual en que se lee `grupos.csv`.
- Las vistas, controladores, modelos y estructura visual utilizadas actualmente por el sistema.
- El sistema actual de autenticación y permisos.

La implementación debe respetar la arquitectura y convenciones existentes del proyecto.

## 1. Nueva vista para cargar grupos.csv

Crear una vista administrativa para cargar el archivo:

`grupos.csv`

La vista debe ser visualmente clara y profesional, utilizando los componentes, estilos y estructura que ya existen en el proyecto.

Debe mostrar claramente:

- Nombre esperado del archivo: `grupos.csv`.
- Ubicación donde será almacenado:
  `files/data/csv/grupos.csv`
- Fecha de última actualización del archivo actual.
- Tamaño del archivo actual.
- Botón para seleccionar archivo.
- Botón "Cargar y sincronizar".
- Mensajes claros de éxito o error.

Cuando se cargue correctamente el archivo, debe reemplazar el archivo existente:

`files/data/csv/grupos.csv`

No crear versiones como:

`grupos(1).csv`
`grupos_2026.csv`
`grupos_nuevo.csv`

Siempre debe quedar exactamente:

`grupos.csv`

## 2. Explicar al usuario cómo debe ser el CSV

Existe un problema frecuente con los separadores CSV.

Cuando el archivo llega automáticamente al servidor mediante FTP actualmente tiene separador:

`,`

Ejemplo:

```csv
PERIODO,NRC,CODIGO_ASIGNATURA,NOMBRE_ASIGNATURA,DOCENTE
202610,12345,ABC001,PROGRAMACION,JUAN PEREZ
```

Sin embargo, cuando un usuario genera o guarda un CSV desde Excel en equipos configurados regionalmente en Colombia, normalmente el separador generado es:

`;`

Ejemplo:

```csv
PERIODO;NRC;CODIGO_ASIGNATURA;NOMBRE_ASIGNATURA;DOCENTE
202610;12345;ABC001;PROGRAMACION;JUAN PEREZ
```

Por esta razón debemos manejar los dos escenarios de manera diferente.

## 3. Archivo cargado manualmente

Si el usuario carga el archivo desde la nueva vista, el sistema debe exigir que el separador sea:

`;`

Antes de reemplazar el archivo existente se debe validar el CSV.

Validaciones mínimas:

1. Debe ser un archivo `.csv`.
2. Debe llamarse `grupos.csv`.
3. No debe estar vacío.
4. Debe utilizar `;` como separador.
5. Debe contener exactamente los encabezados esperados.
6. Los encabezados deben encontrarse en el orden esperado.
7. No permitir archivos con columnas faltantes.
8. No permitir archivos con columnas adicionales inesperadas si pueden afectar la sincronización.
9. Validar que las filas tengan la misma cantidad de columnas que el encabezado.
10. Si el archivo utiliza `,` en lugar de `;`, rechazarlo e informar al usuario claramente.

Ejemplo del mensaje:

"El archivo cargado manualmente debe utilizar punto y coma (;) como separador. Verifique la configuración regional de Excel y vuelva a guardar el archivo como CSV."

IMPORTANTE:

No adivines cuáles son los encabezados.

Primero revisa el archivo `grupos.csv` actualmente existente en:

`files/data/csv/grupos.csv`

y utiliza ese archivo como referencia para determinar:

- cantidad de columnas;
- nombres exactos de encabezados;
- orden de las columnas.

## 4. Mostrar encabezado esperado

En la vista debe existir una sección llamada:

"Formato esperado del archivo"

Mostrar visualmente los encabezados que debe contener `grupos.csv`.

Por ejemplo, puede presentarse mediante una tabla:

| Columna | Nombre esperado |
|---------|-----------------|
| 1 | PERIODO |
| 2 | NRC |
| 3 | ... |

Pero los nombres reales deben obtenerse revisando el archivo actual del proyecto.

También mostrar una pequeña muestra de cómo debe verse el archivo utilizando `;`.

Ejemplo:

```csv
COLUMNA1;COLUMNA2;COLUMNA3
VALOR1;VALOR2;VALOR3
```

No mostrar datos sensibles reales. Solamente encabezados y datos de ejemplo.

## 5. Archivo leído directamente desde el servidor

La sincronización actual también puede ejecutarse cuando el archivo ha sido copiado directamente por FTP.

En ese escenario el archivo utiliza:

`,`

Por lo tanto, debemos modificar la lectura del CSV para soportar ambos escenarios de manera controlada.

Regla:

- Archivo cargado manualmente desde la nueva interfaz: `;`
- Archivo copiado directamente al servidor/FTP: `,`

Sin embargo, intenta implementar el procesamiento de manera robusta.

Idealmente el lector del CSV debe poder detectar el delimitador antes de procesarlo.

Por ejemplo:

- si el encabezado contiene `;`, utilizar `;`;
- si contiene `,`, utilizar `,`;
- si no se puede determinar claramente el delimitador, detener la sincronización y registrar el error.

No hacer reemplazos simples como:

`str_replace(';', ',', ...)`

porque podría modificar valores legítimos dentro de los campos.

Utilizar correctamente las funciones CSV de PHP, por ejemplo `fgetcsv`, indicando el delimitador correspondiente.

## 6. Flujo de carga manual

El flujo esperado debe ser:

Usuario selecciona `grupos.csv`

→ validar extensión

→ validar nombre

→ detectar separador

→ exigir `;` para carga manual

→ leer encabezados

→ comparar encabezados contra la estructura esperada

→ validar estructura de las filas

→ si existe algún problema NO reemplazar el archivo actual

→ mostrar el error al usuario

→ si todo está correcto realizar backup temporal o mecanismo seguro

→ reemplazar:

`files/data/csv/grupos.csv`

→ ejecutar la sincronización

→ mostrar resultado.

Es importante que un archivo incorrecto nunca destruya/reemplace el archivo válido que ya existe.

Realiza el reemplazo solamente después de terminar todas las validaciones.

## 7. Ejecutar actionprogramacion

Después de cargar correctamente el archivo se debe ejecutar el proceso correspondiente a:

`SincronizacionController.php`

`actionprogramacion`

Revisa primero cómo funciona actualmente esta acción.

Evita duplicar la lógica de sincronización.

Si es posible, extrae la lógica reutilizable a un método/servicio que pueda utilizarse tanto desde:

- la acción existente;
- la nueva carga manual.

No realizar una petición HTTP interna innecesaria si la misma lógica puede llamarse directamente desde PHP.

## 8. Token para ejecución externa

También necesitamos permitir que el cliente pueda ejecutar la sincronización mediante una URL enviando un token por GET.

Ejemplo conceptual:

`/sincronizacion/programacion?token=TOKEN`

Implementar una validación segura del token antes de ejecutar la sincronización.

El token:

- no debe estar escrito directamente en el controlador;
- debe estar almacenado en configuración o variable de entorno;
- debe compararse de manera segura;
- si no existe o no coincide, responder con acceso denegado;
- registrar los intentos inválidos sin guardar el token completo en logs.

Utilizar una comparación segura, por ejemplo:

`hash_equals()`

cuando aplique.

La acción nunca debe ejecutarse si el token no es válido.

NOTA DE SEGURIDAD:

Aunque necesitamos compatibilidad con token por GET porque así se integrará inicialmente con el cliente, estructura la implementación para que posteriormente sea sencillo migrarlo a un header HTTP, por ejemplo:

`Authorization: Bearer TOKEN`

ya que enviar tokens por query string puede dejarlos registrados en logs, historiales o proxies.

## 9. Protección de la vista

La nueva vista de carga manual NO debe depender solamente del token.

Debe utilizar el sistema normal de autenticación del aplicativo.

Además, revisar cómo se manejan actualmente los permisos/roles administrativos y aplicar el permiso correspondiente.

Solamente usuarios autorizados deben poder reemplazar `grupos.csv` y ejecutar la sincronización manual.

## 10. Manejo de errores

Mostrar mensajes entendibles para el usuario, por ejemplo:

- "El archivo debe llamarse grupos.csv."
- "Solo se permiten archivos CSV."
- "El archivo está vacío."
- "El archivo debe estar separado por punto y coma (;)."
- "Los encabezados no corresponden con el formato esperado."
- "Falta la columna NRC."
- "La fila 25 contiene una cantidad incorrecta de columnas."
- "No fue posible reemplazar el archivo."
- "El archivo fue cargado correctamente, pero ocurrió un error durante la sincronización."
- "Archivo cargado y sincronización completada correctamente."

Además registrar información técnica en los logs del sistema para diagnóstico.

## 11. Seguridad en la carga

Validar también:

- tamaño máximo permitido;
- evitar path traversal;
- no utilizar directamente el nombre proporcionado por el navegador;
- no permitir cargar PHP u otros archivos renombrados;
- verificar que realmente sea un archivo de texto/CSV;
- escribir únicamente dentro de `files/data/csv/`;
- manejar correctamente permisos de escritura;
- evitar condiciones de carrera si dos usuarios cargan simultáneamente;
- no exponer rutas internas completas del servidor en mensajes de error.

## 12. Interfaz

Quiero que la vista sea fácil de utilizar por una persona no técnica.

Debe contener una sección tipo alerta/información indicando:

"IMPORTANTE: El archivo debe conservar exactamente los encabezados indicados y debe estar separado por punto y coma (;). No cambie los nombres ni el orden de las columnas."

También debe mostrar:

- Último archivo actualizado.
- Fecha de modificación.
- Formato esperado.
- Separador requerido para carga manual: `;`.
- Botón de selección.
- Nombre del archivo seleccionado.
- Botón de carga.
- Estado de la sincronización.

Si el proyecto utiliza Bootstrap, Metronic u otra plantilla, reutilizar los componentes existentes y no agregar una nueva librería únicamente para esta pantalla.

## 13. Auditoría

Si el proyecto tiene información del usuario autenticado, registrar:

- usuario que realizó la carga;
- fecha y hora;
- nombre del archivo;
- tamaño;
- resultado de validación;
- resultado de sincronización.

No almacenar el token en los logs.

## 14. Antes de implementar

Antes de escribir código:

1. Revisa el proyecto.
2. Localiza `SincronizacionController.php`.
3. Analiza `actionprogramacion`.
4. Revisa el `grupos.csv` actual.
5. Identifica exactamente sus encabezados.
6. Revisa cómo se están leyendo actualmente los CSV.
7. Identifica el framework y versión de PHP.
8. Identifica el sistema actual de vistas, rutas, autenticación y permisos.
9. Indica qué archivos vas a modificar o crear.
10. Luego realiza la implementación.

No inventes arquitectura ni crees componentes innecesarios si el proyecto ya tiene una forma estándar de resolverlo.

Finalmente, entrega un resumen con:

- archivos creados;
- archivos modificados;
- ruta de la nueva vista;
- formato esperado del CSV;
- funcionamiento de detección de delimitadores;
- configuración requerida para el token;
- URL de ejecución externa;
- flujo de carga manual;
- medidas de seguridad implementadas;
- pasos para probar la funcionalidad.