refactor: complete bootstrap of ARNES agent harness framework
- Add complete agent harness structure with 8 roles (leader, triager, architect, implementer, reviewer, security, qa, documenter) - Implement strict workflow with 9 stages and mandatory gates - Add comprehensive verification script and runtime status tracking - Create artifact-based evidence system with contracts and schemas - Add agent policy matrix with permissions and anti-cheat rules - Include test suite (44 tests passing) and CI-ready structure - Add documentation: README, HOWTO, CHECKPOINTS, templates - Configure model routing policies and token-aware task assignment - Add BDD/SDD specification guides and feature templates - Include starter pack for quick project onboarding All verification checks pass. Framework ready for production use.
This commit is contained in:
48
spec/sdd/decisions/.template.md
Normal file
48
spec/sdd/decisions/.template.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# ADR-XXX: Título de la Decisión
|
||||
|
||||
## Estado
|
||||
Aceptado | Propuesto | Deprecado
|
||||
|
||||
## Fecha
|
||||
YYYY-MM-DD
|
||||
|
||||
## Contexto
|
||||
_Descripción del problema o situación que motiva esta decisión._
|
||||
|
||||
## Decisión
|
||||
_Qué se decidió y por qué._
|
||||
|
||||
## Justificación
|
||||
_Razones que fundamentan la decisión._
|
||||
|
||||
## Consecuencias
|
||||
|
||||
### ✅ Positivas
|
||||
- ...
|
||||
|
||||
### ❌ Negativas
|
||||
- ...
|
||||
|
||||
### 🔄 Neutrales
|
||||
- ...
|
||||
|
||||
## Alternativas Consideradas
|
||||
|
||||
### Opción A
|
||||
- **Descripción**: ...
|
||||
- **Pros**: ...
|
||||
- **Contras**: ...
|
||||
- **Razón de descarte**: ...
|
||||
|
||||
### Opción B
|
||||
- **Descripción**: ...
|
||||
- **Pros**: ...
|
||||
- **Contras**: ...
|
||||
- **Razón de descarte**: ...
|
||||
|
||||
## Notas
|
||||
_Información adicional o follow-ups._
|
||||
|
||||
## Relacionado con
|
||||
- ADR-YYY
|
||||
- Feature F-XXX
|
||||
63
spec/sdd/decisions/001-stack-tecnologico.md
Normal file
63
spec/sdd/decisions/001-stack-tecnologico.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# ADR-001: Selección de Stack Técnico
|
||||
|
||||
## Estado
|
||||
Aceptado
|
||||
|
||||
## Fecha
|
||||
2026-05-06
|
||||
|
||||
## Contexto
|
||||
Necesitamos seleccionar el stack tecnológico inicial para el proyecto. El equipo tiene experiencia en Python y JavaScript/TypeScript, y requiere:
|
||||
- Rápido bootstrap
|
||||
- Testing BDD nativo
|
||||
- Compatibilidad con el framework ARNES
|
||||
|
||||
## Decisión
|
||||
Usar **Python + Behave** para BDD y **FastAPI** para el backend.
|
||||
|
||||
## Justificación
|
||||
1. **Behave** tiene sintaxis Gherkin nativa y integración simple con Python
|
||||
2. **FastAPI** ofrece validación automática con Pydantic y tests con pytest
|
||||
3. Ambos tienen ecosistema maduro y documentación extensa
|
||||
4. Comunidad activa y soporte a largo plazo
|
||||
|
||||
## Consecuencias
|
||||
|
||||
### ✅ Positivas
|
||||
- Curva de aprendizaje baja (Python)
|
||||
- BDD nativo con Behave (Gherkin)
|
||||
- Type hints en todo el stack
|
||||
- FastAPI: auto-generated docs (Swagger/ReDoc)
|
||||
- Testing integrado con pytest
|
||||
|
||||
### ❌ Negativas
|
||||
- GIL限制了多线程性能 (puede mitigated with async)
|
||||
- Menos opciones de hosting que Node.js
|
||||
|
||||
### 🔄 Neutrales
|
||||
- Requiere Python 3.10+ mínimo
|
||||
|
||||
## Alternativas Consideradas
|
||||
|
||||
### Opción A: Node.js + Cucumber
|
||||
- **Pros**: Más opciones de hosting, JSON nativo, ecosistema npm enorme
|
||||
- **Contras**: TypeScript requiere más setup, testing E2E más complejo
|
||||
- **Razón de descarte**: Mayor complejidad inicial, menor familiaridad del equipo con TS
|
||||
|
||||
### Opción B: Java + Cucumber-JVM
|
||||
- **Pros**: Tipo estático, robusto, enterprise-grade
|
||||
- **Contras**: Verbose, setup pesado, curva de aprendizaje alta
|
||||
- **Razón de descarte**: Over-engineering para MVP
|
||||
|
||||
### Opción C: Go + Godog
|
||||
- **Pros**: Binarios estáticos, excelente performance
|
||||
- **Contras**: BDD tooling inmaduro, less ecosystem para testing
|
||||
- **Razón de descarte**: BDD ecosystem no maduro
|
||||
|
||||
## Notas
|
||||
- Re-evaluar si el proyecto escala a más de 50 servicios
|
||||
- Considerar microservices framework si es necesario
|
||||
|
||||
## Relacionado con
|
||||
- Feature F-001
|
||||
- Stack: Python 3.11+, FastAPI, Behave, PostgreSQL
|
||||
69
spec/sdd/decisions/002-almacenamiento-avatar.md
Normal file
69
spec/sdd/decisions/002-almacenamiento-avatar.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# ADR-002: Almacenamiento de Avatares
|
||||
|
||||
## Estado
|
||||
Aceptado
|
||||
|
||||
## Fecha
|
||||
2026-05-06
|
||||
|
||||
## Contexto
|
||||
Los usuarios pueden subir avatares personalizados. Necesitamos decidir dónde y cómo almacenar las imágenes de perfil para optimizar costo, rendimiento y mantenimiento.
|
||||
|
||||
## Decisión
|
||||
Usar **Storage Service externo (S3-compatible)** con URLs firmadas para avatares.
|
||||
|
||||
## Justificación
|
||||
1. **Simplicidad**: No requerimos procesar imágenes en nuestro servidor
|
||||
2. **Costo**: S3-like storage es económico ($0.023/GB)
|
||||
3. **CDN**: Los avatares se sirven desde CDN automáticamente
|
||||
4. **Seguridad**: URLs firmadas con expiración evitan hotlinking
|
||||
5. **Mantenimiento**: No requiere gestión de sistema de archivos
|
||||
|
||||
## Consecuencias
|
||||
|
||||
### ✅ Positivas
|
||||
- No hay infraestructura de archivos que mantener
|
||||
- Escalabilidad automática
|
||||
- URLs firmadas = más seguridad
|
||||
- Cache CDN = mejor performance
|
||||
|
||||
### ❌ Negativas
|
||||
- Dependencia de proveedor externo
|
||||
- Costo de storage + egress
|
||||
- Latencia extra por redirect a CDN
|
||||
|
||||
### 🔄 Neutrales
|
||||
- Requiere configuración de CORS
|
||||
|
||||
## Alternativas Consideradas
|
||||
|
||||
### Opción A: Almacenamiento local en servidor
|
||||
- **Pros**: Sin dependencia externa, rápido para lecturas
|
||||
- **Contras**: No escala horizontalmente, requiere backup, problemas de disco
|
||||
- **Razón de descarte**: No escala bien con múltiples instancias
|
||||
|
||||
### Opción B: Base de datos como BLOB
|
||||
- **Pros**: Todo en un lugar, transacciones integradas
|
||||
- **Contras**: PostgreSQL no optimizado para archivos grandes, backup lento
|
||||
- **Razón de descarte**: degrada performance de DB, backups muy pesados
|
||||
|
||||
### Opción C: Servicio dedicado de imágenes (Cloudinary/Imgix)
|
||||
- **Pros**: Transformación de imágenes, CDN incluido, optimización automática
|
||||
- **Contras**: Más costoso ($50+/mes), vendor lock-in
|
||||
- **Razón de descarte**: Over-engineering para avatares simples
|
||||
|
||||
## Implementación
|
||||
|
||||
1. Cliente sube imagen a `/api/v1/profile/upload` (multipart)
|
||||
2. Servicio valida tipo (jpg/png/webp) y tamaño (<5MB)
|
||||
3. Servicio sube a S3 con nombre `avatars/{user_id}/{timestamp}.{ext}`
|
||||
4. Servicio genera URL firmada (7 días validez)
|
||||
5. URL se guarda en campo `avatar_url` del perfil
|
||||
|
||||
## Notas
|
||||
- Considerar WebP en el futuro para optimización
|
||||
- Implementar cleanup de avatares huérfanos (job semanal)
|
||||
|
||||
## Relacionado con
|
||||
- Feature F-002
|
||||
- Componente: UserProfileService
|
||||
83
spec/sdd/decisions/003-hashing-contrasena.md
Normal file
83
spec/sdd/decisions/003-hashing-contrasena.md
Normal file
@@ -0,0 +1,83 @@
|
||||
# ADR-003: Hashing de Contraseñas
|
||||
|
||||
## Estado
|
||||
Aceptado
|
||||
|
||||
## Fecha
|
||||
2026-05-06
|
||||
|
||||
## Contexto
|
||||
Necesitamos guardar contraseñas de usuarios de forma segura. La decisión debe considerar:
|
||||
- Resistencia a ataques de fuerza bruta y rainbow tables
|
||||
- Performance (se ejecuta en cada login y cambio de password)
|
||||
- Compatibilidad con estándares de la industria
|
||||
|
||||
## Decisión
|
||||
Usar **bcrypt** con cost factor 12 para hashing de contraseñas.
|
||||
|
||||
## Justificación
|
||||
1. **bcrypt** es diseñado específicamente para password hashing lento
|
||||
2. **Cost factor configurable**: permite aumentar resistencia en el futuro
|
||||
3. **Resistente a GPU/rainbow attacks**: diseñado para ser lento intencionalmente
|
||||
4. **Incorpora salt**: cada password tiene salt único, evitando rainbow tables
|
||||
5. **Estándar de industria**: ampliamente usado (Django, Rails, bcrypt)
|
||||
|
||||
## Consecuencias
|
||||
|
||||
### ✅ Positivas
|
||||
- Resistente a ataques de fuerza bruta
|
||||
- Salt automático evitar rainbow tables
|
||||
- Configurable (cost factor)
|
||||
- Librerías maduras en todos los lenguajes
|
||||
|
||||
### ❌ Negativas
|
||||
- Más lento que MD5/SHA (es el punto, pero afecta latency)
|
||||
- Enorme payload si se guarda en cookies/token
|
||||
|
||||
### 🔄 Neutrales
|
||||
- Requiere Python 3.11+ para bcrypt moderno
|
||||
|
||||
## Implementación
|
||||
|
||||
```python
|
||||
import bcrypt
|
||||
|
||||
def hash_password(password: str) -> str:
|
||||
"""Hash password with bcrypt, cost 12."""
|
||||
return bcrypt.hashpw(
|
||||
password.encode('utf-8'),
|
||||
bcrypt.gensalt(rounds=12)
|
||||
).decode('utf-8')
|
||||
|
||||
def verify_password(password: str, hashed: str) -> bool:
|
||||
"""Verify password using constant-time comparison."""
|
||||
return bcrypt.checkpw(
|
||||
password.encode('utf-8'),
|
||||
hashed.encode('utf-8')
|
||||
)
|
||||
```
|
||||
|
||||
## Alternativas Consideradas
|
||||
|
||||
### Opción A: SHA-256 (con salt)
|
||||
- **Pros**: Rápido, simple
|
||||
- **Contras**: No es lento, vulnerable a GPU attacks, diseñado para speed no security
|
||||
- **Razón de descarte**: No es resistente a hardware moderno
|
||||
|
||||
### Opción B: Argon2
|
||||
- **Pros**: Ganador PHC 2015, configurable memory/CPU
|
||||
- **Contras**: Más complejo de implementar, menos soporte de librerías
|
||||
- **Razón de descarte**: bcrypt es más simple y suficiente para nuestro caso de uso
|
||||
|
||||
### Opción C: scrypt
|
||||
- **Pros**: Diseñado para ser memory-hard
|
||||
- **Contras**: Más lento de configurar, configuración compleja
|
||||
- **Razón de descarte**: bcrypt es más simple y ampliamente soportado
|
||||
|
||||
## Notas
|
||||
- Si en el futuro,我们需要 mayor seguridad, migrar a Argon2
|
||||
- No guardar passwords en logs bajo ninguna circunstancia
|
||||
|
||||
## Relacionado con
|
||||
- Feature F-003
|
||||
- Componente: PasswordService
|
||||
68
spec/sdd/decisions/004-jwt-auth.md
Normal file
68
spec/sdd/decisions/004-jwt-auth.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# ADR-004: JWT Authentication Strategy
|
||||
|
||||
## Status
|
||||
ACCEPTED
|
||||
|
||||
## Context
|
||||
We need a stateless authentication mechanism for the API that:
|
||||
1. Allows users to login with email/password
|
||||
2. Provides secure token-based sessions
|
||||
3. Supports token revocation (logout)
|
||||
4. Handles token refresh without re-login
|
||||
|
||||
## Decision
|
||||
|
||||
We will use **JWT (JSON Web Tokens)** with the following configuration:
|
||||
|
||||
### Token Structure
|
||||
- **Access Token**: 15 minute expiration, contains user identity
|
||||
- **Refresh Token**: 7 day expiration, used to obtain new access tokens
|
||||
|
||||
### Algorithm
|
||||
- **HS256** for signing (symmetric, simpler setup)
|
||||
- Secret key loaded from environment variable `JWT_SECRET`
|
||||
|
||||
### Claims
|
||||
```json
|
||||
{
|
||||
"sub": "user_uuid",
|
||||
"email": "user@example.com",
|
||||
"role": "user",
|
||||
"iat": 1715030400,
|
||||
"exp": 1715031300,
|
||||
"jti": "unique-token-id"
|
||||
}
|
||||
```
|
||||
|
||||
### Session Management
|
||||
- Active sessions tracked in **Redis** (keyed by `jti`)
|
||||
- Sessions invalidated on logout
|
||||
- All user sessions invalidated on password change (from F-003)
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
- Stateless = horizontal scaling friendly
|
||||
- Short-lived access tokens limit damage if compromised
|
||||
- Refresh tokens allow long sessions without storing passwords
|
||||
- Redis-based session tracking enables instant revocation
|
||||
|
||||
### Negative
|
||||
- Cannot revoke individual refresh tokens (need blocklist)
|
||||
- Token size larger than session IDs
|
||||
- Clock sync required between services
|
||||
|
||||
## Alternatives Considered
|
||||
|
||||
| Alternative | Why Rejected |
|
||||
|-------------|--------------|
|
||||
| Session cookies | Not API-friendly, CSRF issues |
|
||||
| OAuth2/OIDC | Overkill for simple auth |
|
||||
| PASETO | Less battle-tested |
|
||||
| opaque tokens | Requires DB lookup on every request |
|
||||
|
||||
## Implementation Notes
|
||||
- JWT library: PyJWT
|
||||
- Redis client: aioredis for async
|
||||
- Both tokens stored in HttpOnly cookies for browser clients
|
||||
- Access token in Authorization header for API clients
|
||||
Reference in New Issue
Block a user