feat(auth): add user registration and response DTOs, implement registration endpoint in AuthService
feat(auth): create registration route and integrate with AuthService feat(auth): implement user registration logic in AuthService with Keycloak integration fix(config): add Keycloak admin credentials to settings fix(middleware): update tenant middleware to include new auth routes chore(docs): remove outdated testing guide and add project architecture documentation feat(frontend): implement user registration page and integrate with API feat(frontend): create login page with tenant selection and error handling refactor(frontend): update layout to use custom auth store and improve loading states
This commit is contained in:
@@ -1,417 +0,0 @@
|
||||
# Guía de Prueba Rápida - Anexo76
|
||||
|
||||
Esta guía te ayudará a probar todas las funcionalidades básicas de Anexo76 después de la instalación.
|
||||
|
||||
## Prerrequisitos
|
||||
|
||||
✅ Haber ejecutado `./start.sh` exitosamente
|
||||
✅ Haber configurado Keycloak siguiendo `docs/KEYCLOAK_SETUP.md`
|
||||
✅ Tener los servicios corriendo
|
||||
|
||||
## Verificar Estado de Servicios
|
||||
|
||||
```bash
|
||||
docker-compose ps
|
||||
```
|
||||
|
||||
Deberías ver 4 servicios en estado "Up":
|
||||
- postgres
|
||||
- keycloak
|
||||
- backend
|
||||
- frontend
|
||||
|
||||
## 1. Probar Backend API
|
||||
|
||||
### Health Check
|
||||
```bash
|
||||
curl http://localhost:8000/health
|
||||
```
|
||||
|
||||
Respuesta esperada:
|
||||
```json
|
||||
{
|
||||
"status": "healthy",
|
||||
"environment": "development"
|
||||
}
|
||||
```
|
||||
|
||||
### Status de API
|
||||
```bash
|
||||
curl http://localhost:8000/v1/status
|
||||
```
|
||||
|
||||
Respuesta esperada:
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"version": "1.0.0",
|
||||
"api": "v1"
|
||||
}
|
||||
```
|
||||
|
||||
### Documentación Interactiva
|
||||
Abrir en navegador: http://localhost:8000/docs
|
||||
|
||||
Deberías ver la interfaz Swagger UI con todos los endpoints documentados.
|
||||
|
||||
## 2. Probar Autenticación con Keycloak
|
||||
|
||||
### Obtener Token (vía API directa)
|
||||
|
||||
```bash
|
||||
# Reemplaza YOUR_CLIENT_SECRET con el secret de Keycloak
|
||||
curl -X POST http://localhost:8080/realms/master/protocol/openid-connect/token \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
-d "client_id=anexo76-backend" \
|
||||
-d "client_secret=YOUR_CLIENT_SECRET" \
|
||||
-d "username=demo" \
|
||||
-d "password=demo123" \
|
||||
-d "grant_type=password"
|
||||
```
|
||||
|
||||
Respuesta esperada (fragmento):
|
||||
```json
|
||||
{
|
||||
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||||
"expires_in": 300,
|
||||
"refresh_expires_in": 1800,
|
||||
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||||
"token_type": "Bearer"
|
||||
}
|
||||
```
|
||||
|
||||
### Usar Token para Llamar API
|
||||
|
||||
```bash
|
||||
# Guarda el access_token en una variable
|
||||
TOKEN="tu-access-token-aqui"
|
||||
|
||||
# Llamar endpoint protegido
|
||||
curl -X GET http://localhost:8000/v1/auth/me \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
Respuesta esperada:
|
||||
```json
|
||||
{
|
||||
"sub": "a1b2c3d4-...",
|
||||
"email": "demo@empresa-demo.com",
|
||||
"name": "Usuario Demo",
|
||||
"preferred_username": "demo",
|
||||
"tenant_id": 1,
|
||||
"roles": ["user", "admin"]
|
||||
}
|
||||
```
|
||||
|
||||
## 3. Probar Módulo de Tenants
|
||||
|
||||
### Listar Tenants (requiere rol admin)
|
||||
```bash
|
||||
curl -X GET http://localhost:8000/v1/tenants \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
Respuesta esperada:
|
||||
```json
|
||||
{
|
||||
"tenants": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Empresa Demo S.A. de C.V.",
|
||||
"slug": "empresa-demo",
|
||||
"type": "shared",
|
||||
"keycloak_realm": "master",
|
||||
"is_active": true,
|
||||
...
|
||||
}
|
||||
],
|
||||
"total": 1,
|
||||
"page": 1,
|
||||
"page_size": 50
|
||||
}
|
||||
```
|
||||
|
||||
### Obtener Tenant por ID
|
||||
```bash
|
||||
curl -X GET http://localhost:8000/v1/tenants/1 \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
### Obtener Tenant por Slug
|
||||
```bash
|
||||
curl -X GET http://localhost:8000/v1/tenants/slug/empresa-demo \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
## 4. Probar Módulo de Licencias
|
||||
|
||||
### Obtener Mi Licencia
|
||||
```bash
|
||||
curl -X GET http://localhost:8000/v1/licenses/my-license \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
Respuesta esperada:
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"tenant_id": 1,
|
||||
"plan": "professional",
|
||||
"status": "active",
|
||||
"max_users": 50,
|
||||
"max_storage_gb": 100,
|
||||
"max_monthly_operations": 25000,
|
||||
"feature_api_access": true,
|
||||
"feature_advanced_reports": true,
|
||||
"feature_integrations": true,
|
||||
"feature_dedicated_support": false,
|
||||
"expires_at": "2026-10-17T...",
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
### Validar Licencia
|
||||
```bash
|
||||
curl -X GET http://localhost:8000/v1/licenses/validate/1 \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
Respuesta esperada:
|
||||
```json
|
||||
{
|
||||
"is_valid": true,
|
||||
"status": "active",
|
||||
"plan": "professional",
|
||||
"expires_at": "2026-10-17T...",
|
||||
"reason": null
|
||||
}
|
||||
```
|
||||
|
||||
### Obtener Uso de Licencia
|
||||
```bash
|
||||
curl -X GET http://localhost:8000/v1/licenses/usage/1 \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
## 5. Probar Frontend
|
||||
|
||||
### Abrir Aplicación
|
||||
Abrir en navegador: http://localhost:5173
|
||||
|
||||
### Probar Login
|
||||
1. Click en botón "Iniciar Sesión"
|
||||
2. Serás redirigido a Keycloak
|
||||
3. Ingresar credenciales:
|
||||
- Usuario: `demo`
|
||||
- Password: `demo123`
|
||||
4. Deberías ser redirigido de vuelta al dashboard
|
||||
|
||||
### Verificar Dashboard
|
||||
Después del login, deberías ver:
|
||||
- ✅ Nombre y email del usuario
|
||||
- ✅ Información de licencia (plan, estado, límites)
|
||||
- ✅ Información de usuario (ID, roles, tenant ID)
|
||||
- ✅ Botón "Cerrar Sesión"
|
||||
|
||||
### Probar Logout
|
||||
1. Click en "Cerrar Sesión"
|
||||
2. Deberías volver a la pantalla de bienvenida
|
||||
|
||||
## 6. Pruebas de Middleware
|
||||
|
||||
### Probar sin Token (debe fallar)
|
||||
```bash
|
||||
curl -X GET http://localhost:8000/v1/tenants/1
|
||||
```
|
||||
|
||||
Respuesta esperada (error 401):
|
||||
```json
|
||||
{
|
||||
"detail": "Missing or invalid authorization header"
|
||||
}
|
||||
```
|
||||
|
||||
### Probar con Token Inválido (debe fallar)
|
||||
```bash
|
||||
curl -X GET http://localhost:8000/v1/tenants/1 \
|
||||
-H "Authorization: Bearer token-invalido"
|
||||
```
|
||||
|
||||
Respuesta esperada (error 401):
|
||||
```json
|
||||
{
|
||||
"detail": "Could not validate credentials"
|
||||
}
|
||||
```
|
||||
|
||||
### Probar sin Tenant ID en Token (debe fallar)
|
||||
Si el token no tiene `tenant_id`, debería recibir error 400:
|
||||
```json
|
||||
{
|
||||
"detail": "Tenant ID not found in token"
|
||||
}
|
||||
```
|
||||
|
||||
## 7. Verificar Logs
|
||||
|
||||
### Ver logs de todos los servicios
|
||||
```bash
|
||||
docker-compose logs -f
|
||||
```
|
||||
|
||||
### Ver logs solo del backend
|
||||
```bash
|
||||
docker-compose logs -f backend
|
||||
```
|
||||
|
||||
### Ver logs solo del frontend
|
||||
```bash
|
||||
docker-compose logs -f frontend
|
||||
```
|
||||
|
||||
### Ver logs de PostgreSQL
|
||||
```bash
|
||||
docker-compose logs -f postgres
|
||||
```
|
||||
|
||||
## 8. Probar Base de Datos
|
||||
|
||||
### Conectarse a PostgreSQL
|
||||
```bash
|
||||
docker-compose exec postgres psql -U postgres -d anexo76_core
|
||||
```
|
||||
|
||||
### Consultas útiles
|
||||
```sql
|
||||
-- Ver tenants
|
||||
SELECT * FROM tenants;
|
||||
|
||||
-- Ver licencias
|
||||
SELECT * FROM licenses;
|
||||
|
||||
-- Ver información de licencia con tenant
|
||||
SELECT t.name, t.slug, l.plan, l.status, l.expires_at
|
||||
FROM tenants t
|
||||
JOIN licenses l ON l.tenant_id = t.id;
|
||||
|
||||
-- Salir
|
||||
\q
|
||||
```
|
||||
|
||||
## 9. Casos de Prueba Adicionales
|
||||
|
||||
### Crear Nuevo Tenant (requiere rol admin)
|
||||
```bash
|
||||
curl -X POST http://localhost:8000/v1/tenants \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"name": "Nueva Empresa S.A.",
|
||||
"slug": "nueva-empresa",
|
||||
"keycloak_realm": "master",
|
||||
"type": "shared",
|
||||
"contact_name": "Juan Pérez",
|
||||
"contact_email": "juan@nueva-empresa.com"
|
||||
}'
|
||||
```
|
||||
|
||||
### Actualizar Tenant
|
||||
```bash
|
||||
curl -X PUT http://localhost:8000/v1/tenants/1 \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"contact_phone": "+52 55 9999 8888"
|
||||
}'
|
||||
```
|
||||
|
||||
### Crear Licencia para Tenant
|
||||
```bash
|
||||
curl -X POST http://localhost:8000/v1/licenses \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"tenant_id": 2,
|
||||
"plan": "basic",
|
||||
"max_users": 20,
|
||||
"max_storage_gb": 50,
|
||||
"max_monthly_operations": 10000,
|
||||
"starts_at": "2025-10-17T00:00:00Z",
|
||||
"expires_at": "2026-10-17T23:59:59Z"
|
||||
}'
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Error: "Connection refused" al llamar API
|
||||
- Verificar que el backend esté corriendo: `docker-compose ps`
|
||||
- Ver logs: `docker-compose logs backend`
|
||||
- Reiniciar: `docker-compose restart backend`
|
||||
|
||||
### Error: "Tenant ID not found in token"
|
||||
- Verificar que el usuario en Keycloak tenga el atributo `tenant_id` configurado
|
||||
- Verificar que el mapper de Keycloak esté configurado correctamente
|
||||
|
||||
### Frontend muestra "Cargando" indefinidamente
|
||||
- Abrir consola del navegador (F12) y revisar errores
|
||||
- Verificar que Keycloak esté accesible: http://localhost:8080
|
||||
- Verificar configuración en `frontend/.env`
|
||||
|
||||
### Base de datos vacía
|
||||
- Ejecutar script de inicialización:
|
||||
```bash
|
||||
docker-compose exec backend python init_db.py
|
||||
```
|
||||
|
||||
### Keycloak no responde
|
||||
- Esperar unos minutos (puede tardar en iniciar)
|
||||
- Ver logs: `docker-compose logs keycloak`
|
||||
- Reiniciar: `docker-compose restart keycloak`
|
||||
|
||||
## Limpiar y Reiniciar
|
||||
|
||||
### Detener todo
|
||||
```bash
|
||||
docker-compose down
|
||||
```
|
||||
|
||||
### Detener y eliminar volúmenes (borra BD)
|
||||
```bash
|
||||
docker-compose down -v
|
||||
```
|
||||
|
||||
### Reiniciar desde cero
|
||||
```bash
|
||||
docker-compose down -v
|
||||
./start.sh
|
||||
```
|
||||
|
||||
## Checklist de Verificación
|
||||
|
||||
- [ ] Backend responde en http://localhost:8000
|
||||
- [ ] Frontend carga en http://localhost:5173
|
||||
- [ ] Keycloak accesible en http://localhost:8080
|
||||
- [ ] Documentación API visible en http://localhost:8000/docs
|
||||
- [ ] Login funciona correctamente
|
||||
- [ ] Dashboard muestra información de usuario
|
||||
- [ ] Dashboard muestra información de licencia
|
||||
- [ ] Logout funciona correctamente
|
||||
- [ ] API responde a peticiones con token válido
|
||||
- [ ] API rechaza peticiones sin token
|
||||
- [ ] Base de datos tiene tenant y licencia de prueba
|
||||
|
||||
## Próximos Pasos
|
||||
|
||||
Una vez que todas las pruebas pasen:
|
||||
|
||||
1. ✅ Revisar la documentación en `docs/ARCHITECTURE.md`
|
||||
2. ✅ Explorar el código fuente de los módulos
|
||||
3. ✅ Personalizar configuración según necesidades
|
||||
4. ✅ Comenzar a desarrollar módulos adicionales
|
||||
5. ✅ Configurar ambiente de producción
|
||||
|
||||
---
|
||||
|
||||
**¿Problemas?** Revisa los logs con `docker-compose logs -f` o abre un issue.
|
||||
|
||||
**¡Todo funciona!** 🎉 Estás listo para desarrollar sobre Anexo76.
|
||||
70
docs/a76.json
Normal file
70
docs/a76.json
Normal file
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"context": {
|
||||
"project_name": "Anexo76",
|
||||
"description": "Aplicación SaaS para gestión de comercio exterior conforme a Anexos 24, 31 y 22 del SAT.",
|
||||
"business_goal": "Ofrecer una plataforma multi-tenant para maquilas, IMMEX y agentes aduanales que permita manejar inventarios, pedimentos y facturas de importación/exportación con control de licencias y cumplimiento normativo."
|
||||
},
|
||||
"architecture": {
|
||||
"frontend": {
|
||||
"framework": "SvelteKit",
|
||||
"auth_integration": "keycloak-js",
|
||||
"ui_goal": "Dashboard moderno, responsivo y rápido para usuarios empresariales."
|
||||
},
|
||||
"backend": {
|
||||
"framework": "FastAPI",
|
||||
"auth": "Keycloak (OpenID Connect)",
|
||||
"db_model": "Hybrid multi-tenant",
|
||||
"shared_db": "Base de datos central para clientes pequeños y medianos",
|
||||
"dedicated_db": "Bases de datos independientes para clientes grandes o con alta operación",
|
||||
"features": [
|
||||
"Conexión dinámica a BD según tenant",
|
||||
"Middleware para validar licencias y tenants",
|
||||
"APIs RESTful versionadas (v1, v2...)",
|
||||
"Separación de capas: models (ORM), dto (Pydantic), service y routes"
|
||||
],
|
||||
"module_structure": {
|
||||
"pattern": "backend/v1/modules/{module_name}/",
|
||||
"files": {
|
||||
"models.py": "Definición ORM con SQLAlchemy",
|
||||
"dto.py": "Definición de Pydantic DTOs para entrada/salida de datos (reemplaza schemas.py)",
|
||||
"service.py": "Lógica de negocio y validaciones específicas del módulo",
|
||||
"routes.py": "Endpoints FastAPI que usan los DTOs y servicios"
|
||||
},
|
||||
"naming_convention": {
|
||||
"models": "Representan entidades persistentes (Base de datos)",
|
||||
"dto": "Data Transfer Objects para transporte entre capas y API",
|
||||
"service": "Capa de negocio (domain logic)",
|
||||
"routes": "Exposición HTTP / API layer"
|
||||
},
|
||||
"reasoning": "Se utiliza dto.py en lugar de schemas.py para reflejar un enfoque DDD y estilo arquitectónico similar a NestJS, manteniendo compatibilidad total con FastAPI y Pydantic."
|
||||
}
|
||||
},
|
||||
"auth_system": {
|
||||
"provider": "Keycloak",
|
||||
"multi_tenant_model": "Un Realm por cliente (tenant)",
|
||||
"roles": ["admin", "user", "auditor", "system"],
|
||||
"license_validation": "Middleware que verifica licencia y plan activo antes de procesar cada request"
|
||||
}
|
||||
},
|
||||
"license_management": {
|
||||
"strategy": "Control centralizado en core_db",
|
||||
"table_structure": {
|
||||
"tenant_id": "int",
|
||||
"plan": "string",
|
||||
"max_users": "int",
|
||||
"expires_at": "datetime",
|
||||
"status": "active|expired|pending"
|
||||
},
|
||||
"upgrade_flow": "El cliente puede escalar de BD compartida a BD dedicada manteniendo mismo tenant_id y realm."
|
||||
},
|
||||
"dev_ops": {
|
||||
"containerization": "Docker / Docker Compose",
|
||||
"orchestration": "Kubernetes (futuro)",
|
||||
"monitoring": ["Prometheus", "Grafana"],
|
||||
"ci_cd": "GitHub Actions o GitLab CI"
|
||||
},
|
||||
"prompt_usage": {
|
||||
"instruction": "Cuando uses este JSON, pide a la IA que genere o revise la arquitectura, código base o estrategia de despliegue respetando el modelo híbrido multi-tenant con Keycloak y FastAPI.",
|
||||
"example_request": "Diseña un flujo de autenticación multi-tenant con Keycloak y FastAPI que detecte automáticamente el tenant y seleccione la base de datos correcta. Usa dto.py en lugar de schemas.py para mantener una arquitectura estilo DDD."
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user