Skip to content

About

Plataforma para reservar servicios en negocios locales: los clientes agendan citas; los proveedores gestionan servicios, recursos y reglas de operación.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Build and analyze

Booking Platform — Sprint 1

Backend de la Plataforma de Reservas de Servicios (caso CodeF@ctory). Monolito modular con arquitectura limpia sobre Spring Boot 4.1.1 (JDK 21), PostgreSQL administrado en Supabase y autenticación delegada en Supabase Auth (GoTrue) con validación JWT por JWKS.

Alcance Sprint 1: HU-001 (registro de cliente con verificación de correo) y HU-021 mínima (login, logout, bloqueo por intentos, recuperación de contraseña). MFA de administradores diferido a Sprint 2.

Documentación

Documento Ruta
Diagrama de paquetes y componentes + estilo docs/architecture/componentes.md
ADR-0001 Monolito modular + clean architecture docs/adr/ADR-0001-*.md
ADR-0002 Supabase (BD + identidad) docs/adr/ADR-0002-*.md
ADR-0003 Autenticación JWT/JWKS + bloqueo propio docs/adr/ADR-0003-*.md
ADR-0004 API versionada, ProblemDetail, traceId docs/adr/ADR-0004-*.md
ADR-0005 Modelo físico escrito a mano + CI de BD docs/adr/ADR-0005-*.md
ADR-0006 Migraciones de esquema con Flyway docs/adr/ADR-0006-*.md
ADR-0007 Correo de la plataforma: bandeja en la app, SMTP opcional docs/adr/ADR-0007-*.md
ADR-0008 Autorización: rol de plataforma y rol en el proveedor docs/adr/ADR-0008-*.md
Guía de la carpeta de base de datos docs/database/README.md
Modelo lógico completo (ER) docs/database/modelo-logico.md
Modelo físico: migraciones de Flyway (V1 = las 19 tablas del Sprint 1) src/main/resources/db/migration/
Datos de prueba docs/database/seed.sql
Restricciones de integridad en acción docs/database/pruebas-integridad.sql
Seguridad Supabase (RLS) src/main/resources/db/migration/V2__rls.sql
Consultas clave del negocio docs/database/consultas-clave.md
Consultas clave, versión ejecutable docs/database/consultas-clave.sql
Diagrama ER editable docs/database/diagrama-er.drawio
Runbook operativo (producción, E2E, troubleshooting) docs/operations/runbook.md
Colección REST de Sprint 1 docs/api/sprint1.http

Estructura del código

com.codefactory.bookingplatform
├── shared/         kernel transversal: error (ProblemDetail+traceId), config
│                   (security, OpenAPI, properties), observability, persistence
├── identity/       HU-001: domain (Client puro + ports) → application (use cases)
│                   → infrastructure (JPA + MapStruct) → api (REST /registrations)
├── auth/           HU-021: domain (policies + ports) → application (fachada
│                   UserProvisioning + use cases) → infrastructure (GoTrueClient,
│                   login_attempts) → api (REST /auth)
├── catalog/        HU-004, HU-009: domain (OfferedService, Resource con mantenimientos y
│                   retiro) → application (use cases, ámbito vía OrganizationAccess) →
│                   infrastructure (JPA + JDBC) → api (REST /organizations/{id}/services,
│                   /resource-types, /resources)
├── scheduling/     HU-006: domain (Agenda con bloques, vigencia y granularidad) →
│                   application (use cases; reservas futuras vía puerto) → infrastructure
│                   (JPA + JDBC) → api (REST /organizations/{id}/agendas)
├── organization/   HU-002: domain (Organization + política versionada) → application
│                   (registro, aprobación, OrganizationAccess) → infrastructure (JPA)
│                   → api (REST /provider-registrations, /organizations, /admin)
└── notification/   correo de la plataforma: fachada EmailNotifications → bandeja en la
                    app (GET /notifications/emails) o SMTP si se configura (ADR-0007)

Reglas de dependencia verificadas con ArchUnit en src/test/.../architecture/ArchitectureTest.java.

Cómo ejecutar el proyecto

Prerrequisitos

  • JDK 21+ (el Maven wrapper mvnw ya viene incluido, no hay que instalar Maven)
  • Docker Desktop (solo para los tests de integración con Testcontainers)
  • Proyecto Supabase gratuito (BD + Auth)

Notas:

  • No hay base de datos local que levantar: la app conecta directo al PostgreSQL administrado de Supabase por el session pooler (puerto 5432).
  • La aplicación solo lee configuración del entorno del proceso (variables de entorno del SO, secret store de Render, etc.).

1) Configurar variables de entorno

Variable Valor de ejemplo (reemplazar) Descripción
SUPABASE_URL https://<ref>.supabase.co URL del proyecto (Dashboard → Settings → API Keys)
SUPABASE_SECRET_KEY sb_secret_... Secret key, solo backend, jamás en frontend ni git
DATABASE_URL jdbc:postgresql://aws-0-<region>.pooler.supabase.com:5432/postgres?sslmode=require JDBC por session pooler, puerto 5432 (nunca 6543)
DATABASE_USER postgres.<ref> Usuario del pooler (con sufijo del proyecto)
DATABASE_PASSWORD ... Contraseña de la BD (Dashboard → Settings → Database)
SPRING_MAIL_HOST smtp.gmail.com Opcional, para local. Sin ella los correos van a la bandeja de la app (ADR-0007). Render gratis bloquea SMTP
SPRING_MAIL_PORT 587 Puerto SMTP con STARTTLS
SPRING_MAIL_USERNAME cuenta@gmail.com Usuario SMTP
SPRING_MAIL_PASSWORD ... Contraseña de aplicación de Gmail, no la de la cuenta
APP_MAIL_FROM reservas@... Opcional. Remitente; si falta, el usuario SMTP

La app no lee archivos .env por sí sola: las variables deben existir en el entorno de la terminal donde corres mvnw. Cada terminal tiene su propio entorno, así que cárgalas en la misma sesión antes de arrancar.

Opción A — una por una (nada persiste, solo esa sesión):

Windows:

$env:SUPABASE_URL="https://<ref>.supabase.co"
$env:SUPABASE_SECRET_KEY="sb_secret_..."
$env:DATABASE_URL="jdbc:postgresql://aws-0-<region>.pooler.supabase.com:5432/postgres?sslmode=require"
$env:DATABASE_USER="postgres.<ref>"
$env:DATABASE_PASSWORD="..."

Linux/macOS:

export SUPABASE_URL="https://<ref>.supabase.co"
export SUPABASE_SECRET_KEY="sb_secret_..."
export DATABASE_URL="jdbc:postgresql://aws-0-<region>.pooler.supabase.com:5432/postgres?sslmode=require"
export DATABASE_USER="postgres.<ref>"
export DATABASE_PASSWORD="..."

Opción B — desde un archivo .env (recomendado):

Crea un archivo .env en la raíz del repo con el formato CLAVE=valor, una por línea (ese archivo ya está ignorado en git, nunca se commitea):

SUPABASE_URL=https://<ref>.supabase.co
SUPABASE_SECRET_KEY=sb_secret_...
DATABASE_URL=jdbc:postgresql://aws-0-<region>.pooler.supabase.com:5432/postgres?sslmode=require
DATABASE_USER=postgres.<ref>
DATABASE_PASSWORD=...

Y cárgalo en la misma terminal antes de arrancar:

Windows:

Get-Content .env | Where-Object { $_ -match '^\s*[^#\s=]+=' } | ForEach-Object { $k,$v = $_ -split '=', 2; [Environment]::SetEnvironmentVariable($k.Trim(), $v.Trim().Trim('"').Trim("'"), 'Process') }

Linux/macOS:

set -a; source .env; set +a

Si algo falla al arrancar, verifica que cargaron (p. ej. $env:DATABASE_URL en Windows o echo $DATABASE_URL en Linux/macOS).

2) Levantar la API

Windows:

.\mvnw.cmd spring-boot:run

Linux/macOS:

./mvnw spring-boot:run

Notas:

  • El esquema lo crea Flyway al arrancar, con las migraciones de src/main/resources/db/migration/ (ADR-0006). Hibernate ya no crea tablas: solo valida que las entidades cuadren con el esquema.
  • La aplicación migra la base a la que apunta DATABASE_URL. Si tu .env apunta a Supabase, al arrancar le aplicas las migraciones de tu rama a la base compartida. Para desarrollar, usa el PostgreSQL de docker compose up -d db (DATABASE_URL=jdbc:postgresql://localhost:5432/postgres).
  • Swagger UI: http://localhost:8080/swagger-ui.html
  • Health: http://localhost:8080/actuator/health

3) Ejecutar pruebas

Windows:

.\mvnw.cmd test      # unitarios de dominio + ArchUnit
.\mvnw.cmd verify    # + integración con Testcontainers (requiere Docker)

Linux/macOS:

./mvnw test          # unitarios de dominio + ArchUnit
./mvnw verify        # + integración con Testcontainers (requiere Docker)

Endpoints (v1)

Método Ruta Auth HU
POST /api/v1/registrations pública HU-001
POST /api/v1/registrations/verification-resends pública HU-001
POST /api/v1/registrations/email-verifications pública HU-001
POST /api/v1/auth/login pública HU-021
POST /api/v1/auth/logout Bearer HU-021
POST /api/v1/auth/password-recovery-requests pública HU-021
POST /api/v1/auth/password-resets pública HU-021
GET /api/v1/auth/me Bearer HU-021
GET /api/v1/organization-categories pública HU-002
GET /api/v1/cities pública HU-002
POST /api/v1/provider-registrations pública HU-002
GET /api/v1/catalog/services?q=&categoryId=&cityId=&providerId=&minPrice=&maxPrice=&sort=&direction=&page=&size= pública HU-005
GET /api/v1/organizations Bearer PROVIDER HU-002
GET /api/v1/organizations/{id} Bearer PROVIDER miembro o ADMIN HU-002, HU-022
PUT /api/v1/organizations/{id}/operation-policy Bearer OWNER o MANAGER del proveedor HU-002
POST /api/v1/admin/organizations/{id}/approval Bearer ADMIN HU-002
GET /api/v1/admin/organizations, /api/v1/admin/organizations/export (CSV) Bearer ADMIN HU-003
POST /api/v1/admin/organizations/{id}/suspension, /reactivation, /rejection Bearer ADMIN HU-003
GET /api/v1/admin/clients, /api/v1/admin/clients/export (CSV) Bearer ADMIN HU-003
POST /api/v1/admin/clients/{id}/suspension, /reactivation Bearer ADMIN HU-003
GET /api/v1/notifications/emails Bearer HU-002 (correo de aprobación), ADR-0007
GET, POST /api/v1/organizations/{id}/resource-types Bearer miembro (POST: OWNER o MANAGER) HU-009
GET, POST /api/v1/organizations/{id}/resources Bearer miembro (POST: OWNER o MANAGER) HU-009
POST /api/v1/organizations/{id}/resources/{resourceId}/maintenances Bearer OWNER o MANAGER HU-009
POST /api/v1/organizations/{id}/resources/{resourceId}/retirement Bearer OWNER o MANAGER HU-009
GET, POST /api/v1/organizations/{id}/services Bearer miembro (POST: OWNER o MANAGER) HU-004
GET, PUT, DELETE /api/v1/organizations/{id}/services/{serviceId} Bearer miembro (PUT, DELETE: OWNER o MANAGER) HU-004
POST /api/v1/organizations/{id}/services/{serviceId}/activation, /deactivation Bearer OWNER o MANAGER HU-004, HU-009
GET, POST /api/v1/organizations/{id}/agendas Bearer miembro (POST: OWNER o MANAGER) HU-006
GET /api/v1/organizations/{id}/agendas/{agendaId} Bearer miembro HU-006
PUT /api/v1/organizations/{id}/agendas/{agendaId}/blocks, /granularity Bearer OWNER o MANAGER HU-006
POST /api/v1/organizations/{id}/agendas/{agendaId}/day-copies Bearer OWNER o MANAGER HU-006

Errores: application/problem+json con errorCode, traceId y details.

Despliegue en Render

Producción: https://bookingplatform-81wi.onrender.com (Web Service Docker desde main, perfil cloud. Al arrancar, Flyway aplica las migraciones pendientes a Supabase y Hibernate valida el esquema).

Crear el servicio

  1. En Render: New → Web Service → Build from Git provider y conecta el repositorio (render.yaml ya describe el servicio).
  2. En Settings → Health Check Path configura /actuator/health/readiness.
  3. En Environment define las mismas variables de la tabla anterior (perfil cloud; DATABASE_URL en formato JDBC con ?sslmode=require). Sin Secret Files: la app solo lee variables de entorno.

Verificar

curl https://bookingplatform-81wi.onrender.com/actuator/health   # {"status":"UP"}

Swagger UI: /swagger-ui/index.html · OpenAPI: /v3/api-docs.

Plan Free: la instancia se duerme tras ~15 min sin tráfico; la primera petición tarda ~1 min (cold start).

Restricciones aplicadas (no tocar sin revisar el runbook)

  • Render inyecta el puerto en PORT → respetar server.port=${PORT:8080}.
  • El session pooler gratuito de Supabase admite 15 clientes totales: pool Hikari fijo en 5/1 (application-cloud.yml) y ninguna otra conexión permanente contra Supabase.

Detalle operativo, E2E manual y troubleshooting: docs/operations/runbook.md.

Convenciones de código

  • Clases/interfaces/records/enums: PascalCase; métodos y variables: camelCase; paquetes: minúsculas.
  • Sufijos: *UseCase (application), *Entity (JPA, infrastructure), *Request/*Response (DTO api), *Port/*Repository (domain), *Adapter/*Client (infrastructure).
  • DTOs de entrada/salida como record con Bean Validation.
  • Dominio sin frameworks (regla verificada por ArchUnit).
  • Ramas feature/*, PR a main con revisión por pares (trunk-based).

About

Plataforma para reservar servicios en negocios locales: los clientes agendan citas; los proveedores gestionan servicios, recursos y reglas de operación.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages