Buscar/Crear módulos .NET con diseño guiado por el dominio (DDD) sin romper capas ni API públicas

Crear módulos .NET con diseño guiado por el dominio (DDD) sin romper capas ni API públicas

Úsalo cuando una IA cambie una aplicación .NET modular con diseño guiado por el dominio. Sigue los patrones existentes, mantiene las capas en un solo sentido, ubica agregados, repositorios y DTO en su capa y prueba en todas las bases de datos sin afectar a los usuarios actuales.

Para usar estas reglas de IA
## Seguir los patrones existentes y mantener las dependencias entre capas en un solo sentido Busque en el repositorio una implementación comparable antes de crear código. Siga la estructura, nomenclatura, dependencias, pruebas y patrones de extensión establecidos, salvo que el cambio solicitado los sustituya expresamente. Mantenga los diffs enfocados; evite cambios incidentales de formato, refactorización o actualización de dependencias. Utilice capas explícitas con dependencias unidireccionales: - **Domain.Shared:** constantes, enumeraciones, recursos de localización, contratos de eventos y tipos compartidos seguros para todas las capas y clientes externos. - **Domain:** entidades, raíces de agregados, contratos de repositorio, servicios de dominio y reglas empresariales. - **Application.Contracts:** interfaces de servicios de aplicación y objetos de transferencia de datos. - **Application:** implementaciones de servicios de aplicación y orquestación de casos de uso. - **Persistence integrations:** contextos, asignaciones e implementaciones de repositorios específicas del proveedor que dependen del dominio. - **HTTP API:** adaptadores de transporte que dependen de los contratos de aplicación, no de las implementaciones. - **Remote client:** proxies generados o escritos a mano que dependen de los contratos de aplicación. - **Web UI:** código de presentación que consume la HTTP API. Mantenga fuera del dominio los aspectos de Web, transporte, contexto de autenticación y ORM. Mantenga la lógica de aplicación independiente de la capa Web. Trate una referencia prohibida como un defecto arquitectónico, aunque acorte una implementación. Conserve las API públicas y los límites de los paquetes. No introduzca un cambio incompatible salvo que se solicite expresamente, esté justificado, tenga una migración y esté cubierto por pruebas de compatibilidad. ## Crear agregados válidos desde el inicio y llevar las reglas entre entidades a servicios de dominio Cree las entidades en la capa de dominio y haga que sean válidas al construirse. El constructor principal debe imponer las invariantes e inicializar todas las colecciones propias. Cuando un ORM lo requiera, proporcione un constructor protegido sin parámetros sin debilitar las reglas normales de creación. Reciba un identificador del llamador en lugar de generarlo dentro de la entidad. Proteja la coherencia mediante setters no públicos y métodos de dominio que expresen su intención. Permita sobrescribir miembros cuando lo requieran el entorno de ejecución, el sistema de proxies o el modelo de extensión compatible. Las raíces de agregados deben utilizar un identificador estable en vez de una clave compuesta, mantenerse pequeñas y referenciar otras raíces mediante su identificador, no mediante una propiedad de navegación. Coloque en un servicio de dominio las reglas entre entidades que pertenezcan al modelo. Cree una interfaz solo cuando varias implementaciones, la sustitución o el aislamiento de pruebas la requieran realmente. Use un sufijo claro orientado al dominio, como `Manager`, acepte objetos de dominio y valores primitivos en vez de DTO, y lance excepciones empresariales localizadas con códigos de error únicos y con espacio de nombres cuando fallen las reglas. Los servicios de dominio pueden realizar búsquedas, normalización, almacenamiento en caché o resolución propios del dominio, pero las consultas sencillas de persistencia pertenecen a los repositorios. No lea el usuario autenticado actual dentro del dominio; pase desde la capa de aplicación los valores necesarios de actor o tenant. ## Crear un repositorio por raíz de agregado, independiente de la base de datos Defina los contratos de repositorio en la capa de dominio, con un contrato dedicado por cada raíz de agregado. No cree repositorios para entidades internas que pertenezcan a un agregado. Mantenga los contratos públicos de repositorio independientes del proveedor. Prefiera capacidades básicas o de solo lectura y no exponga a los consumidores del módulo una abstracción del proveedor de consultas como `IQueryable`. Las implementaciones del proveedor pueden utilizar internamente API de consulta más completas. Haga asíncrona toda operación del repositorio y acepte un token de cancelación opcional. En un método que devuelva un agregado, active por defecto la carga de detalles cuando los llamadores necesiten normalmente el agregado completo. En los métodos de lista, desactívela por defecto para evitar joins y transferencias de datos sin límites. Utilice métodos significativos que devuelvan agregados en lugar de clases de proyección compuestas e improvisadas. Añada métodos específicos de proyección solo cuando lo justifiquen requisitos de rendimiento medidos. Mantenga la lógica de eager loading en un auxiliar `IncludeDetails` específico del proveedor para que los servicios de aplicación no sepan cómo monta el almacén un agregado. Pase los tokens de cancelación por el auxiliar de normalización del framework cuando exista. Asegúrese de que los filtros de datos del proveedor, la tenancy y las reglas de soft-delete permanezcan activos al obtener internamente un queryable. ## Diseñar interfaces de servicios de aplicación con un DTO distinto por operación Coloque en el paquete de contratos una interfaz por servicio de aplicación. Use DTO y valores primitivos en el límite; nunca acepte ni devuelva entidades de dominio. Mantenga los métodos asíncronos, use un sufijo `Async` coherente y evite repetir el nombre de la entidad cuando el contexto del servicio ya sea claro. Use formas CRUD predecibles: mantenga los argumentos identificadores separados de los DTO de actualización; las operaciones de creación y actualización devuelven un DTO detallado cuando sea útil; las eliminaciones no devuelven payload; y las consultas de listas contienen campos opcionales de filtrado, ordenación y paginación con un tamaño máximo de página seguro. Cree un DTO de entrada independiente para cada operación. No reutilice DTO de entrada solo porque los campos coincidan actualmente y evite la herencia entre ellos. Mantenga los DTO libres de lógica empresarial, valídelos en el límite y reutilice constantes compartidas para los límites. Prefiera un DTO de salida básico y una variante detallada frente a muchas formas solapadas. Las implementaciones de aplicación orquestan casos de uso. Deben utilizar repositorios dedicados, cargar los agregados necesarios, llamar a métodos de dominio y persistir explícitamente las actualizaciones en lugar de suponer el change tracking. Mantenga las consultas de datos fuera de los servicios de aplicación. Asigne las propiedades extensibles mediante la convención de mapper compatible. No pase tipos Web, abstracciones de carga ni streams mediante contratos de aplicación. Deje que los adaptadores de transporte conviertan los archivos en una representación estable del nivel de aplicación. Evite llamar a otro servicio de aplicación del mismo módulo; mueva las reglas reutilizables al dominio o a un auxiliar compartido específico. Las llamadas entre módulos deben pasar por los contratos públicos del otro módulo. Permita sobrescribir las operaciones públicas y los auxiliares de extensión previstos. Prefiera puntos de extensión protected frente a auxiliares private cuando la personalización forme parte del contrato del framework. ## Separar el código de cada base de datos y hacer que cada módulo funcione solo Proporcione a cada módulo una interfaz de contexto y una implementación independientes para cada proveedor de persistencia compatible. Exponga sets o colecciones solo para raíces de agregados. Adjunte expresamente el nombre de conexión del módulo, permita configurar los prefijos de tablas o colecciones y reserve los prefijos que pertenecen al framework. No dependa de lazy loading. Configure las asignaciones en una extensión de model builder con nombre, en lugar de llenar el método del ciclo de vida del contexto con detalles de entidades. Aplique la asignación convencional del framework a cada entidad antes de las reglas específicas del módulo. Las implementaciones de repositorio específicas del proveedor deben heredar de su base estándar, utilizar la interfaz de contexto como límite, pasar correctamente los tokens de cancelación e implementar la carga detallada del agregado del modo apropiado. Un almacén documental puede cargar de forma natural las colecciones propias, mientras que un proveedor relacional necesita includes explícitos; ninguna diferencia debe filtrarse al dominio ni al contrato de aplicación. Cada paquete debe exponer una clase de composición del módulo con declaraciones explícitas de dependencias. Registre servicios y opciones durante la configuración; use hooks de inicialización de la aplicación solo para trabajos que necesiten realmente la aplicación en ejecución. Un módulo debe seguir siendo utilizable de forma independiente, sin acoplamiento oculto con otro paquete. Cuando un módulo admita varios proveedores, ejecute el mismo contrato de repositorio y comportamiento para cada integración. La independencia del proveedor es una propiedad probada, no una convención de nombres. ## Añadir puntos de extensión y retirar API antiguas por etapas sin romperlas Diseñe los miembros públicos y protected para el modelo de extensión compatible del framework. Use métodos sobrescribibles, registros de servicios sustituibles, interfaces en puntos reales de sustitución y objetos de opciones para la configuración. Documente los puntos de extensión y las invariantes que deben preservar las implementaciones personalizadas. No elimine ni cambie el nombre de un miembro público sin un ciclo de obsolescencia. Marque el miembro antiguo como obsolete con instrucciones claras de migración, añada parámetros opcionales con valores predeterminados y proporcione implementaciones predeterminadas para los nuevos miembros de clases base siempre que sea posible. Prefiera añadir una interfaz nueva antes que romper una existente. Mantenga las cadenas dirigidas al usuario en recursos de localización pertenecientes al paquete de dominio compartido. Use claves con espacio de nombres y errores empresariales localizados en vez de texto codificado. Defina los nombres de ajustes, funciones y permisos como constantes en su capa propietaria y organícelos bajo espacios de nombres estables del módulo. Use un bus de eventos en proceso para la comunicación dentro de un proceso y un bus de eventos distribuido entre módulos o servicios. Coloque los contratos de eventos distribuidos en el paquete de dominio compartido, manténgalos sencillos y serializables, y use valores primitivos o contratos de eventos anidados en lugar de entidades de dominio. Gestione los eventos de integración en la capa de aplicación. Trate la compatibilidad, la localización y el comportamiento de extensión como superficies públicas del producto. Cubra sus cambios con pruebas específicas y notas de migración. ## Probar cada cambio en todas las bases de datos admitidas y revisar el diff final Antes de un cambio arquitectónico o de contrato público significativo, consiga el acuerdo mediante el proceso de diseño o issues aprobado del proyecto. Mantenga la pull request limitada y revisable, e incluya las pruebas necesarias para demostrar el comportamiento afectado. Use pruebas unitarias para reglas de dominio aisladas y pruebas de integración para repositorios, asignaciones, permisos, validación y composición de módulos. Ejecute todos los proveedores de persistencia compatibles cuando el contrato afirme independencia del proveedor. Nombre las pruebas según la operación, el escenario y el resultado esperado. Compare el diff final con esta lista de comprobación: - La dirección de las dependencias permanece intacta, sin que aspectos Web o de persistencia se filtren hacia dentro. - Las entidades imponen invariantes, las colecciones propias están inicializadas y las referencias a agregados usan identificadores. - Los contratos de repositorio siguen siendo asíncronos, cancelables, centrados en agregados e independientes del proveedor. - Los contratos de aplicación usan DTO mínimos y validados, y formas de métodos estables. - Los servicios de aplicación delegan las consultas en repositorios y las mutaciones en métodos de dominio. - Las integraciones relacionales y documentales siguen sus propias convenciones de asignación y carga de detalles. - Las API públicas, claves de localización, ajustes, funciones, permisos y eventos siguen siendo compatibles. - Las pruebas cubren permisos, validación, casos de fallo, diferencias entre proveedores y condiciones límite. - El diff no contiene refactorizaciones no relacionadas, ediciones de archivos generados ni superficies de API innecesarias. Informe de las comprobaciones específicas ejecutadas y de cualquier ruta de proveedor o compatibilidad que siga sin verificarse. No afirme el cumplimiento arquitectónico basándose únicamente en la compilación.