swl-ses 3.3.2

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 (177) hide show
  1. package/CLAUDE.md +425 -0
  2. package/_userland/agentes/.gitkeep +0 -0
  3. package/_userland/habilidades/.gitkeep +0 -0
  4. package/agentes/accesibilidad-wcag-swl.md +683 -0
  5. package/agentes/arquitecto-swl.md +210 -0
  6. package/agentes/auto-evolucion-swl.md +408 -0
  7. package/agentes/backend-api-swl.md +442 -0
  8. package/agentes/backend-node-swl.md +439 -0
  9. package/agentes/backend-python-swl.md +469 -0
  10. package/agentes/backend-workers-swl.md +444 -0
  11. package/agentes/cloud-infra-swl.md +466 -0
  12. package/agentes/consolidador-swl.md +487 -0
  13. package/agentes/datos-swl.md +568 -0
  14. package/agentes/depurador-swl.md +301 -0
  15. package/agentes/devops-ci-swl.md +352 -0
  16. package/agentes/disenador-ui-swl.md +546 -0
  17. package/agentes/documentador-swl.md +323 -0
  18. package/agentes/frontend-angular-swl.md +603 -0
  19. package/agentes/frontend-css-swl.md +700 -0
  20. package/agentes/frontend-react-swl.md +672 -0
  21. package/agentes/frontend-swl.md +483 -0
  22. package/agentes/frontend-tailwind-swl.md +808 -0
  23. package/agentes/implementador-swl.md +235 -0
  24. package/agentes/investigador-swl.md +274 -0
  25. package/agentes/investigador-ux-swl.md +482 -0
  26. package/agentes/migrador-swl.md +389 -0
  27. package/agentes/mobile-android-swl.md +473 -0
  28. package/agentes/mobile-cross-swl.md +501 -0
  29. package/agentes/mobile-ios-swl.md +464 -0
  30. package/agentes/notificador-swl.md +886 -0
  31. package/agentes/observabilidad-swl.md +408 -0
  32. package/agentes/orquestador-swl.md +490 -0
  33. package/agentes/planificador-swl.md +222 -0
  34. package/agentes/producto-prd-swl.md +565 -0
  35. package/agentes/release-manager-swl.md +545 -0
  36. package/agentes/rendimiento-swl.md +691 -0
  37. package/agentes/revisor-codigo-swl.md +254 -0
  38. package/agentes/revisor-seguridad-swl.md +316 -0
  39. package/agentes/tdd-qa-swl.md +323 -0
  40. package/agentes/ux-disenador-swl.md +498 -0
  41. package/bin/swl-ses.js +119 -0
  42. package/comandos/swl/actualizar.md +117 -0
  43. package/comandos/swl/aprender.md +348 -0
  44. package/comandos/swl/auditar-deps.md +390 -0
  45. package/comandos/swl/autoresearch.md +346 -0
  46. package/comandos/swl/checkpoint.md +296 -0
  47. package/comandos/swl/compactar.md +283 -0
  48. package/comandos/swl/crear-skill.md +609 -0
  49. package/comandos/swl/discutir-fase.md +230 -0
  50. package/comandos/swl/ejecutar-fase.md +302 -0
  51. package/comandos/swl/evolucionar.md +377 -0
  52. package/comandos/swl/instalar.md +220 -0
  53. package/comandos/swl/mapear-codebase.md +205 -0
  54. package/comandos/swl/nuevo-proyecto.md +154 -0
  55. package/comandos/swl/planear-fase.md +221 -0
  56. package/comandos/swl/release.md +405 -0
  57. package/comandos/swl/salud.md +382 -0
  58. package/comandos/swl/verificar.md +292 -0
  59. package/habilidades/accesibilidad-a11y/SKILL.md +584 -0
  60. package/habilidades/angular-avanzado/SKILL.md +491 -0
  61. package/habilidades/angular-moderno/SKILL.md +326 -0
  62. package/habilidades/api-rest-diseno/SKILL.md +302 -0
  63. package/habilidades/api-rest-diseno/recursos/openapi-template.yaml +506 -0
  64. package/habilidades/aprendizaje-continuo/SKILL.md +369 -0
  65. package/habilidades/async-python/SKILL.md +474 -0
  66. package/habilidades/auth-patrones/SKILL.md +488 -0
  67. package/habilidades/auto-evolucion-protocolo/SKILL.md +376 -0
  68. package/habilidades/autoresearch/SKILL.md +248 -0
  69. package/habilidades/autoresearch/recursos/checklist-template.md +191 -0
  70. package/habilidades/autoresearch/scripts/calcular-score.js +88 -0
  71. package/habilidades/checklist-calidad/SKILL.md +247 -0
  72. package/habilidades/checklist-calidad/recursos/quality-report-template.md +148 -0
  73. package/habilidades/checklist-seguridad/SKILL.md +224 -0
  74. package/habilidades/checkpoints-verificacion/SKILL.md +309 -0
  75. package/habilidades/checkpoints-verificacion/recursos/checkpoint-templates.md +360 -0
  76. package/habilidades/ci-cd-pipelines/SKILL.md +583 -0
  77. package/habilidades/ci-cd-pipelines/recursos/github-actions-template.yaml +403 -0
  78. package/habilidades/cloud-aws/SKILL.md +497 -0
  79. package/habilidades/compactacion-contexto/SKILL.md +201 -0
  80. package/habilidades/contenedores-docker/SKILL.md +453 -0
  81. package/habilidades/contenedores-docker/recursos/dockerfile-template.dockerfile +160 -0
  82. package/habilidades/css-moderno/SKILL.md +463 -0
  83. package/habilidades/datos-etl/SKILL.md +486 -0
  84. package/habilidades/dependencias-auditoria/SKILL.md +293 -0
  85. package/habilidades/deprecacion-migracion/SKILL.md +485 -0
  86. package/habilidades/design-tokens/SKILL.md +519 -0
  87. package/habilidades/discutir-fase/SKILL.md +167 -0
  88. package/habilidades/diseno-responsivo/SKILL.md +326 -0
  89. package/habilidades/django-experto/SKILL.md +395 -0
  90. package/habilidades/doc-sync/SKILL.md +259 -0
  91. package/habilidades/ejecutar-fase/SKILL.md +199 -0
  92. package/habilidades/estructura-proyecto-claude/SKILL.md +459 -0
  93. package/habilidades/estructura-proyecto-claude/recursos/claude-md-template.md +261 -0
  94. package/habilidades/estructura-proyecto-claude/recursos/frontmatter-y-hooks-referencia.md +213 -0
  95. package/habilidades/estructura-proyecto-claude/recursos/mcp-json-template.json +77 -0
  96. package/habilidades/estructura-proyecto-claude/recursos/variantes-por-stack.md +177 -0
  97. package/habilidades/event-driven/SKILL.md +580 -0
  98. package/habilidades/extractor-de-aprendizajes/SKILL.md +234 -0
  99. package/habilidades/fastapi-experto/SKILL.md +368 -0
  100. package/habilidades/frontend-avanzado/SKILL.md +555 -0
  101. package/habilidades/git-worktrees-paralelo/SKILL.md +246 -0
  102. package/habilidades/iam-secretos/SKILL.md +511 -0
  103. package/habilidades/instalar-sistema/SKILL.md +140 -0
  104. package/habilidades/kubernetes-orquestacion/SKILL.md +549 -0
  105. package/habilidades/manejo-errores/SKILL.md +512 -0
  106. package/habilidades/mapear-codebase/SKILL.md +199 -0
  107. package/habilidades/microservicios/SKILL.md +473 -0
  108. package/habilidades/mobile-flutter/SKILL.md +566 -0
  109. package/habilidades/mobile-react-native/SKILL.md +493 -0
  110. package/habilidades/monitoring-alertas/SKILL.md +447 -0
  111. package/habilidades/node-experto/SKILL.md +521 -0
  112. package/habilidades/notificaciones-multicanal/SKILL.md +448 -0
  113. package/habilidades/notificaciones-multicanal/recursos/config-template.json +115 -0
  114. package/habilidades/nuevo-proyecto/SKILL.md +183 -0
  115. package/habilidades/patrones-python/SKILL.md +381 -0
  116. package/habilidades/performance-baseline/SKILL.md +243 -0
  117. package/habilidades/planear-fase/SKILL.md +184 -0
  118. package/habilidades/postgresql-experto/SKILL.md +379 -0
  119. package/habilidades/react-experto/SKILL.md +434 -0
  120. package/habilidades/react-optimizacion/SKILL.md +328 -0
  121. package/habilidades/release-semver/SKILL.md +226 -0
  122. package/habilidades/release-semver/scripts/generar-changelog.sh +238 -0
  123. package/habilidades/sql-optimizacion/SKILL.md +314 -0
  124. package/habilidades/tailwind-experto/SKILL.md +412 -0
  125. package/habilidades/tdd-workflow/SKILL.md +267 -0
  126. package/habilidades/testing-python/SKILL.md +350 -0
  127. package/habilidades/threat-model-lite/SKILL.md +218 -0
  128. package/habilidades/typescript-avanzado/SKILL.md +454 -0
  129. package/habilidades/ux-diseno/SKILL.md +488 -0
  130. package/habilidades/validacion-ci-sistema/SKILL.md +543 -0
  131. package/habilidades/validacion-ci-sistema/scripts/validar-sistema.sh +286 -0
  132. package/habilidades/verificar-trabajo/SKILL.md +208 -0
  133. package/habilidades/wireframes-flujos/SKILL.md +396 -0
  134. package/habilidades/workflow-claude-code/SKILL.md +359 -0
  135. package/hooks/calidad-pre-commit.js +578 -0
  136. package/hooks/escaneo-secretos.js +302 -0
  137. package/hooks/extraccion-aprendizajes.js +550 -0
  138. package/hooks/linea-estado.js +249 -0
  139. package/hooks/monitor-contexto.js +230 -0
  140. package/hooks/proteccion-rutas.js +249 -0
  141. package/manifiestos/hooks-config.json +41 -0
  142. package/manifiestos/modulos.json +318 -0
  143. package/manifiestos/perfiles.json +189 -0
  144. package/package.json +45 -0
  145. package/plantillas/PROJECT.md +122 -0
  146. package/plantillas/REQUIREMENTS.md +132 -0
  147. package/plantillas/ROADMAP.md +143 -0
  148. package/plantillas/STATE.md +109 -0
  149. package/plantillas/research/ARCHITECTURE.md +220 -0
  150. package/plantillas/research/FEATURES.md +175 -0
  151. package/plantillas/research/PITFALLS.md +299 -0
  152. package/plantillas/research/STACK.md +233 -0
  153. package/plantillas/research/SUMMARY.md +165 -0
  154. package/plugin.json +144 -0
  155. package/reglas/accesibilidad.md +269 -0
  156. package/reglas/api-diseno.md +400 -0
  157. package/reglas/arquitectura.md +183 -0
  158. package/reglas/cloud-infra.md +247 -0
  159. package/reglas/docs.md +245 -0
  160. package/reglas/estilo-codigo.md +179 -0
  161. package/reglas/git-workflow.md +186 -0
  162. package/reglas/performance.md +195 -0
  163. package/reglas/pruebas.md +159 -0
  164. package/reglas/seguridad.md +151 -0
  165. package/reglas/skills-estandar.md +473 -0
  166. package/scripts/actualizar.js +51 -0
  167. package/scripts/desinstalar.js +86 -0
  168. package/scripts/doctor.js +222 -0
  169. package/scripts/inicializar.js +89 -0
  170. package/scripts/instalador.js +333 -0
  171. package/scripts/lib/detectar-runtime.js +177 -0
  172. package/scripts/lib/estado.js +112 -0
  173. package/scripts/lib/hooks-settings.js +283 -0
  174. package/scripts/lib/manifiestos.js +138 -0
  175. package/scripts/lib/seguridad.js +160 -0
  176. package/scripts/publicar.js +209 -0
  177. package/scripts/validar.js +120 -0
@@ -0,0 +1,497 @@
1
+ ---
2
+ name: cloud-aws
3
+ description: Mejores prácticas de AWS. EC2, S3, RDS, Lambda, ECS/EKS, CloudFront, IAM, VPC, SQS/SNS, DynamoDB. Well-Architected Framework, optimización de costos, patrones serverless vs containers.
4
+ ---
5
+
6
+ # AWS — Mejores Prácticas de Nube
7
+
8
+ Este skill cubre decisiones de arquitectura, seguridad y costos en AWS para sistemas
9
+ de producción. Los ejemplos usan Python (boto3) y configuración de infraestructura.
10
+
11
+ ---
12
+
13
+ ## 1. Well-Architected Framework — 6 Pilares
14
+
15
+ | Pilar | Pregunta clave |
16
+ |-------|---------------|
17
+ | **Excelencia operativa** | ¿Puedes operar y mejorar continuamente? |
18
+ | **Seguridad** | ¿Proteges la información y los sistemas? |
19
+ | **Confiabilidad** | ¿Recuperas de fallos automáticamente? |
20
+ | **Eficiencia de desempeño** | ¿Usas recursos eficientemente? |
21
+ | **Optimización de costos** | ¿Pagas solo por lo que usas? |
22
+ | **Sostenibilidad** | ¿Minimizas impacto ambiental? |
23
+
24
+ ---
25
+
26
+ ## 2. IAM — Mínimo Privilegio Siempre
27
+
28
+ ```json
29
+ // MAL: permisos de administrador para una Lambda
30
+ {
31
+ "Effect": "Allow",
32
+ "Action": "*",
33
+ "Resource": "*"
34
+ }
35
+
36
+ // BIEN: solo lo que necesita la función
37
+ {
38
+ "Version": "2012-10-17",
39
+ "Statement": [
40
+ {
41
+ "Sid": "LeerBucketNomina",
42
+ "Effect": "Allow",
43
+ "Action": ["s3:GetObject", "s3:ListBucket"],
44
+ "Resource": [
45
+ "arn:aws:s3:::empresa-nomina-prod",
46
+ "arn:aws:s3:::empresa-nomina-prod/*"
47
+ ]
48
+ },
49
+ {
50
+ "Sid": "EscribirSecretosNomina",
51
+ "Effect": "Allow",
52
+ "Action": ["secretsmanager:GetSecretValue"],
53
+ "Resource": "arn:aws:secretsmanager:us-east-1:123456789:secret:nomina/*"
54
+ }
55
+ ]
56
+ }
57
+ ```
58
+
59
+ ```python
60
+ import boto3
61
+
62
+ # NUNCA hardcodear credenciales AWS
63
+ # MAL:
64
+ # cliente = boto3.client('s3', aws_access_key_id='AKIA...', aws_secret_access_key='...')
65
+
66
+ # BIEN: usar IAM roles (en EC2/ECS/Lambda automático) o ~/.aws/credentials en local
67
+ cliente_s3 = boto3.client('s3', region_name='us-east-1')
68
+
69
+ # BIEN: usar AWS Secrets Manager para credenciales de terceros
70
+ import json
71
+
72
+ def obtener_credenciales_db() -> dict:
73
+ cliente = boto3.client('secretsmanager', region_name='us-east-1')
74
+ respuesta = cliente.get_secret_value(SecretId='prod/miaplicacion/rds')
75
+ return json.loads(respuesta['SecretString'])
76
+ ```
77
+
78
+ ---
79
+
80
+ ## 3. VPC — Red Segura
81
+
82
+ ```
83
+ Arquitectura de red recomendada:
84
+
85
+ VPC: 10.0.0.0/16
86
+ ├── Public Subnets (2 AZs) — ALB, NAT Gateway, Bastion
87
+ │ ├── 10.0.1.0/24 (us-east-1a)
88
+ │ └── 10.0.2.0/24 (us-east-1b)
89
+ ├── Private App Subnets (2 AZs) — ECS Tasks, EC2 App servers
90
+ │ ├── 10.0.11.0/24 (us-east-1a)
91
+ │ └── 10.0.12.0/24 (us-east-1b)
92
+ └── Private Data Subnets (2 AZs) — RDS, ElastiCache
93
+ ├── 10.0.21.0/24 (us-east-1a)
94
+ └── 10.0.22.0/24 (us-east-1b)
95
+
96
+ Reglas:
97
+ - Internet → ALB (80, 443) ✓
98
+ - ALB → App Servers (8000) ✓
99
+ - App Servers → RDS (5432) ✓
100
+ - App Servers → Internet via NAT (outbound) ✓
101
+ - RDS → Internet ✗ NUNCA
102
+ ```
103
+
104
+ ### Security Groups — Regla de mínimo privilegio
105
+
106
+ ```python
107
+ # Terraform-style pseudocódigo
108
+ security_groups = {
109
+ "alb_sg": {
110
+ "ingress": [
111
+ {"from": 80, "to": 80, "cidr": "0.0.0.0/0"},
112
+ {"from": 443, "to": 443, "cidr": "0.0.0.0/0"},
113
+ ],
114
+ "egress": [{"from": 8000, "to": 8000, "sg": "app_sg"}],
115
+ },
116
+ "app_sg": {
117
+ "ingress": [{"from": 8000, "to": 8000, "sg": "alb_sg"}],
118
+ "egress": [
119
+ {"from": 5432, "to": 5432, "sg": "rds_sg"},
120
+ {"from": 443, "to": 443, "cidr": "0.0.0.0/0"}, # APIs externas
121
+ ],
122
+ },
123
+ "rds_sg": {
124
+ "ingress": [{"from": 5432, "to": 5432, "sg": "app_sg"}],
125
+ "egress": [], # RDS no necesita salida
126
+ },
127
+ }
128
+ ```
129
+
130
+ ---
131
+
132
+ ## 4. S3 — Almacenamiento Seguro
133
+
134
+ ```python
135
+ import boto3
136
+ from botocore.exceptions import ClientError
137
+
138
+ cliente_s3 = boto3.client('s3')
139
+
140
+ # OBLIGATORIO: cifrado en reposo + versionado + bloquear acceso público
141
+ def configurar_bucket_seguro(nombre_bucket: str) -> None:
142
+ s3 = boto3.client('s3')
143
+
144
+ # Bloquear acceso público (SIEMPRE para datos sensibles)
145
+ s3.put_public_access_block(
146
+ Bucket=nombre_bucket,
147
+ PublicAccessBlockConfiguration={
148
+ 'BlockPublicAcls': True,
149
+ 'IgnorePublicAcls': True,
150
+ 'BlockPublicPolicy': True,
151
+ 'RestrictPublicBuckets': True,
152
+ }
153
+ )
154
+
155
+ # Cifrado AES-256 o KMS
156
+ s3.put_bucket_encryption(
157
+ Bucket=nombre_bucket,
158
+ ServerSideEncryptionConfiguration={
159
+ 'Rules': [{'ApplyServerSideEncryptionByDefault': {
160
+ 'SSEAlgorithm': 'aws:kms',
161
+ 'KMSMasterKeyID': 'arn:aws:kms:...',
162
+ }}]
163
+ }
164
+ )
165
+
166
+ # Versionado (recuperación ante errores)
167
+ s3.put_bucket_versioning(
168
+ Bucket=nombre_bucket,
169
+ VersioningConfiguration={'Status': 'Enabled'}
170
+ )
171
+
172
+ # URLs prefirmadas para descarga sin exponer bucket público
173
+ def generar_url_descarga(bucket: str, clave: str, segundos: int = 3600) -> str:
174
+ return cliente_s3.generate_presigned_url(
175
+ 'get_object',
176
+ Params={'Bucket': bucket, 'Key': clave},
177
+ ExpiresIn=segundos,
178
+ )
179
+
180
+ # Ciclo de vida — bajar costos moviendo a clases más baratas
181
+ lifecycle_policy = {
182
+ 'Rules': [{
183
+ 'ID': 'ArchivarDocumentosViejos',
184
+ 'Status': 'Enabled',
185
+ 'Transitions': [
186
+ {'Days': 30, 'StorageClass': 'STANDARD_IA'},
187
+ {'Days': 90, 'StorageClass': 'GLACIER'},
188
+ {'Days': 365, 'StorageClass': 'DEEP_ARCHIVE'},
189
+ ],
190
+ 'Expiration': {'Days': 2555}, # 7 años
191
+ }]
192
+ }
193
+ ```
194
+
195
+ ---
196
+
197
+ ## 5. RDS — Base de Datos en Producción
198
+
199
+ ```python
200
+ # Configuración recomendada para PostgreSQL en RDS
201
+ rds_config = {
202
+ "DBInstanceClass": "db.t3.medium", # Tamaño según carga
203
+ "Engine": "postgres",
204
+ "EngineVersion": "15.4",
205
+ "MultiAZ": True, # OBLIGATORIO en producción
206
+ "StorageEncrypted": True, # OBLIGATORIO
207
+ "BackupRetentionPeriod": 7, # 7 días de backups automáticos
208
+ "EnablePerformanceInsights": True,
209
+ "PerformanceInsightsRetentionPeriod": 7,
210
+ "MonitoringInterval": 60, # Enhanced monitoring
211
+ "DeletionProtection": True, # Evitar eliminación accidental
212
+ "StorageType": "gp3",
213
+ "Iops": 3000,
214
+ }
215
+
216
+ # Connection pool recomendado para Python
217
+ DATABASE_URL = (
218
+ f"postgresql+asyncpg://{usuario}:{password}@{host}:{puerto}/{db}"
219
+ "?ssl=require" # SIEMPRE ssl en RDS
220
+ )
221
+
222
+ # Pool sizing: (núcleos_cpu * 2) + disco_efectivo
223
+ # Para db.t3.medium (2 vCPUs): pool_size = 5, max_overflow = 10
224
+ engine = create_async_engine(
225
+ DATABASE_URL,
226
+ pool_size=5,
227
+ max_overflow=10,
228
+ pool_pre_ping=True,
229
+ pool_recycle=3600, # Reciclar conexiones cada hora (evitar timeout RDS)
230
+ )
231
+ ```
232
+
233
+ ---
234
+
235
+ ## 6. Lambda — Funciones Serverless
236
+
237
+ ```python
238
+ import json
239
+ import logging
240
+ import os
241
+ from typing import Any
242
+
243
+ logger = logging.getLogger()
244
+ logger.setLevel(logging.INFO)
245
+
246
+ # Inicializar clientes FUERA del handler (reutilización en warm start)
247
+ import boto3
248
+ sqs = boto3.client('sqs')
249
+ s3 = boto3.client('s3')
250
+
251
+ def handler(event: dict, context: Any) -> dict:
252
+ """Lambda handler para procesamiento de eventos SQS."""
253
+ logger.info("Evento recibido: %s registros", len(event.get('Records', [])))
254
+
255
+ errores = []
256
+ for record in event.get('Records', []):
257
+ try:
258
+ body = json.loads(record['body'])
259
+ procesar_registro(body)
260
+ except Exception as e:
261
+ logger.error("Error en record %s: %s", record['messageId'], e)
262
+ errores.append({'itemIdentifier': record['messageId']})
263
+
264
+ # Partial batch response — solo reintentar los que fallaron
265
+ return {'batchItemFailures': errores}
266
+
267
+ def procesar_registro(datos: dict) -> None:
268
+ # Lógica de negocio aquí
269
+ pass
270
+
271
+ # Configuración recomendada en serverless.yml / CDK
272
+ lambda_config = {
273
+ "timeout": 30, # Segundos. Nunca dejar el default (3s)
274
+ "memory_size": 512, # MB. Benchmark para encontrar sweet spot
275
+ "reserved_concurrency": 10, # Evitar que explote en concurrencia
276
+ "environment": {
277
+ "QUEUE_URL": "${ssm:/prod/cola-procesamiento}",
278
+ "LOG_LEVEL": "INFO",
279
+ },
280
+ "layers": ["arn:aws:lambda:us-east-1:...:layer:deps:5"], # Dependencias
281
+ }
282
+ ```
283
+
284
+ ---
285
+
286
+ ## 7. ECS Fargate — Containers Administrados
287
+
288
+ ```yaml
289
+ # task-definition.json
290
+ {
291
+ "family": "api-nomina",
292
+ "networkMode": "awsvpc",
293
+ "requiresCompatibilities": ["FARGATE"],
294
+ "cpu": "512",
295
+ "memory": "1024",
296
+ "executionRoleArn": "arn:aws:iam::...:role/ecsTaskExecutionRole",
297
+ "taskRoleArn": "arn:aws:iam::...:role/ecsTaskRole",
298
+ "containerDefinitions": [{
299
+ "name": "api",
300
+ "image": "123456789.dkr.ecr.us-east-1.amazonaws.com/api-nomina:latest",
301
+ "portMappings": [{"containerPort": 8000, "protocol": "tcp"}],
302
+ "environment": [],
303
+ "secrets": [
304
+ {
305
+ "name": "DATABASE_URL",
306
+ "valueFrom": "arn:aws:secretsmanager:...:secret:prod/db-url"
307
+ }
308
+ ],
309
+ "logConfiguration": {
310
+ "logDriver": "awslogs",
311
+ "options": {
312
+ "awslogs-group": "/ecs/api-nomina",
313
+ "awslogs-region": "us-east-1",
314
+ "awslogs-stream-prefix": "ecs"
315
+ }
316
+ },
317
+ "healthCheck": {
318
+ "command": ["CMD-SHELL", "curl -f http://localhost:8000/health || exit 1"],
319
+ "interval": 30,
320
+ "timeout": 5,
321
+ "retries": 3,
322
+ "startPeriod": 60
323
+ }
324
+ }]
325
+ }
326
+ ```
327
+
328
+ ---
329
+
330
+ ## 8. SQS/SNS — Mensajería Desacoplada
331
+
332
+ ```python
333
+ import boto3
334
+ import json
335
+ from typing import Any
336
+
337
+ sqs = boto3.client('sqs', region_name='us-east-1')
338
+ sns = boto3.client('sns', region_name='us-east-1')
339
+
340
+ QUEUE_URL = os.environ['QUEUE_URL']
341
+
342
+ def enviar_mensaje(payload: dict, grupo_id: str | None = None) -> str:
343
+ """Enviar mensaje a SQS. grupo_id para FIFO queues."""
344
+ kwargs: dict[str, Any] = {
345
+ 'QueueUrl': QUEUE_URL,
346
+ 'MessageBody': json.dumps(payload, ensure_ascii=False),
347
+ 'MessageAttributes': {
348
+ 'ContentType': {
349
+ 'StringValue': 'application/json',
350
+ 'DataType': 'String',
351
+ }
352
+ },
353
+ }
354
+ if grupo_id: # FIFO queue
355
+ import uuid
356
+ kwargs['MessageGroupId'] = grupo_id
357
+ kwargs['MessageDeduplicationId'] = str(uuid.uuid4())
358
+
359
+ respuesta = sqs.send_message(**kwargs)
360
+ return respuesta['MessageId']
361
+
362
+ def procesar_mensajes(max_mensajes: int = 10) -> None:
363
+ """Polling de mensajes con visibilidad extendida."""
364
+ mensajes = sqs.receive_message(
365
+ QueueUrl=QUEUE_URL,
366
+ MaxNumberOfMessages=max_mensajes,
367
+ WaitTimeSeconds=20, # Long polling — más eficiente
368
+ VisibilityTimeout=60, # Tiempo para procesar
369
+ AttributeNames=['All'],
370
+ ).get('Messages', [])
371
+
372
+ for msg in mensajes:
373
+ try:
374
+ body = json.loads(msg['Body'])
375
+ procesar(body)
376
+ # Eliminar solo si se procesó exitosamente
377
+ sqs.delete_message(
378
+ QueueUrl=QUEUE_URL,
379
+ ReceiptHandle=msg['ReceiptHandle'],
380
+ )
381
+ except Exception as e:
382
+ logger.error("Error procesando mensaje %s: %s", msg['MessageId'], e)
383
+ # Dejar en cola — irá a DLQ después de maxReceiveCount intentos
384
+
385
+ # Dead Letter Queue — SIEMPRE configurar para auditoría
386
+ dlq_config = {
387
+ 'deadLetterTargetArn': 'arn:aws:sqs:...:cola-nomina-dlq',
388
+ 'maxReceiveCount': '3', # 3 intentos antes de enviar a DLQ
389
+ }
390
+ ```
391
+
392
+ ---
393
+
394
+ ## 9. CloudFront — CDN y Caché
395
+
396
+ ```python
397
+ # Política de caché para API (no cachear datos privados)
398
+ cache_policy = {
399
+ "DefaultTTL": 0,
400
+ "MaxTTL": 0,
401
+ "MinTTL": 0,
402
+ # Assets estáticos: TTL largo
403
+ }
404
+
405
+ # Para frontend SPA en S3 + CloudFront
406
+ distribution_config = {
407
+ "Origins": [{
408
+ "DomainName": "mi-bucket.s3.amazonaws.com",
409
+ "S3OriginConfig": {"OriginAccessIdentity": "origin-access-identity/cloudfront/..."},
410
+ }],
411
+ "DefaultCacheBehavior": {
412
+ "ViewerProtocolPolicy": "redirect-to-https", # SIEMPRE
413
+ "CachePolicyId": "...",
414
+ "ResponseHeadersPolicyId": "...", # Security headers
415
+ },
416
+ "CustomErrorResponses": [
417
+ # SPA routing: 404 → index.html
418
+ {"ErrorCode": 404, "ResponseCode": 200, "ResponsePagePath": "/index.html"},
419
+ {"ErrorCode": 403, "ResponseCode": 200, "ResponsePagePath": "/index.html"},
420
+ ],
421
+ "HttpVersion": "http2and3",
422
+ "PriceClass": "PriceClass_100", # Solo Norte América + Europa
423
+ }
424
+ ```
425
+
426
+ ---
427
+
428
+ ## 10. Optimización de Costos
429
+
430
+ ### Estrategias principales
431
+
432
+ | Servicio | Optimización | Ahorro estimado |
433
+ |----------|-------------|-----------------|
434
+ | EC2/ECS | Spot instances para workers | 60-90% |
435
+ | EC2 | Reserved instances (1-3 años) | 30-60% |
436
+ | RDS | Stop en entornos de dev/staging | 60-70% |
437
+ | S3 | Lifecycle policies | 40-80% en archivos viejos |
438
+ | Lambda | Ajustar memoria (benchmark) | 20-50% |
439
+ | CloudFront | Comprimir respuestas | Reduce transferencia |
440
+ | Data Transfer | Mantener tráfico en misma AZ/región | Evita cargos |
441
+
442
+ ```python
443
+ # AWS Cost Anomaly Detection — alertas automáticas
444
+ import boto3
445
+
446
+ ce = boto3.client('ce', region_name='us-east-1')
447
+
448
+ def crear_monitor_costos(email: str) -> None:
449
+ monitor = ce.create_anomaly_monitor(
450
+ AnomalyMonitor={
451
+ 'MonitorName': 'MonitorGeneral',
452
+ 'MonitorType': 'DIMENSIONAL',
453
+ 'MonitorDimension': 'SERVICE',
454
+ }
455
+ )
456
+
457
+ ce.create_anomaly_subscription(
458
+ AnomalySubscription={
459
+ 'MonitorArnList': [monitor['MonitorArn']],
460
+ 'Subscribers': [{'Address': email, 'Type': 'EMAIL'}],
461
+ 'Threshold': 20.0, # Alertar si costo aumenta $20 USD
462
+ 'Frequency': 'DAILY',
463
+ 'SubscriptionName': 'AlertasCostoDiario',
464
+ }
465
+ )
466
+ ```
467
+
468
+ ---
469
+
470
+ ## 11. Checklist de Arquitectura AWS
471
+
472
+ ### Seguridad
473
+ - [ ] Sin credenciales hardcodeadas — IAM roles siempre
474
+ - [ ] MFA activado en cuenta root y usuarios IAM admin
475
+ - [ ] CloudTrail habilitado en todas las regiones
476
+ - [ ] Config Rules para compliance
477
+ - [ ] GuardDuty habilitado para detección de amenazas
478
+
479
+ ### Confiabilidad
480
+ - [ ] Multi-AZ en RDS, ElastiCache, ALB
481
+ - [ ] Auto Scaling Groups con mínimo 2 instancias
482
+ - [ ] Health checks en ALB y ECS
483
+ - [ ] Backups automatizados con retención mínima 7 días
484
+ - [ ] Runbooks documentados para fallos comunes
485
+
486
+ ### Costos
487
+ - [ ] Budget alerts configuradas ($X USD/mes)
488
+ - [ ] Lifecycle policies en S3
489
+ - [ ] Snapshots de RDS/EBS con retención limitada
490
+ - [ ] Recursos de dev/staging apagados fuera de horario laboral
491
+ - [ ] Reserved instances para carga base predecible
492
+
493
+ ### Desempeño
494
+ - [ ] CloudFront para assets estáticos
495
+ - [ ] ElastiCache para queries frecuentes
496
+ - [ ] Connection pooling en aplicación
497
+ - [ ] Read replicas para reportes pesados
@@ -0,0 +1,201 @@
1
+ ---
2
+ name: compactacion-contexto
3
+ description: Anti-context-rot. Detectar cuándo compactar el contexto, guardar estado antes de compactar, técnicas de resumen progresivo y handoff limpio entre contextos.
4
+ ---
5
+
6
+ # Compactación de Contexto
7
+
8
+ ## El problema: context-rot
9
+
10
+ Un contexto largo y sin estructura se degrada con el tiempo:
11
+ - Las instrucciones tempranas quedan enterradas y se olvidan.
12
+ - El modelo pierde el hilo de qué se hizo y qué falta.
13
+ - Las respuestas se vuelven repetitivas o contradictorias.
14
+ - El rendimiento cae porque el contexto útil se diluye en tokens de ruido.
15
+
16
+ **Context-rot** es el fenómeno donde un contexto largo produce peores resultados que
17
+ uno compacto y fresco con el estado correcto cargado.
18
+
19
+ ---
20
+
21
+ ## Señales de que es hora de compactar
22
+
23
+ ### Señales cuantitativas
24
+ - La ventana de contexto está al 60% o más de su límite.
25
+ - La conversación lleva más de 40 turnos sobre el mismo proyecto.
26
+ - Se han cargado más de 5 archivos grandes sin eliminar contexto anterior.
27
+
28
+ ### Señales cualitativas
29
+ - El agente empieza a repetir preguntas ya respondidas.
30
+ - El agente olvida decisiones tomadas hace 10+ turnos.
31
+ - Las respuestas son más genéricas y menos específicas al proyecto.
32
+ - El agente contradice algo que él mismo propuso anteriormente.
33
+ - La latencia de respuesta aumenta notablemente.
34
+
35
+ ---
36
+
37
+ ## Protocolo: guardar estado ANTES de compactar
38
+
39
+ Antes de iniciar cualquier compactación, el agente DEBE persistir el estado en archivos.
40
+ El estado en la memoria del contexto desaparece; el estado en disco persiste.
41
+
42
+ ### Archivo STATE.md — estado de ejecución
43
+
44
+ ```markdown
45
+ # STATE.md — Estado del proyecto al 2026-03-25T14:32:00
46
+
47
+ ## Fase actual
48
+ - Fase: 3 — Implementación de módulo de reportes
49
+ - Sprint: 2 de 3
50
+ - Última tarea completada: Endpoint GET /reportes/{id}
51
+ - Próxima tarea: Endpoint POST /reportes (slice 3.2)
52
+
53
+ ## Decisiones arquitectónicas tomadas
54
+ - Se usa PostgreSQL con JSONB para metadatos de reportes (no MongoDB).
55
+ - Autenticación via JWT con refresh tokens, no sesiones.
56
+ - El frontend es Angular standalone, sin NgModules.
57
+ - Paginación por cursor, no por offset.
58
+
59
+ ## Archivos modificados en esta sesión
60
+ - backend/app/routers/reportes.py (creado)
61
+ - backend/app/schemas/reporte.py (creado)
62
+ - backend/app/models/reporte.py (modificado: campo metadata JSONB)
63
+ - frontend/src/app/reportes/reportes.component.ts (creado)
64
+
65
+ ## Problemas conocidos / deuda técnica
66
+ - El endpoint DELETE /reportes/{id} falta validación de permisos (ticket #47)
67
+ - La migración 003_reportes.py necesita revisión manual antes de producción
68
+
69
+ ## Tests en estado rojo
70
+ - test_reporte_exportar_pdf → falta dependencia wkhtmltopdf en CI
71
+
72
+ ## Contexto del negocio relevante
73
+ - Los reportes son propiedad del usuario que los crea (no del admin).
74
+ - Los reportes tienen un TTL de 30 días, luego se archivan.
75
+ ```
76
+
77
+ ### Archivo DECISIONS.md — registro de decisiones
78
+
79
+ ```markdown
80
+ # DECISIONS.md
81
+
82
+ ## 2026-03-25 — Paginación por cursor
83
+ **Contexto**: El endpoint GET /reportes necesitaba paginación.
84
+ **Opciones evaluadas**: offset/limit, cursor, keyset.
85
+ **Decisión**: Cursor basado en (created_at, id) para estabilidad con datos en tiempo real.
86
+ **Consecuencia**: Los clientes no pueden saltar a página N directamente.
87
+
88
+ ## 2026-03-24 — JSONB para metadatos
89
+ **Contexto**: Los reportes tienen atributos variables por tipo.
90
+ **Decisión**: Un campo `metadata JSONB` en lugar de tabla EAV.
91
+ **Consecuencia**: Queries de metadatos requieren índices GIN.
92
+ ```
93
+
94
+ ---
95
+
96
+ ## Técnicas de resumen progresivo
97
+
98
+ ### Técnica 1: Resumen en capas
99
+
100
+ No resumir todo en un solo párrafo plano. Usar capas de detalle:
101
+
102
+ ```
103
+ Nivel 0 (1 línea): "Construyendo API REST de reportes con FastAPI + PostgreSQL."
104
+ Nivel 1 (5 líneas): qué fases hay, en cuál estamos, cuál es el siguiente paso.
105
+ Nivel 2 (20 líneas): decisiones clave, archivos importantes, problemas abiertos.
106
+ Nivel 3 (archivo completo): STATE.md detallado.
107
+ ```
108
+
109
+ Cargar el nivel de detalle apropiado según la tarea a realizar.
110
+
111
+ ### Técnica 2: Resumen por dominios
112
+
113
+ Separar el contexto en dominios independientes:
114
+
115
+ ```markdown
116
+ ## Dominio: Backend API
117
+ - Rutas implementadas: GET/POST/DELETE /reportes
118
+ - Pendiente: PUT /reportes/{id}, webhooks
119
+
120
+ ## Dominio: Frontend Angular
121
+ - Componentes: ReportesListComponent, ReporteDetalleComponent
122
+ - Pendiente: ReporteCrearComponent, filtros de búsqueda
123
+
124
+ ## Dominio: Base de datos
125
+ - Migraciones aplicadas: 001, 002, 003
126
+ - Pendiente: índice GIN en metadata (pendiente de medir impacto)
127
+ ```
128
+
129
+ ### Técnica 3: El "snapshot de trabajo"
130
+
131
+ Antes de compactar, crear un mensaje de handoff en lenguaje natural que un nuevo
132
+ contexto pueda leer y continuar sin perder información:
133
+
134
+ ```
135
+ Proyecto: Sistema de reportes SIGAF
136
+ Estoy implementando el módulo de reportes. Completé los endpoints de lectura
137
+ (GET /reportes y GET /reportes/{id}) con paginación por cursor y RBAC.
138
+
139
+ El siguiente paso ES implementar POST /reportes. El schema ReporteCreate ya está
140
+ en backend/app/schemas/reporte.py. El modelo ORM está en backend/app/models/reporte.py.
141
+ El servicio parcial está en backend/app/services/reporte_service.py (falta el método crear).
142
+
143
+ Importante: los reportes deben asociarse al usuario del JWT, nunca confiar en el
144
+ body del request para el owner_id.
145
+ ```
146
+
147
+ ---
148
+
149
+ ## Protocolo de handoff entre contextos
150
+
151
+ ### El contexto saliente (antes de compactar)
152
+
153
+ 1. Escribir STATE.md actualizado con toda la información relevante.
154
+ 2. Hacer commit de todos los cambios pendientes.
155
+ 3. Anotar el hash del último commit en STATE.md.
156
+ 4. Escribir el "snapshot de trabajo" como primer mensaje del nuevo contexto.
157
+
158
+ ### El contexto entrante (después de compactar)
159
+
160
+ Protocolo de arranque:
161
+
162
+ ```
163
+ 1. Leer STATE.md para entender el estado actual.
164
+ 2. Leer DECISIONS.md para entender las decisiones ya tomadas.
165
+ 3. Revisar los últimos 3 commits para entender qué se hizo recientemente.
166
+ 4. Hacer git status para ver si hay cambios sin commitear.
167
+ 5. Leer ÚNICAMENTE los archivos relevantes para la tarea actual.
168
+ ```
169
+
170
+ Nunca cargar TODO el codebase en el nuevo contexto. Cargar solo lo necesario para
171
+ la tarea inmediata.
172
+
173
+ ---
174
+
175
+ ## Estrategias de compactación activa
176
+
177
+ ### Compactación por completitud de tarea
178
+
179
+ Compactar al terminar cada tarea atómica. Una tarea completada = contexto que ya
180
+ no necesita vivir en memoria activa.
181
+
182
+ ### Compactación por fase del proyecto
183
+
184
+ Al pasar de una fase a otra (ej. del diseño a la implementación), compactar toda
185
+ la discusión de diseño y cargar solo las decisiones finales.
186
+
187
+ ### Compactación de archivos grandes
188
+
189
+ Si se leyó un archivo de 500 líneas para extraer 3 funciones relevantes, compactar
190
+ el archivo completo y mantener solo los 3 fragmentos extraídos con sus firmas.
191
+
192
+ ---
193
+
194
+ ## Anti-patrones a evitar
195
+
196
+ - **Compactar sin guardar estado**: El estado debe estar en disco ANTES de compactar.
197
+ - **Cargar todo el codebase al nuevo contexto**: Cargar solo lo necesario para la tarea.
198
+ - **Hacer el handoff en lenguaje ambiguo**: El snapshot debe ser preciso y accionable.
199
+ - **No registrar decisiones tomadas**: Las decisiones no escritas se pierden al compactar.
200
+ - **Compactar en medio de una tarea**: Terminar la unidad atómica de trabajo primero.
201
+ - **Depender de la memoria del contexto para información crítica**: Todo lo crítico va a disco.