@saulwade/swl-ses 2.4.2 → 2.5.1

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 (198) hide show
  1. package/CLAUDE.md +194 -241
  2. package/README.md +600 -597
  3. package/agentes/_intent-spec.md +73 -73
  4. package/agentes/_propose-step.md +90 -90
  5. package/agentes/abogado-diablo-swl.md +145 -0
  6. package/agentes/accesibilidad-wcag-swl.md +690 -690
  7. package/agentes/arquitecto-swl.md +267 -267
  8. package/agentes/auto-evolucion-swl.md +908 -908
  9. package/agentes/backend-api-swl.md +1 -1
  10. package/agentes/backend-csharp-swl.md +420 -420
  11. package/agentes/backend-go-swl.md +390 -390
  12. package/agentes/backend-java-swl.md +281 -281
  13. package/agentes/backend-node-swl.md +1 -1
  14. package/agentes/backend-python-swl.md +1 -1
  15. package/agentes/backend-rust-swl.md +364 -364
  16. package/agentes/backend-workers-swl.md +482 -482
  17. package/agentes/cloud-infra-swl.md +509 -509
  18. package/agentes/consolidador-swl.md +541 -541
  19. package/agentes/datos-swl.md +1 -1
  20. package/agentes/depurador-swl.md +352 -352
  21. package/agentes/devops-ci-swl.md +400 -400
  22. package/agentes/disenador-ui-swl.md +569 -569
  23. package/agentes/documentador-swl.md +345 -345
  24. package/agentes/frontend-angular-swl.md +621 -621
  25. package/agentes/frontend-css-swl.md +716 -716
  26. package/agentes/frontend-react-swl.md +692 -692
  27. package/agentes/frontend-swl.md +496 -496
  28. package/agentes/frontend-tailwind-swl.md +826 -826
  29. package/agentes/gh-fix-ci-swl.md +6 -1
  30. package/agentes/implementador-swl.md +1 -1
  31. package/agentes/investigador-swl.md +432 -432
  32. package/agentes/investigador-ux-swl.md +505 -505
  33. package/agentes/llm-apps-swl.md +1 -1
  34. package/agentes/migrador-swl.md +442 -442
  35. package/agentes/mobile-android-swl.md +511 -511
  36. package/agentes/mobile-cross-swl.md +541 -541
  37. package/agentes/mobile-ios-swl.md +502 -502
  38. package/agentes/mobile-testing-swl.md +302 -302
  39. package/agentes/nemesis-auditor-swl.md +285 -285
  40. package/agentes/notificador-swl.md +1 -1
  41. package/agentes/observabilidad-swl.md +438 -438
  42. package/agentes/pagos-swl.md +310 -310
  43. package/agentes/perfilador-usuario-swl.md +321 -321
  44. package/agentes/planificador-swl.md +399 -399
  45. package/agentes/producto-prd-swl.md +589 -589
  46. package/agentes/red-team-swl.md +218 -218
  47. package/agentes/release-manager-swl.md +590 -590
  48. package/agentes/rendimiento-swl.md +713 -713
  49. package/agentes/resolutor-build-swl.md +10 -1
  50. package/agentes/revisor-angular-swl.md +278 -278
  51. package/agentes/revisor-codigo-swl.md +1 -1
  52. package/agentes/revisor-csharp-swl.md +264 -264
  53. package/agentes/revisor-go-swl.md +259 -259
  54. package/agentes/revisor-java-swl.md +257 -257
  55. package/agentes/revisor-kotlin-swl.md +273 -273
  56. package/agentes/revisor-nextjs-swl.md +281 -281
  57. package/agentes/revisor-php-swl.md +271 -271
  58. package/agentes/revisor-react-swl.md +278 -278
  59. package/agentes/revisor-rust-swl.md +346 -346
  60. package/agentes/revisor-seguridad-swl.md +399 -399
  61. package/agentes/revisor-swift-swl.md +268 -268
  62. package/agentes/revisor-typescript-swl.md +346 -346
  63. package/agentes/sre-swl.md +1 -1
  64. package/agentes/tdd-qa-swl.md +393 -393
  65. package/bin/lib/bot-comandos.js +1 -1
  66. package/bin/swl-ses.js +6 -0
  67. package/comandos/swl/adoptar-proyecto.md +14 -2
  68. package/comandos/swl/configurar-ci.md +8 -1
  69. package/comandos/swl/deuda-codigo.md +97 -97
  70. package/comandos/swl/discutir-fase.md +22 -118
  71. package/comandos/swl/fix.md +118 -0
  72. package/comandos/swl/nuevo-proyecto.md +54 -3
  73. package/comandos/swl/predecir.md +32 -2
  74. package/comandos/swl/seguridad.md +189 -0
  75. package/comandos/swl/status.md +5 -3
  76. package/habilidades/aprendizaje-continuo/SKILL.md +3 -1
  77. package/habilidades/discutir-fase/SKILL.md +84 -81
  78. package/habilidades/discutir-fase/recursos/plantilla-contexto.md +136 -0
  79. package/habilidades/doc-sync/SKILL.md +3 -1
  80. package/habilidades/doubt-driven-review/SKILL.md +15 -1
  81. package/habilidades/ejecutar-task-iterativo/SKILL.md +278 -278
  82. package/habilidades/estructura-proyecto-claude/SKILL.md +11 -2
  83. package/habilidades/harness-claude-code/SKILL.md +3 -1
  84. package/habilidades/instalar-sistema/SKILL.md +3 -1
  85. package/habilidades/meta-reglas-extendido/SKILL.md +92 -0
  86. package/habilidades/meta-reglas-extendido/recursos/analisis-previo-tareas-grandes.md +186 -0
  87. package/habilidades/meta-reglas-extendido/recursos/analizar-directorios-antes-de-escribir.md +235 -0
  88. package/habilidades/meta-reglas-extendido/recursos/api-diseno.md +413 -0
  89. package/habilidades/meta-reglas-extendido/recursos/arquitectura.md +491 -0
  90. package/habilidades/meta-reglas-extendido/recursos/arreglar-al-detectar.md +264 -0
  91. package/habilidades/meta-reglas-extendido/recursos/debatir-antes-de-aceptar.md +152 -0
  92. package/habilidades/meta-reglas-extendido/recursos/git-workflow.md +259 -0
  93. package/habilidades/meta-reglas-extendido/recursos/gobernanza.md +291 -0
  94. package/habilidades/meta-reglas-extendido/recursos/memoria-consolidada.md +263 -0
  95. package/habilidades/meta-reglas-extendido/recursos/seguridad-agentes.md +443 -0
  96. package/habilidades/meta-reglas-extendido/recursos/sesiones-paralelas.md +190 -0
  97. package/habilidades/meta-reglas-extendido/recursos/sin-duplicacion-reglas-globales.md +179 -0
  98. package/habilidades/meta-reglas-extendido/recursos/skills-estandar.md +394 -0
  99. package/habilidades/meta-reglas-extendido/recursos/usar-code-review-graph.md +156 -0
  100. package/habilidades/meta-reglas-extendido/recursos/usar-context7.md +236 -0
  101. package/habilidades/meta-reglas-extendido/recursos/usar-sistema-swl.md +253 -0
  102. package/habilidades/meta-reglas-extendido/recursos/verificar-citas-normativas.md +527 -0
  103. package/habilidades/meta-skills-estandar/SKILL.md +3 -1
  104. package/habilidades/nuevo-proyecto/SKILL.md +20 -3
  105. package/habilidades/php-experto/SKILL.md +10 -3
  106. package/habilidades/{filament-admin/SKILL.md → php-experto/recursos/filament-admin.md} +23 -39
  107. package/habilidades/prevencion-sobreingenieria/recursos/soluciones-nativas.md +166 -166
  108. package/habilidades/prevencion-sobreingenieria/recursos/variables-residuales-post-refactor.md +85 -85
  109. package/habilidades/proceso-debate-adversarial/recursos/personas.md +5 -4
  110. package/habilidades/proceso-ingenieria-requerimientos/SKILL.md +147 -0
  111. package/hooks/check-update.js +19 -10
  112. package/hooks/contexto-subagente.js +68 -68
  113. package/hooks/degradacion-instintos.js +1 -1
  114. package/hooks/extraccion-aprendizajes.js +2 -2
  115. package/hooks/lib/briefing.js +3 -3
  116. package/hooks/lib/nudge-tracker.js +1 -1
  117. package/hooks/lib/otlp-exporter.js +1 -1
  118. package/hooks/lib/webhook-dedup.js +1 -1
  119. package/hooks/session-briefing.js +1 -1
  120. package/llms.txt +6 -6
  121. package/manifiestos/canonical-hashes.json +989 -0
  122. package/manifiestos/hooks-config.json +469 -469
  123. package/manifiestos/invariantes-criticos.json +30 -30
  124. package/manifiestos/modulos.json +168 -135
  125. package/manifiestos/perfiles.json +0 -2
  126. package/manifiestos/skills-lock.json +52 -59
  127. package/package.json +7 -5
  128. package/plantillas/github-workflows/README.md +15 -1
  129. package/plantillas/github-workflows/swl-devsecops.yml +70 -0
  130. package/plugin.json +5 -5
  131. package/reglas/analisis-previo-tareas-grandes.md +30 -156
  132. package/reglas/analizar-directorios-antes-de-escribir.md +30 -211
  133. package/reglas/api-diseno.md +28 -398
  134. package/reglas/arquitectura.md +35 -456
  135. package/reglas/arreglar-al-detectar.md +30 -230
  136. package/reglas/debatir-antes-de-aceptar.md +30 -143
  137. package/reglas/docs.md +7 -0
  138. package/reglas/estilo-codigo.md +9 -0
  139. package/reglas/fragmentos-compartidos.md +6 -0
  140. package/reglas/git-workflow.md +44 -240
  141. package/reglas/gobernanza.md +23 -262
  142. package/reglas/memoria-consolidada.md +34 -228
  143. package/reglas/performance.md +8 -0
  144. package/reglas/pruebas.md +12 -0
  145. package/reglas/seguridad-agentes.md +37 -418
  146. package/reglas/seguridad.md +12 -0
  147. package/reglas/sesiones-paralelas.md +29 -162
  148. package/reglas/sin-duplicacion-reglas-globales.md +25 -166
  149. package/reglas/skills-estandar.md +23 -373
  150. package/reglas/usar-code-review-graph.md +31 -140
  151. package/reglas/usar-context7.md +30 -208
  152. package/reglas/usar-sistema-swl.md +47 -242
  153. package/reglas/verificar-citas-normativas.md +47 -537
  154. package/scripts/actualizar.js +253 -253
  155. package/scripts/audit-tools/auditar-relleno-inventario.js +145 -0
  156. package/scripts/auditar-clases-conocidas.js +106 -0
  157. package/scripts/bootstrap-instintos.js +2 -2
  158. package/scripts/canario-hooks.js +166 -0
  159. package/scripts/cli/configurar-ci.js +2 -1
  160. package/scripts/evidencia-valor.js +93 -0
  161. package/scripts/field-report.js +1 -1
  162. package/scripts/generar-comandos.js +143 -0
  163. package/scripts/generar-inventario.js +236 -23
  164. package/scripts/generar-matriz-lenguajes.js +1 -1
  165. package/scripts/instalador.js +15 -1
  166. package/scripts/lib/configurar-ci.js +10 -3
  167. package/scripts/lib/detectar-runtime.js +12 -3
  168. package/scripts/lib/diary-entry.js +3 -1
  169. package/scripts/lib/drift-detector.js +1 -1
  170. package/scripts/lib/evidencia-valor.js +189 -0
  171. package/scripts/lib/expandir-targets.js +71 -71
  172. package/scripts/lib/frontmatter-md.js +63 -0
  173. package/scripts/lib/parsear-opciones.js +2 -0
  174. package/scripts/lib/prune-componentes.js +180 -0
  175. package/scripts/lib/reglas-globales-conocidas.json +16 -2
  176. package/scripts/lib/scoring-instintos.js +2 -2
  177. package/scripts/lib/toml-merge.js +204 -204
  178. package/scripts/lib/transformadores/claude.js +1 -1
  179. package/scripts/lib/transformadores/codex.js +1 -1
  180. package/scripts/lib/transformadores/copilot.js +1 -1
  181. package/scripts/lib/transformadores/cursor.js +1 -1
  182. package/scripts/lib/transformadores/gemini.js +22 -2
  183. package/scripts/lib/transformadores/opencode.js +1 -1
  184. package/scripts/mcp-server/auth.js +105 -105
  185. package/scripts/mcp-server/cache.js +106 -106
  186. package/scripts/prune.js +102 -0
  187. package/scripts/publicar.js +18 -2
  188. package/scripts/tui/pantallas/inspect.js +175 -175
  189. package/scripts/tui/pantallas/uninstall-wizard.js +210 -210
  190. package/scripts/tui/pantallas/update-wizard.js +234 -234
  191. package/scripts/tui/pantallas/welcome.js +189 -189
  192. package/habilidades/paid-media-tracking/SKILL.md +0 -269
  193. package/habilidades/paid-media-tracking/recursos/auditoria-tracking.md +0 -220
  194. package/habilidades/paid-media-tracking/recursos/google-ads-api.md +0 -215
  195. package/habilidades/tracking-measurement/SKILL.md +0 -239
  196. package/habilidades/tracking-measurement/recursos/consent-mode.md +0 -231
  197. package/habilidades/tracking-measurement/recursos/gtm-datalayer.md +0 -216
  198. package/habilidades/tracking-measurement/recursos/meta-capi.md +0 -262
@@ -0,0 +1,413 @@
1
+ # Diseño de APIs — extendido
2
+
3
+ > Contenido extraído del núcleo `reglas/api-diseno.md` durante la dieta de
4
+ > contexto (Fase D). El núcleo instalado en `~/.claude/rules/api-diseno.md`
5
+ > es la norma vigente; este documento aporta los ejemplos completos, tablas
6
+ > de códigos con casos y detalle narrativo. Si divergen, el núcleo manda.
7
+
8
+ ## Índice
9
+
10
+ - [Versionado obligatorio con prefijo de URL](#versionado-obligatorio-con-prefijo-de-url)
11
+ - [Respuestas consistentes con envelope estándar](#respuestas-consistentes-con-envelope-estándar)
12
+ - [Paginación obligatoria en endpoints de listado](#paginación-obligatoria-en-endpoints-de-listado)
13
+ - [Filtros y ordenamiento estandarizados](#filtros-y-ordenamiento-estandarizados)
14
+ - [HTTP status codes correctos](#http-status-codes-correctos)
15
+ - [Rate limiting obligatorio en endpoints públicos](#rate-limiting-obligatorio-en-endpoints-públicos)
16
+ - [CORS configurado explícitamente](#cors-configurado-explícitamente)
17
+ - [Documentación OpenAPI siempre actualizada](#documentación-openapi-siempre-actualizada)
18
+ - [Error responses con código, mensaje y detalle](#error-responses-con-código-mensaje-y-detalle)
19
+ - [Nomenclatura de recursos y endpoints](#nomenclatura-de-recursos-y-endpoints)
20
+ - [Checklist antes de exponer un endpoint nuevo](#checklist-antes-de-exponer-un-endpoint-nuevo)
21
+
22
+ ---
23
+
24
+ ## Versionado obligatorio con prefijo de URL
25
+
26
+ Toda API debe incluir el número de versión en la URL desde el primer endpoint.
27
+
28
+ - El versionado va en el prefijo de la URL como número entero:
29
+ `/v1/`, `/v2/`, `/v3/`, etc.
30
+ - Formato correcto:
31
+ ```
32
+ https://api.miapp.com/v1/usuarios
33
+ https://api.miapp.com/v1/pedidos/123/items
34
+ ```
35
+ - Formato incorrecto:
36
+ ```
37
+ https://api.miapp.com/usuarios (sin versión — imposible de versionar después)
38
+ https://api.miapp.com/v1.2/usuarios (versión minor en URL — innecesariamente granular)
39
+ https://api.miapp.com/usuarios?v=1 (versión en query param — rompe el caching)
40
+ ```
41
+ - El versionado en headers (`API-Version: 1`) se permite como mecanismo secundario
42
+ pero NUNCA como el único — los logs, el caching y los proxies operan sobre URLs.
43
+ - Al lanzar una nueva versión major (`/v2/`), mantener `/v1/` funcional con un
44
+ período de deprecación documentado de mínimo 6 meses.
45
+ - Comunicar la deprecación en los headers de respuesta:
46
+ `Deprecation: true`, `Sunset: [fecha]`, `Link: </v2/usuarios>; rel="successor-version"`
47
+
48
+ ---
49
+
50
+ ## Respuestas consistentes con envelope estándar
51
+
52
+ Todas las respuestas de la API deben seguir el mismo formato de envelope.
53
+
54
+ ### Respuesta exitosa con un objeto
55
+
56
+ ```json
57
+ {
58
+ "data": {
59
+ "id": "550e8400-e29b-41d4-a716-446655440000",
60
+ "nombre": "Juan Pérez",
61
+ "email": "juan@ejemplo.com"
62
+ },
63
+ "meta": {
64
+ "request_id": "req_abc123",
65
+ "timestamp": "2026-03-25T14:30:00Z",
66
+ "version": "1.0"
67
+ }
68
+ }
69
+ ```
70
+
71
+ ### Respuesta exitosa con lista (paginada)
72
+
73
+ ```json
74
+ {
75
+ "data": [...],
76
+ "meta": {
77
+ "request_id": "req_abc123",
78
+ "timestamp": "2026-03-25T14:30:00Z",
79
+ "total": 150,
80
+ "page": 1,
81
+ "per_page": 20,
82
+ "has_next": true,
83
+ "has_prev": false
84
+ }
85
+ }
86
+ ```
87
+
88
+ ### Respuesta de error
89
+
90
+ ```json
91
+ {
92
+ "errors": [
93
+ {
94
+ "code": "VALIDATION_ERROR",
95
+ "message": "El campo 'email' no tiene formato válido",
96
+ "field": "email",
97
+ "detail": "El valor 'juan-sin-arroba' no es una dirección de correo electrónico"
98
+ }
99
+ ],
100
+ "meta": {
101
+ "request_id": "req_abc123",
102
+ "timestamp": "2026-03-25T14:30:00Z"
103
+ }
104
+ }
105
+ ```
106
+
107
+ - NUNCA devolver `{"success": true, "data": [...]}` — usar el status HTTP para indicar éxito.
108
+ - NUNCA devolver `{"error": "algo falló"}` sin código de error y detalle.
109
+ - El campo `meta.request_id` es OBLIGATORIO — permite correlacionar logs con errores reportados por clientes.
110
+ - El campo `data` puede ser `null` en respuestas 204 No Content.
111
+ - En FastAPI: crear un schema `APIResponse[T]` genérico y usarlo en todos los endpoints.
112
+ - En Express/NestJS: crear un interceptor o middleware que envuelva todas las respuestas.
113
+
114
+ ---
115
+
116
+ ## Paginación obligatoria en endpoints de listado
117
+
118
+ Ningún endpoint que devuelva una colección puede hacerlo sin paginación.
119
+
120
+ - Todo endpoint que devuelva un array DEBE soportar paginación. Sin excepción.
121
+ Sin paginación, la base de datos crece y el endpoint eventualmente colapsa.
122
+
123
+ ### Paginación basada en cursor (preferida para listas grandes o en tiempo real)
124
+
125
+ ```
126
+ GET /v1/pedidos?cursor=eyJpZCI6MTIzfQ==&limit=20
127
+ ```
128
+
129
+ Ventajas: consistente bajo inserciones concurrentes, eficiente para grandes datasets.
130
+
131
+ ```json
132
+ {
133
+ "data": [...],
134
+ "meta": {
135
+ "next_cursor": "eyJpZCI6MTQzfQ==",
136
+ "prev_cursor": "eyJpZCI6MTAzfQ==",
137
+ "has_next": true,
138
+ "has_prev": true,
139
+ "limit": 20
140
+ }
141
+ }
142
+ ```
143
+
144
+ ### Paginación por offset (aceptable para datasets pequeños y UIs con número de página)
145
+
146
+ ```
147
+ GET /v1/productos?page=3&per_page=20
148
+ ```
149
+
150
+ ```json
151
+ {
152
+ "data": [...],
153
+ "meta": {
154
+ "page": 3,
155
+ "per_page": 20,
156
+ "total": 150,
157
+ "total_pages": 8,
158
+ "has_next": true,
159
+ "has_prev": true
160
+ }
161
+ }
162
+ ```
163
+
164
+ - El `per_page` máximo es 100 registros. NUNCA permitir devolver registros ilimitados.
165
+ - El `per_page` por defecto es 20 si no se especifica.
166
+ - Si el cliente pide un `per_page` mayor al máximo, devolver el máximo silenciosamente
167
+ o devolver 400 Bad Request con mensaje explicativo. Documentar cuál de las dos.
168
+ - NUNCA usar `limit=0` para devolver todos los registros — eso rompe el propósito de la paginación.
169
+
170
+ ---
171
+
172
+ ## Filtros y ordenamiento estandarizados
173
+
174
+ Los parámetros de filtrado y ordenamiento siguen convenciones uniformes en toda la API.
175
+
176
+ ### Filtros
177
+
178
+ ```
179
+ GET /v1/pedidos?estatus=pendiente&cliente_id=abc123&fecha_desde=2026-01-01&fecha_hasta=2026-03-31
180
+ ```
181
+
182
+ - Los filtros van como query parameters en GET. NUNCA en el body de un GET.
183
+ - Los nombres de los filtros coinciden con los nombres de campo del recurso.
184
+ - Para rangos: usar sufijos `_desde` y `_hasta` (o `_min` / `_max` para números).
185
+ - Para múltiples valores del mismo campo: repetir el parámetro o usar coma como separador.
186
+ Documentar cuál se usa. No mezclar ambas convenciones:
187
+ ```
188
+ ?estatus=activo&estatus=pendiente (repetición — más estándar)
189
+ ?estatus=activo,pendiente (coma — más compacto)
190
+ ```
191
+ - Los filtros que no existen o tienen valores inválidos devuelven 400 Bad Request
192
+ con un mensaje que indica exactamente cuál parámetro es inválido.
193
+
194
+ ### Ordenamiento
195
+
196
+ ```
197
+ GET /v1/pedidos?sort=fecha_creacion&order=desc
198
+ ```
199
+
200
+ - Parámetro `sort`: nombre del campo por el que ordenar.
201
+ - Parámetro `order`: `asc` (por defecto) o `desc`.
202
+ - Para ordenamiento multi-campo:
203
+ ```
204
+ GET /v1/pedidos?sort=estatus,fecha_creacion&order=asc,desc
205
+ ```
206
+ - Si se pide ordenar por un campo que no existe: 400 Bad Request.
207
+ - Si se pide ordenar por un campo que no es indexado y la tabla tiene >10k registros,
208
+ documentar esta limitación y devolver un error descriptivo.
209
+
210
+ ---
211
+
212
+ ## HTTP status codes correctos
213
+
214
+ El status code es la primera línea de comunicación del resultado. Usarlo correctamente.
215
+
216
+ ```
217
+ 200 OK — GET exitoso, PUT/PATCH exitoso con body en respuesta
218
+ 201 Created — POST exitoso que crea un recurso. Incluir header Location con URL del nuevo recurso
219
+ 204 No Content — DELETE exitoso, PUT/PATCH exitoso sin body
220
+ 400 Bad Request — Error de validación, parámetro inválido, body malformado
221
+ 401 Unauthorized — No autenticado (falta token o token inválido)
222
+ 403 Forbidden — Autenticado pero sin permiso para este recurso/acción
223
+ 404 Not Found — El recurso no existe
224
+ 409 Conflict — Conflicto de estado (ej: email duplicado, stock insuficiente)
225
+ 410 Gone — El recurso existió pero fue eliminado permanentemente
226
+ 422 Unprocessable Entity — La sintaxis es válida pero la semántica falla (ej: fecha de inicio > fecha de fin)
227
+ 429 Too Many Requests — Rate limit alcanzado
228
+ 500 Internal Server Error — Error interno no esperado (con request_id para seguimiento)
229
+ 503 Service Unavailable — Servicio temporalmente no disponible (mantenimiento, dependencia caída)
230
+ ```
231
+
232
+ Errores comunes a EVITAR:
233
+ - NUNCA devolver 200 con `{"success": false}` — usar el status code correcto.
234
+ - NUNCA devolver 500 para errores de validación de input del cliente — esos son 400/422.
235
+ - NUNCA devolver 404 cuando el problema es falta de permisos — eso es 403.
236
+ (Excepción: cuando revelar la existencia del recurso es un problema de seguridad)
237
+ - NUNCA devolver 401 cuando el usuario está autenticado pero no tiene permiso — eso es 403.
238
+
239
+ ---
240
+
241
+ ## Rate limiting obligatorio en endpoints públicos
242
+
243
+ Todo endpoint accesible sin autenticación o con autenticación débil debe tener rate limiting.
244
+
245
+ - Los endpoints públicos (sin autenticación) tienen rate limiting estricto:
246
+ Máximo 60 requests por minuto por IP como punto de partida.
247
+ Ajustar según el caso de uso real.
248
+ - Los endpoints autenticados tienen rate limiting por usuario/token:
249
+ Máximo 1000 requests por minuto por usuario autenticado.
250
+ - Los endpoints de autenticación (login, registro, recuperación de contraseña)
251
+ tienen rate limiting especialmente estricto:
252
+ Máximo 5 intentos por minuto por IP, con bloqueo temporal de 15 minutos al superar.
253
+ - Comunicar el rate limiting en headers de respuesta:
254
+ ```
255
+ X-RateLimit-Limit: 60
256
+ X-RateLimit-Remaining: 45
257
+ X-RateLimit-Reset: 1711379400
258
+ Retry-After: 30 (solo en respuestas 429)
259
+ ```
260
+ - La respuesta al superar el rate limit es siempre 429 Too Many Requests con body:
261
+ ```json
262
+ {
263
+ "errors": [{
264
+ "code": "RATE_LIMIT_EXCEEDED",
265
+ "message": "Demasiadas solicitudes. Intenta de nuevo en 30 segundos.",
266
+ "detail": "Límite: 60 solicitudes por minuto"
267
+ }]
268
+ }
269
+ ```
270
+ - El rate limiting se implementa en el gateway o proxy (nginx, Kong, AWS API Gateway),
271
+ no en la lógica de aplicación. La lógica de aplicación es el último recurso.
272
+
273
+ ---
274
+
275
+ ## CORS configurado explícitamente
276
+
277
+ El navegador solo permite requests cross-origin si el servidor lo autoriza explícitamente.
278
+
279
+ - La lista de orígenes permitidos se define por ambiente y se configura desde
280
+ variables de entorno, NUNCA hardcodeada en el código:
281
+ ```python
282
+ # FastAPI
283
+ origins = os.getenv("CORS_ORIGINS", "").split(",")
284
+ app.add_middleware(CORSMiddleware, allow_origins=origins, ...)
285
+ ```
286
+ - NUNCA usar `allow_origins=["*"]` en producción. Esto permite que cualquier sitio
287
+ haga requests a la API en nombre del usuario.
288
+ - `allow_credentials=True` solo cuando sea necesario (cuando se usan cookies de sesión).
289
+ Incompatible con `allow_origins=["*"]`.
290
+ - Los métodos permitidos deben ser los mínimos necesarios:
291
+ APIs de solo lectura: `["GET", "OPTIONS"]`
292
+ APIs completas: `["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]`
293
+ - Los headers permitidos deben listarse explícitamente si no se usan los estándar.
294
+ - El preflight request (OPTIONS) debe responder correctamente antes de que el browser
295
+ envíe el request real.
296
+ - En APIs públicas de lectura sin credenciales, `allow_origins=["*"]` puede ser
297
+ aceptable. Documentar explícitamente por qué se decidió así.
298
+
299
+ ---
300
+
301
+ ## Documentación OpenAPI siempre actualizada
302
+
303
+ La documentación es parte del contrato de la API. Si está desactualizada, no es documentación.
304
+
305
+ - La especificación OpenAPI debe generarse desde el código, no escribirse manualmente.
306
+ En FastAPI: se genera automáticamente desde los schemas y decoradores.
307
+ En Express: usar `swagger-jsdoc` o `tsoa`.
308
+ - Cada endpoint debe tener:
309
+ - `summary`: descripción corta de qué hace
310
+ - `description`: detalles, casos edge, consideraciones de negocio
311
+ - `tags`: agrupación por dominio (`Usuarios`, `Pedidos`, `Auth`)
312
+ - Todos los parámetros documentados con tipo, formato y si son requeridos
313
+ - Todos los posibles status codes de respuesta con su schema
314
+ - Ejemplos de request y response para los casos principales
315
+ - Los schemas de request y response deben documentar:
316
+ - Qué campos son requeridos vs opcionales
317
+ - Restricciones de longitud, formato y dominio de valores
318
+ - Descripciones en español claras para cada campo
319
+ - La documentación está disponible en `/docs` (Swagger UI) y `/redoc` en ambientes
320
+ de desarrollo y staging. En producción, solo si la API es pública.
321
+ - Los cambios de API sin actualizar la documentación no pasan code review.
322
+ - Los schemas de OpenAPI se validan en CI para detectar documentación rota.
323
+
324
+ ---
325
+
326
+ ## Error responses con código, mensaje y detalle
327
+
328
+ Los errores deben ser diagnósticables por el cliente sin acceso a los logs del servidor.
329
+
330
+ Cada error response incluye:
331
+
332
+ ```json
333
+ {
334
+ "errors": [
335
+ {
336
+ "code": "CÓDIGO_EN_SNAKE_CASE_MAYÚSCULAS",
337
+ "message": "Mensaje legible por humanos en español",
338
+ "field": "nombre_del_campo",
339
+ "detail": "Información adicional para debugging"
340
+ }
341
+ ],
342
+ "meta": {
343
+ "request_id": "req_abc123",
344
+ "timestamp": "2026-03-25T14:30:00Z"
345
+ }
346
+ }
347
+ ```
348
+
349
+ - `code`: identificador de máquina para el tipo de error. En SCREAMING_SNAKE_CASE.
350
+ Ejemplos: `VALIDATION_ERROR`, `RESOURCE_NOT_FOUND`, `INSUFFICIENT_STOCK`,
351
+ `EMAIL_ALREADY_EXISTS`, `INVALID_CREDENTIALS`, `RATE_LIMIT_EXCEEDED`.
352
+ - `message`: mensaje en lenguaje natural, legible por el usuario final si aplica.
353
+ Sin jerga técnica. NUNCA exponer stack traces o nombres de tablas de BD.
354
+ - `field`: nombre del campo que causó el error (solo para errores de validación).
355
+ Si el error no está asociado a un campo específico, omitir este campo.
356
+ - `detail`: información técnica adicional para el desarrollador cliente. Puede ser
357
+ más técnico que `message`. Opcional.
358
+ - Para errores de validación con múltiples campos inválidos, devolver TODOS los errores
359
+ en el array, no solo el primero. El cliente necesita corregir todo de una vez.
360
+ - Para errores 500: el mensaje es genérico ("Error interno del servidor").
361
+ El `request_id` permite correlacionar con los logs del servidor donde está el detalle real.
362
+ NUNCA exponer detalles del error interno al cliente en producción.
363
+ - Los códigos de error deben estar documentados en la spec de OpenAPI.
364
+
365
+ ---
366
+
367
+ ## Nomenclatura de recursos y endpoints
368
+
369
+ Las URLs deben ser predecibles, consistentes y orientadas a recursos, no a acciones.
370
+
371
+ - Los recursos se expresan en sustantivos en plural, en español (o inglés, pero consistente):
372
+ `/v1/usuarios`, `/v1/pedidos`, `/v1/productos`
373
+ - Las acciones CRUD mapean a métodos HTTP, no a verbos en la URL:
374
+ ```
375
+ GET /v1/pedidos — listar pedidos
376
+ POST /v1/pedidos — crear pedido
377
+ GET /v1/pedidos/123 — obtener pedido específico
378
+ PUT /v1/pedidos/123 — reemplazar pedido completo
379
+ PATCH /v1/pedidos/123 — actualizar campos específicos del pedido
380
+ DELETE /v1/pedidos/123 — eliminar pedido
381
+ ```
382
+ - Los sub-recursos se expresan anidando en la URL:
383
+ ```
384
+ GET /v1/pedidos/123/items — items del pedido 123
385
+ POST /v1/pedidos/123/items — agregar item al pedido 123
386
+ ```
387
+ - Para acciones que no mapean limpiamente a CRUD, usar sub-recursos orientados
388
+ a la acción como nombre:
389
+ ```
390
+ POST /v1/pedidos/123/cancelar — cancelar el pedido 123
391
+ POST /v1/usuarios/123/activar — activar cuenta del usuario 123
392
+ ```
393
+ Preferir esto a meter `?action=cancelar` en query params.
394
+ - Los IDs en las URLs deben ser UUIDs o IDs opacos. NUNCA IDs secuenciales que
395
+ exponen el volumen de datos del sistema.
396
+ - Las URLs son case-insensitive por convención, pero usar siempre minúsculas con guiones:
397
+ `/v1/tipos-de-pago` no `/v1/TiposDePago` ni `/v1/tipos_de_pago`.
398
+
399
+ ---
400
+
401
+ ## Checklist antes de exponer un endpoint nuevo
402
+
403
+ - [ ] La URL sigue la convención de recursos y tiene el prefijo `/v{N}/`
404
+ - [ ] El método HTTP es el correcto para la operación (GET no modifica datos)
405
+ - [ ] La respuesta usa el envelope estándar `{data, meta}` o `{errors, meta}`
406
+ - [ ] El endpoint de listado tiene paginación implementada
407
+ - [ ] El status code de respuesta es el correcto para cada caso
408
+ - [ ] Los errores de validación devuelven 400/422 con todos los campos inválidos
409
+ - [ ] El endpoint tiene autenticación si maneja datos no públicos
410
+ - [ ] El endpoint está documentado en OpenAPI con todos los parámetros y responses
411
+ - [ ] El rate limiting está configurado (si es público o de autenticación)
412
+ - [ ] El CORS está configurado correctamente para los orígenes esperados
413
+ - [ ] Los IDs expuestos son UUIDs u opacos, no IDs secuenciales