Skip to content

Plataforma integral para la gestión y participación en talleres de formación profesional. Desarrolla tus habilidades técnicas y blandas con nuestra moderna plataforma de aprendizaje.

License

Notifications You must be signed in to change notification settings

Un2versidad/SkillsForge

 
 

Repository files navigation

Typing SVG

AWS CDK Vercel Next.js Python Serverless

DemoArquitecturaPor qué VercelAPIFlujosRequisitos


🌐 Demo

🖥️ Frontend (Vercel)

Vercel

skills-forge.vercel.app

🚪 API (AWS)

AWS

qt6hwpaad0.execute-api.us-east-1.amazonaws.com/dev/api

Note

El frontend usa Vercel mientras que el backend está 100% en AWS. Ver Por qué Vercel para más detalles.


⚡ Stack Tecnológico

Next.js
Next.js 15
App Router
React
React 19
Server Components
Tailwind
Tailwind
+ shadcn/ui
TypeScript
TypeScript
Strict mode
Vercel
Vercel
Edge Network
Python
Python 3.11
Lambda Runtime
AWS
AWS CDK
IaC
DynamoDB
DynamoDB
Single-Table
Cognito
Cognito
Auth + JWT
Bedrock
Bedrock
Nova Micro

🏗️ Arquitectura

🔍 Ver diagrama de arquitectura completo
flowchart TB
    subgraph Internet
        U["👤 Usuario"]
    end

    subgraph Vercel ["☁️ Vercel (Frontend)"]
        V_EDGE["🌐 Edge Network"]
        V_SSR["⚡ Next.js SSR"]
        V_STATIC["📄 Static Assets"]
    end

    subgraph AWS ["☁️ AWS (Backend)"]
        subgraph Security ["🛡️ Security Layer"]
            WAF["WAF v2"]
        end
        
        subgraph Compute ["⚡ Compute"]
            APIGW["API Gateway"]
            Lambda["Lambda x16"]
        end
        
        subgraph Data ["🗄️ Data Layer"]
            DDB[("DynamoDB")]
            Cognito["Cognito"]
        end
        
        subgraph AI ["🤖 AI"]
            Bedrock["Bedrock Nova"]
        end
        
        subgraph Events ["📨 Events"]
            EB["EventBridge"]
            SNS["SNS"]
            SQS["SQS DLQ"]
        end
        
        subgraph Monitoring ["📊 Observability"]
            CW["CloudWatch"]
            XRAY["X-Ray"]
        end
    end

    U --> V_EDGE
    V_EDGE --> V_SSR
    V_EDGE --> V_STATIC
    V_SSR --> WAF
    WAF --> APIGW
    APIGW --> Lambda
    Lambda --> DDB
    Lambda --> Cognito
    Lambda --> Bedrock
    Lambda --> EB
    EB --> SNS
    EB --> SQS
    Lambda -.-> CW
    Lambda -.-> XRAY
Loading

🚀 Por qué Vercel (y no S3)

Important

S3 no es compatible con Next.js 15 usando App Router.
S3 únicamente sirve contenido estático, mientras que Next.js 15 requiere ejecutar código del lado servidor.

El problema

Este frontend utiliza características que necesitan un runtime activo:

  • Server Components – Renderizado en el servidor
  • Server Actions – Lógica ejecutada desde la UI
  • Rendering dinámico – Generación de páginas por request
  • Middleware – Ejecución previa a cada solicitud

S3 no puede ejecutar código ni manejar lógica en tiempo de ejecución, por lo que no lo usamos ya que no cumple con nuestras necesidades en nuestro caso.

La solución

Vercel ofrece soporte nativo para Next.js y provee los runtimes necesarios sin configuración adicional:

Requisito S3 Vercel
Server Components
Server Actions
Rendering dinámico
Middleware
Alternativas dentro de AWS

Es posible implementar Next.js en AWS, pero con mayor complejidad operativa:

  • AWS Amplify – Soporta SSR con ciertas limitaciones
  • Lambda@Edge + S3 – Arquitectura compleja y difícil de mantener
  • ECS / Fargate – Requiere administrar infraestructura adicional

Vercel simplifica este proceso al manejar todo el entorno automáticamente.

📊 Recursos AWS Desplegados

Ver recursos en producción
Servicio Recurso Detalles
API qt6hwpaad0 REST API + WAF
DynamoDB SkillsForge-Dev-Workshops 37 items, 3 GSIs
Cognito us-east-1_pcERcMaid 7 usuarios
Lambda 16 funciones Python 3.11
EventBridge SkillsForge-Dev-EventBus Event-driven
SNS SkillsForge-Dev-Notifications Email alerts

🗄️ Modelo de Datos

Tip

Usamos Single-Table Design para minimizar costos y maximizar rendimiento.

📊 Ver diagrama ER de entidades
erDiagram
    WORKSHOPS ||--o{ REGISTRATIONS : tiene
    USERS ||--o{ REGISTRATIONS : hace
    
    WORKSHOPS {
        string PK
        string SK
        string nombre
        string descripcion
        int cupo_maximo
        int inscritos
        date fecha
        string categoria
    }
    
    USERS {
        string PK
        string SK
        string nombre
        string role
        date created_at
    }
    
    REGISTRATIONS {
        string PK
        string SK
        string workshop_nombre
        date fecha_registro
    }
Loading

📐 Estructura de Claves

Entidad PK SK
🎓 Taller WORKSHOP#{uuid} META
👤 Usuario USER#{email} META
📝 Inscripción USER#{email} REGISTRATION#{workshop_id}
🔍 Ver diagrama de GSIs
flowchart LR
    subgraph GSI1 ["GSI1: Por Fecha"]
        G1_PK["PK: WORKSHOP#ALL"]
        G1_SK["SK: fecha"]
    end
    
    subgraph GSI2 ["GSI2: Por Categoría"]
        G2_PK["PK: CATEGORY#nombre"]
        G2_SK["SK: fecha"]
    end
    
    subgraph GSI3 ["GSI3: Inscripciones"]
        G3_PK["PK: WORKSHOP#id"]
        G3_SK["SK: fecha_registro"]
    end
    
    GSI1 --> |"Listar todos"| Q1["GET /workshops"]
    GSI2 --> |"Filtrar"| Q2["GET /workshops?category=X"]
    GSI3 --> |"Inscritos"| Q3["GET /workshops/{id}/students"]
Loading
GSI Partition Key Sort Key Uso
GSI1 WORKSHOP#ALL fecha Listar todos por fecha
GSI2 CATEGORY#{nombre} fecha Filtrar por categoría
GSI3 WORKSHOP#{id} fecha_registro Listar inscritos
📝 Ejemplo de Items en DynamoDB
// 🎓 Taller
{
  "PK": "WORKSHOP#abc-123",
  "SK": "META",
  "GSI1PK": "WORKSHOP#ALL",
  "GSI1SK": "2024-02-15",
  "GSI2PK": "CATEGORY#desarrollo",
  "nombre": "Docker para Developers",
  "descripcion": "Aprende contenedores desde cero",
  "cupo_maximo": 30,
  "inscritos": 12,
  "fecha": "2024-02-15T10:00:00Z"
}

// 👤 Usuario
{
  "PK": "USER#juan@email.com",
  "SK": "META",
  "nombre": "Juan Pérez",
  "role": "student",
  "created_at": "2024-01-10T08:30:00Z"
}

// 📝 Inscripción
{
  "PK": "USER#juan@email.com",
  "SK": "REGISTRATION#abc-123",
  "GSI3PK": "WORKSHOP#abc-123",
  "GSI3SK": "2024-01-20T14:00:00Z",
  "workshop_nombre": "Docker para Developers",
  "workshop_fecha": "2024-02-15T10:00:00Z"
}

🔗 API REST

Base URL: https://qt6hwpaad0.execute-api.us-east-1.amazonaws.com/dev

Endpoints Públicos

Método Endpoint Descripción
GET /workshops Listar talleres
GET /workshops/{id} Detalle de taller
GET /workshops/categories Categorías
GET /stats Estadísticas
POST /auth/login Iniciar sesión
POST /auth/register Registrarse

Endpoints Protegidos (JWT)

Método Endpoint Role Descripción
POST /workshops/{id}/register 🎓 Inscribirse
DELETE /workshops/{id}/register 🎓 Cancelar inscripción
GET /registrations/mine 🎓 Mis inscripciones
POST /ai/assistant 🎓 Chat con IA
POST /workshops 👑 Crear taller
PUT /workshops/{id} 👑 Editar taller
DELETE /workshops/{id} 👑 Eliminar taller

🎓 = Student    👑 = Admin

📝 Ejemplos de Request/Response

Login:

curl -X POST https://qt6hwpaad0.execute-api.us-east-1.amazonaws.com/dev/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email": "usuario@mail.com", "password": "MiPassword123!"}'

Response:

{
  "token": "eyJhbGciOiJSUzI1NiIs...",
  "user": {
    "email": "usuario@mail.com",
    "role": "student",
    "nombre": "Usuario Demo"
  }
}

Inscribirse a taller:

curl -X POST .../workshops/abc-123/register \
  -H "Authorization: Bearer {token}"

Response:

{
  "message": "Inscripción exitosa",
  "workshop": "Docker para Developers",
  "fecha": "2024-02-15T10:00:00Z"
}

🔄 Flujos Internos

🔐 Flujo de Autenticación
sequenceDiagram
    autonumber
    participant U as 👤 Usuario
    participant V as ☁️ Vercel
    participant WAF as 🛡️ WAF
    participant API as 🚪 API Gateway
    participant L as ⚡ Lambda
    participant C as 🔐 Cognito

    U->>V: Email + Password
    V->>WAF: POST /auth/login
    WAF->>WAF: Validar rate-limit
    WAF->>API: Forward request
    API->>L: Invoke auth/login
    L->>C: AdminInitiateAuth
    C->>C: Validar credenciales
    C-->>L: JWT Tokens
    L-->>API: {token, user}
    API-->>V: 200 OK
    V->>V: localStorage.setItem('token')
    V-->>U: Redirect /dashboard
Loading
📝 Flujo de Inscripción a Taller
sequenceDiagram
    autonumber
    participant U as 👤 Usuario
    participant API as 🚪 API Gateway
    participant Auth as 🔐 JWT Authorizer
    participant L as ⚡ Lambda
    participant DB as 🗄️ DynamoDB
    participant EB as 📨 EventBridge
    participant SNS as 📧 SNS

    U->>API: POST /workshops/{id}/register
    API->>Auth: Validar JWT
    Auth-->>API: ✅ Token válido
    API->>L: Invoke
    
    L->>DB: GetItem (workshop)
    DB-->>L: Workshop data
    
    alt ✅ Hay cupos disponibles
        L->>DB: TransactWriteItems
        Note over DB: 1. Crear registro<br/>2. Incrementar inscritos
        DB-->>L: Success
        L->>EB: PutEvent (STUDENT_REGISTERED)
        EB->>SNS: Trigger notification
        SNS-->>U: 📧 Email confirmación
        L-->>U: 201 Created
    else ❌ Sin cupos
        L-->>U: 409 Conflict
    end
Loading
🤖 Flujo del Asistente IA (Bedrock)
sequenceDiagram
    autonumber
    participant U as 👤 Usuario
    participant L as ⚡ Lambda
    participant DB as 🗄️ DynamoDB
    participant B as 🤖 Bedrock

    U->>L: POST /ai/assistant
    Note right of U: {message: "¿Qué talleres hay de Python?"}
    
    L->>DB: Query workshops
    DB-->>L: Lista de talleres
    
    L->>L: Construir contexto
    Note over L: System prompt +<br/>datos de talleres +<br/>pregunta usuario
    
    L->>B: InvokeModel (Nova Micro)
    B->>B: Procesar con contexto
    B-->>L: Respuesta generada
    
    L-->>U: {response: "Tenemos 3 talleres..."}
Loading
📊 Sistema de Eventos (EventBridge)
flowchart TB
    subgraph Triggers ["🎯 Eventos"]
        E1["STUDENT_REGISTERED"]
        E2["WORKSHOP_CREATED"]
        E3["WORKSHOP_UPDATED"]
        E4["REMINDER_24H"]
    end
    
    subgraph EventBridge ["📨 EventBridge"]
        EB["Event Bus"]
        R1["Rule: Notifications"]
        R2["Rule: Reminders"]
    end
    
    subgraph Targets ["🎯 Targets"]
        SNS["📧 SNS"]
        L["⚡ Lambda Processor"]
        DLQ["🗑️ SQS DLQ"]
    end
    
    E1 & E2 & E3 --> EB
    E4 --> EB
    EB --> R1 --> SNS
    EB --> R2 --> L
    L -.->|On Error| DLQ
Loading
⏰ Recordatorios Automáticos
flowchart LR
    subgraph Scheduler ["📅 EventBridge Scheduler"]
        CRON["⏰ Cada hora"]
    end
    
    subgraph Process ["⚡ Lambda"]
        CHECK["Buscar talleres próximos"]
        FILTER["Filtrar 24h antes"]
        SEND["Enviar recordatorios"]
    end
    
    subgraph Notify ["📨 Notificaciones"]
        SNS["SNS Topic"]
        EMAIL["📧 Email"]
    end
    
    CRON --> CHECK --> FILTER --> SEND --> SNS --> EMAIL
Loading

✅ Requisitos que se Solicitaron para el Proyecto Final

🧱 Arquitectura Cloud

Requisito Estado
Frontend en Vercel (SSR)
API Gateway REST
Lambda (Python 3.11)
DynamoDB Single-Table
Amazon Cognito (JWT)
EventBridge + SNS
SQS Dead Letter Queue
EventBridge Scheduler
Amazon Bedrock (IA)

🗄️ Base de Datos

Requisito Estado
Tabla única con PK/SK
GSI1 (por fecha)
GSI2 (por categoría)
GSI3 (inscripciones)
Transacciones atómicas

🔗 API REST

Requisito Estado
CRUD Talleres
Sistema inscripciones
Autenticación JWT
Validación de entrada
Códigos HTTP correctos
Rate limiting (WAF)
CORS configurado

🔐 Seguridad

Requisito Estado
WAF v2 (SQLi, XSS)
IAM least-privilege
Secrets Manager
JWT Authorizer

📦 DevOps

Requisito Estado
AWS CDK (IaC)
7 Stacks modulares
CloudWatch Logs
X-Ray Tracing
Alarmas SNS

📁 Estructura del Proyecto

📦 SkillsForge
├── 🎨 app/                         # Next.js 15 App Router
│   ├── admin/                      # Panel administrador
│   ├── estudiantes/                # Portal estudiantes
│   ├── api/                        # API Routes (proxy)
│   └── (pages)/                    # Páginas públicas
│
├── 🧩 frontend/
│   ├── components/                 # React Components
│   │   ├── admin/                  # Formularios admin
│   │   ├── ai/                     # Chat IA, Insights
│   │   ├── shared/                 # UI compartida
│   │   └── workshops/              # Cards, botones
│   ├── lib/                        # Utilidades, hooks
│   └── types/                      # TypeScript types
│
├── ⚡ backend-services/
│   ├── functions/                  # Lambda Handlers
│   │   ├── auth/                   # 🔐 login, register, refresh
│   │   ├── workshops/              # 📚 CRUD, stats, categories
│   │   ├── registrations/          # 📝 register, unregister, list
│   │   ├── events/                 # 📨 processor, reminder
│   │   ├── students/               # 👥 list, delete
│   │   └── ai/                     # 🤖 assistant (Bedrock)
│   └── shared/                     # Lambda Layer (boto3, jwt)
│
└── 🏗️ infrastructure/
    └── lib/stacks/                 # CDK Stacks
        ├── api-stack.ts            # API Gateway + Lambdas
        ├── auth-stack.ts           # Cognito
        ├── data-stack.ts           # DynamoDB
        ├── events-stack.ts         # EventBridge + SNS
        ├── frontend-stack.ts       # (Legacy S3/CF)
        ├── monitoring-stack.ts     # CloudWatch + Alarms
        └── security-stack.ts       # WAF + IAM

🚀 Instalación

Requisitos previos
  • Node.js 18+
  • Python 3.11
  • AWS CLI configurado
  • Cuenta de Vercel

Backend (AWS)

# 1. Clonar repositorio
git clone https://github.com/Venganza-de-Python-II/SkillsForge.git
cd skillsforge

# 2. Instalar dependencias
npm install
cd infrastructure && npm install

# 3. Configurar variables
cp .env.example .env
# Editar .env con tus valores

# 4. Desplegar a AWS
cdk bootstrap
cdk deploy --all

Frontend (Vercel)

# Opción 1: Deploy automático
# Conectar repo en vercel.com → Import Project

# Opción 2: CLI
npm i -g vercel
vercel --prod

Desarrollo Local

# Frontend
npm run dev                    # localhost:3000

# Variables de entorno necesarias
NEXT_PUBLIC_API_URL=https://qt6hwpaad0.execute-api.us-east-1.amazonaws.com/dev

🔒 Seguridad

🛡️ Ver diagrama de capas de seguridad
flowchart TB
    subgraph Internet
        USER["👤 Usuario"]
        ATTACKER["🦹 Atacante"]
    end
    
    subgraph Layer1 ["Capa 1: Edge"]
        WAF["🛡️ AWS WAF v2"]
    end
    
    subgraph Layer2 ["Capa 2: Auth"]
        COGNITO["🔐 Cognito"]
        JWT["JWT Authorizer"]
    end
    
    subgraph Layer3 ["Capa 3: API"]
        THROTTLE["⏱️ Throttling"]
        CORS["🌐 CORS"]
        VALIDATE["✅ Validación"]
    end
    
    subgraph Layer4 ["Capa 4: Data"]
        IAM["🔑 IAM Roles"]
        ENCRYPT["🔒 Encryption"]
    end
    
    USER --> WAF
    ATTACKER --> WAF
    WAF -->|"❌ SQLi/XSS"| BLOCK["🚫 Blocked"]
    WAF -->|"✅ Clean"| COGNITO
    COGNITO --> JWT
    JWT --> THROTTLE --> CORS --> VALIDATE
    VALIDATE --> IAM --> ENCRYPT
Loading
Capa Protección Configuración
WAF Rate limit, SQLi, XSS 2000 req/5min, AWS Managed Rules
Cognito Autenticación JWT RS256, refresh tokens
API Gateway Throttling 1000 req/s burst, 500 req/s steady
IAM Autorización Least privilege, sin wildcards
DynamoDB Datos Encryption at rest (AES-256)

📈 Monitoreo y Observabilidad

📊 Ver diagrama de observabilidad
flowchart LR
    subgraph Sources ["📊 Fuentes"]
        L["Lambda Logs"]
        API["API Gateway"]
        DDB["DynamoDB"]
    end
    
    subgraph CloudWatch ["☁️ CloudWatch"]
        LOGS["📝 Log Groups"]
        METRICS["📊 Metrics"]
        DASH["📈 Dashboard"]
        ALARMS["🚨 Alarms"]
    end
    
    subgraph XRay ["🔍 X-Ray"]
        TRACES["Traces"]
        MAP["Service Map"]
    end
    
    subgraph Alerts ["🔔 Alertas"]
        SNS["📧 SNS"]
        EMAIL["Email Admin"]
    end
    
    L & API & DDB --> LOGS --> METRICS --> DASH
    METRICS --> ALARMS --> SNS --> EMAIL
    L & API --> TRACES --> MAP
Loading

Warning

Las alarmas notifican automáticamente cuando:

  • Errores 5XX > 10 en 5 minutos
  • Lambda errors > 5%
  • DLQ con mensajes pendientes
  • Throttling activado

💰 Costos

Note

Todo el proyecto opera dentro del AWS Free Tier actualmente

Servicio Uso Mensual Free Nuestro Uso
Lambda 1M requests ~10K ✅
API Gateway 1M requests ~10K ✅
DynamoDB 25 GB ~50 MB ✅
Cognito 50K MAU ~10 ✅
EventBridge 14M events ~1K ✅
SNS 1M publish ~100 ✅
CloudWatch 10 metrics ~5 ✅
Vercel 100GB bandwidth ~1GB ✅
Bedrock Nova Free tier

💸 Costos estimados en Producción

Note

Escenario: uso moderado en producción (≈100K usuarios/mes, tráfico constante)

Servicio Supuesto de Uso en Producción Costo Estimado Mensual (USD)
AWS Lambda ~2M requests ~$0.40
API Gateway (REST) ~2M requests ~$7.00
DynamoDB (On-Demand) ~5 GB + lecturas/escrituras ~$3.00
Amazon Cognito ~20K MAU ~$11.00
EventBridge ~2M eventos ~$2.00
SNS ~50K notificaciones ~$1.00
CloudWatch Logs + métricas ~$2.00
AWS WAF Web ACL + reglas ~$6.00
Amazon Bedrock (Nova) Uso ligero ~$5.00
Vercel (Pro) Tráfico alto ~$20.00
Total Aproximado ~$57 USD / mes

🤝 Contribuir

# 1. Fork del repositorio
# 2. Crear branch
git checkout -b feature/nueva-funcionalidad

# 3. Hacer cambios y commit
git commit -m "feat: agregar nueva funcionalidad"

# 4. Push y crear PR
git push origin feature/nueva-funcionalidad

📄 Licencia

Este proyecto está bajo la licencia Apache License 2.0. Ver [LICENSE](Apache License 2.0) para más detalles.


About

Plataforma integral para la gestión y participación en talleres de formación profesional. Desarrolla tus habilidades técnicas y blandas con nuestra moderna plataforma de aprendizaje.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • TypeScript 77.4%
  • Python 19.4%
  • CSS 2.1%
  • JavaScript 1.1%