@@ -46,30 +65,3 @@
-
diff --git a/src/composables/useChat.js b/src/composables/useChat.js
deleted file mode 100644
index 2234b19..0000000
--- a/src/composables/useChat.js
+++ /dev/null
@@ -1,74 +0,0 @@
-import { ref } from "vue"
-
-export function useChat(findBestResponse) {
- const messages = ref([])
- const input = ref("")
- const isLoading = ref(false)
-
- async function sendMessage(text = null) {
- const messageText = text || input.value.trim()
- if (!messageText || isLoading.value) return
-
- // Agregar mensaje del usuario
- const userMessage = {
- id: Date.now(),
- role: "user",
- content: messageText,
- timestamp: Date.now(),
- }
- messages.value.push(userMessage)
-
- // Limpiar input
- input.value = ""
- isLoading.value = true
-
- // Agregar mensaje de typing
- const typingMessage = {
- id: Date.now() + 1,
- role: "assistant",
- content: "",
- typing: true,
- }
- messages.value.push(typingMessage)
-
- // Simular delay de respuesta realista
- const delay = 1000 + Math.random() * 2000 // 1-3 segundos
-
- setTimeout(() => {
- // Remover mensaje de typing
- messages.value.pop()
-
- // Obtener respuesta de la base de conocimiento
- const responseData = findBestResponse(messageText)
-
- // Agregar respuesta real
- const assistantMessage = {
- id: Date.now() + 2,
- role: "assistant",
- content: responseData.content,
- category: responseData.category,
- timestamp: responseData.timestamp,
- }
- messages.value.push(assistantMessage)
-
- isLoading.value = false
- }, delay)
- }
-
- function handleSubmit() {
- sendMessage()
- }
-
- function clearChat() {
- messages.value = []
- }
-
- return {
- messages,
- input,
- isLoading,
- sendMessage,
- handleSubmit,
- clearChat,
- }
-}
diff --git a/src/composables/useKnowledgeBase.js b/src/composables/useKnowledgeBase.js
deleted file mode 100644
index abc2847..0000000
--- a/src/composables/useKnowledgeBase.js
+++ /dev/null
@@ -1,337 +0,0 @@
-import { ref } from "vue"
-
-export function useKnowledgeBase() {
- const knowledgeBase = ref({
- experiencia: {
- keywords: ["experiencia", "trabajo", "laboral", "años", "empresa", "puesto", "carrera"],
- response: `
-
💼 Experiencia Profesional
-
-
Senior Full Stack Developer (2021 - Presente)
-
TechCorp Solutions
- • Liderazgo de equipo de 5 desarrolladores
- • Arquitectura de microservicios con Node.js y Docker
- • Implementación de CI/CD reduciendo deploys en 80%
- • Migración de aplicaciones legacy a arquitecturas modernas
-
-
Frontend Developer (2019 - 2021)
-
StartupXYZ
- • Desarrollo de SPAs con Vue.js y React
- • Optimización de performance (Core Web Vitals)
- • Colaboración estrecha con equipos UX/UI
- • Implementación de testing automatizado
-
-
Junior Developer (2018 - 2019)
-
DevAgency
- • Desarrollo de APIs REST con Express.js
- • Integración con bases de datos SQL y NoSQL
- • Metodologías ágiles (Scrum/Kanban)
- • Participación en code reviews y pair programming
- `,
- },
-
- habilidades: {
- keywords: ["habilidades", "tecnologías", "stack", "lenguajes", "frameworks", "dominas", "herramientas"],
- response: `
-
🚀 Stack Tecnológico
-
-
Frontend (Avanzado):
- • Vue.js 3 (Composition API, Pinia, Nuxt.js)
- • React 18 (Hooks, Context, Redux Toolkit, Next.js)
- • TypeScript - Tipado fuerte y desarrollo escalable
- • Tailwind CSS, SCSS - Diseño responsive y modular
- • Webpack, Vite - Bundling y optimización
-
-
Backend (Avanzado):
- • Node.js (Express, Fastify, NestJS)
- • Python (Django, FastAPI) - APIs y microservicios
- • Bases de datos: PostgreSQL, MongoDB, Redis
- • GraphQL, REST APIs - Diseño de APIs escalables
-
-
DevOps & Cloud (Intermedio-Avanzado):
- • Docker, Kubernetes - Containerización
- • AWS (EC2, S3, Lambda, RDS) - Cloud computing
- • CI/CD (GitHub Actions, Jenkins) - Automatización
- • Nginx, Apache - Configuración de servidores
-
-
Herramientas & Metodologías:
- • Git (GitFlow, conventional commits)
- • Jest, Cypress - Testing automatizado
- • Scrum, Kanban - Metodologías ágiles
- • Figma, Adobe XD - Colaboración con diseño
- `,
- },
-
- proyectos: {
- keywords: ["proyectos", "desarrollado", "creado", "portfolio", "destacados", "aplicaciones"],
- response: `
-
🎯 Proyectos Destacados
-
-
🛒 E-commerce Platform
-
Plataforma completa de comercio electrónico
- • +50,000 usuarios activos mensuales
- • Integración con múltiples pasarelas de pago
- • Panel de administración con analytics en tiempo real
- •
Tech: Vue 3, Node.js, PostgreSQL, Redis, Stripe
- •
Logros: 99.9% uptime, 2s tiempo de carga
-
-
📊 Real-time Analytics Dashboard
-
Dashboard empresarial con visualizaciones interactivas
- • Procesamiento de +1M eventos/día
- • Visualizaciones en tiempo real con WebSockets
- • Exportación de reportes automatizada
- •
Tech: React, D3.js, Socket.io, InfluxDB
- •
Logros: Reducción de 70% en tiempo de análisis
-
-
🏗️ Microservices Architecture
-
Migración de monolito a microservicios
- • Arquitectura distribuida con 12 microservicios
- • Implementación de Event Sourcing y CQRS
- • Monitoreo con Prometheus y Grafana
- •
Tech: Node.js, Docker, Kubernetes, AWS EKS
- •
Logros: 60% reducción latencia, 99.95% disponibilidad
-
-
🤖 AI Portfolio Chat (Este proyecto)
-
Portfolio interactivo con simulación de IA
- • Chat inteligente sin dependencias externas
- • Respuestas contextuales pre-programadas
- • Diseño responsive y accesible
- •
Tech: Vue 3, Tailwind CSS, Vite
- •
Innovación: Portfolio que demuestra habilidades técnicas
- `,
- },
-
- educacion: {
- keywords: ["educación", "estudios", "universidad", "carrera", "certificaciones", "formación"],
- response: `
-
🎓 Formación Académica
-
-
Ingeniería en Sistemas de Información
-
Universidad Tecnológica Nacional (2014-2018)
- • Especialización en Desarrollo de Software
- • Proyecto final: Sistema de gestión hospitalaria
- • Promedio: 8.5/10
-
-
Certificaciones Profesionales:
- •
AWS Certified Developer Associate (2022)
- •
MongoDB Certified Developer (2021)
- •
Certified Scrum Master (CSM) (2020)
- •
Google Cloud Professional Developer (2023)
-
-
Formación Continua:
- •
Arquitectura de Software - Platzi (2023)
- •
Advanced React Patterns - Epic React (2022)
- •
Microservices with Node.js - Udemy (2021)
- •
Machine Learning Fundamentals - Coursera (2023)
-
-
Participación en Comunidad:
- • Speaker en VueConf Argentina 2022
- • Contribuciones a proyectos open source
- • Mentor en programas de coding bootcamps
- • Organizador de meetups locales de JavaScript
- `,
- },
-
- contacto: {
- keywords: ["contacto", "email", "linkedin", "github", "cv", "ubicación", "teléfono"],
- response: `
-
📞 Información de Contacto
-
-
Datos Principales:
- •
Email: tu.email@ejemplo.com
- •
LinkedIn: linkedin.com/in/tu-perfil
- •
GitHub: github.com/tu-usuario
- •
Portfolio: tu-portfolio.com
-
-
Ubicación & Disponibilidad:
- •
Ubicación: Buenos Aires, Argentina
- •
Zona horaria: GMT-3 (Argentina)
- •
Modalidad: Remoto/Híbrido/Presencial
- •
Disponibilidad: Inmediata
-
-
Idiomas:
- •
Español: Nativo
- •
Inglés: Avanzado (C1) - Certificado Cambridge
- •
Portugués: Intermedio (B2)
-
-
Horarios de Contacto:
- • Lunes a Viernes: 9:00 - 18:00 (GMT-3)
- • Respuesta garantizada en menos de 24hs
-
-
¡No dudes en contactarme para discutir oportunidades laborales!
- `,
- },
-
- salario: {
- keywords: ["salario", "sueldo", "pretensiones", "económicas", "remuneración", "dinero", "pago"],
- response: `
-
💰 Expectativas Salariales
-
-
Rango Salarial (USD/mes):
- •
Remoto Internacional: $4,000 - $6,000
- •
Empresas Locales: $2,500 - $4,000
- •
Freelance/Consultoría: $50 - $80/hora
-
-
Factores que Considero:
- • Complejidad técnica del proyecto
- • Responsabilidades de liderazgo
- • Oportunidades de crecimiento profesional
- • Beneficios adicionales (salud, vacaciones, etc.)
- • Cultura y ambiente de trabajo
- • Modalidad de trabajo (remoto/híbrido/presencial)
-
-
Beneficios Valorados:
- • 🏥 Cobertura médica completa
- • 📚 Presupuesto para capacitación y conferencias
- • 💻 Equipamiento de trabajo de calidad
- • 🏖️ Días de vacaciones flexibles
- • 🚀 Stock options o participación en ganancias
- • 🏠 Flexibilidad horaria y trabajo remoto
-
-
Modalidades de Contratación:
- • Relación de dependencia (preferida)
- • Contrato por proyecto
- • Consultoría a largo plazo
-
-
Estoy abierto a negociar un paquete integral que sea beneficioso para ambas partes. Lo más importante para mí es encontrar un proyecto desafiante con un equipo talentoso.
- `,
- },
- })
-
- const defaultResponses = [
- "Esa es una excelente pregunta. Como desarrollador senior con más de 5 años de experiencia, siempre busco mantenerme actualizado con las últimas tecnologías y mejores prácticas del desarrollo web.",
- "Interesante punto. En mi experiencia trabajando tanto en startups como en empresas enterprise, he encontrado que la clave está en encontrar el equilibrio entre innovación y estabilidad.",
- "Desde mi perspectiva técnica, considero fundamental evaluar cada herramienta y tecnología en función del contexto específico del proyecto y las necesidades del negocio.",
- "Basándome en mi experiencia liderando equipos y desarrollando arquitecturas escalables, puedo decir que la comunicación y la documentación son tan importantes como el código.",
- "Como alguien que ha migrado sistemas legacy y implementado arquitecturas modernas, he aprendido que la planificación y el testing son cruciales para el éxito de cualquier proyecto.",
- ]
-
- function findBestResponse(message) {
- const lowerMessage = message.toLowerCase()
-
- // Buscar en la base de conocimiento
- for (const [category, data] of Object.entries(knowledgeBase.value)) {
- if (data.keywords.some((keyword) => lowerMessage.includes(keyword))) {
- return {
- content: data.response,
- category: category,
- timestamp: Date.now(),
- }
- }
- }
-
- // Respuestas contextuales específicas
- if (lowerMessage.includes("react") || lowerMessage.includes("vue")) {
- return {
- content: `
-
⚛️ React vs Vue.js - Mi Perspectiva
-
- Tengo experiencia sólida con ambos frameworks y los uso según el contexto:
-
-
React:
- • Ecosistema maduro y comunidad muy activa
- • Hooks y Context API para gestión de estado elegante
- • Ideal para aplicaciones complejas y equipos grandes
- • Excelente para desarrollo de componentes reutilizables
-
-
Vue.js:
- • Curva de aprendizaje más suave y sintaxis intuitiva
- • Composition API muy potente (similar a React Hooks)
- • Excelente para desarrollo rápido y prototipado
- • Mejor integración con proyectos existentes
-
-
Mi Recomendación:
- •
React: Para SPAs complejas, equipos grandes, ecosistema robusto
- •
Vue: Para desarrollo ágil, equipos pequeños, integración gradual
-
-
En mi experiencia, ambos son excelentes herramientas. La elección depende del proyecto, equipo y contexto específico.
- `,
- category: "tecnologias",
- timestamp: Date.now(),
- }
- }
-
- if (lowerMessage.includes("node") || lowerMessage.includes("backend") || lowerMessage.includes("servidor")) {
- return {
- content: `
-
🔧 Desarrollo Backend con Node.js
-
- Mi experiencia en backend se centra principalmente en el ecosistema JavaScript:
-
-
Frameworks y Librerías:
- •
Express.js: Framework minimalista, ideal para APIs REST
- •
Fastify: Alto rendimiento, excelente para microservicios
- •
NestJS: Arquitectura escalable, perfecto para aplicaciones enterprise
-
-
Bases de Datos:
- •
PostgreSQL: Para datos relacionales complejos
- •
MongoDB: Para datos no estructurados y prototipado rápido
- •
Redis: Para caché y sesiones de usuario
-
-
Arquitecturas que Manejo:
- • APIs REST con documentación OpenAPI/Swagger
- • GraphQL para consultas flexibles
- • Microservicios con comunicación asíncrona
- • Event-driven architecture con message queues
-
-
Mejores Prácticas:
- • Testing automatizado (Jest, Supertest)
- • Validación de datos con Joi/Yup
- • Logging estructurado con Winston
- • Monitoreo con Prometheus y Grafana
-
-
Siempre enfocado en código limpio, escalable y bien documentado.
- `,
- category: "backend",
- timestamp: Date.now(),
- }
- }
-
- if (lowerMessage.includes("docker") || lowerMessage.includes("kubernetes") || lowerMessage.includes("devops")) {
- return {
- content: `
-
🐳 DevOps y Containerización
-
- Mi experiencia en DevOps se enfoca en automatización y escalabilidad:
-
-
Containerización:
- •
Docker: Creación de imágenes optimizadas multi-stage
- •
Docker Compose: Orquestación local y testing
- •
Kubernetes: Despliegue y escalado en producción
-
-
CI/CD Pipelines:
- •
GitHub Actions: Automatización completa de workflows
- •
Jenkins: Pipelines complejos para empresas
- • Testing automatizado, build y deploy
-
-
Cloud Platforms:
- •
AWS: EC2, ECS, Lambda, RDS, S3
- •
Google Cloud: GKE, Cloud Functions, Cloud SQL
- • Infrastructure as Code con Terraform
-
-
Monitoreo y Observabilidad:
- • Prometheus + Grafana para métricas
- • ELK Stack para logs centralizados
- • Health checks y alertas automatizadas
-
-
Mi objetivo es crear pipelines que permitan deploys seguros y frecuentes, reduciendo el time-to-market.
- `,
- category: "devops",
- timestamp: Date.now(),
- }
- }
-
- // Respuesta por defecto
- const randomResponse = defaultResponses[Math.floor(Math.random() * defaultResponses.length)]
- return {
- content: randomResponse,
- category: "general",
- timestamp: Date.now(),
- }
- }
-
- return {
- findBestResponse,
- knowledgeBase,
- }
-}
diff --git a/src/composables/useNavigation.js b/src/composables/useNavigation.ts
similarity index 87%
rename from src/composables/useNavigation.js
rename to src/composables/useNavigation.ts
index 7514536..8adc0bf 100644
--- a/src/composables/useNavigation.js
+++ b/src/composables/useNavigation.ts
@@ -1,5 +1,5 @@
export function useNavigation() {
- function scrollToSection(sectionId) {
+ function scrollToSection(sectionId: string) {
const element = document.getElementById(sectionId)
if (element) {
const offset = 80 // Account for fixed header
diff --git a/src/composables/usePortfolioData.js b/src/composables/usePortfolioData.js
deleted file mode 100644
index 8a70dcb..0000000
--- a/src/composables/usePortfolioData.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import { ref } from "vue"
-import { PortfolioRepository } from "@/infrastructure/repositories/PortfolioRepository"
-
-export function usePortfolioData() {
- const portfolioData = ref({})
- const isLoading = ref(false)
- const error = ref(null)
-
- const portfolioRepository = new PortfolioRepository()
-
- async function loadPortfolioData() {
- try {
- isLoading.value = true
- error.value = null
- portfolioData.value = await portfolioRepository.getPortfolioData()
- } catch (err) {
- error.value = err.message
- console.error("Error loading portfolio data:", err)
- } finally {
- isLoading.value = false
- }
- }
-
- return {
- portfolioData,
- isLoading,
- error,
- loadPortfolioData,
- }
-}
diff --git a/src/composables/useProfile.ts b/src/composables/useProfile.ts
new file mode 100644
index 0000000..6b45fcd
--- /dev/null
+++ b/src/composables/useProfile.ts
@@ -0,0 +1,25 @@
+import {onMounted, ref} from "vue";
+import {ProfileService} from "@/infrastructure/api/ProfileService";
+import {GetProfile} from "@/domain/usecases/GetProfile";
+
+const profileService = new ProfileService();
+const getProfileUseCase = new GetProfile(profileService);
+
+export function useProfile() {
+ const profile = ref
(null);
+ const loading = ref(false);
+ const error = ref(null);
+
+ onMounted(async () => {
+ loading.value = true;
+ try {
+ profile.value = await getProfileUseCase.execute();
+ } catch (err: any) {
+ error.value = err.message;
+ } finally {
+ loading.value = false;
+ }
+ });
+
+ return {profile, loading};
+}
\ No newline at end of file
diff --git a/src/config.ts b/src/config.ts
new file mode 100644
index 0000000..5163645
--- /dev/null
+++ b/src/config.ts
@@ -0,0 +1,32 @@
+interface AppConfig {
+ apiUrl: boolean;
+ sections: {
+ heroEnabled: boolean;
+ aboutEnabled: boolean;
+ experienceEnabled: boolean;
+ projectsEnabled: boolean;
+ skillsEnabled: boolean;
+ educationEnabled: boolean;
+ certificationsEnabled: boolean,
+ contactEnabled: boolean;
+ chatEnabled: boolean;
+ };
+
+}
+
+const config: AppConfig = {
+ apiUrl: import.meta.env.VITE_API_URL || "http://localhost:3000",
+ sections: {
+ heroEnabled: true,
+ aboutEnabled: true,
+ experienceEnabled: true,
+ projectsEnabled: true,
+ skillsEnabled: true,
+ educationEnabled: true,
+ certificationsEnabled: true,
+ contactEnabled: true,
+ chatEnabled: false,
+ }
+};
+
+export default config;
\ No newline at end of file
diff --git a/src/data/portfolio-config.json b/src/data/portfolio-config.json
deleted file mode 100644
index b080180..0000000
--- a/src/data/portfolio-config.json
+++ /dev/null
@@ -1,228 +0,0 @@
-{
- "personal": {
- "name": "Pablo de la Torre Jamardo",
- "title": "Senior Full Stack Developer",
- "subtitle": "Especializado en Vue.js, React y Node.js",
- "email": "pablo.delatorre@ejemplo.com",
- "phone": "+54 11 1234-5678",
- "location": "Buenos Aires, Argentina",
- "avatar": "/src/assets/avatar-bot.png",
- "bio": "Desarrollador Full Stack con más de 5 años de experiencia creando aplicaciones web escalables y modernas. Especializado en JavaScript, Vue.js, React y arquitecturas de microservicios.",
- "social": {
- "github": "https://github.com/pablo-delatorre",
- "linkedin": "https://linkedin.com/in/pablo-delatorre",
- "twitter": "https://twitter.com/pablo_dev",
- "portfolio": "https://pablo-portfolio.com"
- }
- },
- "experience": [
- {
- "id": "exp1",
- "company": "TechCorp Solutions",
- "position": "Senior Full Stack Developer",
- "period": "2021 - Presente",
- "location": "Buenos Aires, Argentina",
- "description": "Liderazgo de equipo de 5 desarrolladores, arquitectura de microservicios con Node.js y Docker, implementación de CI/CD reduciendo deploys en 80%.",
- "technologies": ["Vue.js", "Node.js", "Docker", "AWS", "PostgreSQL"],
- "achievements": [
- "Migración de aplicaciones legacy a arquitecturas modernas",
- "Reducción del 80% en tiempo de deployment",
- "Implementación de testing automatizado"
- ]
- },
- {
- "id": "exp2",
- "company": "StartupXYZ",
- "position": "Frontend Developer",
- "period": "2019 - 2021",
- "location": "Buenos Aires, Argentina",
- "description": "Desarrollo de SPAs con Vue.js y React, optimización de performance y colaboración con equipos UX/UI.",
- "technologies": ["Vue.js", "React", "TypeScript", "Tailwind CSS"],
- "achievements": [
- "Optimización de Core Web Vitals",
- "Implementación de design system",
- "Mejora del 40% en performance"
- ]
- },
- {
- "id": "exp3",
- "company": "DevAgency",
- "position": "Junior Developer",
- "period": "2018 - 2019",
- "location": "Buenos Aires, Argentina",
- "description": "Desarrollo de APIs REST con Express.js, integración con bases de datos y metodologías ágiles.",
- "technologies": ["Node.js", "Express.js", "MongoDB", "Git"],
- "achievements": [
- "Desarrollo de 15+ APIs REST",
- "Participación en metodologías ágiles",
- "Contribución a proyectos open source"
- ]
- }
- ],
- "projects": [
- {
- "id": "proj1",
- "title": "E-commerce Platform",
- "description": "Plataforma completa de comercio electrónico con más de 50,000 usuarios activos mensuales",
- "image": "/placeholder.svg?height=300&width=400",
- "technologies": ["Vue.js", "Node.js", "PostgreSQL", "Redis", "Stripe"],
- "features": [
- "Integración con múltiples pasarelas de pago",
- "Panel de administración con analytics",
- "Sistema de inventario en tiempo real"
- ],
- "metrics": {
- "users": "50,000+",
- "uptime": "99.9%",
- "loadTime": "2s"
- },
- "links": {
- "demo": "https://demo-ecommerce.com",
- "github": "https://github.com/pablo/ecommerce"
- }
- },
- {
- "id": "proj2",
- "title": "Real-time Analytics Dashboard",
- "description": "Dashboard empresarial con visualizaciones interactivas y procesamiento de más de 1M eventos/día",
- "image": "/placeholder.svg?height=300&width=400",
- "technologies": ["React", "D3.js", "Socket.io", "InfluxDB", "Node.js"],
- "features": ["Visualizaciones en tiempo real", "Exportación de reportes automatizada", "Alertas personalizables"],
- "metrics": {
- "events": "1M+/día",
- "reduction": "70% tiempo análisis",
- "users": "500+"
- },
- "links": {
- "demo": "https://analytics-demo.com",
- "github": "https://github.com/pablo/analytics"
- }
- },
- {
- "id": "proj3",
- "title": "Microservices Architecture",
- "description": "Migración de monolito a arquitectura de microservicios con 12 servicios distribuidos",
- "image": "/placeholder.svg?height=300&width=400",
- "technologies": ["Node.js", "Docker", "Kubernetes", "AWS EKS", "MongoDB"],
- "features": ["Event Sourcing y CQRS", "Monitoreo con Prometheus", "Auto-scaling automático"],
- "metrics": {
- "services": "12",
- "latencyReduction": "60%",
- "availability": "99.95%"
- },
- "links": {
- "github": "https://github.com/pablo/microservices"
- }
- }
- ],
- "skills": {
- "frontend": [
- { "name": "Vue.js", "level": 95, "years": 4 },
- { "name": "React", "level": 90, "years": 3 },
- { "name": "TypeScript", "level": 85, "years": 3 },
- { "name": "Tailwind CSS", "level": 90, "years": 2 },
- { "name": "Nuxt.js", "level": 80, "years": 2 }
- ],
- "backend": [
- { "name": "Node.js", "level": 95, "years": 5 },
- { "name": "Express.js", "level": 90, "years": 4 },
- { "name": "NestJS", "level": 80, "years": 2 },
- { "name": "Python", "level": 75, "years": 2 },
- { "name": "GraphQL", "level": 70, "years": 1 }
- ],
- "database": [
- { "name": "PostgreSQL", "level": 85, "years": 4 },
- { "name": "MongoDB", "level": 80, "years": 3 },
- { "name": "Redis", "level": 75, "years": 2 }
- ],
- "devops": [
- { "name": "Docker", "level": 85, "years": 3 },
- { "name": "AWS", "level": 80, "years": 2 },
- { "name": "Kubernetes", "level": 70, "years": 1 },
- { "name": "CI/CD", "level": 85, "years": 3 }
- ]
- },
- "education": [
- {
- "id": "edu1",
- "institution": "Universidad Tecnológica Nacional",
- "degree": "Ingeniería en Sistemas de Información",
- "period": "2014 - 2018",
- "description": "Especialización en Desarrollo de Software. Proyecto final: Sistema de gestión hospitalaria.",
- "grade": "8.5/10"
- }
- ],
- "certifications": [
- {
- "id": "cert1",
- "name": "AWS Certified Developer Associate",
- "issuer": "Amazon Web Services",
- "date": "2022",
- "credentialId": "AWS-123456"
- },
- {
- "id": "cert2",
- "name": "MongoDB Certified Developer",
- "issuer": "MongoDB Inc.",
- "date": "2021",
- "credentialId": "MONGO-789012"
- },
- {
- "id": "cert3",
- "name": "Certified Scrum Master",
- "issuer": "Scrum Alliance",
- "date": "2020",
- "credentialId": "CSM-345678"
- }
- ],
- "chatbot": {
- "welcome": {
- "message": "¡Hola! 👋 Soy el asistente virtual de Pablo. Puedo contarte sobre su experiencia, habilidades, proyectos y más. ¿Qué te gustaría saber?",
- "quickActions": [
- {
- "text": "¿Cuál es su experiencia laboral?",
- "category": "experience"
- },
- {
- "text": "¿Qué tecnologías domina?",
- "category": "skills"
- },
- {
- "text": "Cuéntame sobre sus proyectos",
- "category": "projects"
- },
- {
- "text": "¿Cómo puedo contactarlo?",
- "category": "contact"
- }
- ]
- },
- "responses": {
- "experience": {
- "keywords": ["experiencia", "trabajo", "laboral", "empresa", "puesto", "carrera"],
- "response": "Pablo tiene más de 5 años de experiencia como desarrollador Full Stack. Actualmente es Senior Developer en TechCorp Solutions, donde lidera un equipo de 5 desarrolladores y ha implementado arquitecturas de microservicios que redujeron los tiempos de deployment en un 80%. Anteriormente trabajó en StartupXYZ optimizando performance y en DevAgency desarrollando APIs REST."
- },
- "skills": {
- "keywords": ["habilidades", "tecnologías", "stack", "lenguajes", "frameworks"],
- "response": "Pablo domina un amplio stack tecnológico: Frontend con Vue.js (95%), React (90%) y TypeScript (85%). En Backend maneja Node.js (95%), Express.js (90%) y Python (75%). También tiene experiencia en bases de datos como PostgreSQL y MongoDB, y en DevOps con Docker, AWS y Kubernetes."
- },
- "projects": {
- "keywords": ["proyectos", "desarrollado", "creado", "portfolio", "aplicaciones"],
- "response": "Entre sus proyectos destacados están: una plataforma de e-commerce con +50,000 usuarios activos, un dashboard de analytics en tiempo real que procesa +1M eventos/día, y la migración de un monolito a arquitectura de microservicios que mejoró la disponibilidad al 99.95%."
- },
- "contact": {
- "keywords": ["contacto", "email", "teléfono", "linkedin", "ubicación"],
- "response": "Puedes contactar a Pablo por email: pablo.delatorre@ejemplo.com, teléfono: +54 11 1234-5678. También está en LinkedIn: linkedin.com/in/pablo-delatorre y GitHub: github.com/pablo-delatorre. Se encuentra en Buenos Aires, Argentina."
- },
- "education": {
- "keywords": ["educación", "estudios", "universidad", "carrera", "certificaciones"],
- "response": "Pablo es Ingeniero en Sistemas de Información por la UTN (2014-2018) con especialización en Desarrollo de Software. Tiene certificaciones de AWS Developer Associate, MongoDB Certified Developer y Certified Scrum Master."
- }
- },
- "fallback": [
- "Esa es una excelente pregunta. Pablo siempre busca mantenerse actualizado con las últimas tecnologías.",
- "Interesante punto. En su experiencia, ha encontrado que la clave está en el equilibrio entre innovación y estabilidad.",
- "Desde su perspectiva técnica, considera fundamental evaluar cada herramienta según el contexto del proyecto."
- ]
- }
-}
diff --git a/src/domain/models/Certification.ts b/src/domain/models/Certification.ts
new file mode 100644
index 0000000..1336aad
--- /dev/null
+++ b/src/domain/models/Certification.ts
@@ -0,0 +1,7 @@
+export interface Certification {
+ id: string;
+ name: string;
+ issuer?: string;
+ date?: string;
+ credentialId?: string;
+}
\ No newline at end of file
diff --git a/src/domain/models/Education.ts b/src/domain/models/Education.ts
new file mode 100644
index 0000000..cf080c6
--- /dev/null
+++ b/src/domain/models/Education.ts
@@ -0,0 +1,8 @@
+export interface Education {
+ id: string;
+ institution: string;
+ degree: string;
+ period?: string;
+ description?: string;
+ grade?: string;
+}
\ No newline at end of file
diff --git a/src/domain/models/Experience.ts b/src/domain/models/Experience.ts
new file mode 100644
index 0000000..f70ac8d
--- /dev/null
+++ b/src/domain/models/Experience.ts
@@ -0,0 +1,10 @@
+export interface Experience {
+ id: string;
+ company: string;
+ position: string;
+ period: string;
+ location?: string;
+ description?: string;
+ technologies?: string[];
+ achievements?: string[];
+}
\ No newline at end of file
diff --git a/src/domain/models/Profile.ts b/src/domain/models/Profile.ts
new file mode 100644
index 0000000..082a5c5
--- /dev/null
+++ b/src/domain/models/Profile.ts
@@ -0,0 +1,21 @@
+export interface SocialLinks {
+ url?: string;
+ platform?: string;
+}
+
+export interface Profile {
+ id: number;
+ name: string;
+ title: string;
+ subtitle?: string;
+ email: string;
+ phone?: string;
+ location?: string;
+ avatar?: string;
+ bio?: string;
+ social?: SocialLinks[];
+}
+
+export default class ProfileDefault {
+
+}
\ No newline at end of file
diff --git a/src/domain/models/Project.ts b/src/domain/models/Project.ts
new file mode 100644
index 0000000..2f16dad
--- /dev/null
+++ b/src/domain/models/Project.ts
@@ -0,0 +1,10 @@
+export interface Project {
+ id: string;
+ title: string;
+ description?: string;
+ image?: string;
+ technologies?: string[];
+ features?: string[];
+ demo?: string;
+ repository?: string;
+}
\ No newline at end of file
diff --git a/src/domain/models/Skill.ts b/src/domain/models/Skill.ts
new file mode 100644
index 0000000..96ff609
--- /dev/null
+++ b/src/domain/models/Skill.ts
@@ -0,0 +1,11 @@
+export interface Skill {
+ name: string;
+ level: number;
+ years: number;
+}
+
+export interface SkillGroup {
+ name: string;
+ icon?: string;
+ skills: Skill[];
+}
\ No newline at end of file
diff --git a/src/domain/usecases/GetProfile.ts b/src/domain/usecases/GetProfile.ts
new file mode 100644
index 0000000..9731ff1
--- /dev/null
+++ b/src/domain/usecases/GetProfile.ts
@@ -0,0 +1,32 @@
+import {ProfileService} from "@/infrastructure/api/ProfileService";
+import {Profile} from "@/domain/models/Profile";
+import {Experience} from "@/domain/models/Experience";
+import {Project} from "@/domain/models/Project";
+import {SkillGroup} from "@/domain/models/Skill";
+import {Education} from "@/domain/models/Education";
+import {Certification} from "@/domain/models/Certification";
+
+export interface ProfileData {
+ profile: Profile;
+ experience: Experience[];
+ projects: Project[];
+ skills: SkillGroup[];
+ education: Education[];
+ certifications: Certification[];
+}
+
+export class GetProfile {
+ constructor(private readonly profileService: ProfileService) {
+ }
+
+ async execute(): Promise {
+ const profile = await this.profileService.getProfile();
+ const experience = await this.profileService.getExperience(profile.id);
+ const projects = await this.profileService.getProjects(profile.id);
+ const skills = await this.profileService.getSkills(profile.id);
+ const education = await this.profileService.getEducation(profile.id);
+ const certifications = await this.profileService.getCertifications(profile.id);
+
+ return {profile, experience, projects, skills, education, certifications};
+ }
+}
\ No newline at end of file
diff --git a/src/infrastructure/api/ProfileService.ts b/src/infrastructure/api/ProfileService.ts
new file mode 100644
index 0000000..e375b42
--- /dev/null
+++ b/src/infrastructure/api/ProfileService.ts
@@ -0,0 +1,59 @@
+import {Profile} from "@/domain/models/Profile";
+import {Experience} from "@/domain/models/Experience";
+import {Project} from "@/domain/models/Project";
+import {SkillGroup} from "@/domain/models/Skill";
+import {Education} from "@/domain/models/Education";
+import {Certification} from "@/domain/models/Certification";
+import profileMockData from "@/infrastructure/mock/profile.json";
+import experienceMockData from "@/infrastructure/mock/experience.json";
+import educationMockData from "@/infrastructure/mock/education.json";
+import certificationMockData from "@/infrastructure/mock/certification.json";
+import skillMockData from "@/infrastructure/mock/skill.json";
+import projectMockData from "@/infrastructure/mock/project.json";
+
+const useMock = import.meta.env.VITE_USE_MOCK === "true";
+
+export class ProfileService {
+
+ async getProfile(): Promise {
+ if (useMock) return profileMockData.content;
+ const res = await fetch(`${import.meta.env.VITE_API_URL}/profiles/${import.meta.env.VITE_PORTFOLIO_SLUG}`);
+ if (!res.ok) console.log(new Error("Error fetching personal data"));
+ return await res.json();
+ }
+
+ async getExperience(profileId: number): Promise {
+ if (useMock) return experienceMockData.content;
+ const res = await fetch(`${import.meta.env.VITE_API_URL}/profiles/${profileId}/experience`);
+ if (!res.ok) console.log(new Error("Error fetching experience data"));
+ return await res.json();
+ }
+
+ async getProjects(profileId: number): Promise {
+ if (useMock) return projectMockData.content;
+ const res = await fetch(`${import.meta.env.VITE_API_URL}/profiles/${profileId}/projects`);
+ if (!res.ok) console.log(new Error("Error fetching projects data"));
+ return await res.json();
+ }
+
+ async getSkills(profileId: number): Promise {
+ if (useMock) return skillMockData.content;
+ const res = await fetch(`${import.meta.env.VITE_API_URL}/profiles/${profileId}/skills`);
+ if (!res.ok) console.log(new Error("Error fetching skills data"));
+ return await res.json();
+ }
+
+ async getEducation(profileId: number): Promise {
+ if (useMock) return educationMockData.content;
+ const res = await fetch(`${import.meta.env.VITE_API_URL}/profiles/${profileId}/education`);
+ if (!res.ok) console.log(new Error("Error fetching education data"));
+ return await res.json();
+ }
+
+ async getCertifications(profileId: number): Promise {
+ if (useMock) return certificationMockData.content;
+ const res = await fetch(`${import.meta.env.VITE_API_URL}/profiles/${profileId}/certifications`);
+ if (!res.ok) console.log(new Error("Error fetching certifications data"));
+ return await res.json();
+ }
+}
\ No newline at end of file
diff --git a/src/infrastructure/mock/certification.json b/src/infrastructure/mock/certification.json
new file mode 100644
index 0000000..50cc678
--- /dev/null
+++ b/src/infrastructure/mock/certification.json
@@ -0,0 +1,25 @@
+{
+ "content": [
+ {
+ "id": "cert1",
+ "name": "AWS Certified Developer Associate",
+ "issuer": "Amazon Web Services",
+ "date": "2022",
+ "credentialId": "AWS-123456"
+ },
+ {
+ "id": "cert2",
+ "name": "MongoDB Certified Developer",
+ "issuer": "MongoDB Inc.",
+ "date": "2021",
+ "credentialId": "MONGO-789012"
+ },
+ {
+ "id": "cert3",
+ "name": "Certified Scrum Master",
+ "issuer": "Scrum Alliance",
+ "date": "2020",
+ "credentialId": "CSM-345678"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/infrastructure/mock/chatbot.json b/src/infrastructure/mock/chatbot.json
new file mode 100644
index 0000000..d479e31
--- /dev/null
+++ b/src/infrastructure/mock/chatbot.json
@@ -0,0 +1,83 @@
+{
+ "content": {
+ "welcome": {
+ "message": "¡Hola! 👋 Soy el asistente virtual de Pablo. ¿Te interesa saber sobre su trabajo en backend, despliegue automatizado o LLMs locales?",
+ "quickActions": [
+ {
+ "text": "¿Cuál es su experiencia laboral?",
+ "category": "experience"
+ },
+ {
+ "text": "¿Qué tecnologías domina?",
+ "category": "skills"
+ },
+ {
+ "text": "Cuéntame sobre sus proyectos",
+ "category": "projects"
+ },
+ {
+ "text": "¿Cómo puedo contactarlo?",
+ "category": "contact"
+ }
+ ]
+ },
+ "responses": {
+ "experience": {
+ "keywords": [
+ "experiencia",
+ "trabajo",
+ "laboral",
+ "empresa",
+ "puesto",
+ "carrera"
+ ],
+ "response": "Pablo trabaja actualmente como Arquitecto de Software en la Xunta de Galicia, liderando desarrollos backend complejos. Anteriormente ha trabajado como consultor y freelance, siempre enfocado en eficiencia y automatización."
+ },
+ "skills": {
+ "keywords": [
+ "habilidades",
+ "tecnologías",
+ "stack",
+ "lenguajes",
+ "frameworks"
+ ],
+ "response": "Domina tecnologías como Java (Spring Boot), Vue.js (Quasar), despliegue automatizado con Docker y GitHub Actions, y recientemente integración con modelos LLM offline."
+ },
+ "projects": {
+ "keywords": [
+ "proyectos",
+ "desarrollado",
+ "creado",
+ "portfolio",
+ "aplicaciones"
+ ],
+ "response": "Ha desarrollado una app LLM offline en Java, un sistema de reservas autónomo para un hostel, y una plataforma completa de tramitación electrónica con firma digital y backend distribuido."
+ },
+ "contact": {
+ "keywords": [
+ "contacto",
+ "email",
+ "teléfono",
+ "linkedin",
+ "ubicación"
+ ],
+ "response": "Puedes contactar a Pablo en pablo@pablotj.com o vía LinkedIn: linkedin.com/in/pablotj. Vive en Galicia, España."
+ },
+ "education": {
+ "keywords": [
+ "educación",
+ "estudios",
+ "universidad",
+ "carrera",
+ "certificaciones"
+ ],
+ "response": "Estudió Ingeniería Informática en la Universidade de Vigo. Está certificado en arquitectura Java, GitOps y modelos LLM locales."
+ }
+ },
+ "fallback": [
+ "Buena pregunta. Pablo valora mucho el rendimiento y la mantenibilidad en sus proyectos.",
+ "Interesante. Él suele aplicar principios de arquitectura limpia y buenas prácticas DevOps.",
+ "Siempre busca mantener la simplicidad sin sacrificar funcionalidad o seguridad."
+ ]
+ }
+}
\ No newline at end of file
diff --git a/src/infrastructure/mock/education.json b/src/infrastructure/mock/education.json
new file mode 100644
index 0000000..60c5165
--- /dev/null
+++ b/src/infrastructure/mock/education.json
@@ -0,0 +1,12 @@
+{
+ "content": [
+ {
+ "id": "edu1",
+ "institution": "CIFP Daniel Castelao, Vigo",
+ "degree": "Ciclo Formativo de Grado Superior en Desarrollo de Aplicaciones Multiplataforma",
+ "period": "2015 - 2017",
+ "description": "Formación técnica especializada en desarrollo de aplicaciones móviles y de escritorio multiplataforma, bases de datos, y programación orientada a objetos.",
+ "grade": "No aplicable"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/infrastructure/mock/experience.json b/src/infrastructure/mock/experience.json
new file mode 100644
index 0000000..178b0b7
--- /dev/null
+++ b/src/infrastructure/mock/experience.json
@@ -0,0 +1,77 @@
+{
+ "content": [
+ {
+ "id": "exp1",
+ "company": "Bahia Software",
+ "position": "Analista Programador Senior y Líder Tecnológico",
+ "period": "2019 - Presente",
+ "location": "O Milladoiro, Galicia, España / Remoto",
+ "description": "Evolución desde programador junior hasta líder tecnológico. Responsable de análisis, desarrollo y liderazgo técnico.",
+ "technologies": [
+ "Java 8",
+ "Java 11",
+ "Spring Boot",
+ "Spring Framework",
+ "Spring Security",
+ "Spring Cloud",
+ "Docker",
+ "Jenkins",
+ "Keycloak",
+ "Vue.js",
+ "Oracle DB",
+ "MariaDB",
+ "SOAP",
+ "REST",
+ "WebLogic",
+ "Tomcat",
+ "SonarQube",
+ "JMS",
+ "Arquitectura Hexagonal"
+ ],
+ "achievements": [
+ "Liderazgo técnico en proyectos clave para la AMTEGA",
+ "Automatización de despliegues y calidad de código con Sonar y Jenkins"
+ ]
+ },
+ {
+ "id": "exp2",
+ "company": "Optare Solutions",
+ "position": "Programador Junior",
+ "period": "2018 - 2019",
+ "location": "Vigo, Galicia, España",
+ "description": "Inicio profesional con beca FEUGA y posterior incorporación como programador junior. Participación en proyectos Java, migración de versiones y tareas puntuales relacionadas con VoIP y AWS.",
+ "technologies": [
+ "Java",
+ "Java 8",
+ "Java 11",
+ "Angular",
+ "VoIP",
+ "AWS"
+ ],
+ "achievements": [
+ "Migración de aplicaciones de Java 8 a Java 11",
+ "Colaboración en desarrollo frontend con Angular",
+ "Participación en entornos productivos de telecomunicaciones"
+ ]
+ },
+ {
+ "id": "exp3",
+ "company": "Kidcode",
+ "position": "Tutor de programación didáctica",
+ "period": "2017 - 2018",
+ "location": "Galicia, España",
+ "description": "Tutor de tiempo libre para iniciación a la programación en niños de entre 5 y 12 años. Uso de herramientas educativas como Arduino, Raspberry Pi, Lego y entornos low-code.",
+ "technologies": [
+ "Arduino",
+ "Raspberry Pi",
+ "Lego",
+ "Low-code"
+ ],
+ "achievements": [
+ "Diseño de actividades didácticas adaptadas por edades",
+ "Fomento del pensamiento computacional en edades tempranas",
+ "Introducción práctica a la robótica educativa"
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/infrastructure/mock/profile.json b/src/infrastructure/mock/profile.json
new file mode 100644
index 0000000..3b3fee4
--- /dev/null
+++ b/src/infrastructure/mock/profile.json
@@ -0,0 +1,23 @@
+{
+ "content": {
+ "id": -1,
+ "name": "Pablo de la Torre",
+ "title": "Softaware Developer",
+ "subtitle": "Especializado en Java",
+ "email": "contact@pablotj.com",
+ "phone": "",
+ "location": "Pontevedra, Galicia, España",
+ "avatar": "assets/avatar-bot.png",
+ "bio": "Desarrollador de software con más de 7 años de experiencia. Apasionado por crear sistemas sólidos, automatizar tareas y trabajar con contenedores. Recientemente, he empezado a explorar modelos LLM locales como parte de mis intereses técnicos.",
+ "social": [
+ {
+ "url": "https://github.com/pablotj",
+ "platform": "github"
+ },
+ {
+ "url": "https://linkedin.com/in/pablotj",
+ "platform": "linkedin"
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/src/infrastructure/mock/project.json b/src/infrastructure/mock/project.json
new file mode 100644
index 0000000..e785fb6
--- /dev/null
+++ b/src/infrastructure/mock/project.json
@@ -0,0 +1,78 @@
+{
+ "content": [
+ {
+ "id": "proj1",
+ "title": "E-commerce Platform",
+ "description": "Plataforma completa de comercio electrónico con más de 50,000 usuarios activos mensuales",
+ "image": "/placeholder.svg?height=300&width=400",
+ "technologies": [
+ "Vue.js",
+ "Node.js",
+ "PostgreSQL",
+ "Redis",
+ "Stripe"
+ ],
+ "features": [
+ "Integración con múltiples pasarelas de pago",
+ "Panel de administración con analytics",
+ "Sistema de inventario en tiempo real"
+ ],
+ "metrics": {
+ "users": "50,000+",
+ "uptime": "99.9%",
+ "loadTime": "2s"
+ },
+ "demo": "https://demo-ecommerce.com",
+ "repository": "https://github.com/pablo/ecommerce"
+ },
+ {
+ "id": "proj2",
+ "title": "Real-time Analytics Dashboard",
+ "description": "Dashboard empresarial con visualizaciones interactivas y procesamiento de más de 1M eventos/día",
+ "image": "/placeholder.svg?height=300&width=400",
+ "technologies": [
+ "React",
+ "D3.js",
+ "Socket.io",
+ "InfluxDB",
+ "Node.js"
+ ],
+ "features": [
+ "Visualizaciones en tiempo real",
+ "Exportación de reportes automatizada",
+ "Alertas personalizables"
+ ],
+ "metrics": {
+ "events": "1M+/día",
+ "reduction": "70% tiempo análisis",
+ "users": "500+"
+ },
+ "demo": "https://analytics-demo.com",
+ "repository": "https://github.com/pablo/analytics"
+ },
+ {
+ "id": "proj3",
+ "title": "Microservices Architecture",
+ "description": "Migración de monolito a arquitectura de microservicios con 12 servicios distribuidos",
+ "image": "/placeholder.svg?height=300&width=400",
+ "technologies": [
+ "Node.js",
+ "Docker",
+ "Kubernetes",
+ "AWS EKS",
+ "MongoDB"
+ ],
+ "features": [
+ "Event Sourcing y CQRS",
+ "Monitoreo con Prometheus",
+ "Auto-scaling automático"
+ ],
+ "metrics": {
+ "services": "12",
+ "latencyReduction": "60%",
+ "availability": "99.95%"
+ },
+ "repository": "https://github.com/pablo/microservices"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/infrastructure/mock/skill.json b/src/infrastructure/mock/skill.json
new file mode 100644
index 0000000..16b5eab
--- /dev/null
+++ b/src/infrastructure/mock/skill.json
@@ -0,0 +1,201 @@
+{
+ "content": [
+ {
+ "name": "Backend",
+ "icon": "Server",
+ "skills": [
+ {
+ "name": "Java",
+ "level": 95,
+ "years": 7
+ },
+ {
+ "name": "Spring Boot",
+ "level": 90,
+ "years": 6
+ },
+ {
+ "name": "Spring Framework",
+ "level": 85,
+ "years": 6
+ },
+ {
+ "name": "Spring Security",
+ "level": 80,
+ "years": 5
+ },
+ {
+ "name": "Spring Cloud",
+ "level": 75,
+ "years": 3
+ },
+ {
+ "name": "Node.js",
+ "level": 40,
+ "years": 1
+ },
+ {
+ "name": "Python",
+ "level": 30,
+ "years": 1
+ },
+ {
+ "name": "JUnit",
+ "level": 80,
+ "years": 5
+ },
+ {
+ "name": "Mockito",
+ "level": 75,
+ "years": 4
+ }
+ ]
+ },
+ {
+ "name": "DevOps",
+ "icon": "Server",
+ "skills": [
+ {
+ "name": "Docker",
+ "level": 90,
+ "years": 5
+ },
+ {
+ "name": "Jenkins",
+ "level": 85,
+ "years": 4
+ },
+ {
+ "name": "Keycloak",
+ "level": 80,
+ "years": 3
+ },
+ {
+ "name": "CI/CD",
+ "level": 85,
+ "years": 4
+ },
+ {
+ "name": "SonarQube",
+ "level": 75,
+ "years": 3
+ },
+ {
+ "name": "Linux",
+ "level": 85,
+ "years": 6
+ },
+ {
+ "name": "Git",
+ "level": 90,
+ "years": 6
+ },
+ {
+ "name": "SVN",
+ "level": 60,
+ "years": 4
+ },
+ {
+ "name": "Kubernetes",
+ "level": 40,
+ "years": 1
+ }
+ ]
+ },
+ {
+ "name": "Base de Datos",
+ "icon": "Server",
+ "skills": [
+ {
+ "name": "Oracle",
+ "level": 85,
+ "years": 5
+ },
+ {
+ "name": "MariaDB",
+ "level": 80,
+ "years": 4
+ },
+ {
+ "name": "JMS",
+ "level": 75,
+ "years": 3
+ }
+ ]
+ },
+ {
+ "name": "Frontend",
+ "icon": "Server",
+ "skills": [
+ {
+ "name": "Angular",
+ "level": 85,
+ "years": 5
+ },
+ {
+ "name": "Bootstrap",
+ "level": 75,
+ "years": 4
+ },
+ {
+ "name": "TypeScript",
+ "level": 70,
+ "years": 3
+ },
+ {
+ "name": "Vue.js",
+ "level": 40,
+ "years": 1
+ }
+ ]
+ },
+ {
+ "name": "Methodologies",
+ "icon": "Server",
+ "skills": [
+ {
+ "name": "Agile",
+ "level": 85,
+ "years": 5
+ },
+ {
+ "name": "Scrum",
+ "level": 80,
+ "years": 4
+ },
+ {
+ "name": "Kanban",
+ "level": 70,
+ "years": 3
+ }
+ ]
+ },
+ {
+ "name": "Monitoring",
+ "icon": "Server",
+ "skills": [
+ {
+ "name": "Prometheus",
+ "level": 30,
+ "years": 1
+ },
+ {
+ "name": "Grafana",
+ "level": 30,
+ "years": 1
+ }
+ ]
+ },
+ {
+ "name": "Languages",
+ "icon": "Server",
+ "skills": [
+ {
+ "name": "Inglés",
+ "level": 80,
+ "years": 7
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/infrastructure/repositories/ChatRepository.js b/src/infrastructure/repositories/ChatRepository.ts
similarity index 100%
rename from src/infrastructure/repositories/ChatRepository.js
rename to src/infrastructure/repositories/ChatRepository.ts
diff --git a/src/infrastructure/repositories/PortfolioRepository.js b/src/infrastructure/repositories/PortfolioRepository.js
deleted file mode 100644
index bf82bd6..0000000
--- a/src/infrastructure/repositories/PortfolioRepository.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import portfolioConfig from "@/data/portfolio-config.json"
-
-export class PortfolioRepository {
- async getPortfolioData() {
- // Simulate API call delay
- await new Promise((resolve) => setTimeout(resolve, 100))
-
- return portfolioConfig
- }
-
- async getPersonalInfo() {
- const data = await this.getPortfolioData()
- return data.personal
- }
-
- async getExperience() {
- const data = await this.getPortfolioData()
- return data.experience
- }
-
- async getProjects() {
- const data = await this.getPortfolioData()
- return data.projects
- }
-
- async getSkills() {
- const data = await this.getPortfolioData()
- return data.skills
- }
-
- async getEducation() {
- const data = await this.getPortfolioData()
- return data.education
- }
-
- async getCertifications() {
- const data = await this.getPortfolioData()
- return data.certifications
- }
-}
diff --git a/src/main.js b/src/main.ts
similarity index 52%
rename from src/main.js
rename to src/main.ts
index ccd6235..f2cc79e 100644
--- a/src/main.js
+++ b/src/main.ts
@@ -1,8 +1,11 @@
-import { createApp } from "vue"
-import App from "./App.vue"
+import {createApp} from "vue"
import "./style.css"
+import VueTyper from 'vue3-typer'
+import "vue3-typer/dist/vue-typer.css"
+import App from "./App.vue";
const app = createApp(App)
+app.component('VueTyper', VueTyper)
// Global error handler
app.config.errorHandler = (err, vm, info) => {
diff --git a/src/services/ChatService.js b/src/services/ChatService.ts
similarity index 94%
rename from src/services/ChatService.js
rename to src/services/ChatService.ts
index e2e189a..ab13242 100644
--- a/src/services/ChatService.js
+++ b/src/services/ChatService.ts
@@ -1,5 +1,5 @@
-import { ref } from "vue"
-import { ChatRepository } from "@/infrastructure/repositories/ChatRepository"
+import {ref} from "vue"
+import {ChatRepository} from "@/infrastructure/repositories/ChatRepository"
export function useChatService(chatConfig) {
const messages = ref([])
diff --git a/src/shims-vue.d.ts b/src/shims-vue.d.ts
new file mode 100644
index 0000000..4c0772e
--- /dev/null
+++ b/src/shims-vue.d.ts
@@ -0,0 +1,18 @@
+declare module '*.vue' {
+ import type {DefineComponent} from 'vue'
+ const component: DefineComponent<{}, {}, any>
+ export default component
+}
+
+declare module '*.json' {
+ const value: any
+ export default value
+}
+
+declare module '*.css' {
+ const content: Record
+ export default content
+}
+declare module '*.png'
+declare module '*.jpg'
+declare module '*.svg'
\ No newline at end of file
diff --git a/src/style.css b/src/style.css
index 3312515..cba1844 100644
--- a/src/style.css
+++ b/src/style.css
@@ -2,6 +2,12 @@
@tailwind components;
@tailwind utilities;
+@layer utilities {
+ .border-border {
+ border-color: hsl(var("#4c1d95"));
+ }
+}
+
@layer base {
html {
scroll-behavior: smooth;
@@ -53,7 +59,7 @@
::-webkit-scrollbar-thumb {
/*background: rgba(147, 51, 234, 0.5);*/
- background: rgba(59, 130, 246, 0.5); /* Blue-500 */
+ background: rgb(9, 26, 40); /* Blue-500 */
border-radius: 3px;
}
diff --git a/tailwind.config.js b/tailwind.config.js
index 198de87..cbed1fa 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -7,79 +7,86 @@ module.exports = {
theme: {
extend: {
colors: {
- border: "hsl(var(--border))",
- input: "hsl(var(--input))",
- ring: "hsl(var(--ring))",
- background: "hsl(var(--background))",
- foreground: "hsl(var(--foreground))",
+ background: "#0f0f1f", // fondo oscuro elegante
+ foreground: "#f8f8f2",
primary: {
- DEFAULT: "hsl(var(--primary))",
- foreground: "hsl(var(--primary-foreground))",
- 50: "#f0f9ff",
- 100: "#e0f2fe",
- 200: "#bae6fd",
- 300: "#7dd3fc",
- 400: "#38bdf8",
- 500: "#0ea5e9",
- 600: "#0284c7",
- 700: "#0369a1",
- 800: "#075985",
- 900: "#0c4a6e",
+ DEFAULT: "#8b5cf6", // violeta principal
+ 50: "#f3ebff",
+ 100: "#e0d7ff",
+ 200: "#c0aaff",
+ 300: "#a078ff",
+ 400: "#8b5cf6",
+ 500: "#7c3aed",
+ 600: "#6d28d9",
+ 700: "#5b21b6",
+ 800: "#4c1d95",
+ 900: "#3b1070",
+ foreground: "#ffffff",
},
secondary: {
- DEFAULT: "hsl(var(--secondary))",
- foreground: "hsl(var(--secondary-foreground))",
- },
- destructive: {
- DEFAULT: "hsl(var(--destructive))",
- foreground: "hsl(var(--destructive-foreground))",
- },
- muted: {
- DEFAULT: "hsl(var(--muted))",
- foreground: "hsl(var(--muted-foreground))",
+ DEFAULT: "#c084fc", // púrpura suave para CTA
+ foreground: "#ffffff",
},
accent: {
- DEFAULT: "hsl(var(--accent))",
- foreground: "hsl(var(--accent-foreground))",
+ DEFAULT: "#d8b4fe", // acento claro violeta
+ foreground: "#1f1f2e",
},
- popover: {
- DEFAULT: "hsl(var(--popover))",
- foreground: "hsl(var(--popover-foreground))",
+ muted: {
+ DEFAULT: "#a78bfa", // violeta pálido
+ foreground: "#f8f8f2",
},
card: {
- DEFAULT: "hsl(var(--card))",
- foreground: "hsl(var(--card-foreground))",
+ DEFAULT: "#1e1b2f", // card dark purple
+ foreground: "#f8f8f2",
},
- purple: {
- 400: "#475569", // slate-600
- 500: "#334155", // slate-700
- 600: "#1e293b", // slate-800
- },
- pink: {
- 500: "#0ea5e9", // sky-500 (azul vibrante, pero no chillón)
- 600: "#0284c7", // sky-600
+ popover: {
+ DEFAULT: "#2c2345",
+ foreground: "#f8f8f2",
},
+ success: "#7dd3fc",
+ warning: "#facc15",
+ error: "#f87171",
+ },
+ fontFamily: {
+ sans: ["Inter", ...fontFamily.sans],
+ mono: ["Fira Code", ...fontFamily.mono],
},
animation: {
"bounce-slow": "bounce 2s infinite",
"pulse-slow": "pulse 3s infinite",
- "fade-in": "fadeIn 0.5s ease-in-out",
+ "fade-in": "fadeIn 0.6s ease-in-out",
+ "float": "float 4s ease-in-out infinite",
+ "wiggle": "wiggle 0.8s ease-in-out infinite",
},
keyframes: {
fadeIn: {
"0%": { opacity: "0", transform: "translateY(10px)" },
"100%": { opacity: "1", transform: "translateY(0)" },
},
- },
- fontFamily: {
- sans: ["Inter", ...fontFamily.sans],
+ float: {
+ "0%, 100%": {transform: "translateY(0)"},
+ "50%": {transform: "translateY(-10px)"},
+ },
+ wiggle: {
+ "0%, 100%": {transform: "rotate(-3deg)"},
+ "50%": {transform: "rotate(3deg)"},
+ },
},
borderRadius: {
- lg: "var(--radius)",
- md: "calc(var(--radius) - 2px)",
- sm: "calc(var(--radius) - 4px)",
+ lg: "1rem",
+ md: "0.75rem",
+ sm: "0.5rem",
+ },
+ boxShadow: {
+ "card-light": "0 8px 16px rgba(139,92,246,0.2)",
+ "card-dark": "0 8px 20px rgba(0,0,0,0.5)",
+ glow: "0 0 20px rgba(139,92,246,0.6)",
+ },
+ transitionProperty: {
+ height: "height",
+ spacing: "margin, padding",
},
},
},
plugins: [],
-};
+};
\ No newline at end of file
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..8643230
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,29 @@
+{
+ "compilerOptions": {
+ "target": "ESNext",
+ "module": "ESNext",
+ "moduleResolution": "Node",
+ "lib": [
+ "ESNext",
+ "DOM"
+ ],
+ "types": [
+ "vite/client"
+ ],
+ "resolveJsonModule": true,
+ "esModuleInterop": true,
+ "strict": true,
+ "skipLibCheck": true,
+ "baseUrl": ".",
+ "paths": {
+ "@/*": [
+ "src/*"
+ ]
+ }
+ },
+ "include": [
+ "src/**/*.ts",
+ "src/**/*.d.ts",
+ "src/**/*.vue"
+ ]
+}
\ No newline at end of file
diff --git a/vite.config.js b/vite.config.js
index bd27c78..99df6b6 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -1,10 +1,10 @@
-import { defineConfig } from "vite"
+import {defineConfig} from "vite"
import vue from "@vitejs/plugin-vue"
-import { resolve } from "path"
+import {resolve} from "path"
export default defineConfig({
plugins: [vue()],
- base: process.env.NODE_ENV === "production" ? "/ai-portfolio-chat/" : "/",
+ base: process.env.NODE_ENV === "production" ? "/" : "/",
resolve: {
alias: {
"@": resolve(__dirname, "src"),
@@ -26,5 +26,13 @@ export default defineConfig({
server: {
port: 3000,
open: true,
+ proxy: {
+ '/api': {
+ target: 'http://localhost:8080',
+ changeOrigin: true,
+ secure: false,
+ //rewrite: path => path.replace(/^\/api/, '')
+ }
+ }
},
})