Skip to content

Sprint 2: HU-002, HU-003, HU-004, HU-005, HU-006 y HU-009 - #5

Merged
J3rmed merged 8 commits into
mainfrom
feature/sprint-2
Oct 25, 2026
Merged

J3rmed merged 8 commits into
mainfrom
feature/sprint-2

Conversation

@J3rmed

@J3rmed J3rmed commented Oct 25, 2026

Copy link
Copy Markdown
Contributor

Qué trae

Las seis HU del Sprint 2, cada una en su propio commit, sobre los habilitadores que ya están en main (Flyway, V3, D7, D9 y reglas ArchUnit genéricas).

HU Commit Qué entrega
HU-002 Registro de proveedor 48c8fe3 Registro público con cuenta PROVIDER, sede, política v1 y OWNER. Aprobación por ADMIN con motivo. Cambio de política por versiones. Autorización base (ADR-0008): fuera del proveedor, 404; con un rol insuficiente, 403.
Correo db84dbf Bandeja de correo dentro de la app (GET /api/v1/notifications/emails), porque Render gratis bloquea SMTP (ADR-0007).
HU-009 Recursos 6ce1020 Tipos de recurso e instancias con capacidad, mantenimientos por rango de fechas sin solape, y un retiro que se bloquea mientras haya reservas futuras.
HU-004 Servicios a21ac44 Servicios con sedes y recursos requeridos. Nacen INACTIVE. Para activarlos, cada sede necesita recursos suficientes (HU-009). Desactivar o eliminar depende de si tienen reservas.
HU-006 Agendas ee14210 Agendas por sede o recurso con granularidad de 15, 30 o 60 minutos, vigencia, servicios y bloques. Los cambios se verifican contra las reservas futuras, en la hora local de la sede.
HU-005 Catálogo 8c551bd Búsqueda pública sin distinguir mayúsculas ni tildes, con filtros combinables, orden y paginación. Solo muestra proveedores y servicios activos.
HU-003 Administración 0dfe634 Listados de clientes y proveedores con filtros, orden y exportación a CSV. Suspensión con confirmación y conteo de reservas afectadas; reactivación y rechazo.

Módulos nuevos: organization, catalog, scheduling y notification, con la misma estructura de capas y cubiertos por las reglas ArchUnit genéricas.

Migraciones (se aplican a Supabase al desplegar)

Versión Contenido
V4 Identificación del proveedor como tipo y número; nit pasa a identification_number
V5 Datos de referencia: 5 categorías, 32 ciudades y COP
V6 sent_emails, la bandeja de correo
V7 Capacidad de los recursos, estado RETIRED, organización en la fila (las FK compuestas impiden mezclar proveedores) y resource_maintenances
V8 agendas, agenda_services y schedules como bloques de una agenda
V9 f_sin_tildes() para la búsqueda

Todas las tablas nuevas tienen RLS. El workflow de base de datos cuenta 23 tablas y 24 rechazos de integridad. La idempotencia de V1 y V2 ahora se comprueba antes de las demás migraciones, que es el orden real en una base anterior a Flyway.

Pruebas

mvn clean verify en local con JDK 21: 873 unitarias y 143 de integración, con el umbral de JaCoCo cumplido. Cada HU tiene una prueba de integración de punta a punta (ProviderOnboardingIT, ResourceManagementIT, ServiceManagementIT, AgendaManagementIT, CatalogSearchIT, AdminUsersIT) que también cubre los 403 y 404 de HU-022.

Queda para otras HU

  • HU-008: la "próxima franja disponible" del catálogo (HU-005) y el efecto de un mantenimiento en las franjas (HU-009). La regla Resource.isAvailableDuring ya está lista para usarse.
  • Reenviar la verificación a proveedores, invitar MANAGER y STAFF, y aplicar al instante un cambio de rol (HU-022 y D8).

Antes o después de fusionar

  • Crear el primer administrador en Supabase (runbook, sección 3, paso 6). Sin él no se puede aprobar ningún proveedor.
  • Tras el despliegue, comprobar en flyway_schema_history que las migraciones llegaron a la versión 9.
  • Decisiones del PO: qué pasa con las reservas al suspender un proveedor (hoy se conservan) y si un cliente suspendido debe seguir pudiendo iniciar sesión.

🤖 Generated with Claude Code

J3rmed and others added 8 commits October 25, 2026 13:51
…la autorización base

Módulo organization (domain, application, infrastructure, api):
- Registro público del proveedor con cuenta propia (rol PROVIDER), al
  menos una sede y su política de operación v1. Queda PENDING_APPROVAL.
  Rechaza la identificación duplicada (409, también en carrera), la
  categoría o ciudad desconocidas y la anticipación mínima mayor que la
  máxima. Lo que falla después de crear la cuenta la borra (como D7).
- Aprobación por un administrador con motivo obligatorio (HU-003). El
  correo se envía después del commit.
- Cambio de los parámetros de operación por OWNER o MANAGER: crea una
  versión nueva y las reservas existentes conservan la suya.
- Consulta del propio proveedor y catálogos públicos de categorías y
  ciudades.

Autorización base (ADR-0008): /admin/** solo ADMIN; /organizations/**
solo PROVIDER o ADMIN; OrganizationAccess responde 404 fuera del
proveedor y 403 si el rol no alcanza.

Módulo notification (ADR-0007): SMTP con Spring Mail; sin
SPRING_MAIL_HOST, el correo se registra en el log.

Migraciones: V4 tipo y número de identificación (renombra nit); V5
categorías, 32 ciudades y COP como datos de referencia.

Otros: auth crea cuentas PROVIDER; la confirmación de correo acepta
cuentas sin perfil de cliente; runbook (primer admin, SMTP),
render.yaml y README al día.

Pruebas: 718 unitarias y 89 de integración; ProviderOnboardingIT cubre
los escenarios de HU-002 y los 404/403 de HU-022.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
El plan gratuito de Render bloquea la salida a los puertos SMTP desde
septiembre de 2025, así que el correo por Gmail no funcionaría en
producción. Para el MVP y la demo, sin cuentas ni claves externas:

- V6 crea sent_emails, con RLS. Sin SMTP configurado, InboxEmailSender
  guarda ahí cada correo, en su propia transacción porque se envía en un
  listener AFTER_COMMIT.
- GET /api/v1/notifications/emails devuelve los correos dirigidos al
  email del token, del más reciente al más antiguo.
- SMTP queda como opción con SPRING_MAIL_HOST. Se elimina
  LoggingEmailSender.
- ProviderOnboardingIT comprueba que la aprobación llega a la bandeja
  del proveedor.
- ADR-0007 reescrito con la decisión real. README, runbook, render.yaml
  y el conteo de tablas del workflow (20) quedan al día.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Módulo catalog (domain, application, infrastructure, api) bajo
/api/v1/organizations/{id}:
- Tipos de recurso con nombre único por proveedor (409 DUPLICATE_NAME).
- Recursos de un tipo propio en una sede propia, con capacidad
  simultánea y nombre único por sede. Tipo o sede ajenos dan 400 por
  campo.
- Mantenimientos por rango de fechas: el recurso queda IN_MAINTENANCE
  y Resource.isAvailableDuring lo excluye (regla que usará HU-008).
  Dos periodos solapados dan 409 OVERLAPPING_PERIOD.
- Retiro bloqueado con reservas futuras (409 HAS_FUTURE_BOOKINGS con su
  número). Se consulta booking_resources mediante un puerto hasta que
  exista el módulo de reservas.
- Leen todos los miembros; cambian OWNER y MANAGER; fuera del proveedor,
  404 (ADR-0008).

V7: capacity, estado ACTIVE/RETIRED (INACTIVE pasa a RETIRED),
organization_id con FK compuestas que cuadran tipo y sede, y
resource_maintenances con EXCLUDE de solape. seed.sql, modelo lógico y
dos pruebas de integridad nuevas (21 en total).

ProviderFixture crea proveedores activos por JDBC para las pruebas de
integración de los módulos que dependen de organization.

Pruebas: 751 unitarias y 99 de integración.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bajo /api/v1/organizations/{id}/services:
- Crear un servicio con nombre único por proveedor, duración,
  preparación, limpieza, precio en COP, cupo (1 individual, más de 1
  grupal), sus sedes y al menos un tipo de recurso requerido. Sedes o
  tipos ajenos dan 400 por posición. Nace INACTIVE.
- Activar exige, en cada sede, suficientes recursos ACTIVE de cada tipo
  requerido (HU-009). Si falta alguno, 409 INSUFFICIENT_RESOURCES con
  el faltante por sede y tipo.
- Desactivar conserva el servicio y sus reservas. Eliminar solo si nunca
  tuvo reservas; si las tiene, 409 HAS_BOOKINGS.
- Actualizar nombre, duración, tiempos, precio y cupo: las reservas
  existentes conservan sus horarios. Sedes y requisitos se fijan al
  crear el servicio.

services va por JPA; service_locations y service_resource_requirements
por JDBC en la misma transacción. Sus CF compuestas ya impedían cruzar
proveedores (V1). ProviderFixture crea servicios activos y reservas
por JDBC, compartidos con ResourceManagementIT.

Pruebas: 779 unitarias y 110 de integración.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Módulo scheduling bajo /api/v1/organizations/{id}/agendas:
- Crear una agenda de una sede, u opcionalmente de un recurso de ella,
  con granularidad de 15, 30 o 60 minutos, vigencia, servicios
  reservables (deben prestarse en la sede) y bloques semanales.
- Un bloque que termina antes de empezar, o dos solapados el mismo día,
  no se guardan. Dos agendas vigentes a la vez para la misma sede o
  recurso dan 409 (EXCLUDE en la base).
- Reemplazar los bloques o duplicar un día solo si ninguna reserva
  futura queda fuera de horario; si alguna queda fuera, 409 con la
  lista de reservas. La comparación se hace en la hora local de la
  sede.
- La granularidad no cambia mientras haya reservas futuras.
- Leen todos los miembros; cambian OWNER y MANAGER; fuera del
  proveedor, 404.

V8: agendas, agenda_services y schedules como bloques de una agenda.
seed.sql crea una agenda por recurso activo. Se actualizan la consulta
clave 6, la prueba de integridad 13 y se suman tres más (24 en total).
El workflow comprueba la idempotencia de V1 y V2 antes de las demás
migraciones, como ocurre en una base anterior a Flyway.

Fachadas nuevas: OrganizationAccess.locationZone y
CatalogLookup.resourceAt / serviceOfferedAt.

Pruebas: 823 unitarias y 121 de integración.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GET /api/v1/catalog/services, sin token:
- Solo muestra servicios ACTIVE de proveedores ACTIVE en sedes ACTIVE.
  Los proveedores pendientes o suspendidos y los servicios inactivos no
  aparecen. Cada tarjeta es una pareja servicio-sede.
- La palabra clave busca en el nombre o la descripción del servicio y en
  el nombre del proveedor, sin distinguir mayúsculas ni tildes. Los
  comodines de LIKE escritos por el cliente se buscan literalmente.
- Filtros combinables con AND: categoría, ciudad, proveedor y rango de
  precio. Orden por nombre, precio, duración o proveedor (lista blanca),
  con paginación y total.
- Sin resultados, la respuesta trae un mensaje que sugiere ampliar los
  filtros.

V9: función f_sin_tildes (translate) en lugar de la extensión unaccent,
que cambia de esquema entre Supabase y PostgreSQL. La "próxima franja
disponible" de cada tarjeta queda para HU-008. ProviderFixture permite
elegir la categoría, la ciudad y el estado del proveedor y de sus
servicios.

Pruebas: 836 unitarias y 131 de integración.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bajo /api/v1/admin (solo ADMIN), separado por clientes (identity) y
proveedores (organization):
- Listados paginados con total y filtros combinables: estado, ciudad
  (por nombre, sin tildes), rango de fechas de registro (días en
  Colombia) y, para proveedores, categoría. Orden por columna (lista
  blanca) ascendente o descendente. Sin filtros se listan todos, que es
  "Restablecer filtros".
- Exportación a CSV del listado filtrado, de todas las páginas. Csv en
  shared: RFC 4180, BOM para Excel y protección contra inyección de
  fórmulas.
- Suspender un proveedor con reservas futuras devuelve 409
  CONFIRMATION_REQUIRED con el número de reservas afectadas; con
  "confirm": true lo suspende y guarda ese número con el motivo. Las
  reservas se conservan. También reactivar y rechazar, con motivo.
- Suspender y reactivar clientes con motivo, que queda en
  account_status_changes. Repetir una suspensión da 409.

Otros: un parámetro con tipo inválido (status=FOO, page=x) devuelve 400
nombrando el parámetro en lugar de 500, también en el catálogo.
ListingParams y ResultPage en shared, compartidos con HU-005.

Pruebas: 873 unitarias y 143 de integración.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- S8696: DayOfWeek se compara con equals() en TimeBlock y Agenda.
- S2077: los adaptadores de listado y búsqueda (clientes, proveedores y
  catálogo) arman el SQL con texto, pero todos los valores son
  parámetros enlazados y lo único interpolado es la columna de orden,
  tomada de un mapa fijo. Se suprime la regla en esos métodos con la
  justificación.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@J3rmed
J3rmed merged commit fce134c into main Oct 25, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant