33 Commits

Author SHA1 Message Date
markosbenitez
cf09346f29 feat(auth): recuperación de contraseña self-service en /login
Reusa /auth/confirm sin tocarlo — ya escucha PASSWORD_RECOVERY (lo
armamos para invitaciones, Supabase emite el mismo evento para
recovery). Antes, cualquiera que olvidara su contraseña dependía de
que el director la reseteara a mano por SQL.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 13:09:42 -03:00
markosbenitez
9461ee1e2e feat(admin): menú de navegación compartido — dashboard, respuestas, usuarios
AdminNavBar reemplaza los links sueltos y duplicados entre páginas
(cada una solo enlazaba a una de las otras dos). Ahora las tres
pantallas detrás del login (/dashboard, /admin/responses,
/admin/usuarios) comparten la misma barra con las 3 secciones +
cerrar sesión, sin importar por dónde se entre primero.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 12:43:28 -03:00
markosbenitez
67042b0941 fix(auth): parsear error_code del fragmento de GoTrue en /auth/confirm
GoTrue redirige con #error=...&error_code=... cuando el token de
invitación/recovery ya fue usado o venció, en vez de emitir
PASSWORD_RECOVERY. Antes esto se descubría recién a los 8s (timeout
genérico); ahora se lee el fragmento al montar y se muestra un mensaje
específico (otp_expired, access_denied, etc.) al instante.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 11:18:37 -03:00
markosbenitez
7efab390da fix(admin): layout 3 columnas en invite form, banner de confirmación visible
Email/Organización/botón en una fila en desktop, apilado en mobile.
El mensaje de éxito/error ahora es un banner (no texto inline) visible
al menos 4s o hasta que el usuario vuelva a tocar el formulario.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 16:56:27 -03:00
markosbenitez
4611fb2363 feat(admin): onboarding por invitación — /admin/usuarios + /auth/confirm
Platform admin invita usuarios de empresa desde /admin/usuarios.
inviteUserByEmail + insert inmediato en user_roles (org_admin).
Rollback explícito si falla el insert. /auth/confirm maneja el link
de invitación con PASSWORD_RECOVERY event. Middleware no requirió
cambios — /auth/confirm ya queda fuera del matcher de rutas protegidas.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 14:54:30 -03:00
markosbenitez
d211382e4d fix(usabilidad): required questions, prompt min-height, autocomplete max-width
Activa required=true en todas las preguntas excepto barrio (2.3) y secciones.
El motor ya valida solo preguntas visibles — las condicionales ocultas no se
validan. Elimina min-height fijo del prompt block para mejor UX mobile.
Agrega max-width de seguridad al dropdown autocomplete en viewports angostos.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 09:26:10 -03:00
markosbenitez
a0253b4f90 feat(admin): vista respuestas mejorada + vista detallada [admin]
/admin/responses: filtro survey dinámico (select, no hardcodeado),
paginación 50/página, link a vista detallada, conteos consistentes con
el filtro de preguntas permitidas (evita página fantasma al final).
/admin/responses/[id]: respuestas agrupadas por sección (derivado de
type='section', igual que el wizard — no existen section_number/
section_title, ver TECH-DEBT-011), instancias bajo "Familiar N".
RLS y exclusión de sensibles intactos en ambas vistas.

Fixes de revisión antes de cerrar: toggle expandir/colapsar movido a
un <button> real (evita anidar el link "Ver" dentro de un role=button),
formatDate/renderValue unificados en admin-format.ts, queries
independientes en paralelo (Promise.all).
2026-06-27 16:48:32 -03:00
markosbenitez
a660928085 fix(ui): título card talento en riesgo a carbón #494F4F 2026-06-27 15:46:48 -03:00
markosbenitez
ca3af1a750 fix(quality): contraste teal, submit red, bottombar mobile, autocomplete touch
P1: color de texto teal -> #494F4F en 5 clases del wizard (WCAG AA).
P2: try/catch en handleSubmit - error de red muestra estado error del wizard.
P3: flex-wrap + column-reverse en bottombar <=480px.
P4: onTouchEnd fallback en autocomplete barrio y ciudad.
2026-06-27 15:25:16 -03:00
markosbenitez
b3f039fbd5 fix(ui): toggle password en login + fondo blanco card talento
Fix A: botón inline con ícono SVG (ojo/ojo tachado) en el campo
password de /login, alterna type password/text, aria-label según
estado. Sin librería nueva.
Fix B: .db-widget-star pierde el gradiente, hereda background blanco
de .db-widget igual que los demás cards. Borde y título teal intactos.
2026-06-27 15:18:22 -03:00
markosbenitez
a484ba7849 feat(auth): Supabase Auth email/password + middleware + login [auth]
Protege /admin/* con Supabase Auth. Tabla user_roles con custom claims
(app_role, org_id) en JWT. Middleware Next.js redirige a /login sin sesión.
Página /login con email/password. /admin/responses migrado de service_role
a sesión de usuario autenticado.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-27 09:39:52 -03:00
markosbenitez
6e9ad89f7b fix(wizard): z-index dropdown barrio + texto cortado opciones
Issue A: barrio-autocomplete-list cambia a position:fixed + getBoundingClientRect()
para escapar el overflow-y:auto de wizard-answer-area que clippeaba el dropdown.
z-index: 20 → 30 (clearear sticky topbar/bottombar z-index:10 en stacking context raíz).
Listener de scroll cierra el dropdown si el contenedor scrollea.

Issue B: wizard-answer-area max-height 360px → 480px (desktop) / 320px → 400px (mobile)
para mostrar ~8 opciones completas. .wizard-answer-area.has-overflow { padding-bottom: 44px }
asegura que el fade ::after (28px) cubre espacio vacío, no texto de opción.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 20:03:09 -03:00
markosbenitez
3ec5da0e54 feat(wizard): autocomplete barrios desde geo_paraguay_full.json [4F]
- BarrioAutocompleteField: carga JSON estático, filtra por depto/ciudad (2.1/2.2), mín 2 chars, máx 10 sugerencias, texto libre permitido, teclado (↑↓ Enter Escape), ARIA listbox
- QuestionRenderer: branch code === '2.3' → BarrioAutocompleteField; prop answers? pasado desde WizardForm para contexto depto/ciudad
- globals.css: clases .barrio-autocomplete-* (wrapper, list, item, item--active)
- Incluye public/data/geo_paraguay_full.json (202 KB, sin commitear hasta ahora)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 19:41:55 -03:00
markosbenitez
dbcc60ad95 fix(dashboard): tema claro — widget-star, gap-brecha, lens-intro
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 18:59:31 -03:00
markosbenitez
c847ef3ef5 feat(dashboard): tema claro marca Re — fondos, cards y texto
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 18:22:26 -03:00
markosbenitez
56443a739f Etapa completada (local) — widgets de Mirada Empresa 2026-06-26 11:29:16 -03:00
markosbenitez
2e6fbd7801 feat(submit): submit v3 con validación de integridad server-side [4G]
RPC transaccional SECURITY DEFINER (rpc_submit_response) como único camino
de escritura. Dropea las policies WITH CHECK(true): cierra la falla donde
anon podía insertar cualquier cosa. Validación server-side (7 checks)
reusando el motor. Persistencia atómica con instance_id por instancia.
Verificado contra Postgres real: instancias separadas, atomicidad, RLS.
Riesgo residual de bypass por REST documentado (SEC-004).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 21:27:49 -03:00
markosbenitez
ce679ec1c3 feat(wizard): renderer pregunta-por-pantalla con layout estable [4D] 2026-06-23 22:40:01 -03:00
markosbenitez
7c8b034756 Bug corregido — duplicación de enunciado + fade mal posicionado 2026-06-23 22:12:00 -03:00
markosbenitez
c30688810a Con las mejoras visuales 2026-06-23 21:44:05 -03:00
markosbenitez
5c17a9846a feat(admin): filtro por empresa + contadores filtrados 2026-06-17 10:01:59 -03:00
markosbenitez
b9a3118c84 Filtro en listado de respuestas admin 2026-06-17 09:25:18 -03:00
markosbenitez
edf82bf7fd feat(dashboard): selector de empresa + flag p_all en _dash_responses 2026-06-11 16:35:03 -03:00
markosbenitez
1bab6874a9 feat(admin): colapsar/expandir submissions + eliminar columna Tipo 2026-06-10 21:41:47 -03:00
markosbenitez
157e108322 Los triggers 1.1, 1.6, 1.13 muestran solo Sí · No (sin "Prefiero no decir")
Al responder "No" en las tres, el formulario salta a 6.4 (no muestra secciones 2-5 ni 6.1-6.3)
La pregunta 6.6 aparece antes del cierre
Las preguntas multiple_choice muestran el hint "Podés marcar más de una opción"
2026-06-10 15:49:05 -03:00
markosbenitez
bf963e8894 Con el listado de encuestas cargadas/respondidas 2026-06-10 08:59:50 -03:00
markosbenitez
52295a78d0 Con los números de preguntas y secciones 2026-06-08 20:25:23 -03:00
markosbenitez
307a54dabc refactor completo + truncate de base de datos + reingenieria dashboard 2026-06-05 17:13:45 -03:00
markosbenitez
a17e810ea8 Con marca y dashboards 2026-06-05 07:18:10 -03:00
markosbenitez
b813622e30 Con la marca incorporada primera versión 2026-06-04 22:49:25 -03:00
markosbenitez
b1ca0e0795 Validaciones mandatorias — Sección 8 — IDs concretos 2026-06-04 21:52:39 -03:00
markosbenitez
d91ea6b2ff Instrumento v2: 44 preguntas + widget text_short 2026-06-04 14:30:28 -03:00
markosbenitez
0f376a8b75 Terminado sprint 2A 2026-06-02 10:27:52 -03:00