specleap-framework 2.1.0 → 2.1.5

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 (75) hide show
  1. package/.agents/backend.md +3 -3
  2. package/.agents/frontend.md +2 -2
  3. package/.agents/producto.md +9 -11
  4. package/.claude/hooks/spec-guard.sh +132 -0
  5. package/.claude/settings.json.template +15 -0
  6. package/.clinerules +3 -3
  7. package/.coderabbit.yaml +2 -4
  8. package/.commands/compliance.md +89 -0
  9. package/.commands/inicio.md +15 -15
  10. package/.commands/nuevo/README.md +2 -2
  11. package/.commands/planificar.md +1 -1
  12. package/.continue/rules/04-git-workflow.md +5 -5
  13. package/.continuerules +3 -4
  14. package/.cursorrules +1 -1
  15. package/.github/copilot-instructions.md +1 -1
  16. package/.specleap/i18n/en.json +177 -0
  17. package/.specleap/i18n/es.json +177 -0
  18. package/.specleap/i18n.sh +63 -0
  19. package/CHANGELOG.md +276 -0
  20. package/CLAUDE.md +54 -13
  21. package/README.md +169 -528
  22. package/SETUP.md +16 -13
  23. package/openspec/INDEX.md +53 -0
  24. package/openspec/README.md +104 -0
  25. package/openspec/SPEC-FORMAT.md +168 -0
  26. package/openspec/changes/.gitkeep +0 -0
  27. package/openspec/cli/COMMAND_REFERENCE.md +817 -0
  28. package/openspec/cli/README.md +189 -0
  29. package/openspec/cli/apply.sh +229 -0
  30. package/openspec/cli/archive.sh +240 -0
  31. package/openspec/cli/code-review.sh +207 -0
  32. package/openspec/cli/common.sh +171 -0
  33. package/openspec/cli/enrich.sh +188 -0
  34. package/openspec/cli/ff.sh +329 -0
  35. package/openspec/cli/new.sh +260 -0
  36. package/openspec/cli/openspec +82 -0
  37. package/openspec/cli/report.sh +244 -0
  38. package/openspec/cli/status.sh +178 -0
  39. package/openspec/cli/verify.sh +246 -0
  40. package/openspec/config.yaml +76 -0
  41. package/openspec/examples/CHANGE-SAMPLE-001-user-authentication/00-original-user-story.md +5 -0
  42. package/openspec/examples/CHANGE-SAMPLE-001-user-authentication/01-refined-user-story.md +106 -0
  43. package/openspec/examples/CHANGE-SAMPLE-001-user-authentication/README.md +333 -0
  44. package/openspec/examples/CHANGE-SAMPLE-001-user-authentication/design.md +461 -0
  45. package/openspec/examples/CHANGE-SAMPLE-001-user-authentication/proposal.md +124 -0
  46. package/openspec/examples/CHANGE-SAMPLE-001-user-authentication/specs/functional/F001-authentication.spec.md +399 -0
  47. package/openspec/examples/CHANGE-SAMPLE-001-user-authentication/specs/technical/T001-jwt-implementation.spec.md +606 -0
  48. package/openspec/examples/CHANGE-SAMPLE-001-user-authentication/tasks.md +433 -0
  49. package/openspec/examples/MERMAID_DIAGRAMS.md +481 -0
  50. package/openspec/examples/README.md +334 -0
  51. package/openspec/specs/functional/.gitkeep +0 -0
  52. package/openspec/specs/integration/.gitkeep +0 -0
  53. package/openspec/specs/security/.gitkeep +0 -0
  54. package/openspec/specs/technical/.gitkeep +0 -0
  55. package/openspec/templates/.coderabbit.yaml +259 -0
  56. package/openspec/templates/design.md +181 -0
  57. package/openspec/templates/proposal.md +79 -0
  58. package/openspec/templates/tasks.md +193 -0
  59. package/package.json +10 -5
  60. package/rules/git-workflow.md +3 -3
  61. package/rules/session-protocol.md +3 -3
  62. package/scripts/README.md +13 -25
  63. package/scripts/compliance-audit.sh +325 -0
  64. package/scripts/generate-contract.sh +4 -4
  65. package/scripts/install-skills.sh +12 -11
  66. package/scripts/lib/render-contrato.py +1 -1
  67. package/scripts/quality-baseline.sh +210 -0
  68. package/scripts/quality-healing.sh +241 -0
  69. package/setup.sh +3 -3
  70. package/.claude/skills/ui-ux-pro-max/scripts/__pycache__/core.cpython-314.pyc +0 -0
  71. package/.claude/skills/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-314.pyc +0 -0
  72. package/.claude/skills/ui-ux-pro-max/scripts/__pycache__/search.cpython-314.pyc +0 -0
  73. package/scripts/lib/jira-project-utils.sh +0 -222
  74. package/scripts/setup-mcp.sh +0 -654
  75. package/scripts/test-cuestionario.sh +0 -428
@@ -0,0 +1,399 @@
1
+ # F001 — Autenticación de Usuario
2
+
3
+ | Campo | Valor |
4
+ |-------|-------|
5
+ | ID | F001 |
6
+ | Título | Autenticación de Usuario |
7
+ | Dominio | functional |
8
+ | Estado | implemented |
9
+ | Autor | SpecLeap Contributor |
10
+ | Fecha Creación | 2026-02-12 |
11
+ | Última Actualización | 2026-02-12 |
12
+ | Versión | 1.0 |
13
+
14
+ ## Descripción
15
+
16
+ Sistema de autenticación basado en email y contraseña que permite a los usuarios identificarse de forma segura y acceder a funcionalidades protegidas del sistema mediante tokens JWT.
17
+
18
+ ## Actores
19
+
20
+ - **Usuario Registrado:** Usuario con cuenta activa en el sistema
21
+ - **Sistema:** Backend que valida credenciales y genera tokens
22
+ - **Usuario Anónimo:** Visitante sin credenciales válidas
23
+
24
+ ## Precondiciones
25
+
26
+ - El usuario debe estar registrado en el sistema
27
+ - El email del usuario debe estar verificado (fuera de alcance de esta spec)
28
+ - El sistema debe tener par de claves RSA configuradas para JWT
29
+
30
+ ## Escenarios
31
+
32
+ ### Escenario 1: Login exitoso con credenciales válidas
33
+
34
+ **Descripción:** Usuario registrado se autentica correctamente.
35
+
36
+ **GIVEN:**
37
+ - Un usuario registrado con email `usuario@example.com`
38
+ - Contraseña válida `Passw0rd!123`
39
+ - Menos de 5 intentos fallidos en los últimos 15 minutos
40
+
41
+ **WHEN:**
42
+ - El usuario envía POST a `/api/v1/auth/login` con:
43
+ ```json
44
+ {
45
+ "email": "usuario@example.com",
46
+ "password": "Passw0rd!123"
47
+ }
48
+ ```
49
+
50
+ **THEN:**
51
+ - El sistema valida las credenciales contra la base de datos
52
+ - AND genera un token JWT válido por 24 horas
53
+ - AND devuelve respuesta 200 OK con:
54
+ ```json
55
+ {
56
+ "token": "eyJhbGciOiJSUzI1NiIs...",
57
+ "token_type": "Bearer",
58
+ "expires_in": 86400,
59
+ "user": {
60
+ "id": 123,
61
+ "email": "usuario@example.com"
62
+ }
63
+ }
64
+ ```
65
+ - AND registra el intento exitoso en `login_attempts`
66
+ - AND resetea el contador de intentos fallidos
67
+
68
+ ---
69
+
70
+ ### Escenario 2: Login con "Remember Me"
71
+
72
+ **Descripción:** Usuario solicita sesión extendida.
73
+
74
+ **GIVEN:**
75
+ - Un usuario registrado con credenciales válidas
76
+
77
+ **WHEN:**
78
+ - El usuario envía POST a `/api/v1/auth/login` con:
79
+ ```json
80
+ {
81
+ "email": "usuario@example.com",
82
+ "password": "Passw0rd!123",
83
+ "remember": true
84
+ }
85
+ ```
86
+
87
+ **THEN:**
88
+ - El sistema genera token JWT válido por **30 días** (en lugar de 24h)
89
+ - AND devuelve respuesta 200 OK con `expires_in: 2592000`
90
+ - AND el token incluye claim `remember: true`
91
+
92
+ ---
93
+
94
+ ### Escenario 3: Login fallido - contraseña incorrecta
95
+
96
+ **Descripción:** Usuario ingresa contraseña errónea.
97
+
98
+ **GIVEN:**
99
+ - Un usuario registrado con email `usuario@example.com`
100
+ - Contraseña incorrecta `WrongPassword`
101
+
102
+ **WHEN:**
103
+ - El usuario envía POST con contraseña incorrecta
104
+
105
+ **THEN:**
106
+ - El sistema devuelve 401 Unauthorized con:
107
+ ```json
108
+ {
109
+ "error": "Credenciales inválidas"
110
+ }
111
+ ```
112
+ - AND **NO** revela que el email existe
113
+ - AND **NO** revela que la contraseña es incorrecta
114
+ - AND registra el intento fallido en `login_attempts`
115
+ - AND incrementa contador de intentos fallidos
116
+
117
+ ---
118
+
119
+ ### Escenario 4: Login fallido - email no registrado
120
+
121
+ **Descripción:** Usuario intenta login con email que no existe.
122
+
123
+ **GIVEN:**
124
+ - Email `noexiste@example.com` no está en la base de datos
125
+
126
+ **WHEN:**
127
+ - El usuario envía POST con ese email
128
+
129
+ **THEN:**
130
+ - El sistema devuelve 401 Unauthorized con:
131
+ ```json
132
+ {
133
+ "error": "Credenciales inválidas"
134
+ }
135
+ ```
136
+ - AND **NO** revela que el email no existe
137
+ - AND registra el intento con IP y email
138
+ - AND **NO** bloquea por intentos (no hay cuenta que bloquear)
139
+
140
+ ---
141
+
142
+ ### Escenario 5: Bloqueo por intentos fallidos
143
+
144
+ **Descripción:** Protección contra brute force.
145
+
146
+ **GIVEN:**
147
+ - Un usuario ha fallado 5 intentos de login en los últimos 15 minutos
148
+ - Desde la misma IP
149
+
150
+ **WHEN:**
151
+ - El usuario intenta login nuevamente (6º intento)
152
+
153
+ **THEN:**
154
+ - El sistema devuelve 429 Too Many Requests con:
155
+ ```json
156
+ {
157
+ "error": "Cuenta temporalmente bloqueada por intentos fallidos. Intente nuevamente en 30 minutos."
158
+ }
159
+ ```
160
+ - AND **NO** valida las credenciales (bloqueo preventivo)
161
+ - AND registra el intento bloqueado
162
+ - AND el bloqueo dura 30 minutos desde el 5º intento fallido
163
+
164
+ ---
165
+
166
+ ### Escenario 6: Desbloqueo automático tras expiración
167
+
168
+ **Descripción:** Bloqueo temporal se levanta automáticamente.
169
+
170
+ **GIVEN:**
171
+ - Un usuario fue bloqueado hace 31 minutos
172
+ - No hubo más intentos desde entonces
173
+
174
+ **WHEN:**
175
+ - El usuario intenta login con credenciales válidas
176
+
177
+ **THEN:**
178
+ - El sistema permite el login
179
+ - AND resetea contador de intentos fallidos
180
+ - AND genera token JWT normal
181
+
182
+ ---
183
+
184
+ ### Escenario 7: Logout
185
+
186
+ **Descripción:** Usuario cierra sesión.
187
+
188
+ **GIVEN:**
189
+ - Un usuario autenticado con token JWT válido
190
+
191
+ **WHEN:**
192
+ - El usuario envía POST a `/api/v1/auth/logout` con header:
193
+ ```
194
+ Authorization: Bearer {token}
195
+ ```
196
+
197
+ **THEN:**
198
+ - El sistema invalida el token (añade a blacklist o marca como revocado)
199
+ - AND devuelve 200 OK con:
200
+ ```json
201
+ {
202
+ "message": "Sesión cerrada exitosamente"
203
+ }
204
+ ```
205
+ - AND el token ya no es válido para requests subsiguientes
206
+
207
+ ---
208
+
209
+ ### Escenario 8: Acceso a ruta protegida con token válido
210
+
211
+ **Descripción:** Middleware de autenticación permite acceso.
212
+
213
+ **GIVEN:**
214
+ - Un usuario tiene token JWT válido y no expirado
215
+
216
+ **WHEN:**
217
+ - El usuario envía request a ruta protegida con header:
218
+ ```
219
+ Authorization: Bearer {token}
220
+ ```
221
+
222
+ **THEN:**
223
+ - El middleware valida el token
224
+ - AND extrae el user_id del payload
225
+ - AND adjunta el objeto `user` al request
226
+ - AND permite continuar con el request
227
+
228
+ ---
229
+
230
+ ### Escenario 9: Acceso a ruta protegida con token expirado
231
+
232
+ **Descripción:** Middleware rechaza tokens expirados.
233
+
234
+ **GIVEN:**
235
+ - Un usuario tiene token JWT que expiró hace 1 hora
236
+
237
+ **WHEN:**
238
+ - El usuario envía request a ruta protegida con token expirado
239
+
240
+ **THEN:**
241
+ - El middleware valida el token
242
+ - AND detecta que está expirado
243
+ - AND devuelve 401 Unauthorized con:
244
+ ```json
245
+ {
246
+ "error": "Token expirado. Inicie sesión nuevamente."
247
+ }
248
+ ```
249
+ - AND **NO** procesa el request
250
+
251
+ ---
252
+
253
+ ### Escenario 10: Acceso a ruta protegida sin token
254
+
255
+ **Descripción:** Middleware rechaza requests sin autenticación.
256
+
257
+ **GIVEN:**
258
+ - Un usuario no autenticado
259
+
260
+ **WHEN:**
261
+ - El usuario envía request a ruta protegida sin header `Authorization`
262
+
263
+ **THEN:**
264
+ - El middleware devuelve 401 Unauthorized con:
265
+ ```json
266
+ {
267
+ "error": "No autenticado. Token requerido."
268
+ }
269
+ ```
270
+
271
+ ---
272
+
273
+ ### Escenario 11: Token con firma alterada (tampered)
274
+
275
+ **Descripción:** Detección de tokens manipulados.
276
+
277
+ **GIVEN:**
278
+ - Un token JWT con firma modificada manualmente
279
+
280
+ **WHEN:**
281
+ - Se envía request con el token alterado
282
+
283
+ **THEN:**
284
+ - El middleware detecta firma inválida
285
+ - AND devuelve 401 Unauthorized con:
286
+ ```json
287
+ {
288
+ "error": "Token inválido"
289
+ }
290
+ ```
291
+ - AND registra el intento en logs de seguridad
292
+
293
+ ---
294
+
295
+ ### Escenario 12: Obtener información del usuario autenticado
296
+
297
+ **Descripción:** Endpoint `/me` devuelve datos del usuario actual.
298
+
299
+ **GIVEN:**
300
+ - Un usuario autenticado con token válido
301
+
302
+ **WHEN:**
303
+ - El usuario envía GET a `/api/v1/auth/me` con token válido
304
+
305
+ **THEN:**
306
+ - El sistema devuelve 200 OK con:
307
+ ```json
308
+ {
309
+ "id": 123,
310
+ "email": "usuario@example.com",
311
+ "created_at": "2026-01-15T10:30:00Z"
312
+ }
313
+ ```
314
+
315
+ ---
316
+
317
+ ## Reglas de Negocio
318
+
319
+ ### RN-001: Contraseñas hasheadas
320
+ - Las contraseñas NUNCA se almacenan en texto plano
321
+ - Usar bcrypt con cost factor 12 mínimo
322
+ - Verificación con `Hash::check()` o equivalente
323
+
324
+ ### RN-002: Rate limiting
325
+ - Máximo 5 intentos fallidos por IP + email en 15 minutos
326
+ - Bloqueo automático de 30 minutos tras exceder límite
327
+ - No aplicar rate limiting a intentos exitosos
328
+
329
+ ### RN-003: Mensajes de error genéricos
330
+ - NUNCA revelar si un email existe o no en el sistema
331
+ - Siempre responder "Credenciales inválidas" (sin detalles)
332
+ - Evitar ataques de enumeración de usuarios
333
+
334
+ ### RN-004: Tokens JWT
335
+ - Firma con RS256 (asimétrico)
336
+ - Expiración: 24 horas (normal) / 30 días (remember me)
337
+ - Payload mínimo: user_id, exp, iat
338
+ - No incluir datos sensibles en el payload
339
+
340
+ ### RN-005: Logging y auditoría
341
+ - Registrar TODOS los intentos de login (exitosos y fallidos)
342
+ - Almacenar: email, IP, user agent, timestamp, resultado
343
+ - Retener logs mínimo 90 días (configurable)
344
+
345
+ ### RN-006: HTTPS obligatorio
346
+ - En producción, rechazar requests HTTP
347
+ - Redirigir HTTP → HTTPS automáticamente
348
+
349
+ ## Dependencias
350
+
351
+ ### Dependencias de Entrada
352
+ - Usuario debe estar registrado (tabla `users`)
353
+ - Par de claves RSA generadas y configuradas
354
+ - Sistema de logging disponible
355
+
356
+ ### Dependencias de Salida
357
+ - Tabla `login_attempts` para auditoría
358
+ - Cache (Redis) opcional para tokens revocados
359
+ - Sistema de notificaciones para alertas de bloqueo
360
+
361
+ ## Métricas
362
+
363
+ ### KPIs
364
+ - **Tasa de éxito de login:** >95%
365
+ - **Tiempo medio de autenticación:** <500ms
366
+ - **Intentos de brute force bloqueados:** trackear y alertar
367
+
368
+ ### Monitoreo
369
+ - Alertar si tasa de fallos >10% en 1 hora
370
+ - Alertar si múltiples IPs atacan mismo usuario
371
+ - Dashboard de intentos por hora/día
372
+
373
+ ## Casos No Cubiertos (Fuera de Alcance)
374
+
375
+ - OAuth / Social login
376
+ - Autenticación de dos factores (2FA)
377
+ - Recuperación de contraseña
378
+ - Verificación de email
379
+ - SSO (Single Sign-On)
380
+ - Biometría
381
+
382
+ Estos se abordarán en specs futuras.
383
+
384
+ ## Referencias
385
+
386
+ - OWASP Authentication Cheat Sheet: https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html
387
+ - JWT RFC 7519: https://tools.ietf.org/html/rfc7519
388
+ - Bcrypt: https://en.wikipedia.org/wiki/Bcrypt
389
+
390
+ ## Historial de Cambios
391
+
392
+ | Versión | Fecha | Autor | Cambios |
393
+ |---------|-------|-------|---------|
394
+ | 1.0 | 2026-02-12 | SpecLeap Contributor | Versión inicial implementada |
395
+
396
+ ---
397
+
398
+ **Estado:** implemented
399
+ **Última revisión:** 2026-02-12