# Plan PoC Reservas de Espacios Documento vivo con el plan original del PoC y el estado actual de implementacion en `hu-rooms`. ## Plan original ### Alcance confirmado - Login PoC: ingreso escribiendo email `@humand.co` (sin password, sin validacion de inbox). - MVP hackathon: busqueda de disponibilidad, reserva/cancelacion, calendario, panel admin, check-in y deteccion de no-show. ### Flujos funcionales del MVP - **Login PoC**: usuario ingresa email; backend valida dominio `@humand.co`; sesion por cookie. - **Reserva**: filtro por ubicacion/tipo/fecha/capacidad; validacion contra DB; estado `confirmed`. - **Cancelacion**: dentro de politica. - **Check-in**: manual en app (y opcion QR). - **No-show**: job marca no-show si no hubo check-in en ventana (ej. 10 min). ### Diferencial del PoC: Sammy (chatbot accionable) - Objetivo: chatbot que tambien ejecuta acciones (primera accion: `reservar_sala` simulada). - Flujo: intencion -> recoleccion de datos -> sugerencia de opciones -> confirmacion obligatoria -> reserva mock y comprobante. - Guardrails: - confirmacion explicita; - no inventar disponibilidad; - etiquetado visible `simulado/mock`. ### Pitch para jurado (6 bullets) - De chatbot informativo a transaccional: Sammy ejecuta acciones. - Reserva conversacional en lenguaje natural; menos friccion que formularios. - Flujo completo: intencion, validacion, confirmacion y comprobante. - Diseno extensible: mismo patron para salas, parking, escritorios, lockers. - Impacto operativo: reserva + check-in + no-show para mejor uso real de espacios. - Mock funcional hoy; base lista para integracion productiva despues. ### Roadmap de expansion a "mas que salas" - Tipos inmediatos: estacionamientos, escritorios flex, lockers, cabinas, equipos compartidos. - Futuro: reglas por tipo, aprobaciones, prioridades, cupos por persona, sanciones por no-show. ### Criterios de exito demo - Usuario `@humand.co` inicia sesion y reserva un recurso disponible. - Sin solapes para el mismo recurso/hora. - Admin crea/edita recursos sin tocar codigo. - Check-in y no-show visibles en la reserva. - Demo con al menos dos tipos: `meeting_room` + `parking_spot`. - Sammy completa flujo de reserva de sala punta a punta (resultado simulado/mock). ### Features adicionales planteadas - Carga masiva por Excel (descargar template, completar y subir). - Deeplinks de busqueda: filtros en query params para compartir una reserva prefiltrada. ### UX admin (objetivo funcional) Login -> creacion y gestion de recursos (`sala`, `estacionamiento`, etc.) con: - nombre; - descripcion (opcional); - foto (opcional); - ubicacion jerarquica (ej: pais -> ciudad -> oficina -> piso -> salon -> asiento); - modelo de reserva: - bloquea unidad o maneja cupos; - permitir incluir acompanantes en reserva ("voy yo con ..."); - disponibilidad: - slot fijo; - rango (ej. 8-12); - repeticion (ej. semanal); - aprobaciones por admin (similar Time Off); - cancelacion: - tiempo limite antes de penalidad; - lista de espera ante cancelacion; - tiempo de antelacion maxima para reservar; - tags multiples para filtros (ej. "Tiene proyector"); - deshabilitar recurso (mantenimiento); - visibilidad (oculto/visible); - preguntas de satisfaccion (opcional). Adicionales de administracion: - heatmap de uso de recursos; - visualizacion de usuarios (uso, no-shows, cancelaciones). ### UX usuario (objetivo funcional) Login -> vista de reservas disponibles/ocupadas. Si es admin, puede cancelar reservas. - UI inspirada en reservas de avion/cine: - filtros arriba y resultados abajo; - actualizacion en tiempo real al cambiar filtros; - filtros persistidos en URL (query params) para compartir vistas prefiltradas; - sugerencias cuando no hay resultados (tags/alternativas similares); - sugerencias por reservas previas (repetir); - reportar problemas en salas + encuesta de satisfaccion (guardado parcial); - historial de reservas previas ("pedir de nuevo"). - seccion "Mis reservas" separada en: - **Proximas**: reservas por ocurrir ordenadas por proximidad de fecha; - **Historial**: reservas pasadas con accion de "pedir de nuevo". - acciones por reserva proxima: - editar/cancelar sujetas a politica de antelacion y limite de cancelacion; - recordatorio previo cuando el tipo de recurso tenga notificaciones habilitadas; - reconfirmacion explicita de uso (confirmar/cancelar/editar) antes del limite maximo de cancelacion. ### Decisiones de arquitectura (Next.js + Supabase) - **Stack**: `Next.js` (App Router + Route Handlers) como UI + BFF en un deploy a Vercel. - **DB**: `Postgres` en Supabase. - **Auth demo actual**: endpoint server `app/api/auth/poc-login/route.ts` prepara usuario en Supabase Auth (sin email) y el cliente inicia sesion con credencial deterministica para evitar SMTP/rate limits. - **Principio de producto**: recurso generico reservable (no solo salas). ```mermaid flowchart LR user[Usuario Humand] --> web[Next.js Web UI] web --> api[Next.js API Routes] api --> db[(Supabase Postgres)] admin[Admin Operaciones] --> web ``` ### Repos propuestos - `humand-space-booking-app` (app completa, frontend + backend, deploy Vercel). - `humand-space-booking-infra` (IaC/documentacion operativa; opcional en hackathon). ### Estructura objetivo del repo app - `app/(public)/login/page.tsx` - `app/(app)/calendar/page.tsx` - `app/(app)/resources/page.tsx` - `app/(app)/admin/resources/page.tsx` - `app/api/auth/poc-login/route.ts` - `app/api/reservations/route.ts` - `app/api/reservations/[id]/cancel/route.ts` - `app/api/checkins/route.ts` - `lib/auth/poc-auth.ts` - `lib/auth/session.ts` - `lib/db/client.ts` - `lib/reservations/availability.ts` - `supabase/migrations/*.sql` - `supabase/seed.sql` ### Modelo de datos base (escalable) - `users`: perfil minimo (`email`, `display_name`, `company_id`). - `offices`: tabla legacy de sedes fisicas (en desuso funcional). - `locations`: jerarquia de ubicaciones multinivel (padre/hijo) para reemplazar el uso plano de `offices` como unica ubicacion. - `resource_types`: catalogo (`meeting_room`, `parking_spot`, `desk`, `locker`, `equipment`) + configuracion por tipo (`booking_unit` siempre `hour` en producto, `booking_window_start` / `booking_window_end`, `slot_size` 15/30/60 min, `time_granularity`, `reminders_enabled`). - `resources`: entidad reservable (`resource_type_id`, `location_id`, `office_id` legacy opcional, `name`, `capacity`, `attributes_jsonb`). - `reservations`: `resource_id`, `user_id`, `start_at`, `end_at`, `status`, `checked_in_at`, `cancelled_at`. - `resource_policies`: reglas por tipo/sede (lead time de reserva, duracion maxima, ventana de cancelacion/edicion, aprobacion) + ventanas operativas (`booking_advance_minutes`, `cancellation_deadline_minutes`, `editing_deadline_minutes`). - `no_show_events`: registro explicito para analitica y reglas futuras. Snippet clave anti-solapamiento (Postgres): ```sql ALTER TABLE reservations ADD CONSTRAINT no_overlap_reservations EXCLUDE USING gist ( resource_id WITH =, tstzrange(start_at, end_at, '[)') WITH && ) WHERE (status IN ('confirmed','checked_in')); ``` ### Plan de ejecucion por fases (hackathon) 1. Fundacion tecnica: bootstrap Next.js + Supabase + CI minima. 2. Dominio y migraciones: esquema base + seeds. 3. Auth PoC + sesion: login por dominio + proteccion de rutas. 4. Reservas core: disponibilidad, alta, cancelacion, calendario/lista. 5. Admin + check-in/no-show: CRUD de recursos/reglas + job de no-show. 6. Sammy actions (mock): flujo conversacional + confirmacion explicita. 7. Hardening demo: datos realistas, tracking de errores, smoke tests E2E. ### Riesgos y mitigaciones (PoC) - Suplantacion por login sin verificacion -> allowlist `@humand.co`, disclaimer, plan de migracion a SSO/magic-link. - Condiciones de carrera en concurrencia -> constraint de exclusion + transacciones. - Complejidad prematura de reglas -> politicas minimas en MVP, diferir complejidad. ## Estado actual del proyecto HU Rooms ### Completado 1. **Database Schema (Supabase)** - Tablas: `users`, `offices`, `resource_types`, `resources`, `reservations`, `resource_policies`, `no_show_events`. - RLS policies configuradas. - Triggers para auto-crear usuarios y actualizar timestamps. - Datos semilla insertados (2 oficinas, 5 tipos de recursos, 7 recursos de ejemplo). 2. **Infraestructura Supabase** - `lib/supabase/client.ts` (cliente browser). - `lib/supabase/server.ts` (cliente server). - `lib/supabase/proxy.ts` (session handling). - `lib/supabase/database.types.ts` (tipos TypeScript generados). - `proxy.ts` (entrypoint de proxy/middleware en Next 16). 3. **Paginas creadas** - `app/auth/login/page.tsx` (login demo con validacion `@humand.co`, sin magic link). - `app/(protected)/dashboard/page.tsx` (dashboard principal). - `app/(protected)/admin/page.tsx` (panel admin). - `app/(protected)/admin/offices/page.tsx` (redirect a ubicaciones, legado). - `app/(protected)/admin/resources/page.tsx` (CRUD recursos). - `app/(protected)/reservations/page.tsx` (nueva reserva). - `app/(protected)/reservations/my-reservations/page.tsx` (mis reservas). - `app/(protected)/sammy/page.tsx` (chatbot mock). - `app/api/auth/poc-login/route.ts` (provision/login demo sin SMTP). - Navegacion de dashboard/sidebar alineada a rutas reales (`/reservations`, `/reservations/my-reservations`, `/sammy`) con deeplink opcional `?type=`. - Sidebar sin seccion "Reservar": la reserva se inicia desde Menu Principal > Dashboard, donde se muestran todos los tipos de recurso y se selecciona uno para ir a `/reservations?type=...`. 4. **Componentes** - `components/app-sidebar.tsx` (navegacion lateral). - `components/admin/office-dialog.tsx` (legacy, sin acceso desde navegacion). - `components/admin/resource-dialog.tsx` (crear/editar recurso). - `components/reservations/reservation-dialog.tsx` (nueva reserva). 5. **Validaciones recientes comprobadas** - Build local: `pnpm build` compila correctamente. - Lint local: `pnpm lint` corre sin errores bloqueantes (hay warnings). 6. **Operativa check-in/no-show** - `app/api/checkins/route.ts`: check-in server-side con validacion de estado, ownership/admin y ventana de check-in por policy. - `app/api/jobs/no-show/route.ts`: job de no-show que marca reservas y registra `no_show_events`. - `vercel.json`: cron diario (`0 6 * * *`) para ejecutar `/api/jobs/no-show` y evitar fallo de deploy en planes Hobby. 7. **Design system foundations + refresh visual de login** - Skill de proyecto agregada en `.cursor/skills/design-system-foundations/` (con referencias de colores, tipografia, spacing, border-radius, grid y elevation). - `app/layout.tsx` actualizado para usar Roboto (400/600) acorde al foundation. - `app/globals.css` extendido con tokens `--ds-*` del skill y utilidades tipograficas. - `app/auth/login/page.tsx` redisenada aplicando tokens de color/espaciado/radius/elevation sin tocar el flujo funcional de autenticacion PoC. 8. **Refresh visual DS - paso 1 (shell + dashboard)** - `app/(protected)/layout.tsx`: header y contenedor principal alineados a grilla, spacing y jerarquia tipografica del design system. - `components/app-sidebar.tsx`: sidebar y footer de usuario redisenados con tokens DS, estados activos consistentes y acentos de marca. - `app/(protected)/dashboard/page.tsx`: hero, quick actions y bloque de proximas reservas actualizados con tokens DS (color, spacing, radius y elevation). - `app/globals.css`: sidebar semantic tokens conectados al set `--ds-*` y clase utilitaria `ds-grid-shell` para margenes responsive. 9. **Refresh visual DS - paso 2 (reservas)** - `app/(protected)/reservations/page.tsx`: cabecera, filtros, tarjetas de recursos y slots horarios redisenados con tokens DS. - Filtros de reservas: ocultos por defecto; boton "Filtrar" (icono funnel) abre popover estilo Notion: primer nivel = tipo de filtro (tipo de recurso, ubicacion, dia, etiqueta), segundo nivel = opciones del filtro seleccionado. - `app/(protected)/reservations/my-reservations/page.tsx`: tabs, tarjetas de reserva, estados y acciones (check-in/cancelar) alineados al mismo lenguaje visual. - `components/reservations/reservation-dialog.tsx`: modal de nueva reserva actualizado con tokens DS para superficies, campos, estados y CTAs. 10. **Refresh visual DS - paso 3 (admin + sammy)** - `app/(protected)/admin/page.tsx` y `app/(protected)/admin/resources/page.tsx` actualizados con la misma jerarquia visual (hero, cards, tablas, badges y acciones). - `app/(protected)/sammy/page.tsx` adaptado a tokens DS en todo el layout de chat (cabecera, burbujas, sugerencias, input y estados). - Ajustes menores de higiene en `sammy` (ids y fallback de sugerencias) para eliminar warnings de funciones impuras durante render. 11. **Refresh visual DS - paso 4 (flujo auth restante)** - `app/auth/error/page.tsx` alineada al mismo language visual de login y del resto de pantallas (tipografia, colores semanticos, radios y elevation del DS). 12. **Compatibilidad de policies en check-in/no-show** - `app/api/checkins/route.ts` y `app/api/jobs/no-show/route.ts`: se elimina el filtro SQL `.eq("is_active", true)` sobre `resource_policies` para evitar error `column resource_policies.is_active does not exist` en esquemas que no incluyen esa columna. - `lib/reservations/policies.ts`: el filtrado de politicas activas pasa a ser tolerante a ambos esquemas (`is_active` opcional); si existe y es `false`, se excluye, y si no existe, la policy se considera activa. 13. **Ajuste de regla operativa para CD** - `AGENTS.md`: se agrega la directiva de hacer push a `origin/main` al terminar cualquier feature/fix para testeo rapido en produccion. 14. **Polling live en reservas (smooth, 10s)** - `app/(protected)/reservations/page.tsx`: se agrega polling cada 10 segundos para refrescar disponibilidad de `reservations` en la fecha seleccionada sin recargar toda la vista. - El polling se pausa cuando la pestana no esta visible (`document.visibilityState`) y hace refresh inmediato al volver al foco. - Se evita el flash visual: los refresh periodicos no activan el estado `loading` global ni reemplazan la grilla por spinner. 15. **Regla operativa: sync antes de editar** - `AGENTS.md`: se agrega la directiva de sincronizar `main` con `origin/main` via `git pull --ff-only` antes de comenzar cualquier feature/fix. 16. **Regla operativa: uso obligatorio de skill de design system** - `AGENTS.md` y `CLAUDE.md`: se agrega la directiva de consultar y aplicar siempre la skill `design-system-foundations` antes de implementar cambios de UI/UX. 17. **Reservas v2 (usuario): historial + proximas + rebook + edicion/cancelacion por ventana** - `app/(protected)/reservations/my-reservations/page.tsx`: tabs `Proximas` (ordenadas por fecha cercana) e `Historial` (incluye estados historicos y accion `Pedir de nuevo`). - Se agregan acciones de `Editar` y `Cancelar` en reservas proximas con validacion server-side de ventanas de edicion/cancelacion. - `components/reservations/reservation-editor-dialog.tsx`: modal para editar todos los campos de la reserva o crear una nueva "prellenada" desde historial. 18. **Recordatorios + reconfirmacion de reserva** - `app/api/reservations/[id]/send-reminder/route.ts`: envio de email de recordatorio (24h antes) y boton de trigger de demo. - `app/api/reservations/[id]/reconfirm/route.ts`: endpoint de reconfirmacion explicita. - `app/(protected)/reservations/my-reservations/page.tsx`: banner de recordatorio en proximas con acciones `Confirmar uso`, `Editar`, `Cancelar` y `Enviar email demo`. 19. **Policies por tipo de recurso (admin)** - `components/admin/resource-type-dialog.tsx`: configuracion por tipo de recurso para: - activar/desactivar recordatorios por email; - antelacion maxima para reservar; - limite para cancelar; - limite para editar. - `app/(protected)/admin/resource-types/page.tsx`: visualizacion de estado de recordatorios y ventanas por tipo. 20. **Ubicaciones jerarquicas (arbol libre)** - `app/(protected)/admin/locations/page.tsx` + `app/api/locations/*`: CRUD admin para nodos de ubicacion (hasta 20 niveles, valores libres). - `components/admin/resource-dialog.tsx`: asignacion de ubicacion jerarquica por niveles al recurso (guardada en `resources.metadata`). - `app/(protected)/reservations/page.tsx`: filtro top-down de ubicacion para seleccion de recursos. - `components/app-sidebar.tsx` y `app/(protected)/admin/page.tsx`: acceso de navegacion a la nueva seccion de ubicaciones. 21. **APIs de reservas centralizadas** - `app/api/reservations/route.ts`: creacion de reserva con validaciones de politica (antelacion maxima y solapes). - `app/api/reservations/[id]/route.ts`: edicion de reserva con politicas y validacion de conflictos. - `app/api/reservations/[id]/cancel/route.ts`: cancelacion con validacion de ventana permitida. - `components/reservations/reservation-dialog.tsx`: alta de reserva migrada a API server-side. 22. **Script SQL incremental para aplicar en Supabase** - `scripts/004_reservations_v2_locations_notifications.sql`: columnas/politicas para reservas v2, notificaciones por tipo y tabla `locations`. 23. **Configuracion de reserva por tipo (integrado desde remoto)** - `scripts/005_resource_type_booking_config.sql`: agrega `booking_unit`, `slot_size` y `time_granularity` en `resource_types`. - `components/admin/resource-type-dialog.tsx` y `app/(protected)/admin/resource-types/page.tsx`: administracion y visualizacion de esa configuracion junto con recordatorios/ventanas. 23b. **Ventana horaria por tipo y reserva siempre por hora (2025-03)** - `scripts/009_booking_window_hour_only.sql`: columnas `booking_window_start` / `booking_window_end` (TIME), fuerza `booking_unit = hour`, normaliza `slot_size` legacy (`half_day`/`full_day` → `1h`), CHECK de `slot_size` solo valores por hora. - Admin: sin selector Horas/Días; inputs de ventana; listado/detalle muestran rango horario. - `lib/booking.ts`: generación de slots, solapes por duración = granularidad, opción día completo vía rango de ventana. - `app/(protected)/reservations/page.tsx`, `app/(protected)/dashboard/book/[typeSlug]/page.tsx`, `components/reservations/reservation-dialog.tsx`, `components/reservations/reservation-editor-dialog.tsx`: consumen config del tipo. - `app/api/reservations/route.ts` y `[id]/route.ts`: validan ventana (tz `BOOKING_LOCAL_TIMEZONE`) y duración mínima. 23c. **Granularidad 60min (1 hora)** - `scripts/010_time_granularity_60min.sql`: extiende CHECK de `time_granularity` con `60min`. - Admin y `lib/booking.ts`: opción "1 hora" en selector de granularidad; `timeGranularityToMinutes` → 60. 23d. **Seed de reservas de demo** - `scripts/011_seed_reservations_demo.sql`: INSERT idempotente (`ON CONFLICT (id) DO NOTHING`) con UUID fijos; resuelve `user_id` y `resource_id` por email y nombre; horarios en `America/Santiago`; marca `notes = 'Seed demo hu-rooms'`. - `scripts/seed-reservations.default.json` + `scripts/seed-reservations.mjs` + npm script `seed:reservations`: misma data vía `SUPABASE_SERVICE_ROLE_KEY`, con chequeo de solapes antes de insertar (además del conflicto por PK). - `SEED_AUTO=1` / `pnpm seed:reservations:auto`: consulta `users` y `resources` en Supabase (y ventana del tipo) y genera reservas sin dataset fijo; UUID idempotentes prefijo `a1000000-…`. 24. **Fix visual global de toggles (Switch)** - `components/ui/switch.tsx`: se corrigen dimensiones y traslacion del thumb a valores enteros (`h-5`, `w-9`, `translate-x-4`) para evitar desborde visual. - Se agrega `overflow-hidden` y `p-px` al track para garantizar que el thumb no sobresalga en ninguno de los dialogs que reutilizan el componente. 25. **Reemplazo funcional de oficinas por ubicaciones** - Se elimina `Oficinas` de la navegacion admin y del flujo funcional; `app/(protected)/admin/offices/page.tsx` ahora redirige a `app/(protected)/admin/locations/page.tsx`. - `app/(protected)/admin/resources/page.tsx`, `app/(protected)/reservations/page.tsx`, `app/(protected)/dashboard/book/[typeSlug]/page.tsx`, `app/(protected)/reservations/my-reservations/page.tsx`, `components/reservations/*` y `app/(protected)/sammy/page.tsx` dejan de usar/mostrar oficina y priorizan ubicacion jerarquica. - `app/api/reservations/[id]/send-reminder/route.ts` deja de armar labels con oficina y usa ubicacion jerarquica + detalle. - El reemplazo en UI/API quedo aplicado; para entornos legacy queda pendiente formalizar un script incremental de backfill para `resources.location_id` (ver pendientes). 26. **Estandar colaborativo para queries/mutations remotas** - Se centraliza la lectura de env Supabase en `lib/supabase/env.ts` y `lib/supabase/env.server.ts`. - Compatibilidad de llaves publishable para equipos mixtos: se acepta `NEXT_PUBLIC_SUPABASE_ANON_KEY` y tambien `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEY`. - `lib/supabase/client.ts`, `lib/supabase/server.ts`, `lib/supabase/proxy.ts`, `app/api/auth/poc-login/route.ts` y `app/api/jobs/no-show/route.ts` usan ahora la misma resolucion de entorno para evitar drift entre maquinas. - Se agrega `.env.example` y se documenta en `README.md` el workflow de colaboracion para aplicar scripts SQL sin pisarse. 27. **Hotfix prod env key (separacion local vs produccion)** - `lib/supabase/env.ts`: en produccion vuelve a requerirse `NEXT_PUBLIC_SUPABASE_ANON_KEY` como canon (comportamiento seguro para deploy). - Se mantiene compatibilidad con `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEY` solo en local/dev para no bloquear setups de colaboradores. - `README.md` y `AGENTS.md` actualizados con esta separacion explicita. 28. **Catalogo publico de iconos Lucide para consumo en deploy** - Se agrega `public/lucide-icons.json` con el listado completo de nombres de iconos publicados en `https://lucide.dev/icons/`. - El archivo queda disponible para frontend/backend en runtime via ruta publica `/lucide-icons.json` (ej. formularios de tipos de recurso). - Se guarda metadata de origen (`source`, `extracted_from`), fecha de generacion (`generated_at`) y total (`total_icons`) para trazabilidad. 29. **Autocomplete de iconos Lucide en formularios admin** - `components/admin/resource-type-form.tsx` y `components/admin/resource-type-dialog.tsx` ahora usan un selector buscable de iconos consumiendo `/lucide-icons.json`. - El selector abre automaticamente al tipear y tambien permite apertura manual mostrando la lista completa o filtrada por texto. - Se mejora accesibilidad del selector con navegacion por teclado (`ArrowUp`/`ArrowDown` para navegar, `Enter` para seleccionar, `Escape` para cerrar). - Ajuste UX solicitado: al escribir/borrar en el input se reinicia el estado del listado, reabriendo solo cuando hay resultados para evitar paneles vacios, y la flecha de apertura/cierre evita el toggle incorrecto que reabria inmediatamente. - Ajuste adicional UX: la vista previa del icono ahora sigue la opcion activa mientras se navega por la lista (teclado o hover), sin requerir seleccion previa. - Se agrega precarga de modulos de iconos "visibles/probables" al abrir o filtrar el selector para reducir el parpadeo a fallback durante navegacion rapida entre opciones. - Ajuste de renderizado en preview: cuando cambia la opcion activa se mantiene el ultimo icono resuelto en pantalla hasta que el siguiente modulo termina de cargar, evitando el salto visual intermedio a icono por defecto. - Se agrega `hooks/use-lucide-icon-names.ts` con cache en cliente para reutilizar el listado sin refetch innecesario entre pantallas/componentes. - Ambos formularios muestran feedback si el icono tipeado no existe en el catalogo local, reduciendo errores de carga en runtime. 30. **Fix check-in en home (Próximas reservas)** - Se agrega `components/dashboard/dashboard-check-in-button.tsx` (client component) para ejecutar `POST /api/checkins`, mostrar feedback de resultado y refrescar el dashboard. - `app/(protected)/dashboard/page.tsx` reemplaza el botón estático de check-in por la nueva acción funcional. - El botón ahora se muestra solo cuando aplica check-in (reserva confirmada del día y no finalizada), alineado al criterio usado en `mis reservas`. - Se unifica estado de carga del CTA de check-in usando `Spinner` en lugar de texto temporal para mantener consistencia visual. 31. **Alineación UI check-in con ventana real de backend** - `app/(protected)/dashboard/page.tsx` y `app/(protected)/reservations/my-reservations/page.tsx` pasan a usar `resolveCheckInWindowMinutes` + `isCheckInWindowOpen` para decidir si se muestra el botón `Check-in`. - Se elimina el criterio simplificado (solo "hoy y no finalizada"), evitando que la UI ofrezca check-in cuando el endpoint devolvería `409 Check-in window is closed`. - En dashboard se amplía el select de `resource_types` para incluir `id`, necesario para resolver correctamente policies por tipo. 32. **Tooltips en acciones/slots deshabilitados por policies** - Se agrega `components/reservations/policy-disabled-tooltip.tsx` para mostrar una razon contextual cuando un control queda deshabilitado por reglas de policy. - `app/(protected)/reservations/page.tsx`: los slots deshabilitados por antelacion muestran tooltip explicando la restriccion (bloqueo total del dia o franja aun no habilitada). - `app/(protected)/reservations/my-reservations/page.tsx`: los botones `Editar` y `Cancelar` (incluyendo modal de confirmacion y banner de recordatorio) muestran tooltip cuando la ventana de edicion/cancelacion ya cerro. - `lib/reservations/advance-restriction.ts`: `getAdvanceRestriction` unifica la antelación mínima de reserva (`booking_advance_minutes`); `minSlotStart` aplica en cualquier día civil donde caiga el primer instante permitido (no solo cuando el día seleccionado es “hoy”). La vista global y el flujo por tipo usan la misma regla para slots y para el auto-avance al primer día con al menos un hueco libre que cumpla política + ventana + conflictos. En `/reservations`, al cambiar el filtro de tipo se vuelve a la fecha de hoy salvo query `date` en la URL, invalidando el ref de auto-avance para recalcular. En `/dashboard/book/[typeSlug]` se cargan `resource_policies`, los botones de horario respetan antelación y el día inicial se auto-ajusta igual que en la lista global; al cambiar de `typeSlug` se reinicia la fecha y el ref de auto-avance. 33. **Allowlist de admins por defecto actualizado** - `lib/auth/is-admin.ts`: se cambia el fallback de `DEMO_ADMIN_EMAILS` para usar por defecto `sebastian.favaron@humand.co`, `lucia.strozza@humand.co`, `gaston.rios@humand.co` y `marcos.palacio@humand.co`. - `app/(protected)/admin/layout.tsx`: el gate de admin pasa a reutilizar `isAdminUser` para evitar drift con otras validaciones server-side. - `app/api/auth/poc-login/route.ts`: la asignacion de `role` en `user_metadata` y en `public.users` pasa a depender del mismo allowlist (`DEMO_ADMIN_EMAILS`), dejando de hardcodear `admin@humand.co`. - `.env.example`: se actualiza `DEMO_ADMIN_EMAILS` con los nuevos mails por defecto. 34. **Migración de login a Google SSO (sin restricción de dominio)** - `app/auth/login/page.tsx`: se reemplaza el formulario PoC por botón `Continuar con Google` usando `supabase.auth.signInWithOAuth` y callback a `/auth/callback`. - `app/auth/callback/route.ts`: nuevo handler que hace `exchangeCodeForSession`, valida sesión y redirige a `/dashboard` (o `next` relativo) tras autenticar. - `lib/auth/ensure-user-profile.ts`: nuevo helper idempotente para garantizar perfil en `public.users` (`id`, `email`, `full_name`, `role`, `is_active`) y evitar roturas por FK en reservas. - `app/(protected)/layout.tsx`: se asegura el perfil de usuario en cada ingreso autenticado y se resuelve `role` con `isAdminUser` para mantener navegación/admin consistente con allowlist. 35. **Sammy AI real (Claude) con acciones** - `app/api/sammy/route.ts`: nuevo endpoint server-side que usa Claude con fallback de modelos solo `claude-*`, interpreta intencion y decide accion estructurada. - Politica operativa implementada: - consultas (`check_availability`) se ejecutan automaticamente; - mutaciones (`create/edit/cancel`) quedan en estado pendiente hasta confirmacion explicita del usuario. - Ejecucion de mutaciones reusa APIs existentes de reservas (`/api/reservations`, `/api/reservations/[id]`, `/api/reservations/[id]/cancel`) para mantener validaciones de negocio unificadas. - `app/(protected)/sammy/page.tsx`: reemplazo del mock por chat transaccional real contra `/api/sammy`, con UI de confirmacion/descartar accion pendiente. - `.env.example` y `README.md`: nuevas variables `ANTHROPIC_API_KEY` y `SAMMY_CLAUDE_MODELS`. 36. **Fix de sesion/interaccion en Sammy (401 + confirmacion por texto)** - `proxy.ts` vuelve a conectar el entrypoint de Next 16 con `updateSession` (`lib/supabase/proxy.ts`) para refrescar cookies/sesion en requests de app y API. - `lib/supabase/proxy.ts` incorpora `/sammy` en rutas protegidas para mantener comportamiento consistente con otras pantallas autenticadas. - `app/(protected)/sammy/page.tsx` ahora interpreta confirmaciones explicitas por texto (`confirmo`, `si`, `ok`, etc.) para ejecutar la accion pendiente aunque el usuario no use el boton. - Si `/api/sammy` responde `401`, el chat informa que la sesion expiro y pide relogin en vez de mostrar un error generico. 37. **Fix anti-loop en disponibilidad Sammy (horario/recurso inferidos)** - `app/api/sammy/route.ts` agrega enriquecimiento server-side de `check_availability` para completar `startAt`, `endAt` y `resourceId` cuando Claude no los devuelve aunque ya esten implícitos en la conversacion. - El endpoint ahora infiere ventana horaria desde mensajes del usuario (ej. "manana 11-12") y referencia de recurso por nombre o deicticos ("ese/esa"), usando el contexto real de recursos activos. - `executeAvailabilityAction` acepta filtro por `resourceId` para validar disponibilidad del recurso exacto y cortar el loop de "Necesito horario exacto..." en casos con datos ya provistos. - Prompt de sistema ajustado para que Sammy no pida nombre del usuario autenticado y priorice params estructurados (`ISO 8601` + `resourceId`) en acciones. 38. **UX Sammy: confirmacion persistente en timeline + CTA visible** - `app/(protected)/sammy/page.tsx` migra el bloque de accion pendiente a una tarjeta persistente dentro del historial del chat (timeline), manteniendo estados `pendiente`, `confirmada` o `descartada`. - La accion pendiente activa conserva botones de `Confirmar`/`Descartar` in-line en la tarjeta del chat; una vez resuelta, el registro queda visible para trazabilidad de la conversacion. - El CTA `Confirmar` deja de usar un token inexistente (`--ds-success-600`) y pasa a `--ds-success-700` para visibilidad consistente sin depender de hover. 39. **Sammy: confirmacion unificada + mensaje claro de ventana de cancelacion** - `app/api/sammy/route.ts` mantiene mutaciones siempre en modo `texto de confirmacion + accion pendiente`, evitando ejecucion directa en la misma respuesta del modelo. - Flujo objetivo unificado: primero pregunta de confirmacion en el mensaje, luego tarjeta/modal clickeable para ejecutar o descartar la accion. - El error de cancelacion por ventana vencida se traduce a mensaje entendible para usuario final: se informa que la ventana cerro y se muestra el limite (ej. `5 horas antes del inicio`) en lugar de propagar solo el texto tecnico. 40. **Error de cancelacion en castellano y con contexto de policy** - `app/api/reservations/[id]/cancel/route.ts` devuelve error `409` en castellano cuando vence la ventana de cancelacion, explicando que es una restriccion de policy de esa reserva/recurso (no un fallo de plataforma). - El payload agrega `errorCode: CANCELLATION_POLICY_WINDOW_CLOSED` y `policyScope` (`resource`, `resource_type`, `default`) para consumo consistente desde UI/chat. - `app/api/sammy/route.ts` prioriza ese `errorCode` y muestra el texto de negocio tal cual llega del endpoint de cancelacion. 41. **Sammy: resultados de disponibilidad en cards + CTA reservar** - `app/api/sammy/route.ts` agrega respuesta estructurada `availabilityResults` (id, tipo, ubicacion, capacidad, amenities, imagen y ventana horaria) para consultas `check_availability`. - `app/(protected)/sammy/page.tsx` renderiza esos resultados como grilla de cards en el timeline del chat, reutilizando el lenguaje visual de `reservations`. - Cada card incluye boton `Reservar`: - si ya hay horario completo, dispara mensaje con datos exactos (`resourceId`, `startAt`, `endAt`) para continuar en flujo transaccional; - si faltan datos, dispara mensaje de continuidad para que Sammy pida lo minimo necesario. 42. **Demo 100% castellano: normalizacion de errores app + backend** - Se traducen a castellano los mensajes de error controlados en endpoints de reservas (`create/edit/cancel/reconfirm/send-reminder`), check-in, ubicaciones, jobs y Sammy. - Se evita exponer mensajes crudos en ingles de proveedores/DB en errores de negocio frecuentes, devolviendo copy consistente en español para toasts y chat. - `lib/supabase/env.ts` y `lib/supabase/env.server.ts` tambien pasan a mensajes de configuracion en castellano para mantener consistencia en troubleshooting de entorno. 43. **Sammy: reserva directa desde card cuando ya hay datos completos** - `app/(protected)/sammy/page.tsx` ejecuta reserva directa al clickear `Reservar` en una card de disponibilidad que ya incluye `resourceId + startAt + endAt`. - Se evita la confirmacion extra en ese caso porque el click en CTA funciona como confirmacion explicita de accion. - Si la card no tiene horario completo, el mismo boton mantiene el flujo conversacional para pedir datos faltantes. 44. **Fix timezone en disponibilidad Sammy (hora pedida = hora mostrada)** - `app/(protected)/sammy/page.tsx` envia `clientNowIso` y `clientUtcOffsetMinutes` en cada request a `/api/sammy`. - `app/api/sammy/route.ts` usa ese contexto temporal para inferir `hoy/manana` y construir `startAt/endAt` en ISO respetando la zona horaria del cliente, no la del servidor. - Se evita desfase UTC en cards (ej. pedir `12-13` y ver `09-10`). 45. **Login: hero con valor de producto** - `app/auth/login/page.tsx`: el panel azul deja de centrarse en el mecanismo de Google; muestra titular/subtítulo de la solución y 3 bullets con iconos (Layers, BarChart3, CalendarDays) sobre gestión de recursos limitados, visualización/métricas de uso y reservas con reglas. Los detalles de SSO siguen en la tarjeta de ingreso. 46. **Carga masiva demo (6 tipos × 5 recursos)** - `recursos_carga_masiva_demo.xlsx`: Excel generado con las mismas columnas que `plantilla_recursos.xlsx`, rotando ubicaciones hoja (Córdoba B/C, Neuquén Oficina A, Montevideo). - `scripts/generate-recursos-carga-masiva.cjs` + script npm `generate:bulk-xlsx` para regenerar el archivo. - `scripts/007_bulk_demo_resource_types.sql`: upsert de tipos `Celulares`, `Escritorios`, `Espacios Deportivos`, `Parkings`, `Sala de conferencias` (sin duplicar `meeting_room` / Sala de reuniones). - `scripts/README-bulk-recursos.md`: notas sobre columna Ubicación y template dinámico. 47. **Limpieza acotada: recursos y reservas** - `scripts/008_clean_resources_and_reservations.sql`: `TRUNCATE reservations CASCADE`, borrado de `resource_policies` con `resource_id` seteado, `DELETE FROM resources` (evita error de FK al truncar el padre con constraint activa); no borra users, locations, resource_types ni políticas solo por tipo. Diferente de `000_reset_data.sql` (reset completo). 48. **Home: cards de "Reserva rapido" simplificadas (descripcion del tipo)** - `app/(protected)/dashboard/page.tsx`: se vuelve al enfoque simple por card, mostrando solo la descripcion del tipo de recurso. - Se compacta el espaciado vertical del card y la descripcion queda visualmente pegada al CTA `Reservar`, manteniendo un `min-height` mas chico para evitar saltos entre cards. 49. **Fix lint en icono dinámico (React static-components)** - `components/ui/dynamic-icon.tsx`: se elimina la creación de componentes `lazy(...)` durante render. - Se preconstruye un mapa de iconos lazy a nivel de módulo (`lazyIcons`) y el componente sólo selecciona por `name`, evitando el error `react-hooks/static-components`. 50. **Ajuste de naming global a "Recursos"** - `app/(protected)/layout.tsx`: breadcrumb principal pasa de `Reservas y Espacios` a `Reserva y Recursos`. - `components/app-sidebar.tsx`: título/subtítulo del brand ajustados a `Reserva y Recursos` / `Reserva de recursos`. - `app/layout.tsx`: metadata global actualizada para eliminar typo de `Recursoss` y alinear naming a `Recursos`. 51. **Reservas: filtros persistidos en URL + limpieza rápida + fallback de fecha** - `app/(protected)/reservations/page.tsx`: los filtros de tipo, ubicación, día, etiqueta y búsqueda ahora se hidratan desde query params (`type`, `location`, `date`, `tag`, `q`) y se sincronizan de vuelta a la URL para compartir vistas filtradas. - Se mantiene compatibilidad con deeplinks existentes por `type` (slug) y también por `id`, resolviendo ambos formatos al cargar. - En el popover de filtros se agrega acción de limpieza individual (icono de tacho) para tipo, ubicación, día y etiqueta sin abrir sub-vistas adicionales. - Si la fecha default (hoy) no tiene ningún slot reservable, la vista salta automáticamente al próximo día con disponibilidad (ventana de búsqueda: 30 días), excepto cuando el usuario llega con una fecha explícita por URL. 52. **Fix defensivo en modal de reserva ante horarios inválidos** - `components/reservations/reservation-dialog.tsx`: se agrega validación estricta para `startTime` (`HH:mm`), `duration` (> 0) y fechas calculadas antes de formatear o enviar la reserva. - El resumen de horario (`inicio - fin`) ahora usa fallback `--:--` cuando el dato no es válido, evitando crash por `Invalid time value`. - `handleSubmit` corta con mensaje claro cuando la configuración horaria es inválida (rango día completo inválido o combinación hora/duración inválida) en vez de romper en runtime. - El botón `Confirmar reserva` queda deshabilitado cuando el horario calculado no es válido, para prevenir requests inconsistentes. 53. **Fix filtro de tipo: limpiar no re-aplica query param anterior** - `app/(protected)/reservations/page.tsx`: la hidratación de `type` desde URL se limita a la carga inicial (una sola vez) para evitar que al limpiar el filtro vuelva automáticamente al valor previo del query param. - Al limpiar tipo (`tacho`), se marca explícitamente como resuelta la hidratación inicial de `type`, priorizando la acción del usuario sobre cualquier estado stale de `searchParams`. 54. **Filtro de reservas: popover forzado hacia abajo** - `app/(protected)/reservations/page.tsx`: el popover de filtros se configura con `side="bottom"` + `avoidCollisions={false}` para renderizar siempre hacia abajo y evitar que aparezca recortado por reposicionamientos automáticos. - Se agrega `sideOffset={8}` para mantener separación visual consistente respecto al botón `Filtrar`. 55. **Métricas admin: filtro por tipo de recurso** - `app/(protected)/admin/metrics/page.tsx`: el selector del dashboard y el de la pestaña "Todas las reservas" filtran por tipo de recurso (`resource_types` activos), no por sala/recurso individual. - La consulta de reservas incluye `resource_type_id` en el join de `resources`; los KPIs de ocupación usan el conteo de recursos activos del tipo seleccionado (o el total si el filtro es "todos"). 56. **RLS admin: `is_admin_user()` con fallback por email JWT** - `scripts/012_is_admin_user_email_fallback.sql`: reemplaza `public.is_admin_user()` para que, además de `public.users.id = auth.uid()` con `role = 'admin'`, considere admin si el email del JWT (`auth.jwt() ->> 'email'`) coincide con una fila `public.users` con `role = 'admin'`. - Corrige el caso en que el usuario entra al panel admin (allowlist/email) pero los joins a `users` desde el cliente devolvían vacío para terceros por desalineación entre `auth.uid()` y el `id` del perfil admin en `public.users`. 57. **Sammy: sin auto-reserva por default + prioridad visual en cards** - `app/(protected)/sammy/page.tsx`: el CTA de cada card de disponibilidad deja de ejecutar reservas en un solo click; ahora siempre prepara la accion y espera confirmacion explicita posterior del usuario. - `app/api/sammy/route.ts`: se bloquean acciones `create/edit` si no hay horario explicitamente indicado en el mensaje del usuario (evita asumir ventanas por defecto como 24h). - `app/api/sammy/route.ts`: para consultas de disponibilidad se prioriza respuesta breve cuando hay `availabilityResults`, dejando que la grilla de cards comunique el detalle en lugar de duplicarlo en texto largo. - Hardening adicional: - el mensaje generado por click en card nunca envia `startAt/endAt`; siempre pide elegir horario antes de preparar la accion. - en `check_availability`, si el ultimo mensaje del usuario no incluye hora explicita, se ignoran ventanas horarias de contexto para evitar heredar rangos implicitos. - si llega un rango invalido en UI (`end <= start`), la card muestra "Horario no confirmado" y no un intervalo engañoso. - ajuste visual de cards en `app/(protected)/sammy/page.tsx`: layout con alturas consistentes, area de ubicacion reservada a 3 lineas y copy simplificado de fallback (`Sin ubicación`). - cards de disponibilidad usan `gap-0` en `Card`, `CardContent` con `flex-1` y `CardFooter` dedicado para el botón; esto fuerza que `Reservar` quede pegado al fondo incluso cuando la grilla estira tarjetas de una misma fila. - ajuste de copy en sugerencias: se elimina placeholder `` y se reemplaza por un prompt realista sin identificadores mock. - loader de typing ajustado a una variante simple y estable (`flex items-center` + `py` tokenizado). 58. **Reservas: buscador y filtro alineados en toolbar superior** - `app/(protected)/reservations/page.tsx`: el botón `Filtrar` se mueve al extremo derecho de la misma fila del buscador para mantener patrón "controles arriba, resultados abajo". - Buscador y botón de filtro quedan con la misma altura visual (`h-10`) y estilos consistentes con tokens del design system (radius, spacing, colores y tipografía). - Ajuste adicional DS en el input de búsqueda: paddings/offset del ícono pasan a tokens (`--ds-space-*`) en lugar de valores hardcodeados. 59. **Reservas: tokenización visual extendida (incluye popover de filtros)** - `app/(protected)/reservations/page.tsx`: se reemplazan tamaños/espaciados hardcodeados por tokens `--ds-*` en toolbar de filtros, popover y acciones de limpieza (íconos, botones y contenedores). - Se normalizan superficies de cards e input/filter trigger a variables de color/tamaño del sistema (`--background`, `--ds-space-*`, `--ds-radius-*`, `--ds-shadow-*`), evitando utilidades visuales sueltas. - Ajustes de consistencia DS en estados/metadata de la lista de recursos (íconos, separadores y hover de slots), manteniendo intacta la lógica funcional de reservas y filtros. 60. **Reservas: reforzar lenguaje visual azul (Humand) en filtros** - `app/(protected)/reservations/page.tsx`: la toolbar superior (`buscar + filtrar`) pasa a fondo/borde azul semántico (`--ds-blueprimary-100`, `--ds-brand-400`) con texto/acento `--ds-blueprimary-800`. - Popover de filtros: borde y headers en paleta azul de marca; filas de filtros y acciones de limpieza agregan estados hover azules para reforzar jerarquía visual sin cambiar funcionalidad. - Selectores y CTAs `Listo` dentro del flujo de filtros migran a variantes azules tokenizadas para coherencia con el resto de la pantalla de reservas. 61. **Ajuste visual puntual en reservas: input neutro + header de popover corregido** - `app/(protected)/reservations/page.tsx`: se revierte el input de búsqueda a estilo neutro (sin fondo/borde azul) para mantener contraste y balance visual. - Popover de filtros: se corrige el “pintado” superior del header agregando clip del contenedor (`overflow-hidden`) y ajuste de top-radius del bloque de cabecera. - Se elimina padding vertical extra en la vista principal del popover para evitar el artefacto visual en el borde superior. 62. **Calendario UI en Humand Blue** - `components/ui/calendar.tsx`: el componente base de calendario pasa a usar acentos de marca (`--ds-brand-400`, `--ds-blueprimary-100`, `--ds-blueprimary-800`) en navegación, caption, estados seleccionados y rangos. - Se ajustan estados `today`, `outside` y `disabled` para mantener contraste y coherencia con tokens semánticos del design system. - El cambio es global: impacta todos los calendarios que reutilizan `Calendar` (reservas, filtros y dialogs) sin modificar lógica funcional. 63. **Calendario: alineación visual entre día actual y seleccionado** - `components/ui/calendar.tsx`: se corrige la diferencia visual de padding/tamaño entre `today` y `selected`. - `today` deja de usar `border` y pasa a `inset shadow` para mantener el mismo box model interno. - Se agrega `border transparent` base en el botón de día para que todos los estados compartan la misma caja visual. 64. **Calendario: unificación de estilos en el mismo nodo DOM (`button`)** - Se detecta diferencia residual porque `today` estaba estilado en `td.rdp-day` y `selected` en `button.rdp-day_button`. - `components/ui/calendar.tsx`: se mueve el estilo de `today` al `button` usando `group-data-[today=true]/day:*` y se neutraliza el estilo custom de `classNames.today`. - Resultado esperado: `today` y `selected` comparten exactamente el mismo box model y desaparece la diferencia aparente de padding. 65. **Sammy: no repregunta horario si ya está explícito + IDs solo en acciones** - `app/(protected)/sammy/page.tsx`: el CTA `Reservar` en cards con franja horaria confirmada ahora envía al backend `resourceId + startAt + endAt` en el mensaje API, sin exponer IDs en el texto visible del chat. - `app/api/sammy/route.ts`: `create/edit` enriquecen datos desde la conversación (recurso y ventana) y solo piden horario cuando realmente falta, evitando repreguntar si ya estaba explícito. - `app/api/sammy/route.ts`: en respuestas informativas (`check_availability` y `none`) se redactan IDs para no mostrarlos en búsquedas; los IDs quedan reservados para resultados de acciones ejecutadas (crear/editar/cancelar). 66. **Tokenización DS (alto impacto): flujo de reserva por tipo** - `app/(protected)/dashboard/book/[typeSlug]/page.tsx`: se reemplaza el estilo legacy (muted/primary y tamaños default de shadcn) por tokens `--ds-*` en hero, barra de filtros, toggles de flujo, cards de recursos y estados de slots. - Se normalizan superficies, tipografía y spacing a la misma gramática visual de `reservations` (`bg-[var(--background)]`, `--ds-radius-*`, `--ds-shadow-*`, `ds-type-global-*`). - La lógica funcional (filtros, disponibilidad, selección de slot y apertura de diálogo) se mantiene sin cambios. 67. **Tokenización DS (alto impacto): dashboard de métricas admin** - `app/(protected)/admin/metrics/page.tsx`: se eliminan colores hardcodeados y estilos legacy en charts/KPIs (`#hex`, `red-*`, `white`) migrándolos a tokens DS (`--ds-brand-400`, `--ds-error-700`, `--ds-neutral-200`, `--ds-text-neutral-*`). - Se unifican estados visuales de filtros, tablas, botones e indicadores con sizing/spacing tokenizado y colores semánticos del sistema. - Recharts queda alineado a DS mediante constantes de estilo reutilizables para grilla, ticks y tooltip. 68. **Seed local: usuarios fake + actividad para métricas/admin** - `scripts/seed-users-activity.mjs`: nuevo seed idempotente con IDs determinísticos para crear usuarios demo (`demo.user.XX@humand.co`) y reservas con estados mixtos (`confirmed`, `checked_in`, `completed`, `cancelled`, `no_show`). - El script valida solapes para estados activos (`confirmed`/`checked_in`) antes de insertar, para no romper constraints de no-overlap en recursos. - También crea `no_show_events` para las reservas fake con estado `no_show`. - `package.json`: nuevo comando `seed:users-activity`. - `README.md`: documentación de uso y variables opcionales (`SEED_FAKE_USERS_COUNT`, `SEED_FAKE_RESERVATIONS_PER_USER`, `SEED_FAKE_FUTURE_PER_USER`, `SEED_DRY_RUN`). 69. **Allowlist admin actualizado con Nico y Gero** - `lib/auth/is-admin.ts`: se agregan `nico@humand.co` y `gero@humand.co` al fallback `DEFAULT_ADMIN_EMAILS`. - `.env.example`: `DEMO_ADMIN_EMAILS` también incluye ambos correos para alinear configuración local/deploy. - Con SSO, `ensureUserProfile` toma `isAdminUser(user)` y persiste `role='admin'` en `public.users` para esos emails cuando inician sesión. ### Pendiente / por mejorar 1. Aplicar en Supabase el script `scripts/003_fix_users_rls.sql` para corregir policies recursivas de `public.users` (error `42P17` en prod). 2. Validar en deploy que este seteada `SUPABASE_SERVICE_ROLE_KEY` para mutaciones server-side (jobs y endpoints que usan cliente de servicio). 3. Setear `NO_SHOW_CRON_SECRET` (o `CRON_SECRET` para Vercel Cron) y verificar ejecucion real del cron. 4. Validar en deploy el flujo de check-in (ventana y permisos) y no-show (cambio de estado + evento). 5. Sammy AI (siguiente paso de hardening): - validar en deploy comportamiento de fallback de modelos Claude y errores transitorios del provider; - evaluar persistencia de conversaciones y auditoria de acciones ejecutadas por Sammy. 6. Reservas v2 en deploy: - validar en produccion los flujos de editar/cancelar/rebook/reconfirmar con datos reales. 7. Recordatorios y reconfirmacion: - aplicar en Supabase los scripts `scripts/004_reservations_v2_locations_notifications.sql`, `scripts/005_resource_type_booking_config.sql`, `scripts/006_reminder_advance_minutes.sql` y `scripts/009_booking_window_hour_only.sql`; - configurar `RESEND_API_KEY` y `RESEND_FROM_EMAIL` en deploy para envio real de emails; - agregar job/cron dedicado para reminder automatico independiente de navegacion de usuario. 8. Ubicaciones jerarquicas: - crear y aplicar un script incremental de backfill para `resources.location_id` en entornos legacy (el archivo `scripts/006_replace_offices_with_locations.sql` no existe en el repo actual); - terminar migracion de datos historicos y limpiar datos legacy de `offices` cuando deje de ser necesario. 9. Reservas multiples (un usuario reserva N recursos en una sola operacion): - definir alcance funcional: mismo rango horario para todos los recursos vs. horarios independientes por recurso, y politica de rollback (`todo o nada` vs. `parcial`). - backend: - crear endpoint bulk (`POST /api/reservations/bulk`) con `items[]` y validaciones por item (policy, solapes, ownership, disponibilidad); - ejecutar en transaccion para soportar `all_or_nothing=true` y devolver errores por item para UI/Sammy. - frontend web: - agregar modo multi-seleccion en flujo de reservas con resumen final y confirmacion unica; - mostrar claramente resultados por recurso (creada / rechazada + motivo) cuando se permita modo parcial. - Sammy: - extender actions con `create_reservations_batch` para que pueda proponer y confirmar varias reservas juntas en un solo paso.