{"id":51199556,"url":"https://github.com/jaimejaramilloperez/dev-habit","last_synced_at":"2026-06-27T23:32:17.602Z","repository":{"id":301244450,"uuid":"964236447","full_name":"jaimejaramilloperez/dev-habit","owner":"jaimejaramilloperez","description":"This repository follows Milan Jovanović's course Pragmatic REST APIs using the latest ASP.NET Core features and best practices.","archived":false,"fork":false,"pushed_at":"2025-10-31T21:58:19.000Z","size":442,"stargazers_count":5,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-31T23:28:37.188Z","etag":null,"topics":["api","docker","dotnet","dotnet-core","webapi"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jaimejaramilloperez.png","metadata":{"files":{"readme":"README-ES.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-04-10T22:40:18.000Z","updated_at":"2025-10-31T21:58:23.000Z","dependencies_parsed_at":"2025-06-25T22:33:05.978Z","dependency_job_id":"3ab2adfb-c65c-42d6-8d46-3089c2f5dac4","html_url":"https://github.com/jaimejaramilloperez/dev-habit","commit_stats":null,"previous_names":["jaimejaramilloperez/dev-habit"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/jaimejaramilloperez/dev-habit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaimejaramilloperez%2Fdev-habit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaimejaramilloperez%2Fdev-habit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaimejaramilloperez%2Fdev-habit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaimejaramilloperez%2Fdev-habit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jaimejaramilloperez","download_url":"https://codeload.github.com/jaimejaramilloperez/dev-habit/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaimejaramilloperez%2Fdev-habit/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34872279,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-27T02:00:06.362Z","response_time":126,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","docker","dotnet","dotnet-core","webapi"],"created_at":"2026-06-27T23:32:17.514Z","updated_at":"2026-06-27T23:32:17.583Z","avatar_url":"https://github.com/jaimejaramilloperez.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"![.NET](https://img.shields.io/badge/-.NET%209.0-blueviolet)\n![PostgreSQL](https://img.shields.io/badge/PostgreSQL-316192?logo=postgresql\u0026logoColor=white)\n![Docker](https://img.shields.io/badge/Docker-2496ED?logo=docker\u0026logoColor=fff)\n![OpenAPI](https://img.shields.io/badge/-Swagger-85EA2D?style=flat\u0026logo=swagger\u0026logoColor=white)\n![OpenAPI](https://img.shields.io/badge/-Scalar-0F0F0F?style=flat\u0026logo=swagger\u0026logoColor=white)\n\n# DevHabit API\n\n## Tabla de Contenidos\n\n\u003col\u003e\n  \u003cli\u003e\n    \u003ca href=\"#-resumen\"\u003eResumen\u003c/a\u003e\n  \u003c/li\u003e\n  \u003cli\u003e\n    \u003ca href=\"#-tecnologías-utilizadas\"\u003eTecnologías Utilizadas\u003c/a\u003e\n  \u003c/li\u003e\n  \u003cli\u003e\n    \u003ca href=\"#-características\"\u003eCaracterísticas\u003c/a\u003e\n  \u003c/li\u003e\n  \u003cli\u003e\n    \u003ca href=\"#-primeros-pasos\"\u003ePrimeros Pasos\u003c/a\u003e\n    \u003cul\u003e\n      \u003cli\u003e\u003ca href=\"#-requisitos-previos\"\u003eRequisitos Previos\u003c/a\u003e\u003c/li\u003e\n      \u003cli\u003e\u003ca href=\"#-instalación\"\u003eInstalación\u003c/a\u003e\u003c/li\u003e\n    \u003c/ul\u003e\n  \u003c/li\u003e\n  \u003cli\u003e\n    \u003ca href=\"#-configuración-del-entorno\"\u003eConfiguración del Entorno\u003c/a\u003e\n    \u003cul\u003e\n      \u003cli\u003e\u003ca href=\"#-desarrollo-en-local\"\u003eDesarrollo en Local\u003c/a\u003e\u003c/li\u003e\n      \u003cli\u003e\u003ca href=\"#-docker-para-desarrollo\"\u003eDocker para Desarrollo\u003c/a\u003e\u003c/li\u003e\n      \u003cli\u003e\u003ca href=\"#-docker-para-producción\"\u003eDocker para Producción\u003c/a\u003e\u003c/li\u003e\n    \u003c/ul\u003e\n  \u003c/li\u003e\n  \u003cli\u003e\n    \u003ca href=\"#-pruebas\"\u003ePruebas\u003c/a\u003e\n  \u003c/li\u003e\n  \u003cli\u003e\n    \u003ca href=\"#-documentación-de-la-api\"\u003eDocumentación de la API\u003c/a\u003e\n  \u003c/li\u003e\n\u003c/ol\u003e\n\n\n## 🎯 Resumen\n\nDevHabit API es un servicio web RESTful versionado, construido con .NET 9, que ayuda a los usuarios a hacer seguimiento de hábitos y rutinas personales. Ofrece autenticación segura basada en JWT, procesamiento de tareas en segundo plano, integración con GitHub y observabilidad estructurada mediante OpenTelemetry. El sistema utiliza PostgreSQL, Docker y sigue buenas prácticas en validación, pruebas y despliegue. Soporta desarrollo local, pipelines de CI/CD y entornos de producción en contenedores.\n\nEste proyecto fue desarrollado siguiendo el curso [Pragmatic REST APIs](https://www.milanjovanovic.tech/pragmatic-rest-apis) de [Milan Jovanović](https://github.com/m-jovanovic), usando las últimas características de ASP.NET Core y buenas prácticas recomendadas.\n\n## 🔧 Tecnologías Utilizadas\n\n- [.NET 9](https://dotnet.microsoft.com/) – Framework moderno para construir APIs web escalables\n- [PostgreSQL](https://www.postgresql.org/) – Base de datos relacional de código abierto\n- [Entity Framework Core](https://learn.microsoft.com/en-us/ef/core/) – ORM para acceso a datos\n- [Docker](https://www.docker.com/) – Contenerización e infraestructura local\n- [Swagger (Swashbuckle)](https://swagger.io/) – Documentación interactiva basada en OpenAPI\n- [Scalar](https://scalar.com/) – Explorador interactivo de APIs (alternativo)\n- [FluentValidation](https://docs.fluentvalidation.net/) – Framework de validación de modelos\n- [Quartz.NET](https://www.quartz-scheduler.net/) – Tareas en segundo plano y programación\n- [Polly (via Microsoft.Extensions.Http.Resilience)](https://www.pollydocs.org/) – Manejo de fallos y resiliencia\n- [Refit](https://reactiveui.github.io/refit/) – Clientes REST tipados\n- [CsvHelper](https://joshclose.github.io/CsvHelper/) – Utilidades para importar/exportar archivos CSV\n- [OpenTelemetry](https://opentelemetry.io/) – Trazabilidad distribuida y observabilidad\n- [.NET Aspire](https://learn.microsoft.com/en-us/dotnet/aspire/) – Modelo simplificado de aplicaciones distribuidas con soporte para OpenTelemetry\n- [Seq](https://datalust.co/seq) – Agregación centralizada de logs (opcional)\n- [Azure Monitor](https://learn.microsoft.com/en-us/azure/azure-monitor/) – Integración de telemetría (opcional)\n- [xUnit](https://xunit.net/) – Framework para pruebas unitarias\n- [NSubstitute](https://nsubstitute.github.io/) – Mocking amigable para .NET\n- [Testcontainers](https://dotnet.testcontainers.org/) – Pruebas de integración con contenedores\n- [WireMock.Net](https://wiremock.org/) – Simulación y mocking de HTTP\n- [SonarAnalyzer](https://rules.sonarsource.com/csharp) – Análisis estático de código\n\n## ✨ Características\n\n#### 🧭 Diseño de la API\n- Filtrado, ordenamiento, paginación y modelado de datos en colecciones de recursos\n- Negociación de contenido y soporte para HATEOAS\n- Versionado de la API con soporte para media types\n- Clientes HTTP tipados mediante Refit\n- Documentación interactiva de la API con Swagger y Scalar\n\n#### ⚙️ Infraestructura e Integración\n- PostgreSQL con EF Core y convenciones de nombres\n- Tareas en segundo plano con Quartz\n- Integración con GitHub para datos externos o automatización\n- Importación de datos desde archivos (soporte para CSV)\n\n#### 🔐 Seguridad\n- Autenticación y autorización basada en JWT\n- Configuración de políticas CORS\n- Almacenamiento seguro de llaves de API de GitHub mediante encriptación\n\n#### 📈 Observabilidad y Resiliencia\n- Trazabilidad distribuida basada en OpenTelemetry\n- Soporte para health checks\n- Patrones de resiliencia HTTP mediante Polly (.NET Resilience)\n- Azure Monitor (integración opcional)\n- Logging con .NET Aspire o Seq\n\n#### 🧪 Stack de Pruebas\n- Pruebas unitarias con xUnit y NSubstitute\n- Pruebas de integración con Testcontainers y PostgreSQL\n- Mocking HTTP mediante WireMock.Net\n- Cobertura de código con Coverlet\n\n#### 📦 Despliegue y DevOps\n- Soporte para desarrollo local con Docker Compose\n- Versionado centralizado de paquetes con MSBuild\n- Soporte para imágenes de producción en Docker\n\n## 🚀 Primeros Pasos\n\n### 📋 Requisitos Previos\n\nAsegúrate de tener instalado el CLI de .NET en tu sistema. Puedes verificarlo ejecutando:\n\n```bash\ndotnet --version\n```\n\nEsto debería mostrar la versión instalada del CLI de .NET. Si no está instalado, descárgelo desde la [pagina oficial de .NET](https://dotnet.microsoft.com/download).\n\nPara verificar qué versiones del SDK están instalados:\n\n```bash\ndotnet --list-sdks\n```\n\n\u003e [!IMPORTANT]\n\u003e La versión mínima requerida del SDK de .NET es **9.0.0**\n\nAdicionalmente, el proyecto utiliza Docker para ejecutar servicios de soporte (por ejemplo, PostgreSQL, pgAdmin, Seq). Necesitará:\n\n- [**Docker**](https://www.docker.com/products/docker-desktop): Se recomienda instalar Docker Desktop.\n- [**Docker  Compose**](https://docs.docker.com/compose/): Usualmente incluido con Docker Desktop.\n\nPara comprobar que Docker está instalado y en funcionamiento:\n\n```bash\ndocker --version\ndocker compose version\n```\n\nSi estos comandos fallan o arrojan errores, consulte la [guía de instalación de Docker](https://docs.docker.com/get-docker/).\n\n---\n\n### 📥 Instalación\n\nPara comenzar, clona el repositorio y configura el entorno:\n\n1. Clone el repositorio:\n\n```bash\ngit clone https://github.com/jaimejaramilloperez/dev-habit.git\n```\n\n2. Navege al directorio del proyecto:\n\n```bash\ncd dev-habit\n```\n\n3. Genere y confíe en el certificado de desarrollo HTTPS:\n\n```bash\ndotnet dev-certs https -ep ./src/DevHabit.Api/aspnetapp.pfx -p Test1234!\ndotnet dev-certs https --trust\n```\n\n4. Copie la plantilla de entorno y configúrelo:\n\n```bash\ncp .env.template .env\n# Edite el archivo .env según sea necesario\n```\n\nDespués de la instalación, estarás listo para ejecutar la aplicación localmente o usando Docker. Consulta las secciones de [Desarrollo en local](#-desarrollo-en-local) o [Docker](#-docker-para-desarrollo) para más detalles.\n\n## 💻 Configuración del Entorno\n\nConfigura tu entorno para ejecutar la API de DevHabit ya sea localmente o con Docker, según tu flujo de trabajo.\n\n\u003e [!NOTE]\n\u003e Los valores de configuración mostrados (por ejemplo, contraseñas, puertos, claves, cadenas de conexión) se proporcionan solo con fines demostrativos. Puede modificarlos según sea necesario — especialmente para entornos de producción.\n\n#### Nota sobre Observabilidad:\n\nEste proyecto soporta trazabilidad distribuida y telemetría mediante el [Dashboard de .NET Aspire](https://learn.microsoft.com/en-us/dotnet/aspire/) o [Seq](https://datalust.co/seq).\n\nSegún la herramienta elegida, deberá definir las siguientes variables de entorno:\n\n- `OTEL_EXPORTER_OTLP_ENDPOINT`\n- `OTEL_EXPORTER_OTLP_PROTOCOL`\n\nPara .NET Aspire:\n\n```dotenv\nOTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:18889\nOTEL_EXPORTER_OTLP_PROTOCOL=grpc\n```\nPara Seq:\n\n```dotenv\nOTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:5341/ingest/otlp\nOTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf\n```\n\n\u003e [!TIP]\n\u003e Si la API se ejecuta dentro de un contenedor Docker, `localhost` hace referencia al propio contenedor. En ese caso, reemplace `localhost` con el nombre del servicio definido en la red de Docker (por ejemplo, `devhabit.seq` o `devhabit.aspire-dashboard`).\n\nPuede alternar entre ambas opciones modificando el archivo `.env` o los archivos de entorno correspondientes a Docker.\n\n---\n\n### 🧑‍💻 Desarrollo en Local\n\nPuede ejecutar la API localmente utilizando la CLI de .NET, mientras los servicios de soporte (PostgreSQL, pgAdmin, Seq) se ejecutan a través de Docker Compose.\n\n1. Configure los secretos de usuario:\n\nLos valores sensibles deben almacenarse de forma segura mediante [user secrets](https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-9.0\u0026tabs=linux):\n\n```json\n{\n  \"ConnectionStrings:Database\": \"Server=localhost;Port=5432;Database=devhabit;Username=devhabit;Password=123456;\",\n  \"Jwt:Key\": \"HTycXOjdDRfrtNYzQQbkx2L7ncCEe2989cWH6yrTFdSPRmFFe4K9qmbnjHJBRGHfaeRKvDEWzaS\",\n  \"Encryption:Key\": \"Ubf/RatKuzJ4p8Fc9nr9LKZFV5L8CjIZZCqcFlYZeEo=\"\n}\n```\n\n2. Actualice `appsettings.Development.json`\n\n```json\n{\n  \"ConnectionStrings\": {\n    \"Database\": \"your-database-connection-string-here\"\n  },\n  \"Jwt\": {\n    \"Key\": \"your-secret-key-here-that-should-also-be-fairly-long\",\n    \"Issuer\": \"dev-habit.api\",\n    \"Audience\": \"dev-habit.app\",\n    \"ExpirationInMinutes\": 30,\n    \"RefreshTokenExpirationInDays\": 7\n  },\n  \"Encryption\": {\n    \"Key\": \"your-secret-key-here-that-should-also-be-exactly-32-bytes-or-44-characters-in-base64-long\"\n  },\n  \"Cors\": {\n    \"AllowedOrigins\": [\n      \"http://localhost:3000\"\n    ]\n  },\n  \"Jobs\": {\n    \"ScanIntervalInMinutes\": 50\n  },\n  \"GitHub\": {\n    \"BaseUrl\": \"https://api.github.com\"\n  },\n  \"OTEL_EXPORTER_OTLP_ENDPOINT\": \"http://localhost:18889\",\n  \"OTEL_EXPORTER_OTLP_PROTOCOL\": \"grpc\",\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft.AspNetCore\": \"Information\"\n    }\n  }\n}\n```\n\n3. Configure las variables de entorno (archivo `.env`):\n\n```dotenv\n# postgresql\nPOSTGRES_PORT=\"5432\"\nPOSTGRES_DB=\"devhabit\"\nPOSTGRES_USER=\"spartan\"\nPOSTGRES_PASSWORD=\"123456\"\n\n# pgadmin\nPGADMIN_EMAIL=\"user@mail.com\"\nPGADMIN_PASSWORD=\"123456\"\n\n# seq\nSEQ_PASSWORD=\"12345678\"\n```\n\n4. Inicie los servicios de Docker:\n\n```bash\ndocker compose up -d\n```\n\n5. Ejecute la API:\n\n```bash\ndotnet run --project src/DevHabit.Api\n# o con HTTPS\ndotnet run --launch-profile https --project src/DevHabit.Api\n```\n\n---\n\n### 🐳 Docker para Desarrollo\n\nEste modo ejecuta tanto la aplicación como los servicios en contenedores Docker utilizando una imagen de desarrollo.\n\n1. Cree o ajuste el archivo `.env.docker-debug`:\n\n```dotenv\n# docker\nDOCKER_REGISTRY=\"\"\nDOCKER_IMAGE_TAG=\"dev\"\nDOCKER_BUILD_TARGET=\"dev\"\nDOCKER_ASPNETCORE_BUILD_CONFIGURATION=\"Debug\"\n\n# app\nENVIRONMENT=\"Development\"\nHTTP_PORT=\"5000\"\nHTTPS_PORT=\"5001\"\nCERTIFICATE_PATH=\"/https/aspnetapp.pfx\"\nCERTIFICATE_PASSWORD=\"Test1234!\"\nENCRYPTION_KEY=\"Ubf/RatKuzJ4p8Fc9nr9LKZFV5L8CjIZZCqcFlYZeEo=\"\nOTEL_EXPORTER_OTLP_ENDPOINT=\"http://devhabit.aspire-dashboard:18889\"\nOTEL_EXPORTER_OTLP_PROTOCOL=\"grpc\"\n\n# postgresql\nPOSTGRES_SERVER=\"devhabit.postgres\"\nPOSTGRES_PORT=\"5432\"\nPOSTGRES_DB=\"devhabit\"\nPOSTGRES_USER=\"devhabit\"\nPOSTGRES_PASSWORD=\"123456\"\n\n# pgadmin\nPGADMIN_EMAIL=\"user@mail.com\"\nPGADMIN_PASSWORD=\"123456\"\n\n# seq\nSEQ_PASSWORD=\"12345678\"\n```\n\n2. Inicie los contenedores:\n\n```bash\ndocker compose -f ./docker-compose.debug.yml --env-file .env.docker-debug up -d\n```\n\n#### 🐞 Depuración en el contenedor\n\n\u003e [!IMPORTANT]\n\u003e La depuración dentro de contenedores requiere el depurador `vsdbg`. Si aún no está instalado, consulte la [guía oficial de configuración](https://github.com/microsoft/MIEngine/wiki/Offroad-Debugging-of-.NET-Core-on-Linux---OSX-from-Visual-Studio) para instrucciones sobre cómo instalarlo manualmente.\n\nSi está utilizando Visual Studio Code, puede depurar la aplicación que se ejecuta dentro del contenedor de dos formas:\n\n1. **Containers: .NET Launch**\n\nEsta opción compila y ejecuta el contenedor en modo depuración y lanza automáticamente el depurador.\n\nAsegúrese de tener un archivo `.env.docker-debug-image` con la siguiente configuración:\n\n```dotenv\nASPNETCORE_HTTP_PORTS=5000\nASPNETCORE_HTTPS_PORTS=5001\nASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx\nASPNETCORE_Kestrel__Certificates__Default__Password=Test1234!\nConnectionStrings__Database=Server=devhabit.postgres;Port=5432;Database=devhabit;Username=devhabit;Password=123456;\nOTEL_EXPORTER_OTLP_ENDPOINT=http://devhabit.aspire-dashboard:18889\nOTEL_EXPORTER_OTLP_PROTOCOL=grpc\n```\n\n2. **Containers .NET Attach (Preview)**\n\nEsta opción más sencilla permite adjuntar el depurador a un contenedor en ejecución, sin necesidad de configuración adicional más allá de iniciar los contenedores como se describe en el paso 2 de la sección [docker para desarrollo](#-docker-para-desarrollo).\n\n\u003e [!WARNING]\n\u003e Esta funcionalidad aún se encuentra en versión preliminar (preview) y podría presentar un rendimiento general más lento.\n\n---\n\n### 📦 Docker para Producción\n\nPara compilar y ejecutar la API en modo producción utilizando una imagen Docker mínima:\n\n1. Cree o ajuste el archivo `.env.docker-prod`:\n\n```dotenv\nDOTNET_USE_POLLING_FILE_WATCHER=\"1\"\nASPNETCORE_ENVIRONMENT=\"Production\"\nASPNETCORE_HTTP_PORTS=5000\n\nConnectionStrings__Database=Server=devhabit.postgres;Port=5432;Database=devhabit;Username=devhabit;Password=123456;\n\nJwt__Key=\"your-secret-key-here-that-should-also-be-fairly-long\"\nJwt__Issuer=\"dev-habit.api\"\nJwt__Audience=\"dev-habit.app\"\nJwt__ExpirationInMinutes=30\nJwt__RefreshTokenExpirationInDays=7\n\nEncryption__Key=\"Ubf/RatKuzJ4p8Fc9nr9LKZFV5L8CjIZZCqcFlYZeEo=\"\nCors__AllowedOrigins__0=\"\"\nJobs__ScanIntervalInMinutes=50\nGitHub__BaseUrl=\"https://api.github.com\"\n\n# Required\nAPPLICATIONINSIGHTS_CONNECTION_STRING=\u003cyour-azure-application-insights-connection-string\u003e\n```\n\n2. Compile la imagen:\n\n```bash\ndocker buildx build \\\n  --platform linux/amd64 \\\n  -f src/DevHabit.Api/Dockerfile \\\n  --target prod \\\n  -t devhabit.api:latest .\n```\n\n2. Inicie los contenedores:\n\n```bash\ndocker compose up -d\n```\n\n3. Ejecute el contenedor:\n\n```bash\ndocker container run \\\n  -d \\\n  -p 5000:5000 \\\n  --env-file .env.docker-prod \\\n  --network dev-habit_default \\\n  --name devhabit.api \\\n  devhabit.api:latest\n```\n\n## 🧪 Pruebas\n\nEste proyecto incluye pruebas unitarias, de integración y funcionales.\n\n\u003e [!NOTE]\n\u003e Las pruebas se encuentran en el directorio `test/`.\n\n#### Tecnologías utilizadas:\n\n- **xUnit**: Framework de pruebas.\n- **NSubstitute**: Mocking.\n- **Testcontainers**: Pruebas de integración con instancias efímeras de PostgreSQL.\n- **WireMock.Net**: Simulación de APIs externas.\n- **coverlet**: Cobertura de código.\n- **Microsoft.AspNetCore.Mvc.Testing**: Pruebas funcionales de extremo a extremo.\n\n#### Ejecutar todas las pruebas\n\n```bash\ndotnet test\n```\n\n#### Cobertura de código\n\nPara generar un informe de cobertura de código en formato HTML, es necesario instalar [dotnet reportgenerator tool](https://reportgenerator.io/).\n\nPuede instalarla globalmente con el siguiente comando:\n\n```bash\ndotnet tool install -g dotnet-reportgenerator-globaltool\n```\n\nExiste un script auxiliar ubicado en `./scripts/coverage.sh` que automatiza el proceso.\n\nAntes de ejecutar el script, asegúrese de otorgar permisos de ejecución:\n\n```bash\nchmod +x ./scripts/coverage.sh\n```\n\nLuego ejecútelo con argumentos opcionales:\n\n```bash\n./scripts/coverage.sh [output_dir] [verbosity]\n```\n\n- **output_dir**: Directorio donde se guardará el informe (por defecto: `coverage`)\n- **verbosity**: Nivel de detalle del ReportGenerator (por defecto: `Error`)\n\nUna vez ejecutado, el informe HTML estará disponible en:\n\n```bash\n\u003coutput_dir\u003e/index.html\n```\n\n\u003e [!TIP]\n\u003e Si utiliza Windows, puede usar la versión PowerShell del script: `.\\scripts\\coverage.ps1`\n\n## 📘 Documentación de la API\n\nDevHabit API ofrece documentación interactiva a través de Swagger y Scalar, con soporte para endpoints versionados y autenticación JWT.\n\nUna vez la API esté en ejecución:\n\n- **OpenAPI spec (JSON)**: `https://localhost:5001/swagger/1.0/swagger.json`\n- **Swagger UI**: `https://localhost:5001/swagger`\n- **Scalar UI**: `https://localhost:5001/scalar`\n\n\u003e [!NOTE]\n\u003e Reemplace `5001` con el puerto HTTPS correspondiente si utiliza uno distinto.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjaimejaramilloperez%2Fdev-habit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjaimejaramilloperez%2Fdev-habit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjaimejaramilloperez%2Fdev-habit/lists"}