Resincronización con la plataforma de origen: código y documentación rebrandeados al satélite - #14
Merged
Merged
Conversation
…ndeado al satélite Reemplaza Ums.Domain/Application/Infrastructure/Presentation/ReadModels y sus pruebas por el árbol de la plataforma de origen, aplicando el mapa de marca del satélite: Unimar.Ums -> Ums, Unimar.Shells.Net -> BeyondNetCode.Shell (nuget.org, sin feed privado), inquilino raíz UNIMAR -> BEYONDNET (mismo GUID, que es el que el arnés e2e ya esperaba), prefijo de telemetría unimar. -> evolith. Se preserva lo que es del satélite y no existe en el origen: - Branding por inquilino. La entidad hija vuelve al agregado Tenant (SetBranding, UpdateBranding, VerifyBrandingDns, FailBrandingDns, RemoveBranding), con sus cinco eventos, sus dos códigos de DomainErrors.Tenant y el catálogo DomainErrors.Branding. Se retira la migración DropTenantBrandingTable del origen —este satélite nunca soltó la tabla, que ya la crea InitialPostgresCreate— y se regenera el snapshot de EF: sin cambios pendientes de modelo y sin drop/re-create que destruya datos. - GraphQL. Vuelve HotChocolate al csproj y el cableado al bootstrapper (AddUmsGraphQl + MapGraphQlSurface, sin rate limiter porque el árbol nuevo no registra ninguno). Los resolvers pasan a static: son sin estado y el gate heredado promueve S2325 a error. - Evolith.Contracts.MasterData conserva su namespace a propósito: es el contrato de wire del productor (MMS) y MassTransit enruta por el URN del tipo (ADR-0106). Se retira lo que el diseño nuevo sustituye: Menu/SubMenu/Option (los reemplaza MenuNode), los SchemaBootstrapper de SQLite/PostgreSQL y los umsdev.db (el arranque migra con EF y el proveedor es PostgreSQL), RequestContextAccessor, CorrelationIdMiddleware, el sink y el background service de AuditTrail, RemoveBranch (lo sustituye CloseBranch, ADR-0164), RemoveTemplateItem (DeactivateItem) y PromotionStatus (modelo IGA de madurez de rol). Ums.slnx se va por obsoleto: apuntaba a libs/shell inexistentes. Se corrige un fallo que también está en el origen: faltaba Apply(TemplateAutoAssignedEvent) en ProfileDomainEventsManager, y sin él CreateProfileCommandHandler revienta al auto-asignar plantilla (3 pruebas). Validación: build 0 errores; Domain.Test 930/930; Application.Test 933/934. El fallo restante es del reloj, no del cambio: T12_AuditFields compara DateTime.UtcNow.Date contra un CreatedAt que el paquete externo BeyondNetCode.Shell.Ddd.ValueObjects estampa en hora local, así que falla en la ventana UTC 00:00-05:00 (ahora mismo UTC es 10-ago y Lima 9-ago). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…rma de origen Trae el árbol de libs/sdk rebrandeado: Unimar.Ums.Sdk.* -> Ums.Sdk.*, Unimar.Shells.Net.Aop* -> BeyondNetCode.Shell.Aop* (el namespace del instalador de DI no es el id del paquete: BeyondNetCode.Shell.Aop.DI como paquete, BeyondNetCode.Shell.Aop.Microsoft.Extensions.DependencyInjection.Aspects.Installer como namespace), @unimar-peru/ums-sdk-* -> @ums/sdk-* y <Authors> a BeyondNetCode. Validación: build 0 errores; Ums.Sdk.Tests 53/53. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…rvando Branding y GraphQL Reemplaza src/ y tests/ del web-app por el árbol de origen rebrandeado y vuelve a enganchar lo que es del satélite y el origen no tiene: - BrandingPanel quedaba huérfano tras la sustitución de TenantDetailPanel. Se reintroduce la pestaña «Identidad Visual» de punta a punta: el tipo de pestaña en use-tenant-dashboard, el icono y la etiqueta en el panel, y las claves tabBranding en los dos idiomas. - Se conserva la capa GraphQL (graphqlClient y los módulos *.graphql.ts), que sigue siendo el transporte de lectura de branding.service. Se retiran dos ficheros que quedan sin consumidor porque el árbol nuevo accede a datos por REST: query-transport.service (elegía REST/GraphQL por parámetro) y branding.model (ya estaba muerto antes de este cambio). Los componentes de jerarquía MenuRow/SubMenuRow/OptionRow/ModuleCard se van con el modelo de menú de tres niveles: los sustituye SuiteNode/SuiteNodeTree. Validación: vite build OK; vitest 1697/1697. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… provisioning Trae tests/e2e-functional, infra, provisioning y scripts del origen, rebrandeados: el clúster local pasa a evolith-ums-cluster (kind-evolith-ums-cluster), el host de UAT a evolith-ums-uat.local, unimar-core/unimar_arch a Evolith Core y las credenciales de prueba al inquilino BEYONDNET (beyondnet.com.pe, BeyondNet.Dev.2026). Con esto el arnés y la siembra por fin nombran al mismo inquilino raíz: hasta ahora el arnés ya decía BEYONDNET_TENANT_ID y el seeder seguía sembrando UNIMAR. Se elimina src/Ums.ReadModels: estaba mal ubicado —con rutas anidadas rotas (src/Ums.ReadModels/... y src/Ums/ReadModels/...) que dejó una resincronización anterior— y la solución referencia apps/ums.api/Ums.ReadModels, que es donde el proyecto vive ahora. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…a del satélite La documentación de origen usa taxonomía SDLC (01-concepcion..05-entrega) y la de este repo es bilingüe por dominio. Cada documento se ubica donde le corresponde, rebrandeado; no se importa el árbol de fases. - 02-diseno/dominio/** -> docs/domain-es/** (85 fichas actualizadas). Entra menu-node.md y salen menu/option/sub-menu.md, también del espejo en inglés: describían un modelo que el código ya no tiene. Se conserva identity/branding.md, que es del satélite. - 02-diseno/historias-funcionales/** -> governance/requirements-es/functional-stories, traduciendo el slug español al inglés que ya usa este repo (fs-01-autenticacion-usuario -> fs-01-user-authentication) y manteniendo el número. - 01-concepcion -> governance/product-es (PRD y backlog ágil). - 02-diseno/*.md transversales y detallados -> architecture/*.es.md. - 04-validacion/plan-e2e-fase1-autenticacion -> qa/phase1-authentication-e2e-plan.es.md. FS-25, FS-26 y FS-27 colisionaban: el código resincronizado usa FS-25 para el dataset semilla y FS-26 para el Admin Root, así que las tres historias propias de este repo se renumeran a FS-38 (jerarquía DDD), FS-39 (preview del grafo) y FS-40 (broken rules), con sus referencias e índices al día. Sus variantes .es.md se mueven a requirements-es, que es donde toca. Las fichas de dominio nuevas y las historias FS-25/26/36/37 llegan solo en español; los índices en inglés las enlazan marcadas como tal. La traducción queda pendiente. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
| 'Content-Type': 'application/json', | ||
| ...(portador ? { Authorization: `Bearer ${portador}` } : {}), | ||
| }, | ||
| body: cuerpo === undefined ? undefined : JSON.stringify(cuerpo), |
| ...(cookie ? { Cookie: cookie } : {}), | ||
| Accept: 'application/json', | ||
| }, | ||
| body: cuerpo ? JSON.stringify(cuerpo) : undefined, |
| * fallos de carga y mentía sobre qué se había cargado. Se espera lo que la propia respuesta pide. | ||
| */ | ||
| async function api(metodo, ruta, cuerpo, intento = 0) { | ||
| const res = await fetch(`${URL_BASE}${ruta}`, { |
There was a problem hiding this comment.
CodeQL found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.
- npm audit (high): el lockfile del origen arrastra nanoid 3.3.16 vía @vitejs/plugin-react -> vite -> postcss, afectado por GHSA-2v37-7h3g-55p8 (bucle infinito con size 0). Se fija override "nanoid": "3.3.17", versión exacta como el resto. El lock se actualiza en sitio (--package-lock-only, 3 líneas), no se regenera: regenerarlo desde cero en este monorepo deja fuera dependencias transitivas. `npm audit --omit=dev --audit-level=high` pasa a 0. - Sensitive Information Scan: el escáner busca `password\s*[:=]\s*['"]` en docs/ y el ejemplo de e2e-sdlc-dashboard-integration-analysis.es.md casaba con un placeholder ya redactado (`password:'…'`). Se sustituye por `<omitido>`, que dice lo mismo sin parecer un literal. Validación: vite build OK; vitest 1697/1697. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Los cuatro fallan por bugs propios del workflow, no por hallazgos. Dos de ellos (npm audit y hadolint) llevan `if: github.event_name == 'pull_request'` y en los push a main salen `skipped`, así que se ejecutaron por primera vez en este PR y salieron rotos de fábrica. security.yml - npm Vulnerability Audit: `npm ci` moría con ENOENT buscando un package.json en la raíz. El workspace npm/nx vive bajo src/. Se añade el mismo `defaults.run.working-directory: src` que ya usa ci.yml, con node 22 (React Router v8 exige >=22, el NODE_VERSION global es 20) y cache sobre src/package-lock.json. La auditoría pasa a `--omit=dev` por la razón que ci.yml ya documenta: se audita lo que se despliega; las high restantes son de tooling de build y no llegan al runtime. - Docker Image Security Scan: `hadolint/hadolint-action@v3` no es un tag que exista y el job moría en «Set up job». Se fija a v3.3.0. Además apuntaba a un Dockerfile en la raíz que no hay: el `if [ -f "Dockerfile" ]` nunca se cumplía, no se construía imagen y Trivy escaneaba una referencia inexistente (lo tapaba su continue-on-error). Ahora apunta a src/apps/ums.api/Dockerfile y construye con contexto src/, que es lo que el grafo de proyectos necesita. docs-quality.yml - Mermaid Diagram Syntax: `grep -r "```mermaid"` entre comillas dobles abre una sustitución de comandos y el paso moría con «unexpected EOF while looking for matching `». Se pasa a comillas simples y se añade `|| true` para el caso sin coincidencias, que en grep es salida 1 y bajo `bash -e` tumbaba el paso igual. - Check for TODO/demo references: buscaba la palabra suelta en todo docs/, así que disparaba sobre prosa española («TODOS los perfiles») y sobre los documentos que hablan DE los marcadores —el registro de deuda técnica, el TODO del proyecto que es su inventario, las actas de release—. Cumplirlo exigía borrar el inventario de deuda para poder publicar documentación. Ahora busca el marcador (`TODO:`, `TODO(`, `FIXME`, `HACK:`, `DEMO`), excluye esos documentos meta y vacía los code spans antes de comparar: citar `TODO(G-069)` para explicar dónde está la deuda no es tener deuda. Verificado en local: los dos YAML parsean, la extracción de mermaid produce 7095 bloques sin reventar, el check de TODO queda limpio y `npm audit --omit=dev --audit-level=high` da 0 vulnerabilidades. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…l web-app - security.yml: el job de Docker seguía muriendo en «Set up job», ahora por `github/codeql-action/upload-security-results@v2`, que no existe. La acción real es `upload-sarif`, y v2 está retirada. Se pasa a v3 y se sube solo si Trivy llegó a escribir el fichero, en vez de fallar el paso. - web-app: se aplica `eslint --fix` y `prettier --write` sobre el árbol importado (45 ficheros). Baja de 858 a 645 hallazgos; lo corregido es formato y arreglos automáticos, sin cambios de comportamiento. Validación: vite build OK; vitest 1697/1697. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool. What Enabling Code Scanning Means:
For more information about GitHub Code Scanning, check out the documentation. |
…rbol importado
Primer tramo de la limpieza de lint sobre el código traído en la resincronización:
598 -> 372 errores. Todo es código inerte; no hay cambios de comportamiento.
- Imports sin usar: se quitan los especificadores que nadie referencia y las
sentencias que quedan vacías.
- Bindings sin usar: propiedades de desestructuración que nadie lee y `const`
cuyo valor no se consume. Solo se borran cuando el inicializador no encierra
llamadas; los que sí las tenían se revisaron uno a uno para confirmar que la
llamada es una consulta pura (useI18n, useQueryClient, getActionState) antes de
retirarla.
- Casos con criterio: `PaginationControls` declaraba estado de colapso en el
componente que no lo pinta (lo usa el segundo del fichero); `DataViewShell`
destructuraba los manejadores de un splitter horizontal que no monta;
`ParameterCatalogScreen` construía tres catálogos de opciones que ninguna vista
consume; el test del esquema de auditoría usaba el idioma
`const { x: _omitted, ...resto }` y ahora omite la clave sin dejar un binding
muerto.
Validación: tsc sin errores; vite build OK; vitest 1697/1697.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… switch
Segundo tramo de la limpieza de lint: 372 -> 237 errores.
- `as any` en mocks de test (64 casos) pasa a `as unknown as ReturnType<typeof X>`:
un mock parcial sigue siendo parcial, pero deja de apagar el comprobador de tipos
en todo lo que toque ese valor.
- `console.info/warn` (19) pasa al `logger` del repo. El helper de limpieza de
Playwright conserva `console` con un disable justificado: corre en Node y su
salida ES el diagnóstico, igual que utils/logger.ts.
- Bloques `catch {}` vacíos (8): se documenta por qué se traga el error. Son dos
motivos distintos —logout best-effort y sessionStorage que puede lanzar en modo
privado— frente a los formularios, donde el error ya lo notifica la mutación.
- `switch` de login: los `case` llamaban a `fail()` sin `break`. `fail` devuelve
`never`, así que la caída era inalcanzable y no había bug, pero solo lo sabía
quien mirara la firma. Ahora es `return fail(...)`.
- `case` con `const`/`let` sin acotar (6): se cierra el bloque para que no se
filtren al resto del switch.
- `void mutation.mutate(...)`: el `void` sobraba porque `mutate` ya devuelve void.
En TenantSignupRequestsPanel sí tapaba una promesa al aire (`mutateAsync`); se
cambia a `mutate`, la variante fire-and-forget que usan los demás paneles.
- Arreglos con criterio: `setApiHeaderProvider` acepta `null` en su firma —el
módulo ya lo contemplaba y solo el tipo lo prohibía—; el test de M3Card usa
`createRef<HTMLDivElement>` en vez de un objeto suelto; se extrae el tipo
`ViewMode`, que estaba repetido en seis sitios; y el panel de permisos de módulo
descarta 'thumbnail' con una guarda explicada en vez de forzar el tipo.
- `httpClient`: la cascada de ternarios que sacaba el mensaje de error se convierte
en `extractErrorMessage`, que recorre las claves por orden de preferencia.
Validación: tsc sin errores; vite build OK; vitest 1697/1697.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ción Tercer tramo: 237 -> 198 errores. Las cascadas de ternarios anidados se sustituyen por tablas con nombre, que es donde ya vivía la decisión, solo que repartida. - `logger`: el nivel elige el canal de consola. Se resuelve como `console[level]` en la llamada, no al importar: capturar la referencia antes dejaba fuera los espías que instalan las pruebas (lo comprobó el primer intento, que las rompió). - `PermissionTemplateDetailPanel` y `NodeDetailPanel`: icono, color, etiqueta y frase explicativa de cada estado efectivo pasan a una tabla por estado. Estaban en cuatro cascadas por componente, y había que leerlas enteras para saber de qué color se pinta un «Partial». - `SystemSuiteDomainResourcesPanel`: misma idea para agregado / entidad / método de dominio. Además, la cadena de ternarios que elegía cuerpo dentro del JSX se convierte en un `bodyState` con nombre y cuatro bloques independientes. - `M3TextField`: la densidad deja de deducirse cuatro veces y se decide una vez (`resolveDensity`), con tablas para altura y espaciado. Las matrices foco/error de borde y color de etiqueta pasan a funciones con retorno temprano. Validación: tsc sin errores; vite build OK; vitest 1697/1697. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
| @@ -0,0 +1,58 @@ | |||
| import { test, expect } from '@playwright/test'; | |||
| import { PaginaDeAcceso } from '../paginas/acceso.pagina'; | |||
| import { TABLERO, USUARIOS, claveDe, exigirIdentidadConfigurada } from '../fixtures/entorno'; | |||
…ffect y las credenciales dev 198 -> 175 errores. Los dos grupos que no se arreglan reescribiendo código, porque el código ya dice lo que quiere decir. - `react-hooks/set-state-in-effect` (17 sitios, 15 ficheros): son patrones deliberados del árbol importado —selección inicial cuando la lista llega del servidor, sincronización del formulario con la entidad en edición, reinicio al cerrar un diálogo, carga al montar, cierre del cajón al pasar a escritorio, y el temporizador de bloqueo del login—. Cada fichero lleva su propio motivo, no uno genérico. La regla sigue activa en el resto del repositorio. Mismo criterio que el resync anterior (81ed609). - `sonarjs/no-hardcoded-passwords` (6): son las DEV_PERSONAS que siembra CoreDevDataSeeder (FS-25 §4.4) y que el popup «Datos de prueba» publica en pantalla. Ahí la credencial ES el dato: moverla a variables de entorno no ocultaría nada —la UI la enseña— y rompería la funcionalidad. El disable se acota al array, no al fichero. Validación: tsc sin errores; vite build OK; vitest 1697/1697. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… cascadas de ternarios 175 -> 145 errores. - Nuevo `shared/components/field-state.ts`: la matriz foco/error del borde y del color de etiqueta estaba duplicada en M3TextField, M3Select, M3FieldsetWrapper y SearchableSelect, cuatro veces la misma cascada. Ahora la regla se lee una vez: el foco manda en el grosor, el error manda en el color. - `IdpPanel`: el botón de activar/desactivar tiene TRES estados, no dos —en modo Local la activación está bloqueada—, y eso se colaba como primera rama de dos cascadas distintas (tooltip y clases). Ahora hay un `idpToggleState` con nombre y una tabla. El filtro y la ordenación pasan a funciones; la cadena del cuerpo, a bloques independientes. - `ApiErrorBanner`: icono, título y pista se decidían por separado sobre los mismos dos booleanos. Ahora hay un `ApiErrorKind` y una tabla por clase de error. - `TreeNode`: icono y color por estado, misma tabla que ya usa NodeDetailPanel. - `ProfileForm`: el efecto del permiso y las etiquetas de los selects pasan a funciones con retorno temprano (`pickLabel` deja escrito que bloqueado gana sobre cargando, porque sin el prerequisito no hay nada que cargar), y el cuerpo del árbol se parte en bloques. Validación: tsc sin errores; vite build OK; vitest 1697/1697. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
145 -> 104 errores. `@typescript-eslint/no-explicit-any` queda a cero. - Decoradores (`RequireOption`, `RequirePermission`): `target` no se usa en el cuerpo, así que pasa a `_target: unknown`; los argumentos se reenvían tal cual con `apply`, así que `unknown[]` es exactamente lo que se sabe de ellos. - `catch (err: any)` (5 sitios) pasa a `unknown`, que es lo que un catch debe recibir. El acceso al cuerpo del error va por `asApiError`, nuevo en httpClient: no valida nada —el error viene de la red y puede ser cualquier cosa— sino que da acceso tipado a los sitios donde tiene sentido mirar (`normalised`, `response.data`, `message`). - Mocks y stubs de test (32): selectores de store, variables de mutación, colecciones y stubs de componentes quedan tipados. Un mock parcial sigue siendo parcial, pero deja de apagar el comprobador en todo lo que toque. Validación: tsc sin errores; vite build OK; vitest 1697/1697. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
104 -> 82 errores. - `todo-tag`: tres de los seis eran falsos positivos sobre la palabra española «todo» en prosa («por todo el subárbol», «en todo src/»); se reescribe la frase. Los otros tres eran marcadores reales en specs de Playwright ya saltadas: el motivo pasa al propio `test.skip(true, '…')`, que es donde un lector lo va a buscar. - `no-clear-text-protocols` (6): las URLs `http://` de security.test SON la entrada bajo prueba —se comprueba que se rechacen direcciones privadas y de loopback—; escribirlas en https no probaría nada. Disable acotado al fichero con esa razón. - `use-type-alias` (5): uniones repetidas que ganan nombre (`DateLike`, `ConsoleTab`, `DomainResourceType`, `UserCategory`). - Regex: se quita un escape inútil dentro de una clase de caracteres, `[A-Za-z0-9_]` pasa a `\w`, y el patrón de email acota sus cuantificadores (con `+` sin techo, una cadena larga sin arroba hace retroceder al motor de forma cuadrática; 254 es el máximo por RFC 5321). - `pseudo-random`: el token de una corrida e2e pasa a `crypto.randomUUID`. - `assertions-in-tests`: el test «auto-selects first suite» renderizaba el hook y no afirmaba nada, pese a que su nombre prometía la comprobación. Ahora comprueba que la suite seleccionada es la primera de la lista sembrada; pasa. - `AccessGuard`: las dos últimas puertas eran ramas de un if/else con cuerpos idénticos. Las cuatro comprobaciones pasan a una conjunción, que se lee de una vez y cortocircuita igual. Validación: tsc sin errores; vite build OK; vitest 1697/1697. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… guardas 82 -> 67 errores. La transformación preserva el orden de evaluación —cada rama lleva la negación de todas las anteriores, que es lo que hacía el ternario— y es segura porque las ramas son elementos JSX: nunca 0 ni cadena vacía, así que `&&` no puede renderizar un valor falsy por accidente. Las negaciones invierten el comparador (`length !== 0`) en vez de envolver en `!(...)`, que es lo que pide sonarjs/no-inverted-boolean-check. Se aplicó fichero a fichero con `tsc` como puerta: cuatro casos con JSX más enrevesado no sobrevivieron a la transformación automática y quedaron intactos para tratarlos a mano. Validación: tsc sin errores; vite build OK; vitest 1697/1697. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…o supo transformar
67 -> 63 errores.
- `M3AuthorizationGraphPanel` y `M3DataView`: cadenas cargando/error/vacío/contenido que pasan a
bloques con guardas.
- `AppConfigurationDetailPanel`: la cadena vivía dentro de un `content={...}`, que espera UN
valor y no admite guardas con `&&`. Se extrae a `renderValue()` con retornos tempranos, y de
paso queda escrito que «cifrado» gana sobre los otros dos estados.
- `SearchableSelect`: la lista desplegable tenía cuatro ramas (cargando, vacío, agrupado, plano).
- `M3DataView` además saca el aspecto de la píldora del splitter a una tabla: arrastrando gana
sobre plegado, que antes había que deducir del orden de los ternarios.
Validación: tsc sin errores; vite build OK; vitest 1697/1697.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…presiones 63 -> 48 errores. Mismo criterio que en los tramos anteriores: la decisión pasa a una tabla o a una función con nombre, en vez de deducirse del orden de los ternarios. - `ConfirmDialog`: clases de botón e icono por variante, con `primary` cayendo en los valores por defecto en vez de ser la última rama. - `ProfileSystemActionsPanel`: icono, color y etiqueta de cada estado de acción. - `BrandingPanel`: mensaje por estado de verificación DNS. - `FeatureFlagDetailPanel`: icono por estado de la bandera. - `DomainResourcesPanel` y `ProfileDomainResourcesPanel`: `nodeTypeLabel` (para un CRUD la etiqueta es el verbo; para un método, una marca fija) y `ExpandChevron`, que saca el ternario anidado del JSX del árbol. - `PermissionTemplateForm` y `ParameterDefinitionPickerDialog`: etiquetas por estado, con el orden explicado —bloqueado gana sobre cargando porque sin suite no hay roles que traer—. - `DataList`: `viewMode === 'list' || !renderThumbnail` dice de una vez lo que el ternario anidado repartía en dos ramas con el mismo cuerpo. Validación: tsc sin errores; vite build OK; vitest 1697/1697. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…atro niveles 48 -> 39 errores. - Bandejas de solicitudes (perfil, alta de inquilino, alta de usuario): el manejador que despliega una fila se declaraba dentro del `map`, dejando cinco funciones anidadas (render -> map -> onToggle -> actualizador de estado). Sube a un `useCallback` del componente: no necesitaba el cierre del map, le bastaba el id. - `ToastQueue`: los actualizadores del estado de la cola pasan a funciones de módulo (`marcarSaliente`, `quitarPorId`). Estaban dentro de un efecto y de un temporizador, y el `map`/`filter` de dentro sumaba el quinto nivel. Validación: vite build OK; vitest 1697/1697. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
39 -> 28 errores. Estas no eran cuestión de estilo. - `useQueryClient()` dentro de un try/catch en dos hooks: es una llamada CONDICIONAL a un hook (rules-of-hooks). El helper de react-query lanza cuando no hay proveedor, y el try/catch quería tolerar justo eso —montarse en una prueba sin QueryClientProvider—. Se lee el contexto directo con `useContext(QueryClientContext)`, que devuelve undefined sin proveedor y se llama siempre, en el mismo orden. - `useSessionMonitor` leía `Date.now()` durante el render. No lo importa nadie: era código muerto, y se elimina en vez de arreglarse. - `ParameterDefinitionPickerDialog`: el efecto llamaba a `loadParameters` antes de su declaración. La declaración sube. - `LoginScreen`: el bloqueo por intentos fallidos no contaba atrás. El efecto solo corría al CAMBIAR `lockoutUntil`, así que escribía «Espere N segundos» una vez, el número se quedaba congelado y el desbloqueo dependía de que algo ajeno provocara un render. Ahora hay un intervalo de verdad, y `isLocked` sale de estado en vez de leer el reloj en render. Además se recoloca `renderValue` en `AppConfigurationDetailPanel`: al extraerlo en el tramo anterior quedó DENTRO del guard `if (!config)`, y la línea que lo usa vive fuera de ese alcance. Habría sido un ReferenceError en cuanto se abriera el panel. Ni el build ni las pruebas lo detectaron; ver el gap del typecheck. Validación: vite build OK; vitest 1697/1697. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
28 -> 16 errores. `sonarjs/no-nested-conditional` queda a cero. - `PermissionTemplateDetailPanel`: estado efectivo del recurso, píldora de color por tipo de nodo y frase explicativa pasan a funciones y tablas. Además `const Icon = getIcon()` creaba un tipo de componente nuevo en cada render y React remontaba el subárbol (react-hooks/static-components); ahora se indexa una tabla externa. De paso se ve que `getIcon` devolvía `Component` en dos de sus tres ramas. - `ProfileDetailPanel`: `targetLabel` deja escrito que el backend manda '-' o '—' cuando no hay nombre, y que para una suite se cae al nombre de la suite cargada. - `TenantSelect` pasa a usar el `resolveBorderClass` compartido; `EntityRow` saca fondo y borde de la fila a una tabla (seleccionada gana sobre interactiva). - `LoginScreen` y `BranchManager`: cadenas JSX a bloques con guardas. - `DataGrid`: `cellPaddingClass` explica que la primera columna de una fila hija se sangra para marcar jerarquía y que, si no, manda la clase de la columna. Validación: vite build OK; vitest 1697/1697. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
16 -> 13 errores. - `asHttpError` (complejidad 33, la peor del repo) repetía a mano la misma comprobación `typeof x === 'string' ? x : undefined` una vez por campo. Se extraen `str`, `num` y `asErrorData`, y el caso «no hay response» sale por retorno temprano en vez de anidar. - La búsqueda de una opción en el grafo de autorización estaba escrita DOS veces —en `use-access-resolution` y en el decorador `RequireAccess`— con cuatro bucles anidados cada una. Pasa a `authorization/utils/graph-lookup`, que además deja escrito el porqué de la parte que no se ve: `menuCode` puede nombrar un menú o directamente un submenú, porque quien declara un guard no siempre sabe a qué nivel colgó la opción en la suite. Validación: vite build OK; vitest 1697/1697 (incluidas las 23 de http-error y las 7 de use-access-resolution, que cubren estos dos cambios). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
13 -> 10 errores. - `graphqlClient`: la construcción de cabeceras y la traducción de una respuesta no-ok a su excepción salen a `buildHeaders` y `throwForResponse`. Esta última deja escrito por qué 502/503/0 se distinguen del resto: significan «el backend no está», no «la petición está mal», y quien los captura arriba enseña otro mensaje. - `computeNodeState` (en los dos árboles de recursos): el recuento recursivo sale a `countEffects` y el caso hoja a `resolveLeafState`. Queda escrito el criterio que antes había que deducir: con reglas de un solo signo el nodo hereda ese signo si él mismo la lleva; si la traen solo sus hijos, es «parcial» porque no está decidido a su nivel. Validación: vite build OK; vitest 1697/1697. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
10 -> 4 errores. - `auth.service.login`: la traducción de una respuesta fallida al error que ve quien entra sale a `throwLoginError`, con los mensajes por código en una tabla. Queda escrito por qué el `supportReferenceId` viaja con el error: es lo único que permite cruzar una queja de usuario con la traza del servidor. - `buildQueryString`: los nueve `if (params.x) p.set(...)` idénticos pasan a un recorrido sobre la lista de claves opcionales; la paginación sigue aparte porque siempre va, con sus valores por defecto. - `ProfileForm.handleSave`: la cadena de cinco validaciones sale a `primerCampoQueFalta`, y se deja escrito que el ORDEN importa —es el del formulario, así que el mensaje señala el primer hueco que quien rellena se va a encontrar—. - `computeNodeState`/`computeEffectiveState` en los árboles de navegación y de permisos: misma descomposición que en los de recursos. - `use-local-overrides`: el memo escribía una ref durante el render. No hacía falta: el dueño del snapshot es `patchItem`/`patchItems`, que lo guardan ANTES de crear el override, así que cuando el memo ve un patch el original ya está registrado. Validación: vite build OK; vitest 1697/1697. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
4 -> 0 errores. El lint del web-app queda limpio: 598 -> 0. - `M3TextField`: las ocho medidas del campo salían de dos banderas y cada una releía `dense` por su cuenta; ahora se resuelven de una vez en `resolveMetrics`. Las clases del <input> y la decisión de flotar la etiqueta salen del cuerpo del componente, esta última con el porqué escrito: los tipos fecha/hora flotan siempre porque el navegador ya pinta su propio texto y una etiqueta centrada se solaparía. - `M3DataView`: textos y clases del plegado y del arrastre pasan a dos tablas. `zoneClasses` deja dicho que sin altura fija el contenido desborda A PROPÓSITO —los desplegables tienen que poder salirse— y que mientras se arrastra no se anima porque la transición pelearía con el puntero. - `ProfileForm.handleSave`: el cuerpo del bucle que sincroniza cada permiso sale a `aplicarAjustesLocales`, que además explica por qué se salta lo que no tiene contraparte: sin el permiso guardado y sin el ítem de plantilla no hay nada contra qué comparar. - `PermissionTemplateDetailPanel`: la cabecera pasa a componente propio. Sus condicionales —qué botón se ve en cada estado y el paso de confirmación de borrado— eran la mitad de la complejidad del panel. Validación: vite build OK; vitest 1697/1697. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…robado nada `tsconfig.app.json` y `tsconfig.node.json` declaran `tsBuildInfoFile` sin `incremental`, que es un ERROR de configuración (TS5111): tsc lo reporta y sale ANTES de comprobar tipos. Un identificador inexistente pasa sin queja y con salida 0. Salió a la luz durante la resincronización: un import de `useCallback` omitido en tres componentes pasó el «typecheck» y lo cazó vitest en tiempo de render; un segundo caso —un helper extraído dentro del guard `if (!config)` mientras su consumidor vivía fuera— pasó también el build y habría sido un ReferenceError al abrir el panel. No es una regresión: la plataforma de origen tiene el mismo tsconfig y, por tanto, los mismos errores ocultos. Al habilitar `incremental` afloran 545 errores de tipos preexistentes, entre ellos un desajuste entre el esquema del grafo de autorización (`nodes`) y sus consumidores (`menus`), que es la ruta que decide lo que un usuario puede ver. No se arregla en este PR: meter 545 errores dentro de la resincronización los enterraría. El arreglo es una línea; el trabajo es el backlog que hay detrás. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…an en claro CodeQL levanta tres alertas de severidad alta en la resincronización. Dos no son accionables —una clave RSA de 1024 bits generada A PROPÓSITO por un test que comprueba que el SDK la descarta, y un claim que sí gobierna una decisión de autorización pero sobre un token cuya firma se verifica antes—. La tercera es real. `SimulatedNotificationAdapter` es la ÚNICA implementación de `INotificationService` y se registra sin ninguna guarda de entorno, escribiendo el cuerpo completo de cada notificación en `LogInformation`. Esos cuerpos llevan enlaces de restablecimiento de contraseña y tokens de aprobación: en el log son credenciales que funcionan, durante todo el tiempo de retención. Viene de la plataforma de origen, no de este cambio. Se registra en vez de arreglarse aquí porque el arreglo completo exige decidir qué pasa fuera de desarrollo, donde hoy no hay adaptador real que entregue nada. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…la app no arrancaba Regresión que introduje en 8a9de0c al hacer `static` los 39 resolvers para satisfacer S2325. HotChocolate descubre los campos de un `[ExtendObjectType]` por reflexión sobre los métodos de INSTANCIA del tipo. En static son invisibles para esa reflexión: el tipo `Query` se queda sin un solo campo y el esquema no compila —«The object type `Query` has to at least define one field in order to be valid»—. Como el esquema se construye al arrancar, la aplicación NO LEVANTA. Se manifestó en CI de la forma más cara posible: 229 de 316 pruebas de integración en rojo, no porque fallara ninguna aserción sino porque el host no llegaba a estar en pie. Yo no había ejecutado esa suite en local, solo Domain, Application y SDK; el hueco era mío. S2325 deja de gatearse bajo `Ums.Presentation/GraphQL` mediante una sección de .editorconfig que explica por qué: el analizador tiene razón sobre el lenguaje —los resolvers no usan estado de instancia— y se equivoca sobre el framework. Validación: build 0 errores; ContractTest 37/38. El fallo restante (`VerifyAllPacts_ForUmsWebApp`) es deuda heredada: la plataforma de origen falla exactamente la misma prueba, con las mismas dos discrepancias (falta `status`/`title` en la respuesta de error y un 404 donde el pacto espera 400). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…índice de BoundedContext Cierra los 6 fallos de integración que quedaban. Los dos son consecuencias del rebranding que no se ven leyendo el diff. 1) `BeyondNetCode.Shell.Factory` NO es equivalente a `Unimar.Shells.Net.Factory`. El mapeo de paquetes 1:1 asumió que sí. No lo es: el ensamblado de origen lleva lambdas `<AddTransient>b__3_0` / `<AddSingleton>b__2_0` que el de BeyondNetCode no tiene, y que registran además el TIPO CONCRETO. Aquí solo quedaba registrada la interfaz, así que en cuanto la factoría elegía una rama y pedía la implementación al contenedor, reventaba con «No service for type '...Strategy' has been registered» —mapeado a 400 por el manejador global—. Se registran los 23 tipos concretos explícitamente, que funciona con cualquiera de los dos shells y no depende de un comportamiento no documentado. Afectaba a aprobaciones (creación manual y auto-aprobada), reglas de notificación y resolución de IdP: cuatro caminos de negocio caídos, no un detalle de pruebas. 2) `UmsSerilogLogger.BoundedContext` leía el 4.º segmento del namespace. Al pasar de `Unimar.Ums.Application.X` a `Ums.Application.X` el namespace perdió un segmento, así que ese índice devolvía el SIGUIENTE: «Tenant» en vez de «Identity», «FeatureFlag» en vez de «Configuration». El script de rebranding incluso reescribió el comentario que lo explicaba, dejándolo coherente en apariencia. Cada traza de la aplicación salía etiquetada con el contexto acotado equivocado. Validación: build 0 errores; IntegrationTest 314/316 (2 omitidas), antes 229 en rojo. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ación en ejecución Al levantar la API contra una base PostgreSQL limpia para comprobar el funcionamiento real —no solo que compila— aparecieron dos defectos heredados que ningún pipeline toca: TD-006: `UpdatePostgresMassTransitOutbox` usa `gen_random_bytes` (pgcrypto) y la migración que declara la extensión va DESPUÉS. Sobre una base vacía el migrador aborta con 42883 y la API no llega a arrancar. No se nota porque los entornos existentes ya tienen la extensión y las suites usan el proveedor InMemory: ningún pipeline migra jamás un PostgreSQL vacío. TD-007: la cadena de conexión de desarrollo apunta al puerto 5433 y el compose publica el 5432; las contraseñas tampoco coinciden. El camino documentado «levanta el stack local y arranca la API» no funciona tal como está escrito. Ambos son idénticos en la plataforma de origen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…o en inglés Ambos ADR se citaban desde más de quince documentos como decisiones aceptadas y no existían como ficheros —tampoco en la plataforma de origen—, así que esas citas no tenían destino. Se redactan a partir del código que ya los implementa y de las propias citas, en versión bilingüe, y se registran en los dos índices. - **ADR-0090** (árbol recursivo `MenuNode`): documenta por qué se retiró la cadena rígida de cuatro niveles —un submenú obligatorio que había que inventar, funcionalidad↔opción 1:1 sin clave ajena, cero metadatos de gobernanza por nodo, y tres entidades para un solo concepto recursivo— y qué se paga a cambio: el árbol se reconstruye en memoria al cargar, y la recursión admite ciclos que una cadena fija no permitía. - **ADR-0164** (cierre terminal de sucursal): documenta las tres cosas que estaban mal en `RemoveBranch` —huérfanos silenciosos porque `Profiles.BranchId` y `UserAccounts.BranchId` no tienen clave ajena, un pasado que dejaba de ser explicable, y un código de sucursal liberado que volvía ambigua cualquier consulta histórica— y lo que cuesta: la colección crece de forma monótona y las lecturas tienen que acordarse de filtrar `!IsClosed`. Además se corrige el espejo inglés de `domain/`, que seguía describiendo como vigente lo que ya no existe: `Menu`/`SubMenu`/`Option` en los índices y en las reglas de consistencia, `RemoveBranch` en el agregado Tenant y en el registro de broken rules, y `RemoveTemplateItemCommand` en las plantillas de permisos —donde además el nombre documentado del sustituto estaba mal: es `DeactivateTemplateItemCommand`, no `DeactivateItemCommand`—. La nota sobre el modo de consulta de EF Core deja de justificarse por SQLite, que ya no se usa. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…l servidor ya no envía `hasMenuAccess`, `hasOptionAccess` y el decorador `RequireAccess` recorrían `menuAccess[].menus[].subMenus[].options[]`. El contrato v2.0.0 (`@ums/sdk-contracts`, `MenuModule.nodes`; y su gemelo .NET `AuthorizationGraph.cs`) es un árbol RECURSIVO de `NavigationNode` con `children` y `actions`, y `MenuModule` NO tiene `menus`. Contra un grafo real esas lecturas daban `undefined`: los guards de menú y de opción no concedían ni denegaban, fallaban. La prueba que cubría esto no lo detectaba porque su fixture usaba la MISMA forma retirada que el código. Confirmaba el error en vez de encontrarlo. Ahora el fixture es el contrato real, con `nodes`/`children`/`actions`. Se preserva la semántica que tenía el modelo retirado: `optionCode` casa contra el código del nodo O contra el de una de sus acciones —quien declara un guard nombra «la opción», y en la suite eso podía ser cualquiera de las dos—, y el primer parámetro acota a un subárbol, que ahora puede ser cualquier ancestro porque la profundidad dejó de ser fija. Es deuda heredada: la plataforma de origen lee `mod.menus` igual. Es exactamente el desajuste que TD-004 anticipaba —«el esquema del grafo (`nodes`) y sus consumidores (`menus`) han derivado»— y que el typecheck apagado no podía señalar. Validación: lint 0 errores; vite build OK; vitest 1697/1697 en tres corridas seguidas. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…rbol recursivo La documentación describía `menuAccess[].menus[].subMenus[].options[]` con un efecto por opción. El contrato real —v2.0.0, ADR-0090, en los dos SDK— es `menuAccess[].nodes[]`: un árbol recursivo de `NavigationNode` con `children` y una lista de `actions` por nodo. `MenuModule` no tiene `menus`. Es la misma forma retirada que leía el código del web-app (arreglada en el commit anterior), así que la documentación llevaba a escribir consumidores rotos. Se corrigen, en versión bilingüe: el esquema del SDK de contratos, el README del SDK .NET, y los diagramas de árbol y los ejemplos JSON de la ficha `auth-graph` del dominio. Queda escrito lo que antes había que descubrir leyendo el emisor: que `kind` clasifica el papel del nodo sin fijar su profundidad, que hay que recorrer `children` hasta agotarlo, y que solo viaja lo alcanzable —la ausencia significa «no concedido», no «error»—. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ta lo nuevo
- **Persistencia**: la referencia aplicada del API .NET decía «baseline SQL Server y soporte
SQLite local»; es PostgreSQL como único proveedor relacional (ADR-0082), con el esquema
aplicado por migraciones de EF. El patrón que `shell-libraries/bootstrapper` recomendaba
—encadenar `SqlServerSchemaBootstrapper`— está retirado con los propios bootstrappers; se
sustituye por lo que UMS hace de verdad (`Database.MigrateAsync`) y se deja dicho dónde el
patrón Bootstrapper sí se gana su sitio: en la composición de servicios, no en el esquema.
- **`governance/architecture{,-es}/persistence-phase1/`** (18 ficheros) se marca como histórico.
Es el análisis de una fase cerrada, escrito cuando SQL Server era la línea base supuesta;
vale por el razonamiento, no como estado actual.
- **Transporte de consultas**: `FRONTEND_CONFIG_TRANSPORT` se marca retirado en el catálogo de
parámetros, y TD-002 se reescribe: su *workaround* era precisamente ese flag, que ya no
existe, así que la deuda pasa de «tiene solución conocida» a «hay que volver a medirla» —y se
dice que si ya no reproduce, lo correcto es cerrarla, porque arrastrar un fantasma es peor que
no arrastrar nada—. Las notas que llamaban «transitorio» al REST-only dejan de hacerlo.
- **`PromotionStatus` → `RolePromotionStatus`** en las fichas IGA y en el contexto DDD.
- **Artefactos nuevos documentados** en la referencia React aplicada, biling��e: `field-state`,
`graph-lookup` y `asApiError`/`NormalisedApiError`, cada uno con la razón por la que existe.
- El árbol de ficheros de `overview.es.md` listaba `menu.md`, `sub-menu.md` y `option.md`, que no
existen; ahora lista `menu-node.md`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Último tramo de la puesta al día. Los documentos ER físicos y el modelo conceptual no se
reescriben a medias: llevan un aviso preciso de qué parte quedó superada —la cadena
`FUNCTIONAL_MENU`/`FUNCTIONAL_SUBMENU`/`FUNCTIONAL_OPTION`, que hoy es una sola tabla recursiva
`SystemSuiteNodes` más el puente `SystemSuiteNodeActions`— y dicen dónde está la fuente de
verdad. El resto de esos documentos sigue siendo válido, y un aviso honesto vale más que un
diagrama reescrito a medias que vuelva a envejecer mal.
Se corrige la prosa que sí era corta y clara de arreglar: el índice DDD, el PRD, el árbol del
grafo en ADR-0071, la historia funcional FS-04 y los trackers de agregados, en las dos lenguas
donde existe el gemelo.
En el análisis de integración con el Tablero se aclara la equivalencia en vez de tachar el
recuento: la spec declarativa sigue escrita con el vocabulario menú/submenú/opción y el cargador
la traduce a altas de `MenuNode` sobre `/modules/{id}/nodes`, así que el número es correcto y lo
que faltaba era decir en qué se convierte.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Resincroniza
src/ydocs/con la plataforma de origen (unimar-ums), aplicando el mapa de marca del satélite y preservando lo que es propio de este repo. Cero residuos de marca en todo el repositorio.Mapa de marca
Unimar.Ums.*Ums.*Unimar.Shells.Net.*(feed privadounimar-peru)BeyondNetCode.Shell.*(nuget.org)@unimar-peru/ums-sdk-*@ums/sdk-*UNIMAR/unimar.com.peBEYONDNET/beyondnet.com.pe(mismo GUID)unimar-cluster-ums,unimar-core,unimar_archevolith-ums-cluster, Evolith Core,evolith-coreunimar.evolith.El namespace del instalador de AOP no coincide con el id del paquete:
BeyondNetCode.Shell.Aop.DIcomo paquete,BeyondNetCode.Shell.Aop.Microsoft.Extensions.DependencyInjection.Aspects.Installercomo namespace.Con esto el arnés e2e y la siembra por fin nombran al mismo inquilino raíz: el arnés ya decía
BEYONDNET_TENANT_IDmientras el seeder seguía sembrandoUNIMAR.Preservado del satélite
Activos que no existen en la plataforma de origen y que un reemplazo ciego habría borrado:
Tenant(SetBranding,UpdateBranding,VerifyBrandingDns,FailBrandingDns,RemoveBranding), sus cinco eventos,DomainErrors.Branding, endpoints REST y la pestaña «Identidad Visual» reenganchada en el web (BrandingPanelhabía quedado huérfano al sustituirseTenantDetailPanel)..csprojy el cableado al bootstrapper (AddUmsGraphQl+MapGraphQlSurface). Los resolvers pasan astatic: son sin estado y el gate heredado promueve S2325 a error.Evolith.Contracts.MasterData— conserva su namespace a propósito. Es el contrato de wire del productor (MMS) y MassTransit enruta por el URN del tipo (ADR-0106). No sigue la convenciónUms.*del satélite deliberadamente.Dockerfile, clúster local yevolith.yaml.Retirado por sustitución
Menu/SubMenu/Option→MenuNode· SchemaBootstrapper SQLite/PostgreSQL yumsdev.db→ migraciones EF ·RemoveBranch→CloseBranch(ADR-0164) ·RemoveTemplateItem→DeactivateItem·RequestContextAccessor→Observability/RequestContext· sink y background service de AuditTrail →AuditTrailPersistenceConsumer·PromotionStatus→ modelo IGA de madurez de rol.También se van
Ums.slnx(apuntaba alibs/shellinexistentes) ysrc/Ums.ReadModels, que estaba mal ubicado con rutas anidadas rotas (src/Ums.ReadModels/...ysrc/Ums/ReadModels/...) que dejó una resincronización anterior; el proyecto vive enapps/ums.api/Ums.ReadModels, que es lo que la solución referencia.Documentación
La documentación de origen usa taxonomía SDLC (
01-concepcion..05-entrega) y la de este repo es bilingüe por dominio. Cada documento se ubica donde le corresponde; no se importa el árbol de fases.02-diseno/dominio/**→docs/domain-es/**(85 fichas actualizadas)02-diseno/historias-funcionales/**→governance/requirements-es/functional-stories(slug español → inglés, mismo número)01-concepcion→governance/product-es·02-diseno/*.md→architecture/*.es.md·04-validacion→qa/Validación
Ums.slnbuildUms.Domain.TestUms.Application.TestUms.Sdk.Testsvite build+vitestEl único fallo es del reloj, no del cambio:
T12_AuditFields_OnCreate_CarryActorFromUserContextcomparaDateTime.UtcNow.Datecontra unCreatedAtque el paquete externoBeyondNetCode.Shell.Ddd.ValueObjectsestampa en hora local, así que falla en la ventana UTC 00:00–05:00 (al ejecutarlo, UTC era 10-ago y Lima 9-ago).Decisiones que conviene revisar
DropTenantBrandingTableen vez de añadir un re-create. Este satélite nunca soltó la tabla —InitialPostgresCreateya la crea— y así se evita undrop/createque destruiría datos de branding. El snapshot de EF se regenera: sin cambios pendientes de modelo.Apply(TemplateAutoAssignedEvent)enProfileDomainEventsManagery sin élCreateProfileCommandHandlerrevienta al auto-asignar plantilla (3 pruebas en rojo).Pendiente (no bloquea)
Las fichas de dominio nuevas y las historias FS-25/26/36/37 llegan solo en español; los índices en inglés las enlazan marcadas como tales.
docs/domain/(EN) queda por detrás dedocs/domain-es/.🤖 Generated with Claude Code