diff --git a/presentacion/arquitectura.png b/presentacion/arquitectura.png new file mode 100644 index 0000000..e1d4498 Binary files /dev/null and b/presentacion/arquitectura.png differ diff --git a/presentacion/index.html b/presentacion/index.html new file mode 100644 index 0000000..353f5f9 --- /dev/null +++ b/presentacion/index.html @@ -0,0 +1,487 @@ + + +
+ + +Backend for Frontend para Dolibarr ERP
+Trabajo Fin de Grado — JavierMB — 2026
+
+ ❌ Dolibarr devuelve todo como string (ids, fechas, decimales, estados)
+ ❌ API REST inconsistente (snake_case, unix timestamps, codigos numericos)
+ ❌ Exponer el ERP directamente al navegador = riesgo de seguridad
+ ❌ El frontend tendria que parsear y transformar todo manualmente
+
+ ✅ El BFF transforma, valida y cachea — frontend recibe datos limpios
+ ✅ JWT propio — credenciales Dolibarr nunca llegan al navegador
+ ✅ Contratos tipados con DataAnnotations y mappers
+
Un BFF es una API disenada exclusivamente para un tipo de cliente frontend.
+
+Elegimos .NET 10 LTS (soporte hasta noviembre 2028). Ventajas clave:
+PERFORMANCE
+JIT inlining, escape analysis, NativeAOT mas rapido y ligero
+C# 14
+Field-backed properties, extension types, ?=
ASP.NET CORE 10
+OpenAPI 3.1 por defecto, validacion built-in, rate limiting nativo
+LTS = Long Term Support — parches de seguridad y soporte durante 3 anos. La eleccion correcta para un TFG.
+Backend
+.NET 10 LTS
ASP.NET Core Web API
JWT Bearer Auth
Rate Limiting nativo
Health Checks
Patrones
+CQRS-lite (command/query)
Service Layer
Static Mappers
ProblemDetails (RFC 7807)
IMemoryCache
Interface segregation
Infra
+Docker + Compose
MySQL 8.0
Dolibarr (container)
xUnit + Moq
Swagger / OpenAPI
Controllers/
+AuthController
ClientsController
InvoicesController
DocumentController
✓ [ProducesResponseType]
Services/
+Auth/ AuthService, TokenCache, JwtProvider
Clients/ IDolibarrApiClient interfaz
InvoiceService, ClientService, DocumentService
Dtos/
+command/ CreateInvoice...
query/ InvoiceDto...
Dolibarr/ *Response...
Otros
+Mappers/
Exceptions/
Program.cs
clave IDolibarrApiClient es una interfaz — facilita mocking y testing
Dos capas de autenticacion transparentes para el frontend:
+FRONTEND ↔ BFF
+JWT HMAC-SHA256
Claims: sessionId + username
Expiracion: 30 min
ASP.NET Core valida
BFF ↔ DOLIBARR
+DOLAPIKEY por sesion
Cacheada en IMemoryCache
Clave: sessionId del JWT
Inyectada como header
✅ La API key de Dolibarr nunca sale del servidor
+POST /api/Auth/login{ sessionId → DOLAPIKEY }{ sessionId, username } (30 min)Authorization: Bearer para cada requestCada request: JWT → sessionId → DOLAPIKEY en cache → header inyectado
+✓ JWT secreto via variable de entorno (nunca hardcodeado)
+ASP.NET Core 10 incluye rate limiting nativo. Lo usamos para proteger el login:
+builder.Services.AddRateLimiter(options =>
+{
+ options.RejectionStatusCode = 429;
+ options.GlobalLimiter = PartitionedRateLimiter
+ .Create<HttpContext, string>(context =>
+ {
+ if (context.Request.Path.StartsWith("/api/Auth/login"))
+ return RateLimitPartition.GetSlidingWindowLimiter(
+ "login", _ => new SlidingWindowRateLimiterOptions
+ {
+ PermitLimit = 5, Window = TimeSpan.FromMinutes(1)
+ });
+ return RateLimitPartition.GetNoLimiter("default");
+ });
+});
+ Maximo 5 intentos de login por minuto. Exceso → 429 Too Many Requests.
HEALTH CHECKS
+Endpoint /health que verifica el estado del BFF. Ideal para Docker y Kubernetes.
builder.Services.AddHealthChecks();
+app.MapHealthChecks("/health");
+ AUTHORIZE + SWAGGER DOCS
+Todos los controllers con [Authorize]. Todos los endpoints documentados con [ProducesResponseType] — OpenAPI生成 automático.
[ProducesResponseType(typeof(InvoiceDetailDto),
+ StatusCodes.Status200OK)]
+[ProducesResponseType(typeof(ProblemDetails),
+ StatusCodes.Status404NotFound)]
+ | Metodo | Ruta | Descripcion | Auth |
|---|---|---|---|
| Auth | |||
| POST | /api/Auth/login | Login → JWT | No |
| Clients | |||
| GET | /api/Clients | Listar clientes + contactos | JWT |
| Invoices | |||
| GET | /api/Invoices | Listar (pag., filtros) | JWT |
| GET | /api/Invoices/{id} | Detalle con lineas | JWT |
| POST | /api/Invoices | Crear factura | JWT |
| PUT | /api/Invoices/{id} | Actualizar | JWT |
| PATCH | /api/Invoices/{id}/status | Cambiar estado | JWT |
| POST | /api/Invoices/{id}/validate | Validar borrador | JWT |
| DELETE | /api/Invoices/{id} | Eliminar borrador | JWT |
| POST | /api/Invoices/{id}/lines | Anadir linea | JWT |
| DELETE | /api/Invoices/{id}/lines/{lineId} | Eliminar linea | JWT |
| GET | /api/Invoices/{id}/payments | Listar pagos | JWT |
| POST | /api/Invoices/{id}/payments | Registrar pago | JWT |
| Document | |||
| GET | /api/Document/invoice/{ref}/pdf | Generar PDF | JWT |
| Health | |||
| GET | /health | Estado del servicio | No |
El BFF no es solo un proxy — anade valor:
+VALIDACION
+[Required], [Range], [StringLength]
Paginacion 1-based con validacion
REGLAS DE NEGOCIO
+Solo drafts se pueden eliminar, validar o anadir lineas
Estados limitados: draft/unpaid/paid
TRANSFORMACION
+Strings → int/decimal/DateOnly"1" → "unpaid"
Enriquecer con nombres de cliente
public async Task ValidateInvoiceAsync(int id)
+{
+ var invoice = await GetRawInvoiceAsync(id);
+ if (invoice.Statut != "0")
+ throw new ForbiddenException("Solo se pueden validar facturas en borrador");
+ await _apiClient.PostAsync($"invoices/{id}/validate", null);
+}
+Command (entrada)
+Query (salida)
+Tambien Dolibarr DTOs modelan la respuesta cruda del ERP — todo como string.
+La comunicacion con Dolibarr se abstrae en una interfaz, permitiendo mocking en tests:
+public interface IDolibarrApiClient
+{
+ Task<T> GetResourceAsync<T>(string endpoint) where T : class;
+ Task<List<T>> GetCollectionAsync<T>(string endpoint) where T : class;
+ Task<string> PostAsync(string endpoint, object requestBody);
+ Task<string> PutAsync(string endpoint, object requestBody);
+ Task DeleteAsync(string endpoint);
+}
+ PRODUCCION
+DolibarrApiClient — inyecta DOLAPIKEY desde cache y llama al ERP real
TESTS
+Mock<IDolibarrApiClient> — tests unitarios sin depender de Dolibarr
Dolibarr (crudo)
+{
+ "statut": "1",
+ "total_ttc": "150.50",
+ "date": "1715673600",
+ "socid": "3",
+ "note_public": null
+}
+ BFF (limpio)
+{
+ "status": "unpaid",
+ "total": 150.50,
+ "date": "2024-05-14",
+ "clientId": 3,
+ "notePublic": null
+}
+ Resultado El frontend recibe datos limpios, tipados y en camelCase
+// Excepciones de dominio
+public class NotFoundException : Exception { }
+public class UnauthorizedException : Exception { }
+public class ForbiddenException : Exception { }
+public class BadRequestException : Exception { }
+public class ApiException : Exception { }
+
+// Handler global (Program.cs)
+app.UseExceptionHandler(options =>
+{
+ options.Map<NotFoundException>(ex => Results.Problem(
+ statusCode: 404, title: "Recurso no encontrado", detail: ex.Message));
+ options.Map<UnauthorizedException>(ex => Results.Problem(
+ statusCode: 401, title: "No autorizado", detail: ex.Message));
+ // Forbidden -> 403, BadRequest -> 400, Api -> 500
+});
+ Todas las respuestas siguen ProblemDetails RFC 7807: {"type":"...", "title":"...", "status":404}
# compose.yaml
+services:
+ mysql:
+ image: mysql:8.0
+ environment:
+ MYSQL_ROOT_PASSWORD: dolibarr
+ MYSQL_DATABASE: dolibarr
+ volumes: [mysql_data:/var/lib/mysql]
+
+ dolibarr:
+ image: dolibarr/dolibarr:latest
+ depends_on: [mysql]
+ ports: ["80:80"]
+
+ dolimiddlewareapi:
+ build: ./DoliMiddlewareApi
+ ports: ["5000:8080"]
+ depends_on: [dolibarr]
+
+ # redis: # Cache distribuida (planificado)
+ # image: redis:7-alpine
+FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
+WORKDIR /src
+COPY *.csproj .
+RUN dotnet restore
+COPY . .
+RUN dotnet publish -c Release -o /app
+
+FROM mcr.microsoft.com/dotnet/aspnet:10.0
+WORKDIR /app
+COPY --from=build /app .
+USER $APP_UID # No-root por seguridad
+EXPOSE 8080 8081
+ENTRYPOINT ["dotnet", "DoliMiddlewareApi.dll"]
+ .NET 10 Multi-stage build — runtime ligero, usuario no-root por defecto
+✓ BFF justificado — el frontend no deberia lidiar con APIs inconsistentes
+✓ Doble token — credenciales Dolibarr nunca salen del servidor
+✓ Contratos tipados — DTOs con validacion evitan datos incorrectos
+✓ Seguridad nativa — Rate limiting, health checks y [Authorize]
+✓ Errores centralizados — RFC 7807 ProblemDetails consistentes
+✓ Abstraccion para testing — IDolibarrApiClient permite mocking completo
+☐ Tests unitarios (proyecto xUnit + Moq preparado, IDolibarrApiClient facilita mocking)
☐ Redis para cache distribuida
+☐ Response caching
+☐ Metadatos de paginacion (X-Total-Count)
+☐ CI/CD
+☐ Mas endpoints: productos, pedidos, terceros...
+DoliMiddlewareApi — BFF para Dolibarr
+.NET 10 LTS • JWT • Rate Limiting • Health Checks • Docker
+Preguntas →
+