siesa-agents 2.1.72-qa.2 → 2.1.72-qa.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/bmad/bmm/config.yaml +33 -0
  2. package/claude/skills/sa-agent-sre-sentinel/SKILL.md +180 -0
  3. package/claude/skills/sa-aplicar/SKILL.md +268 -0
  4. package/claude/skills/sa-auditar-servicio/SKILL.md +255 -0
  5. package/claude/skills/sa-nueva-transversal/SKILL.md +317 -0
  6. package/claude/skills/sa-nuevo-ambiente/SKILL.md +147 -0
  7. package/claude/skills/sa-nuevo-servicio/SKILL.md +530 -0
  8. package/claude/skills/sa-onboard-db/SKILL.md +122 -0
  9. package/claude/skills/sa-qa-data-generator/SKILL.md +200 -51
  10. package/claude/skills/sa-quality-process/SKILL.md +6 -0
  11. package/claude/skills/sa-registrar-permisos/SKILL.md +233 -0
  12. package/package.json +1 -1
  13. package/siesa-agents/bmm/workflows/3-solutioning/quality-process/prompts/prompt_design_test.md +1037 -60
  14. package/siesa-agents/bmm/workflows/3-solutioning/quality-process/prompts/prompt_dor_gate.md +419 -379
  15. package/siesa-agents/bmm/workflows/3-solutioning/quality-process/prompts/prompt_e2e_executor.md +273 -0
  16. package/siesa-agents/bmm/workflows/3-solutioning/quality-process/prompts/prompt_playwright_impl.md +359 -355
  17. package/siesa-agents/bmm/workflows/3-solutioning/quality-process/prompts/prompt_test_plan.md +73 -111
  18. package/siesa-agents/bmm/workflows/3-solutioning/quality-process/workflow.md +1320 -997
  19. package/siesa-agents/resources/playwright-kit/.env.example +42 -0
  20. package/siesa-agents/resources/playwright-kit/README.md +228 -0
  21. package/siesa-agents/resources/playwright-kit/allure/categories.json +26 -0
  22. package/siesa-agents/resources/playwright-kit/global-setup.ts +34 -0
  23. package/siesa-agents/resources/playwright-kit/helpers/blazor-e2e-helpers.ts +417 -0
  24. package/siesa-agents/resources/playwright-kit/helpers/react-e2e-helpers.ts +297 -0
  25. package/siesa-agents/resources/playwright-kit/package-lock.json +850 -0
  26. package/siesa-agents/resources/playwright-kit/package.json +27 -0
  27. package/siesa-agents/resources/playwright-kit/playwright.config.ts +60 -0
  28. package/siesa-agents/resources/playwright-kit/proposed/.gitkeep +0 -0
  29. package/siesa-agents/resources/playwright-kit/reporters/agiletest-reporter.ts +252 -0
  30. package/siesa-agents/resources/playwright-kit/specs/.gitkeep +0 -0
  31. package/siesa-agents/resources/playwright-kit/specs/architecture-brief-siesa-erp.md +85 -0
  32. package/siesa-agents/resources/playwright-kit/specs/architecture-brief-siesa-react.md +109 -0
  33. package/siesa-agents/resources/playwright-kit/specs/architecture-brief-template.md +69 -0
  34. package/siesa-agents/resources/playwright-kit/tests/seed-example.spec.ts +95 -0
  35. package/siesa-agents/resources/playwright-kit/tools/locator-overlay.js +1306 -0
  36. package/siesa-agents/resources/playwright-kit/tools/locator-recorder.spec.ts +986 -0
  37. package/siesa-agents/scripts/__pycache__/bmad_to_agiletest.cpython-36.pyc +0 -0
  38. package/siesa-agents/scripts/bmad_to_agiletest.py +352 -337
  39. package/siesa-agents/scripts/converters/convert_csv_to_test_design.py +327 -0
  40. package/siesa-agents/scripts/converters/convert_excel_to_test_design.py +360 -0
  41. package/siesa-agents/scripts/converters/convert_md_to_test_design.py +359 -0
  42. package/siesa-agents/scripts/converters/convert_pdf_to_test_design.py +412 -0
  43. package/siesa-agents/scripts/converters/export_yaml_to_csv.py +149 -0
  44. package/siesa-agents/scripts/converters/export_yaml_to_excel.py +233 -0
  45. package/siesa-agents/scripts/converters/export_yaml_to_markdown.py +172 -0
  46. package/siesa-agents/scripts/converters/export_yaml_to_pdf.py +297 -0
  47. package/siesa-agents/scripts/merge_test_design.py +106 -106
  48. package/siesa-agents/scripts/playwright/yaml-to-playwright-spec.ts +203 -0
  49. package/siesa-agents/scripts/requirements.txt +7 -0
@@ -0,0 +1,147 @@
1
+ ---
2
+ name: sa-nuevo-ambiente
3
+ description: 'Adds a new environment (staging or prod) to this transversal by reading environments/{env}.yaml and generating the matching Terraform, CI/CD, and Kubernetes overlay artifacts. Use whenever the user wants to add a new deploy target to an existing transversal.'
4
+ ---
5
+
6
+ > **Contexto de ejecución:** este skill asume que el cwd está dentro de la carpeta del workspace de despliegue (`_siesa-agents/devops/` en Siesa-Agents tras correr `/sa-init-devops`, o la raíz de un clon directo de `architecture-sa-devops`). Las rutas relativas (`environments/`, `terraform/`, `k8s/`, `scripts/`, etc.) se resuelven contra ese cwd.
7
+
8
+ Agrega un nuevo ambiente (staging o prod) a esta transversal. Lee el `environments/{ambiente}.yaml` ya configurado y genera los artefactos Terraform, CI/CD y K8s overlay correspondientes.
9
+
10
+ **Uso:** `/sa-nuevo-ambiente {ambiente}`
11
+
12
+ **Ejemplo:** `/sa-nuevo-ambiente staging`
13
+
14
+ **Prerequisito:** El archivo `environments/{ambiente}.yaml` debe existir y tener todos los `<PLACEHOLDER>` completados antes de invocar este flow.
15
+
16
+ ---
17
+
18
+ ## Instrucciones
19
+
20
+ El argumento es: `$ARGUMENTS`
21
+
22
+ `AMBIENTE` = el argumento (ej: `staging`, `prod`)
23
+
24
+ Primero lee `environments/{AMBIENTE}.yaml` y valida que no existan `<PLACEHOLDER>` sin completar. Si los hay, muestra cuáles faltan y detente.
25
+
26
+ Luego lee los valores:
27
+ - `PROJECT_ID` = `.gcp.project_id`
28
+ - `PROJECT_NUM` = `.gcp.project_number`
29
+ - `REGION` = `.gcp.region`
30
+ - `GATEWAY_NAME` = `.gateway.name`
31
+ - `GKE_CLUSTER` = `.gke.cluster_name`
32
+ - `WORKER_POOL` = `.cloud_build.worker_pool`
33
+ - `DEPLOY_SA` = `.deploy.sa_name`
34
+ - `SUITE` = `.naming.product_suite`
35
+ - `BUSINESS_UNIT` = `.naming.business_unit`
36
+ - `PROJECT_ID_DEV` = leyendo `environments/dev.yaml` → `.gcp.project_id` (para el bucket de estado)
37
+
38
+ Si `PROJECT_NUM` contiene `<PLACEHOLDER>` o está vacío, resuélvelo con Bash antes de continuar:
39
+ ```bash
40
+ gcloud projects describe {PROJECT_ID} --format='value(projectNumber)'
41
+ ```
42
+ Si el comando falla (proyecto no creado aún), detente y pide al usuario que cree el proyecto GCP primero.
43
+
44
+ Lee también `environments/dev.yaml` para obtener la lista de servicios y namespaces actuales.
45
+
46
+ ---
47
+
48
+ ### Paso 1 — `terraform/environments/{AMBIENTE}/main.tf`
49
+
50
+ Copia la estructura de `terraform/environments/qa/main.tf` (NO de dev — QA tiene los recursos IAM del worker pool privado) y aplica estos cambios:
51
+ - `bucket = "bkt-sie-{SUITE}-iac-state-{PROJECT_ID_DEV}"` — mismo bucket, distinto prefix
52
+ - `prefix = "terraform/environments/{AMBIENTE}"`
53
+ - `config = yamldecode(file("${path.module}/../../../environments/{AMBIENTE}.yaml"))`
54
+ - Comentario de cabecera: actualizar para describir el ambiente `{AMBIENTE}`
55
+ - El provider kubernetes apunta al cluster `{GKE_CLUSTER}`
56
+
57
+ **CRÍTICO — IAM para worker pool privado:** El deploy vía `gcloud builds submit k8s/` con worker pool requiere 4 recursos IAM que NO están en `dev/main.tf` pero SÍ en `qa/main.tf`. Asegúrate de incluirlos (copiando de QA):
58
+ 1. `cicd_sa_storage_admin` — `roles/storage.admin` a cada CI/CD SA (escribir fuente al bucket `{project}_cloudbuild`)
59
+ 2. `compute_sa_storage_admin` — `roles/storage.admin` al Compute SA (leer fuente desde el bucket en el worker pool)
60
+ 3. `compute_sa_container_admin` — `roles/container.admin` al Compute SA (kubectl dentro del container)
61
+ 4. `compute_sa_secret_accessor` — `roles/secretmanager.secretAccessor` al Compute SA (leer secrets al crear K8s secrets)
62
+
63
+ Sin estos 4, `gcloud builds submit` falla con `forbidden from accessing bucket`.
64
+
65
+ ### Paso 2 — `.github/workflows/infra-pipeline-{AMBIENTE}.yml`
66
+
67
+ Copia `.github/workflows/infra-pipeline-dev.yml` y aplica estos cambios:
68
+ - `name: Infrastructure Pipeline — Dev` → `name: Infrastructure Pipeline — {AMBIENTE}`
69
+ - Reemplaza todos los paths que dicen `environments/dev.yaml` → `environments/{AMBIENTE}.yaml`
70
+ - Reemplaza todos los paths que dicen `k8s/overlays/dev/` → `k8s/overlays/{AMBIENTE}/`
71
+ - Reemplaza en los triggers `paths:`:
72
+ ```yaml
73
+ - 'terraform/environments/{AMBIENTE}/**'
74
+ - 'environments/{AMBIENTE}.yaml'
75
+ - 'k8s/base/**'
76
+ - 'k8s/overlays/{AMBIENTE}/**'
77
+ ```
78
+ - Reemplaza todos los `yq` que leen `environments/dev.yaml` → `environments/{AMBIENTE}.yaml`
79
+ - Reemplaza `terraform/environments/dev/` → `terraform/environments/{AMBIENTE}/`
80
+ - Reemplaza `k8s/overlays/dev/` → `k8s/overlays/{AMBIENTE}/` en los kubectl apply y tar
81
+
82
+ Si el ambiente es `prod`, agrega al job `terraform-apply`:
83
+ ```yaml
84
+ environment:
85
+ name: prod
86
+ url: https://{DOMINIO}
87
+ ```
88
+ (lee el dominio de `environments/prod.yaml` → `.dns.domain`)
89
+
90
+ ### Paso 3 — `k8s/overlays/{AMBIENTE}/` (estructura completa)
91
+
92
+ Copia todos los archivos de `k8s/overlays/dev/` a `k8s/overlays/{AMBIENTE}/` y aplica estos reemplazos en el contenido de cada archivo YAML:
93
+
94
+ **En archivos `dapr/**/pubsub.yaml` y `dapr/**/secretstore.yaml`:**
95
+ - `value: {PROJECT_ID_DEV}` → `value: {PROJECT_ID}`
96
+
97
+ **En archivos `routes/*.yaml`:**
98
+ - `name: {GATEWAY_NAME_DEV}` → `name: {GATEWAY_NAME}`
99
+ (donde `GATEWAY_NAME_DEV` se lee de `environments/dev.yaml` → `.gateway.name`)
100
+
101
+ **El resto de archivos** (healthcheck, import-map, cron bindings) se copian sin modificar.
102
+
103
+ ---
104
+
105
+ ### Paso 4 — Mostrar resumen
106
+
107
+ ```
108
+ ✅ GENERADO para ambiente {AMBIENTE}:
109
+
110
+ terraform/environments/{AMBIENTE}/main.tf
111
+ .github/workflows/infra-pipeline-{AMBIENTE}.yml
112
+ k8s/overlays/{AMBIENTE}/
113
+ dapr/*/* (pubsub, secretstore, statestore, crons)
114
+ routes/*
115
+ healthcheck/*
116
+ import-map/
117
+
118
+ ⚠️ PASOS MANUALES REQUERIDOS:
119
+
120
+ 1. Verificar que el proyecto GCP {PROJECT_ID} existe y tiene APIs habilitadas.
121
+
122
+ 2. Ejecutar bootstrap si es la primera vez con este proyecto:
123
+ cd terraform/bootstrap
124
+ terraform apply -var="project_id={PROJECT_ID}"
125
+
126
+ 3. Crear SA de deploy (si no existe):
127
+ gcloud iam service-accounts create {DEPLOY_SA} --project={PROJECT_ID}
128
+
129
+ 4. Para cada servicio: crear el secret de conexión DB en el nuevo proyecto.
130
+ IMPORTANTE — verificar el nombre real del secret antes de codificarlo en el pipeline:
131
+ gcloud secrets list --project={PROJECT_ID} --filter="name:{AMBIENTE}"
132
+ Convención QA: prefijo corto (`baseconfig`, `tprt`, `acct`) no el nombre del servicio completo.
133
+ Crear si no existe:
134
+ gcloud secrets create {servicio-corto}-{AMBIENTE}-db-connection \
135
+ --project={PROJECT_ID} --data-file=-
136
+
137
+ 5. Commit + merge a main → el pipeline infra-pipeline-{AMBIENTE}.yml se dispara (Terraform apply).
138
+
139
+ 6. CRÍTICO — Instalar Dapr en el cluster (primera vez):
140
+ El job k8s-manifests salta cuando no hay cambios K8s. Para forzarlo:
141
+ gh workflow run infra-pipeline-{AMBIENTE}.yml --ref main
142
+ Sin esto, los deploys de servicios fallan con:
143
+ "no matches for kind Configuration in version dapr.io/v1alpha1"
144
+
145
+ 7. Aplicar DDL de grants en el nuevo Cloud SQL para cada servicio:
146
+ /sa-onboard-db {schema} {owner-role}
147
+ ```
@@ -0,0 +1,530 @@
1
+ ---
2
+ name: sa-nuevo-servicio
3
+ description: 'Adds a new service to this transversal, generating every artifact needed in the deploy repo plus the CI/CD file ready to drop into the services own repo. Supports fullstack, backend-only, or frontend-only modes via flags. Use whenever the user wants to onboard a new service into the deploy infrastructure.'
4
+ ---
5
+
6
+ > **Contexto de ejecución:** este skill asume que el cwd está dentro de la carpeta del workspace de despliegue (`_siesa-agents/devops/` en Siesa-Agents tras correr `/sa-init-devops`, o la raíz de un clon directo de `architecture-sa-devops`). Las rutas relativas (`environments/`, `terraform/`, `k8s/`, `scripts/`, etc.) se resuelven contra ese cwd.
7
+
8
+ Agrega un nuevo servicio a esta transversal. Genera todos los artefactos necesarios en el repo deploy y el archivo CI/CD listo para copiar al repo del servicio.
9
+
10
+ **Uso:** `/sa-nuevo-servicio {nombre} [api-port] [mfe-port] [--no-mfe] [--no-api]`
11
+
12
+ - Ambos puertos → servicio fullstack (backend + MFE)
13
+ - Solo `api-port` con `--no-mfe` → servicio backend puro (sin MFE)
14
+ - Solo `mfe-port` con `--no-api` → servicio frontend puro (sin API backend, ej: app-shell)
15
+
16
+ **Ejemplos:**
17
+ - `/sa-nuevo-servicio treasury 7022 8022` ← fullstack
18
+ - `/sa-nuevo-servicio payroll 7024 --no-mfe` ← backend puro
19
+ - `/sa-nuevo-servicio app-shell 8000 --no-api` ← frontend puro
20
+
21
+ ---
22
+
23
+ ## Instrucciones
24
+
25
+ Los argumentos son: `$ARGUMENTS`
26
+
27
+ ### PRINCIPIO FUNDAMENTAL — El estándar siempre prevalece
28
+
29
+ **Cada artefacto generado por este flow SOBREESCRIBE lo que exista**, sin preguntar. Si el servicio ya existe parcialmente, sus artefactos se actualizan al estándar actual. Nada del estándar anterior se conserva por inercia.
30
+
31
+ - Archivos K8s → se sobreescriben con Write si difieren del template
32
+ - `environments/dev.yaml` y `environments/shared.yaml` → se actualizan si la entrada ya existe
33
+ - `ci-pipeline.yml` en el repo del servicio → se sobreescribe siempre con el template actual
34
+ - `cloudbuild-deploy.yaml` u otros artefactos del estándar anterior → se eliminan del repo del servicio si existen
35
+
36
+ La única excepción son acciones que puedan dejar un servicio sin desplegar en producción (como eliminar un deployment activo o borrar un secret en uso). En esos casos, sí se pregunta antes de actuar.
37
+
38
+ ---
39
+
40
+ Parsea los argumentos:
41
+ - Detecta flags primero: `HAS_MFE` = `false` si `--no-mfe` está presente, `true` en caso contrario. `HAS_API` = `false` si `--no-api` está presente, `true` en caso contrario.
42
+ - `NOMBRE` = primer argumento posicional (sin contar flags)
43
+ - Si `HAS_API = true` y `HAS_MFE = true`: `API_PORT` = segundo arg, `MFE_PORT` = tercer arg
44
+ - Si `HAS_API = true` y `HAS_MFE = false` (--no-mfe): `API_PORT` = segundo arg, `MFE_PORT` = vacío
45
+ - Si `HAS_API = false` y `HAS_MFE = true` (--no-api): `API_PORT` = vacío, `MFE_PORT` = segundo arg
46
+
47
+ Lee `environments/dev.yaml` para obtener:
48
+ - `PROJECT_ID` = `.gcp.project_id`
49
+ - `PROJECT_NUM` = `.gcp.project_number`
50
+ - `REGION` = `.gcp.region`
51
+ - `GATEWAY_NAME` = `.gateway.name`
52
+ - `SUITE` = `.naming.product_suite`
53
+ - `BUSINESS_UNIT` = `.naming.business_unit`
54
+ - `GKE_CLUSTER` = `.gke.cluster_name`
55
+ - `WORKER_POOL` = `.cloud_build.worker_pool`
56
+
57
+ Si `PROJECT_NUM` contiene `<PLACEHOLDER>` o está vacío, resuélvelo con Bash antes de continuar:
58
+ ```bash
59
+ gcloud projects describe {PROJECT_ID} --format='value(projectNumber)'
60
+ ```
61
+ Si el comando falla, detente y pide al usuario que complete `gcp.project_number` en `environments/dev.yaml`.
62
+
63
+ Lee `environments/shared.yaml` para obtener:
64
+ - `HUB_PROJECT` = `.hub.project_id` (Hub donde vive el Artifact Registry)
65
+
66
+ Calcula:
67
+ - `SA_SHORT` = `NOMBRE` con hyphens removidos, truncado a 10 caracteres (ej: `treasury` → `treasury`, `third-party` → `thirdparty`)
68
+ - `SA_NAME` = `sa-sie-{SUITE}-{SA_SHORT}-cicd`
69
+ - `GITHUB_REPO` = `SiesaTeams/business-{BUSINESS_UNIT}-{NOMBRE}-service`
70
+
71
+ ---
72
+
73
+ ### Fase A — Validación previa (ejecutar antes de generar artefactos)
74
+
75
+ #### A1 — API Guard: Habilitar APIs obligatorias
76
+
77
+ ```bash
78
+ gcloud services enable \
79
+ container.googleapis.com \
80
+ sqladmin.googleapis.com \
81
+ pubsub.googleapis.com \
82
+ secretmanager.googleapis.com \
83
+ artifactregistry.googleapis.com \
84
+ iam.googleapis.com \
85
+ --project={PROJECT_ID}
86
+ ```
87
+
88
+ Opcional según stack:
89
+ ```bash
90
+ # Cloud Run (si aplica)
91
+ gcloud services enable run.googleapis.com --project={PROJECT_ID}
92
+ # Firestore
93
+ gcloud services enable firestore.googleapis.com --project={PROJECT_ID}
94
+ # Redis/Memorystore (PROD)
95
+ gcloud services enable redis.googleapis.com --project={PROJECT_ID}
96
+ ```
97
+
98
+ #### A2 — Workload Identity Binding
99
+
100
+ El SA `{SA_NAME}` y su binding WIF se crean automáticamente vía Terraform tras agregar el servicio a `environments/shared.yaml` y ejecutar `infra-pipeline-shared`. Verificar que existen antes del primer CI/CD:
101
+
102
+ ```bash
103
+ gcloud iam service-accounts describe {SA_NAME}@{PROJECT_ID}.iam.gserviceaccount.com \
104
+ --project={PROJECT_ID}
105
+ ```
106
+
107
+ Si falta el SA, es señal de que el pipeline `infra-pipeline-shared` no ha aplicado aún — no continuar hasta que esté aplicado.
108
+
109
+ #### A3 — Production-Ready Checklist
110
+
111
+ Verificar en el repo `{GITHUB_REPO}` antes de generar artefactos:
112
+
113
+ - [ ] **Secrets:** Solo Secret Manager. **PROHIBIDO** variables de entorno para datos sensibles. Usar `{NOMBRE}-dev-db-connection` (convención esta transversal) o `sec-sie-{NOMBRE}-dev-db` (estándar org).
114
+ - [ ] **Estructura K8s:** `k8s/base/` + `k8s/overlays/{env}/` presentes en el repo del servicio.
115
+ - [ ] **Migraciones:** Framework containerizado (EF Core `MigrateAsync`, Prisma, Liquibase). **PROHIBIDO** migraciones manuales o SQL suelto.
116
+
117
+ Si algún punto no se cumple, detener y coordinar con el equipo antes de continuar.
118
+
119
+ ---
120
+
121
+ Luego genera los siguientes artefactos **en este orden**, creando o sobreescribiendo cada archivo con Write:
122
+
123
+ ---
124
+
125
+ ### Paso 1 — `k8s/overlays/dev/dapr/{NOMBRE}/pubsub.yaml`
126
+
127
+ ```yaml
128
+ apiVersion: dapr.io/v1alpha1
129
+ kind: Component
130
+ metadata:
131
+ name: pubsub
132
+ namespace: {NOMBRE}
133
+ spec:
134
+ type: pubsub.gcp.pubsub
135
+ version: v1
136
+ metadata:
137
+ - name: projectId
138
+ value: {PROJECT_ID}
139
+ - name: disableEntityManagement
140
+ value: "true"
141
+ ```
142
+
143
+ ### Paso 2 — `k8s/overlays/dev/dapr/{NOMBRE}/secretstore.yaml`
144
+
145
+ ```yaml
146
+ apiVersion: dapr.io/v1alpha1
147
+ kind: Component
148
+ metadata:
149
+ name: secretstore
150
+ namespace: {NOMBRE}
151
+ spec:
152
+ type: secretstores.gcp.secretmanager
153
+ version: v1
154
+ metadata:
155
+ - name: projectId
156
+ value: {PROJECT_ID}
157
+ ```
158
+
159
+ ### Paso 3 — `k8s/overlays/dev/routes/{NOMBRE}-route.yaml`
160
+
161
+ El contenido del route depende de qué componentes tiene el servicio:
162
+
163
+ **Si HAS_API = true Y HAS_MFE = true (fullstack):**
164
+ ```yaml
165
+ apiVersion: gateway.networking.k8s.io/v1
166
+ kind: HTTPRoute
167
+ metadata:
168
+ name: {NOMBRE}-route
169
+ namespace: {NOMBRE}
170
+ labels:
171
+ app.kubernetes.io/name: {NOMBRE}
172
+ app.kubernetes.io/part-of: {BUSINESS_UNIT}-platform
173
+ spec:
174
+ parentRefs:
175
+ - name: {GATEWAY_NAME}
176
+ namespace: gateway-infra
177
+ sectionName: https
178
+ rules:
179
+ - matches:
180
+ - path:
181
+ type: PathPrefix
182
+ value: /mfe/{NOMBRE}
183
+ filters:
184
+ - type: URLRewrite
185
+ urlRewrite:
186
+ path:
187
+ type: ReplacePrefixMatch
188
+ replacePrefixMatch: /
189
+ backendRefs:
190
+ - name: {NOMBRE}-mfe
191
+ port: 80
192
+ - matches:
193
+ - path:
194
+ type: PathPrefix
195
+ value: /api/{NOMBRE}/health
196
+ filters:
197
+ - type: URLRewrite
198
+ urlRewrite:
199
+ path:
200
+ type: ReplacePrefixMatch
201
+ replacePrefixMatch: /health
202
+ backendRefs:
203
+ - name: {NOMBRE}-api
204
+ port: 8080
205
+ - matches:
206
+ - path:
207
+ type: PathPrefix
208
+ value: /api/{NOMBRE}
209
+ filters:
210
+ - type: URLRewrite
211
+ urlRewrite:
212
+ path:
213
+ type: ReplacePrefixMatch
214
+ replacePrefixMatch: /api/v1
215
+ backendRefs:
216
+ - name: {NOMBRE}-api
217
+ port: 8080
218
+ ```
219
+
220
+ **Si HAS_API = true Y HAS_MFE = false (backend puro, --no-mfe):**
221
+ Omitir el bloque de regla MFE (`/mfe/{NOMBRE}`). Incluir solo las dos reglas de `/api/{NOMBRE}`.
222
+
223
+ **Si HAS_API = false Y HAS_MFE = true (frontend puro, --no-api):**
224
+ Incluir solo la regla del MFE (`/mfe/{NOMBRE}`). Omitir las dos reglas de `/api/{NOMBRE}`.
225
+
226
+ ### Paso 4 — `k8s/overlays/dev/healthcheck/{NOMBRE}-api-hc.yaml` (solo si HAS_API)
227
+
228
+ Generar este archivo únicamente si `HAS_API = true`.
229
+
230
+ ```yaml
231
+ apiVersion: networking.gke.io/v1
232
+ kind: HealthCheckPolicy
233
+ metadata:
234
+ name: {NOMBRE}-api-hc
235
+ namespace: {NOMBRE}
236
+ spec:
237
+ default:
238
+ checkIntervalSec: 15
239
+ timeoutSec: 5
240
+ healthyThreshold: 1
241
+ unhealthyThreshold: 3
242
+ config:
243
+ type: TCP
244
+ tcpHealthCheck:
245
+ port: 8080
246
+ targetRef:
247
+ group: ""
248
+ kind: Service
249
+ name: {NOMBRE}-api
250
+ ```
251
+
252
+ ### Paso 5 — `k8s/overlays/dev/healthcheck/{NOMBRE}-mfe-hc.yaml` (solo si HAS_MFE)
253
+
254
+ ```yaml
255
+ apiVersion: networking.gke.io/v1
256
+ kind: HealthCheckPolicy
257
+ metadata:
258
+ name: {NOMBRE}-mfe-hc
259
+ namespace: {NOMBRE}
260
+ spec:
261
+ default:
262
+ checkIntervalSec: 15
263
+ timeoutSec: 5
264
+ healthyThreshold: 1
265
+ unhealthyThreshold: 3
266
+ config:
267
+ type: TCP
268
+ tcpHealthCheck:
269
+ port: 80
270
+ targetRef:
271
+ group: ""
272
+ kind: Service
273
+ name: {NOMBRE}-mfe
274
+ ```
275
+
276
+ ### Paso 6 — Actualizar `environments/dev.yaml`
277
+
278
+ Lee el archivo actual. Si ya existe la entrada para `{NOMBRE}` bajo `services:`, sobreescríbela con los valores calculados. Si no existe, agrégala. Mismo criterio para `namespaces:`.
279
+
280
+ ```yaml
281
+ {NOMBRE}:
282
+ sa_name: {SA_NAME}
283
+ github_repo: {GITHUB_REPO}
284
+ description: "Docker images for {NOMBRE} service"
285
+ ```
286
+
287
+ Agrega `- {NOMBRE}` a la lista `namespaces:` si no está ya.
288
+
289
+ ### Paso 7 — Actualizar `environments/shared.yaml`
290
+
291
+ Lee el archivo actual. Si ya existe la entrada para `{NOMBRE}` bajo `services:`, sobreescríbela con los valores calculados. Si no existe, agrégala.
292
+
293
+ ```yaml
294
+ {NOMBRE}:
295
+ sa_name: {SA_NAME}
296
+ github_repo: {GITHUB_REPO}
297
+ description: "Docker images for {NOMBRE} service"
298
+ roles:
299
+ - roles/cloudbuild.builds.editor
300
+ - roles/artifactregistry.writer
301
+ - roles/container.developer
302
+ - roles/secretmanager.secretAccessor
303
+ - roles/cloudsql.client
304
+ - roles/cloudbuild.workerPoolUser
305
+ - roles/clouddeploy.releaser
306
+ - roles/iam.serviceAccountUser
307
+ - roles/storage.admin
308
+ - roles/pubsub.publisher
309
+ - roles/pubsub.subscriber
310
+ ```
311
+
312
+ ### Paso 8 — Actualizar `k8s/overlays/dev/import-map/import-map.yaml` (solo si HAS_MFE)
313
+
314
+ Lee el archivo actual. Agrega al JSON de imports si no está ya:
315
+ ```json
316
+ "@siesa/{NOMBRE}": "/mfe/{NOMBRE}/spa-entry.js"
317
+ ```
318
+
319
+ ### Paso 9 — Generar y aplicar el CI/CD pipeline en el repo del servicio
320
+
321
+ **El pipeline se sobreescribe siempre. El estándar prevalece sobre cualquier pipeline anterior.**
322
+
323
+ #### 9a — Detectar estructura del repo del servicio
324
+
325
+ Calcula `LOCAL_REPO_PATH` = directorio padre de este repo + `/{GITHUB_REPO última parte}`.
326
+ - Ejemplo: deploy en `~/SiesaTeams/business-financiero-deploy` + `GITHUB_REPO = SiesaTeams/business-financiero-segments-service` → `LOCAL_REPO_PATH = ~/SiesaTeams/business-financiero-segments-service`
327
+
328
+ Si el repo no está clonado localmente, clónalo:
329
+ ```bash
330
+ git clone https://github.com/{GITHUB_REPO}.git {LOCAL_REPO_PATH}
331
+ ```
332
+
333
+ Detecta las rutas de Dockerfile ejecutando:
334
+ ```bash
335
+ # API Dockerfile
336
+ if [ -f "{LOCAL_REPO_PATH}/api/Dockerfile" ]; then
337
+ echo "API_DOCKERFILE=api/Dockerfile"
338
+ echo "API_CONTEXT=api/"
339
+ elif [ -f "{LOCAL_REPO_PATH}/src/backend/Dockerfile" ]; then
340
+ echo "API_DOCKERFILE=src/backend/Dockerfile"
341
+ echo "API_CONTEXT=."
342
+ fi
343
+
344
+ # MFE Dockerfile
345
+ if [ -f "{LOCAL_REPO_PATH}/mfe/Dockerfile" ]; then
346
+ echo "MFE_DOCKERFILE=mfe/Dockerfile"
347
+ echo "MFE_CONTEXT=mfe/"
348
+ elif [ -f "{LOCAL_REPO_PATH}/src/frontend/Dockerfile" ]; then
349
+ echo "MFE_DOCKERFILE=src/frontend/Dockerfile"
350
+ echo "MFE_CONTEXT=src/frontend"
351
+ fi
352
+
353
+ # ¿Necesita build args de GitHub Packages?
354
+ grep -l "NUGET_GITHUB_TOKEN\|NPM_GITHUB_TOKEN" \
355
+ {LOCAL_REPO_PATH}/src/backend/Dockerfile \
356
+ {LOCAL_REPO_PATH}/api/Dockerfile \
357
+ {LOCAL_REPO_PATH}/src/frontend/Dockerfile \
358
+ {LOCAL_REPO_PATH}/mfe/Dockerfile 2>/dev/null && echo "NEEDS_GITHUB_PACKAGES=true"
359
+ ```
360
+
361
+ Con estos valores, construye el pipeline adaptado.
362
+
363
+ #### 9b — Eliminar artefactos del estándar anterior
364
+
365
+ Si el repo del servicio tiene `cloudbuild-deploy.yaml` en la raíz, eliminarlo:
366
+ ```bash
367
+ rm -f {LOCAL_REPO_PATH}/cloudbuild-deploy.yaml
368
+ ```
369
+
370
+ Si tiene `cloudbuild-sandbox.yaml`, eliminarlo también:
371
+ ```bash
372
+ rm -f {LOCAL_REPO_PATH}/cloudbuild-sandbox.yaml
373
+ ```
374
+
375
+ #### 9c — Construir el pipeline estándar
376
+
377
+ Lee `cicd-templates/.github/workflows/ci-pipeline.yml` como base. Genera el pipeline final con:
378
+
379
+ 1. **Sección `env:`** — siempre estos valores:
380
+ ```yaml
381
+ env:
382
+ PROJECT_ID: {PROJECT_ID}
383
+ HUB_PROJECT_ID: {HUB_PROJECT}
384
+ PROJECT_NUM: "{PROJECT_NUM}"
385
+ REGION: {REGION}
386
+ GKE_CLUSTER: {GKE_CLUSTER}
387
+ WORKER_POOL: {WORKER_POOL}
388
+ SERVICE_NAME: {NOMBRE}
389
+ NAMESPACE: {NOMBRE}
390
+ BUILD_API: "{HAS_API}"
391
+ BUILD_MFE: "{HAS_MFE}"
392
+ VITE_MODE: development
393
+ ```
394
+
395
+ 2. **Sección `permissions:`** — siempre incluir `packages: read`:
396
+ ```yaml
397
+ permissions:
398
+ contents: read
399
+ id-token: write
400
+ packages: read
401
+ ```
402
+
403
+ 3. **Paso "Build & Push API image"** — adaptar rutas según detección:
404
+
405
+ Si `API_DOCKERFILE = api/Dockerfile`:
406
+ ```yaml
407
+ - name: Build & Push API image
408
+ if: env.BUILD_API == 'true'
409
+ run: |
410
+ IMAGE="${{ env.REGION }}-docker.pkg.dev/${{ env.HUB_PROJECT_ID }}/art-fin-shared/${{ env.SERVICE_NAME }}/${{ env.SERVICE_NAME }}-api"
411
+ docker build -t ${IMAGE}:${{ github.sha }} -f api/Dockerfile api/
412
+ docker push ${IMAGE}:${{ github.sha }}
413
+ ```
414
+
415
+ Si `API_DOCKERFILE = src/backend/Dockerfile`:
416
+ ```yaml
417
+ - name: Build & Push API image
418
+ if: env.BUILD_API == 'true'
419
+ run: |
420
+ IMAGE="${{ env.REGION }}-docker.pkg.dev/${{ env.HUB_PROJECT_ID }}/art-fin-shared/${{ env.SERVICE_NAME }}/${{ env.SERVICE_NAME }}-api"
421
+ docker build \
422
+ --build-arg NUGET_GITHUB_USER=x-access-token \
423
+ --build-arg NUGET_GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} \
424
+ -t ${IMAGE}:${{ github.sha }} \
425
+ -f src/backend/Dockerfile .
426
+ docker push ${IMAGE}:${{ github.sha }}
427
+ ```
428
+
429
+ 4. **Paso "Build & Push MFE image"** — adaptar rutas según detección:
430
+
431
+ Si `MFE_DOCKERFILE = mfe/Dockerfile`:
432
+ ```yaml
433
+ - name: Build & Push MFE image
434
+ if: env.BUILD_MFE == 'true'
435
+ run: |
436
+ IMAGE="${{ env.REGION }}-docker.pkg.dev/${{ env.HUB_PROJECT_ID }}/art-fin-shared/${{ env.SERVICE_NAME }}/${{ env.SERVICE_NAME }}-mfe"
437
+ docker build \
438
+ --build-arg VITE_MODE=${{ env.VITE_MODE }} \
439
+ -t ${IMAGE}:${{ github.sha }} \
440
+ -f mfe/Dockerfile mfe/
441
+ docker push ${IMAGE}:${{ github.sha }}
442
+ ```
443
+
444
+ Si `MFE_DOCKERFILE = src/frontend/Dockerfile`:
445
+ ```yaml
446
+ - name: Build & Push MFE image
447
+ if: env.BUILD_MFE == 'true'
448
+ run: |
449
+ IMAGE="${{ env.REGION }}-docker.pkg.dev/${{ env.HUB_PROJECT_ID }}/art-fin-shared/${{ env.SERVICE_NAME }}/${{ env.SERVICE_NAME }}-mfe"
450
+ docker build \
451
+ --build-arg NPM_GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} \
452
+ --build-arg VITE_MODE=${{ env.VITE_MODE }} \
453
+ -t ${IMAGE}:${{ github.sha }} \
454
+ -f src/frontend/Dockerfile src/frontend
455
+ docker push ${IMAGE}:${{ github.sha }}
456
+ ```
457
+
458
+ 5. El resto del pipeline (secciones Deploy via Cloud Build y Smoke test) se toma intacto del template.
459
+
460
+ Guarda el pipeline generado en `/tmp/ci-pipeline-{NOMBRE}.yml` y también en:
461
+ ```
462
+ {LOCAL_REPO_PATH}/.github/workflows/ci-pipeline.yml
463
+ ```
464
+
465
+ #### 9d — Commit y push al repo del servicio
466
+
467
+ ```bash
468
+ cd {LOCAL_REPO_PATH}
469
+ git checkout develop
470
+ git add .github/workflows/ci-pipeline.yml
471
+ # Si se eliminaron artefactos del estándar anterior:
472
+ git add -u cloudbuild-deploy.yaml cloudbuild-sandbox.yaml 2>/dev/null || true
473
+ git commit -m "ci: migrar a pipeline estándar build & deploy DEV
474
+
475
+ - Imagen: Hub AR (prj-sie-sb-fin-common/art-fin-shared/{NOMBRE})
476
+ - Deploy: Cloud Build config inline (sin cloudbuild-deploy.yaml externo)
477
+ - Tag: SHA completo del commit"
478
+ git push origin develop
479
+ ```
480
+
481
+ ---
482
+
483
+ ### Paso 10 — Mostrar resumen
484
+
485
+ ```
486
+ ✅ GENERADO/ACTUALIZADO AUTOMÁTICAMENTE:
487
+ k8s/overlays/dev/dapr/{NOMBRE}/pubsub.yaml
488
+ k8s/overlays/dev/dapr/{NOMBRE}/secretstore.yaml
489
+ k8s/overlays/dev/routes/{NOMBRE}-route.yaml
490
+ [k8s/overlays/dev/healthcheck/{NOMBRE}-api-hc.yaml] (si HAS_API)
491
+ [k8s/overlays/dev/healthcheck/{NOMBRE}-mfe-hc.yaml] (si HAS_MFE)
492
+ environments/dev.yaml ← service + namespace
493
+ environments/shared.yaml ← service + roles IAM
494
+ [k8s/overlays/dev/import-map/import-map.yaml] (si HAS_MFE)
495
+ {LOCAL_REPO_PATH}/.github/workflows/ci-pipeline.yml ← pipeline estándar aplicado
496
+
497
+ ⚠️ PASOS MANUALES REQUERIDOS (en orden):
498
+
499
+ 0. Ejecutar Fase A — Validación previa:
500
+ - API Guard: habilitar APIs en {PROJECT_ID}
501
+ - Confirmar WI Binding existente para {SA_NAME}
502
+ - Verificar Production-Ready checklist en {GITHUB_REPO}
503
+
504
+ 1. Puertos locales — agregar en docs/developer-guide.md:
505
+ {NOMBRE}: [API {API_PORT}] (si HAS_API) / [MFE {MFE_PORT}] (si HAS_MFE)
506
+
507
+ [Si HAS_API = true]
508
+ 2. Secret Manager — crear antes del primer CI/CD:
509
+ gcloud secrets create {NOMBRE}-dev-db-connection \
510
+ --project={PROJECT_ID} \
511
+ --data-file=<(echo "Host=127.0.0.1;Port=5432;Database=finance-dev;Username=dev;Password=CHANGE_ME")
512
+
513
+ ⚠️ Naming: esta transversal usa `{NOMBRE}-dev-db-connection`.
514
+ Estándar org: `sec-sie-{NOMBRE}-dev-db`. Referenciar desde Secret Manager en
515
+ ambos casos — nunca pasar contraseñas como variable de entorno plana.
516
+
517
+ [Si HAS_API = true]
518
+ 3. Cloud SQL — ejecutar DDL de grants (usar /sa-onboard-db {schema} {owner-role}):
519
+ Reemplaza {schema} con el nombre del schema PostgreSQL del servicio.
520
+
521
+ 4. Registrar permisos en access-manager (usar /sa-registrar-permisos):
522
+ Después del primer deploy exitoso. Solo aplica si HAS_API = true.
523
+
524
+ 5. Commit en este repo deploy + push a main → infra-pipeline-dev disparará automáticamente.
525
+
526
+ 6. Artefactos inmutables — verificar en el pipeline:
527
+ - Docker images se etiquetan con el SHA completo del commit (inmutables por diseño).
528
+ - NUNCA re-buildear el mismo código para distintos ambientes.
529
+ - Para QAS/PROD: promover el digest existente de dev — no hacer nuevo build.
530
+ ```