# Saúl Morales Pacheco - Portfolio Website

Portfolio personal y sitio web de Saúl Morales Pacheco, Full Stack Developer especializado en desarrollo backend con PHP/Symfony y frontend moderno.

![Symfony](https://img.shields.io/badge/Symfony-8.0.5-black.svg?style=flat-square&logo=symfony)
![PHP](https://img.shields.io/badge/PHP-8.4.18-777BB4.svg?style=flat-square&logo=php)
![License](https://img.shields.io/badge/License-Proprietary-red.svg?style=flat-square)

## 🚀 Características

- ✅ **Symfony 8.0.5** - Framework PHP moderno
- ✅ **PHP 8.4** - Últimas características del lenguaje
- ✅ **Multilenguaje** - Español/Inglés con Symfony Translation
- ✅ **Formulario de contacto** con validación y reCAPTCHA
- ✅ **Integración con WhatsApp Cloud API** - Automatización de mensajes
- ✅ **Blog** - Integración con WordPress REST API
- ✅ **Sistema de donaciones** - Procesamiento de contribuciones
- ✅ **Tests unitarios** - PHPUnit 9.6
- ✅ **Sin base de datos** - Arquitectura stateless
- ✅ **Webpack Encore** - Bundling de assets frontend

## 📋 Requisitos

- **PHP**: 8.4 o superior
- **Composer**: 2.x
- **Node.js**: 18+ (para compilar assets)
- **NPM/Yarn**: Para gestión de dependencias frontend

### Extensiones PHP requeridas

```bash
ext-ctype
ext-iconv
ext-json
ext-mbstring
ext-xml
```

## 🔧 Instalación

### 1. Clonar el repositorio

```bash
git clone <repository-url> saulmoralespa.com
cd saulmoralespa.com
```

### 2. Instalar dependencias PHP

```bash
composer install
```

### 3. Instalar dependencias frontend

```bash
npm install
# o
yarn install
```

### 4. Configurar variables de entorno

```bash
cp .env .env.local
```

Edita `.env.local` con tus valores:

```env
###> symfony/framework-bundle ###
APP_ENV=dev
APP_SECRET=your-secret-key-here
###< symfony/framework-bundle ###

###> symfony/mailer ###
MAILER_DSN=smtp://user:pass@smtp.example.com:587
SEND_TO_EMAIL=your-email@example.com
###< symfony/mailer ###

###> Google reCAPTCHA ###
RECAPTCHA_SECRET_KEY=your-recaptcha-secret-key
###< Google reCAPTCHA ###

###> Google Drive CV ###
FILE_ID_CV_DRIVE_GOOGLE=your-google-drive-file-id
###< Google Drive CV ###

###> Zoho CRM ###
USER_ZOHO_WEBHOOK=username
PASSWORD_ZOHO_WEBHOOK=password
###< Zoho CRM ###

###> WhatsApp Cloud API ###
TOKEN_WEBHOOK_WHATSAPP=your-token
ACCESS_TOKEN_WHATSAPP=your-access-token
FROM_PHONE_NUMBER_WHATSAPP_ID=your-phone-id
FLOW_TOKEN=your-flow-token
FLOW_ID=your-flow-id
###< WhatsApp Cloud API ###

###> WordPress Blog ###
SITE_WP_POSTS=https://blog.saulmoralespa.com
###< WordPress Blog ###
```

### 5. Compilar assets frontend

```bash
# Desarrollo (con watch)
npm run watch

# Producción
npm run build
```

### 6. Iniciar servidor de desarrollo

```bash
# Opción 1: Symfony CLI (recomendado)
symfony server:start

# Opción 2: PHP built-in server
php -S localhost:8000 -t public/

# Opción 3: Apache/Nginx
# Configurar document root a /public
```

Accede a: `http://localhost:8000`

## 📁 Estructura del Proyecto

```
saulmoralespa.com/
├── assets/                 # Assets frontend
│   ├── js/                # JavaScript modules
│   │   ├── app.js        # Entry point
│   │   ├── contact.js    # Formulario de contacto
│   │   ├── cursor.js     # Custom cursor
│   │   ├── nav.js        # Navegación
│   │   └── reveal.js     # Scroll animations
│   └── styles/           # CSS modules
│       ├── app.css       # Main stylesheet
│       ├── _tokens.css   # Design tokens
│       ├── _nav.css      # Navegación
│       ├── _hero.css     # Hero section
│       ├── _about.css    # About section
│       ├── _skills.css   # Skills section
│       └── ...
├── bin/                   # Binarios ejecutables
│   └── console           # Symfony console
├── config/                # Configuración
│   ├── packages/         # Configuración por bundle
│   ├── routes/           # Rutas HTTP
│   └── services.yaml     # Definición de servicios
├── public/                # Directorio público (web root)
│   ├── index.php         # Front controller
│   ├── build/            # Assets compilados (generado)
│   ├── css/              # CSS legacy
│   ├── js/               # JS legacy
│   └── img/              # Imágenes
├── src/
│   ├── Controller/       # Controladores HTTP
│   │   ├── PageController.php
│   │   ├── DonationController.php
│   │   └── UnsubscribeController.php
│   ├── Form/             # Form Types
│   │   └── ContactType.php
│   ├── Service/          # Servicios de negocio
│   └── Kernel.php        # Kernel de la aplicación
├── templates/             # Plantillas Twig
│   ├── base.html.twig    # Layout base
│   ├── home/             # Página principal
│   ├── donation/         # Sistema de donaciones
│   ├── unsubscribe/      # Desuscripción
│   └── partials/         # Componentes reutilizables
│       ├── _nav.html.twig
│       ├── _hero.html.twig
│       ├── _about.html.twig
│       ├── _skills.html.twig
│       ├── _experience.html.twig
│       ├── _portfolio.html.twig
│       ├── _testimonials.html.twig
│       ├── _contact.html.twig
│       └── _footer.html.twig
├── tests/                 # Tests PHPUnit
│   └── Controller/
│       └── PageControllerTest.php
├── translations/          # i18n
│   ├── messages.es.yaml  # Español
│   └── messages.en.yaml  # Inglés
├── var/                   # Cache y logs (generado)
│   ├── cache/
│   └── log/
├── vendor/                # Dependencias PHP (generado)
├── node_modules/          # Dependencias Node (generado)
├── composer.json          # Dependencias PHP
├── package.json           # Dependencias Node
├── webpack.config.js      # Configuración Webpack Encore
└── phpunit.xml.dist       # Configuración PHPUnit
```

## 🎯 Rutas de la Aplicación

| Ruta | Método | Descripción |
|------|--------|-------------|
| `/` | GET | Página principal con todas las secciones |
| `/new_message` | POST | Procesa formulario de contacto (AJAX) |
| `/test-encore` | GET | Página de prueba Webpack Encore |
| `/unsubscribe/{campaign}/{email}` | GET | Desuscripción de newsletter |
| `/webhookzoho` | POST | Webhook Zoho CRM (requiere auth) |
| `/webhookwhatsapp` | GET\|POST | Webhook WhatsApp Cloud API |
| `/donation` | GET | Página de donaciones |
| `/donation/confirmation` | POST | Confirmación de donación |

## 🧪 Testing

### Ejecutar tests

```bash
# Todos los tests
php bin/phpunit

# Test específico
php bin/phpunit tests/Controller/PageControllerTest.php

# Con cobertura (requiere xdebug)
php bin/phpunit --coverage-html var/coverage
```

### Tests disponibles

- ✅ `PageControllerTest` - Tests del controlador principal
  - Homepage rendering
  - Cambio de idioma
  - Formulario de contacto (validaciones, CSRF, éxito/error)
  - Integración con blog WordPress

## 🌍 Multilenguaje

El sitio soporta español e inglés usando Symfony Translation:

```twig
{# En plantillas Twig #}
{{ 'hero.greeting'|trans }}
{{ 'nav.home'|trans }}
```

### Cambiar idioma

```javascript
// Via URL parameter
?_locale=en
?_locale=es

// Via cookie (implementado en nav.js)
localStorage.setItem('locale', 'en');
```

### Archivos de traducción

- `translations/messages.es.yaml` - Textos en español
- `translations/messages.en.yaml` - Textos en inglés

## 📦 Dependencias Principales

### Backend (PHP)

```json
{
  "symfony/framework-bundle": "8.0.*",
  "symfony/form": "8.0.*",
  "symfony/mailer": "8.0.*",
  "symfony/security-bundle": "8.0.*",
  "symfony/validator": "8.0.*",
  "symfony/twig-bundle": "8.0.*",
  "symfony/translation": "8.0.*",
  "symfony/webpack-encore-bundle": "^2.2",
  "twig/twig": "^3.18",
  "netflie/whatsapp-cloud-api": "^2.1"
}
```

### Frontend (Node)

```json
{
  "@babel/core": "^7.24",
  "@babel/preset-env": "^7.24",
  "webpack": "^5.90",
  "@symfony/webpack-encore": "^5.0",
  "core-js": "^3.36",
  "regenerator-runtime": "^0.14"
}
```

## 🚀 Despliegue a Producción

### 1. Preparar assets

```bash
npm run build
```

### 2. Instalar dependencias de producción

```bash
composer install --no-dev --optimize-autoloader
```

### 3. Configurar variables de entorno

```bash
APP_ENV=prod
APP_DEBUG=0
APP_SECRET=<genera-un-secret-seguro>
```

### 4. Optimizar cache

```bash
APP_ENV=prod php bin/console cache:clear
APP_ENV=prod php bin/console cache:warmup
```

### 5. Configurar servidor web

#### Apache (.htaccess en public/)

Ya incluido en el proyecto.

#### Nginx

```nginx
server {
    server_name saulmoralespa.com;
    root /path/to/project/public;

    location / {
        try_files $uri /index.php$is_args$args;
    }

    location ~ ^/index\.php(/|$) {
        fastcgi_pass unix:/var/run/php/php8.4-fpm.sock;
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        fastcgi_param DOCUMENT_ROOT $realpath_root;
        internal;
    }

    location ~ \.php$ {
        return 404;
    }
}
```

### 6. Permisos

```bash
chmod -R 755 .
chmod -R 777 var/
```

## 🔒 Seguridad

### Protecciones implementadas

- ✅ **CSRF Protection** - Tokens en formularios
- ✅ **reCAPTCHA v3** - Protección anti-spam
- ✅ **Input Validation** - Symfony Validator
- ✅ **HTML Sanitization** - Regex patterns
- ✅ **HTTP Basic Auth** - Webhook de Zoho
- ✅ **Rate Limiting** - (considerar implementar)

### Auditoría de seguridad

```bash
composer audit
```

## 🛠️ Comandos Útiles

### Symfony Console

```bash
# Información del sistema
php bin/console about

# Listar rutas
php bin/console debug:router

# Listar servicios
php bin/console debug:container

# Verificar variables de entorno
php bin/console debug:container --env-vars

# Limpiar caché
php bin/console cache:clear
```

### Webpack Encore

```bash
# Compilar assets (desarrollo)
npm run dev

# Compilar y watch
npm run watch

# Compilar para producción
npm run build
```

### Composer

```bash
# Instalar dependencias
composer install

# Actualizar dependencias
composer update

# Verificar vulnerabilidades
composer audit

# Autoload optimizado
composer dump-autoload --optimize
```

## 🐛 Troubleshooting

### Error 404 en todas las rutas

**Problema**: Web Profiler capturando rutas

**Solución**: Verifica que `config/routes/web_profiler.yaml` tenga el prefijo correcto:

```yaml
when@dev:
    web_profiler_wdt:
        resource: '@WebProfilerBundle/Resources/config/routing/wdt.php'
        prefix: /_wdt  # <-- Este prefijo es importante
```

### Formulario de contacto no funciona

**Problema**: Error 404 al enviar formulario

**Solución**: Verifica que la ruta `/new_message` acepte POST:

```php
#[Route('/new_message', name: 'new_message', methods: ['POST'])]
```

### Assets no se cargan

**Problema**: Archivos 404 en `/build/`

**Solución**: Compila los assets:

```bash
npm run build
```

### reCAPTCHA errors

**Problema**: "Invalid site key"

**Solución**: 
1. Verifica que las claves en `.env` coincidan con Google reCAPTCHA Console
2. Verifica que el dominio esté autorizado
3. Limpia caché del navegador

## 📚 Documentación

- [Symfony 8.0](https://symfony.com/doc/8.0/index.html)
- [Twig 3.x](https://twig.symfony.com/doc/3.x/)
- [Webpack Encore](https://symfony.com/doc/current/frontend.html)
- [PHPUnit](https://phpunit.de/documentation.html)

## 👨‍💻 Autor

**Saúl Morales Pacheco**

- 🌐 Website: [saulmoralespa.com](https://saulmoralespa.com)
- 📧 Email: info@saulmoralespa.com
- 📝 Blog: [blog.saulmoralespa.com](https://blog.saulmoralespa.com)
- 🕐 Timezone: America/Bogota

## 📄 Licencia

Copyright © 2026 Saúl Morales Pacheco. Todos los derechos reservados.

---

**Última actualización**: Febrero 2026  
**Versión**: 1.0.0  
**Symfony**: 8.0.5  
**PHP**: 8.4.18

## 💳 ePayco Smart Checkout v2 Integration

This project integrates ePayco Smart Checkout v2 for handling donations securely.

### Features

- ✅ Smart Checkout v2 with session-based authentication
- ✅ Support for COP (Colombian Peso) and USD (US Dollar)
- ✅ Multi-language support (Spanish/English)
- ✅ URL parameters for pre-filled amounts
- ✅ Auto-submit functionality
- ✅ Comprehensive test coverage (22 tests)
- ✅ TDD implementation

### Usage Examples

#### Basic donation page:
```
/donation
/es/donation
/en/donation
```

#### With pre-filled parameters:
```
/donation/currency/USD/amount/50
/es/donation/currency/COP/amount/30000
/en/donation/currency/USD/amount/100
```

### Configuration

Set your ePayco credentials in `.env`:

```env
EPAYCO_PUBLIC_KEY="your_public_key"
EPAYCO_PRIVATE_KEY="your_private_key"
EPAYCO_TEST_MODE=false
```

### Architecture

```
Frontend (donation.js)
    ↓ POST /donation/create-session
Backend (DonationController)
    ↓ Call EpaycoService
EpaycoService
    ↓ POST /login (Basic Auth)
    ↓ POST /payment/session/create (Bearer Token)
Apify (ePayco API)
    ↓ Return sessionId
Frontend
    ↓ ePayco.checkout.configure({sessionId})
Smart Checkout v2 Modal
```

### Testing

Run the donation tests:

```bash
php bin/phpunit tests/Controller/DonationControllerTest.php
```

All 22 tests should pass:
- Page rendering tests
- API endpoint tests
- Validation tests
- Multi-language tests
- Auto-submit tests
