# Seguimiento de Impuestos GLM > Aplicación interna que centraliza el calendario tributario regional de GomezLee Marketing y automatiza el envío de recordatorios por correo y WhatsApp. --- ## INFORMACIÓN GENERAL | Campo | Detalle | |---|---| | **Proyecto** | Seguimiento de Impuestos GLM | | **Área** | Administración | | **Estado** | Listo para producción | | **Developer principal** | Isaac Aracena | | **IT Manager** | Luis Matos | | **Fecha de inicio** | 2026-07-24 | | **Fecha de cierre** | 2026-07-27 | --- ## OBJETIVO ### Problema que resuelve El seguimiento de las obligaciones tributarias de los diferentes países de GLM se realizaba mediante calendarios y archivos separados. Esto dificultaba consultar las fechas límite, identificar a los responsables y garantizar que los avisos fueran enviados a tiempo. Además, agregar o cambiar destinatarios requería modificar manualmente los flujos de automatización. ### Solución implementada Seguimiento de Impuestos GLM centraliza en una sola aplicación: - El calendario tributario regional. - Las obligaciones de Nómina y Administración. - Los países y fechas límite. - Los contactos responsables. - Los canales habilitados para cada contacto. - El historial de notificaciones enviadas. La aplicación permite administrar obligaciones y contactos desde una interfaz web. Un flujo de n8n consulta diariamente la información almacenada en Supabase y envía los recordatorios correspondientes por Gmail y WhatsApp. ### Usuarios y beneficiarios - Equipo de Administración. - Equipo de Nómina. - Responsables tributarios de cada país. - Contactos regionales. - Dirección de Recursos Humanos. - Equipo de IT de GomezLee Marketing. --- ## ARQUITECTURA ### Diagrama general ```text Usuario autorizado | v Frontend React + Vite | +------> Supabase Auth | +------> Supabase PostgreSQL | v Obligaciones y contactos | v n8n — Ejecución 8:00 AM | v RPC tax_due_reminders | +--------+--------+ | | v v Gmail HTML WhatsApp | | +--------+--------+ | v tax_notification_log ``` ### Stack tecnológico | Componente | Tecnología | Propósito | |---|---|---| | Frontend | React 19 | Interfaz de usuario | | Lenguaje | TypeScript | Tipado y lógica de la aplicación | | Bundler | Vite | Desarrollo y compilación | | Estilos | Tailwind CSS | Diseño visual | | Autenticación | Supabase Auth + Google OAuth | Control de acceso | | Base de datos | Supabase / PostgreSQL | Obligaciones, países, contactos y bitácora | | API de datos | Supabase REST / PostgREST | Comunicación entre frontend, n8n y base de datos | | Automatización | n8n | Orquestación de recordatorios | | Correo | Gmail OAuth | Envío de correos HTML | | Mensajería | WhatsApp GLM | Envío de avisos por WhatsApp | | Hosting | EasyPanel / servidor GLM | Despliegue de la aplicación y servicios | ### Integraciones externas | Sistema | Tipo de integración | Datos que fluyen | |---|---|---| | Supabase Auth | Google OAuth | Inicio de sesión y sesión del usuario | | Supabase REST | API REST / RPC | Obligaciones, contactos, países y notificaciones | | n8n | Webhook y Schedule Trigger | Ejecución manual, diaria y notificación de cambios | | Gmail | OAuth | Correos de recordatorio | | WhatsApp GLM | API REST | Mensajes de recordatorio | | Google Workspace | OAuth | Identidad corporativa de los usuarios | --- ## REGLAS DE NEGOCIO ### Regla de recordatorios La fórmula principal es: > **Miércoles estrictamente anterior y el mismo día de la fecha límite.** Ejemplos: | Fecha límite | Primer aviso | Segundo aviso | |---|---|---| | Lunes | Miércoles anterior | Lunes | | Martes | Miércoles anterior | Martes | | Miércoles | Miércoles de la semana anterior | Miércoles | | Jueves | Miércoles anterior | Jueves | | Viernes | Miércoles anterior | Viernes | | Sábado | Miércoles anterior | Sábado | | Domingo | Miércoles anterior | Domingo | El miércoles calculado debe ser estrictamente anterior. Si la obligación vence un miércoles, el primer aviso corresponde al miércoles de la semana anterior. ### Enrutamiento de contactos - Los contactos de área **Regional** reciben todas las obligaciones de todos los países. - Los contactos regionales de **Nómina** reciben las obligaciones de Nómina de todos los países. - Los contactos regionales de **Administración** reciben las obligaciones administrativas de todos los países. - Los contactos de un país específico reciben solamente las obligaciones de su país y categoría. - Solo se utilizan contactos activos. - El correo se envía únicamente cuando el canal de correo está habilitado. - WhatsApp se envía únicamente cuando el canal de WhatsApp está habilitado. - Los números deben guardarse con código internacional. ### Obligaciones tributarias - El país es obligatorio. - Las únicas categorías disponibles son: - Nómina. - Administración. - Una obligación puede editarse o eliminarse mientras no tenga avisos enviados. - Después del primer correo o WhatsApp registrado, la obligación queda bloqueada. - Las obligaciones bloqueadas permanecen disponibles en modo de solo lectura. - Cuando un día tiene más de tres obligaciones, la opción **Ver todos** permite consultar la lista completa. ### Prevención de duplicados Cada notificación enviada se registra en `tax_notification_log`. La combinación de obligación, contacto, canal y tipo de aviso evita que el mismo recordatorio sea enviado dos veces. --- ## BASE DE DATOS ### Tablas La aplicación utiliza cinco tablas: | Tabla | Propósito | |---|---| | `tax_calendar_access` | Correos autorizados para ingresar | | `tax_countries` | Catálogo de países | | `tax_obligations` | Obligaciones y eventos tributarios | | `tax_contacts` | Contactos responsables y canales habilitados | | `tax_notification_log` | Bitácora de correos y WhatsApp enviados | ### Funciones principales | Función | Propósito | |---|---| | `has_tax_calendar_access` | Valida si el correo puede utilizar la aplicación | | `tax_previous_wednesday` | Calcula el miércoles estrictamente anterior | | `tax_due_reminders` | Devuelve los recordatorios y destinatarios pendientes | | `tax_record_notification` | Registra un envío exitoso | | `tax_obligation_delivery_status` | Consulta si una obligación ya fue notificada | | `tax_prevent_sent_obligation_changes` | Bloquea cambios después del primer aviso | ### Instalación completa Para una instalación nueva, ejecutar en Supabase: ```text supabase/Seguimiento-de-Impuestos-GLM.sql ``` El script incluye: - Tablas. - Índices. - Triggers. - Funciones RPC. - Políticas RLS. - Accesos iniciales. - Países. - Contactos. - Obligaciones históricas de 2026. - Prevención de notificaciones duplicadas. ### Actualizaciones incrementales Para bases que ya tenían una versión anterior: ```text supabase/actualizacion_eventos_bloqueados.sql supabase/actualizacion_final_calendario_y_nomina.sql ``` No ejecutar actualizaciones incrementales si ya se utilizó el script completo más reciente. --- ## CONFIGURACIÓN Y SETUP ### Prerrequisitos - Node.js instalado. - npm instalado. - Acceso al Supabase empresarial. - Acceso a Google Cloud y Supabase Auth. - Acceso a n8n. - Credencial de Gmail configurada en n8n. - Acceso a la API de WhatsApp de GLM. - Acceso al hosting de EasyPanel. - Correo autorizado para ingresar a la aplicación. ### Variables del frontend Copiar el archivo de ejemplo: ```powershell Copy-Item .env.example .env ``` Configurar: ```env VITE_SUPABASE_URL=https://dbit.digitalcompass.agency VITE_SUPABASE_PUBLISHABLE_KEY=REEMPLAZAR_CON_LA_LLAVE_PUBLICA VITE_TAX_WEBHOOK_URL=https://agenteit.digitalcompass.agency/webhook/seguimiento-impuestos ``` También puede utilizarse: ```env VITE_SUPABASE_ANON_KEY=REEMPLAZAR_CON_LA_ANON_KEY ``` Nunca colocar la llave `service_role` dentro del frontend. ### Variables y credenciales de n8n | Configuración | Descripción | |---|---| | Supabase URL | URL del Supabase empresarial | | Supabase Service Role | Llave privada para ejecutar RPC y registrar envíos | | Gmail Credential | Cuenta que envía los recordatorios | | WhatsApp Base URL | Endpoint del servicio de WhatsApp | | WhatsApp Instance | Instancia `botsoporte` | | WhatsApp API Key | Credencial privada del servicio | | GLM Tax App URL | `https://home.digitalcompass.agency/` | | GLM Logo URL | Logo público utilizado en el correo HTML | Las llaves privadas deben administrarse en n8n o en el vault de credenciales de GLM. > **Nunca commitear `.env`, llaves privadas, tokens, contraseñas o credenciales reales al repositorio.** ### Supabase Auth La URL autorizada para regresar a la aplicación después del login es: ```text https://home.digitalcompass.agency/ ``` En el servicio de Supabase Auth debe agregarse: ```env ADDITIONAL_REDIRECT_URLS=https://home.digitalcompass.agency/ ``` El callback de Google OAuth hacia Supabase permanece en: ```text https://dbit.digitalcompass.agency/auth/v1/callback ``` --- ## INSTALACIÓN LOCAL ### 1. Clonar el repositorio ```powershell git clone https://git.digitalcompass.agency/Isaac_Aracena/seguimiento-impuestos.git cd seguimiento-impuestos ``` ### 2. Instalar dependencias ```powershell npm install ``` ### 3. Crear el archivo de entorno ```powershell Copy-Item .env.example .env ``` Editar `.env` con la configuración pública correspondiente. ### 4. Ejecutar en desarrollo ```powershell npm run dev ``` Aplicación local: ```text http://localhost:5173/ ``` ### 5. Validar el proyecto ```powershell npm run typecheck npm run lint npm run format:check ``` ### 6. Generar el build ```powershell npm run build ``` ### 7. Probar el build ```powershell npm run preview ``` --- ## DESPLIEGUE La aplicación se publica directamente en la raíz del subdominio: ```text https://home.digitalcompass.agency/ ``` La configuración de Vite utiliza: ```ts base: "/" ``` Proceso general: ```powershell npm install npm run build ``` El contenido generado en `dist/` debe desplegarse en el servicio correspondiente de EasyPanel. Después del despliegue: 1. Abrir la aplicación. 2. Iniciar sesión con Google. 3. Confirmar que Supabase redirige a la raíz del subdominio. 4. Verificar que carguen obligaciones, países y contactos. 5. Crear un registro de prueba. 6. Confirmar su almacenamiento en Supabase. --- ## CONFIGURACIÓN DE N8N Importar el archivo: ```text n8n/Seguimiento-de-Impuestos-GLM.json ``` Después de importarlo: 1. Seleccionar la credencial en **Gmail - Enviar recordatorio**. 2. Configurar la conexión privada con Supabase. 3. Configurar el endpoint y la API key de WhatsApp. 4. Verificar la zona horaria `America/Santo_Domingo`. 5. Ejecutar una prueba manual. 6. Confirmar el correo recibido. 7. Confirmar el WhatsApp recibido. 8. Verificar el registro en `tax_notification_log`. 9. Activar el workflow. --- ## CÓMO FUNCIONA ### Flujo diario 1. El Schedule Trigger inicia el workflow a las 8:00 a. m. 2. n8n obtiene la fecha correspondiente a la ejecución. 3. El nodo de Supabase llama la RPC `tax_due_reminders`. 4. Supabase identifica las obligaciones que deben notificarse. 5. Supabase cruza cada obligación con los contactos aplicables. 6. n8n genera el correo HTML con el branding de GLM. 7. n8n genera el mensaje de WhatsApp. 8. Gmail envía los correos habilitados. 9. La API de WhatsApp envía los mensajes habilitados. 10. Cada envío exitoso se registra en Supabase. 11. Los registros enviados quedan protegidos contra duplicados. ### Cambios desde la aplicación Cuando el usuario: - Crea una obligación. - Actualiza una obligación. - Elimina una obligación. - Crea un contacto. - Actualiza un contacto. - Desactiva un contacto. La información se guarda directamente en Supabase. El flujo de n8n consulta siempre la información vigente, por lo que no es necesario modificar manualmente el workflow cuando cambien los contactos. ### Schedules y triggers | Trigger | Frecuencia | Descripción | |---|---|---| | Schedule Trigger | Diario, 8:00 a. m. | Envía los recordatorios correspondientes | | Manual Trigger | Bajo demanda | Permite realizar pruebas desde n8n | | Webhook `seguimiento-impuestos` | Bajo demanda | Recibe acciones del frontend o ejecuciones controladas | ### Prueba con una fecha específica ```json { "action": "run_now", "run_date": "2026-07-24" } ``` --- ## TESTING ### Casos de prueba mínimos | Caso | Input | Resultado esperado | Estado | |---|---|---|---| | Login autorizado | Correo incluido en `tax_calendar_access` | Acceso concedido | Validado | | Login no autorizado | Correo no incluido | Acceso denegado | Validado | | Crear obligación | Fecha, descripción, categoría y país | Registro visible en calendario | Validado | | País vacío | Obligación sin país | Formulario no permite guardar | Validado | | Categoría inválida | Valor diferente a Nómina o Administración | Registro rechazado | Validado | | Editar sin aviso | Obligación sin notificaciones | Cambios permitidos | Validado | | Editar con aviso | Obligación ya notificada | Modo de solo lectura | Validado | | Eliminar sin aviso | Obligación sin notificaciones | Eliminación permitida | Validado | | Eliminar con aviso | Obligación ya notificada | Eliminación bloqueada | Validado | | Más de tres obligaciones | Día con cuatro o más registros | Opción Ver todos disponible | Validado | | Contacto regional | Área Regional activa | Recibe todas las obligaciones | Validado | | Contacto regional de Nómina | País Regional y área Nómina | Recibe Nómina de todos los países | Validado | | Correo deshabilitado | `email_enabled = false` | No se genera correo | Validado | | WhatsApp deshabilitado | `whatsapp_enabled = false` | No se genera WhatsApp | Validado | | Aviso duplicado | Mismo contacto, obligación, canal y tipo | Segundo envío bloqueado | Validado | | API de WhatsApp caída | Error HTTP | Ejecución registrada como fallida | Pendiente de prueba controlada | | Gmail no disponible | Error de credencial o servicio | Nodo falla y queda visible en Executions | Pendiente de prueba controlada | --- ## ERRORES CONOCIDOS Y TROUBLESHOOTING | Error | Causa probable | Solución | |---|---|---| | El login vuelve a Supabase | Redirect URL incorrecta | Agregar `https://home.digitalcompass.agency/` a `ADDITIONAL_REDIRECT_URLS` | | Pantalla en blanco después del deploy | Base de Vite incorrecta | Confirmar `base: "/"` y reconstruir | | 401 Unauthorized en Supabase | Llave incorrecta o expirada | Revisar la llave pública o `service_role` según el componente | | No cargan obligaciones | Error en URL, RLS o sesión | Revisar consola del navegador y políticas RLS | | No llegan correos | Credencial de Gmail no seleccionada | Abrir el nodo Gmail y seleccionar la credencial | | No llega WhatsApp | API key, número o instancia incorrectos | Revisar encabezado `apikey`, instancia y código internacional | | Recordatorio duplicado | Bitácora no registrada correctamente | Revisar los nodos `Supabase - Registrar correo/WhatsApp` | | Obligación editable después del aviso | Trigger de protección no instalado | Ejecutar el script actualizado de Supabase | | Contacto no recibe avisos | País, área, canal o estado incorrecto | Revisar el contacto desde la app | | Webhook no responde | Workflow inactivo o URL incorrecta | Revisar activación y Production URL en n8n | | Error al compilar | Dependencias incompletas | Eliminar `node_modules`, ejecutar `npm install` y reconstruir | --- ## MONITOREO ### n8n Revisar periódicamente: - **Executions**. - Ejecuciones fallidas. - Respuesta de Gmail. - Respuesta de WhatsApp. - Respuesta de los nodos de registro en Supabase. Una ejecución normal debe finalizar sin nodos rojos y registrar cada canal enviado. ### Supabase Revisar: - Nuevas obligaciones. - Contactos activos. - Estado de acceso de usuarios. - Registros recientes en `tax_notification_log`. - Duplicados o errores de datos. - Obligaciones bloqueadas después del primer envío. ### Resultado esperado Cada día a las 8:00 a. m.: - Se consultan las obligaciones pendientes. - Se identifican los contactos aplicables. - Se envían los canales habilitados. - Se registra cada envío exitoso. - No se repiten avisos ya enviados. --- ## ESTRUCTURA DEL REPOSITORIO ```text seguimiento-impuestos/ |-- README.md |-- AGENTS.md |-- package.json |-- package-lock.json |-- vite.config.ts |-- tsconfig.json |-- eslint.config.js |-- index.html |-- .env.example |-- .gitignore | |-- public/ | |-- favicon.ico | |-- favicon-32.png | |-- favicon-192.png | └-- apple-touch-icon.png | |-- src/ | |-- App.tsx | |-- TaxApp.tsx | |-- main.tsx | |-- styles.css | | | |-- assets/ | | └-- glm-logo.png | | | |-- auth/ | | └-- AuthGate.tsx | | | └-- lib/ | |-- supabase-auth.ts | |-- supabase-data.ts | └-- tax-utils.ts | |-- supabase/ | |-- README.md | |-- Seguimiento-de-Impuestos-GLM.sql | |-- seguimiento_impuestos_auth.sql | |-- actualizacion_eventos_bloqueados.sql | └-- actualizacion_final_calendario_y_nomina.sql | |-- n8n/ | |-- CONFIGURACION.md | └-- Seguimiento-de-Impuestos-GLM.json | └-- dist/ └-- Build generado para producción ``` `node_modules/`, `.env` y demás archivos sensibles o generados no deben subirse al repositorio. --- ## CHANGELOG ### 2026-07-27 — v1.0.0 - Aplicación preparada para producción. - Migración del calendario histórico 2026 a Supabase. - Login con Google y control de accesos. - Gestión de obligaciones por país y categoría. - Gestión dinámica de contactos. - Filtros por país y nombre. - Búsqueda en la vista Lista. - Recordatorios por Gmail y WhatsApp. - Correo HTML con identidad visual GLM. - Prevención de envíos duplicados. - Bloqueo de obligaciones después del primer aviso. - Vista completa para días con más de tres obligaciones. - Despliegue configurado en la raíz del subdominio. - Flujo n8n con ejecución diaria a las 8:00 a. m. ### 2026-07-25 — v0.9.0 - Integración del frontend con Supabase. - Creación de las tablas principales. - Migración de obligaciones históricas. - Creación del flujo inicial de n8n. - Incorporación de contactos regionales y por país. ### 2026-07-24 — v0.1.0 - Limpieza del prototipo generado por Lovable. - Eliminación de archivos y dependencias innecesarias. - Estandarización del proyecto con React, Vite y TypeScript. - Aplicación inicial del branding de GLM. --- ## DECISIONS LOG ### DEC-001 — Supabase como fuente única de datos - **Fecha:** 2026-07-24 - **Contexto:** El prototipo almacenaba el calendario directamente en el frontend. - **Opciones consideradas:** Mantener datos estáticos o migrarlos a Supabase. - **Decisión:** Utilizar Supabase/PostgreSQL. - **Razón:** Permite persistencia, administración multiusuario, integración con n8n y trazabilidad. ### DEC-002 — Lógica determinística para las fechas - **Fecha:** 2026-07-24 - **Contexto:** Se consideró utilizar Gemini para decidir cuándo enviar los avisos. - **Opciones consideradas:** IA generativa o funciones de fechas en PostgreSQL. - **Decisión:** Utilizar funciones determinísticas. - **Razón:** La regla es exacta y no debe depender de interpretaciones probabilísticas. ### DEC-003 — Contactos administrados desde la aplicación - **Fecha:** 2026-07-25 - **Contexto:** Cada cambio de destinatario obligaba a editar n8n. - **Opciones consideradas:** Contactos hardcodeados o contactos en Supabase. - **Decisión:** Guardar contactos en `tax_contacts`. - **Razón:** Los usuarios pueden mantener destinatarios sin modificar el workflow. ### DEC-004 — Bloqueo después del primer envío - **Fecha:** 2026-07-26 - **Contexto:** Modificar una obligación después de notificarla podía generar inconsistencias. - **Opciones consideradas:** Permitir cambios siempre o bloquear después del envío. - **Decisión:** Bloquear edición y eliminación después del primer aviso. - **Razón:** Preserva la integridad del historial y evita discrepancias con mensajes ya enviados. ### DEC-005 — Despliegue en subdominio - **Fecha:** 2026-07-27 - **Contexto:** La app inicialmente utilizaba `/calendario-impuestos/` como base. - **Opciones consideradas:** Ruta interna o subdominio independiente. - **Decisión:** Publicar en `https://home.digitalcompass.agency/`. - **Razón:** Simplifica navegación, OAuth, despliegue y mantenimiento. --- ## CONTACTOS DEL PROYECTO | Rol | Nombre | Contacto | |---|---|---| | Solicitante funcional | Ada | Pendiente de documentar | | IT Manager | Luis Matos | `lmatos@gomezleemarketing.com` | | Developer principal | Isaac Aracena | `iaracena@gomezleemarketing.com` | | Contacto regional de Nómina | Mati Soto Valenzuela | `msoto@gomezleemarketing.com` | | Contacto regional de Nómina | Iveth Herrera | `iherrera@gomezleemarketing.com` | --- ## DEFINITION OF DONE - [x] Calendario histórico migrado a Supabase. - [x] Aplicación integrada con la base de datos. - [x] Login con Google implementado. - [x] Accesos administrables desde Supabase. - [x] Obligaciones administrables desde la aplicación. - [x] Contactos administrables desde la aplicación. - [x] País obligatorio. - [x] Categorías limitadas a Nómina y Administración. - [x] Filtros y búsquedas implementados. - [x] Regla del miércoles anterior implementada. - [x] Aviso del mismo día implementado. - [x] Correos HTML con branding GLM. - [x] Envíos por WhatsApp. - [x] Prevención de duplicados. - [x] Bloqueo después del primer aviso. - [x] Vista para días con más de tres obligaciones. - [x] Workflow exportado en `/n8n`. - [x] Scripts SQL almacenados en `/supabase`. - [x] Variables públicas documentadas en `.env.example`. - [x] Proyecto subido a Gitea. - [x] Manual de uso elaborado. - [ ] Ejecutar monitoreo controlado durante los primeros días en producción. - [ ] Registrar el enlace definitivo del board de Kan.bn. - [ ] Documentar la aprobación funcional final. --- ## SEGURIDAD - No subir el archivo `.env`. - No almacenar la llave `service_role` en React. - No publicar la API key de WhatsApp. - No almacenar contraseñas o tokens en el README. - Utilizar únicamente llaves públicas en variables `VITE_*`. - Mantener RLS activo en las tablas. - Restringir los accesos mediante `tax_calendar_access`. - Revisar periódicamente los usuarios autorizados. - Rotar credenciales cuando una persona deje de necesitar acceso. --- ## DOCUMENTACIÓN ADICIONAL - `AGENTS.md`: reglas para agentes y asistentes de programación. - `supabase/README.md`: instrucciones específicas de la base de datos. - `n8n/CONFIGURACION.md`: configuración del workflow. - `supabase/Seguimiento-de-Impuestos-GLM.sql`: instalación completa. - `n8n/Seguimiento-de-Impuestos-GLM.json`: workflow importable. --- Documento mantenido por el equipo **GLM IT**.