Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
be8f17d
fix: corregir workflow de Lighthouse CI para iniciar servidor correct…
DevFBI Dec 12, 2025
485768c
fix: corregir configuración de Vercel para monorepo y workflow CI
DevFBI Dec 12, 2025
ba1fd67
hip
DevFBI Dec 12, 2025
738fb57
fix: restaurar cd en vercel.json y agregar packageManager
GMNAPI Dec 12, 2025
a85bdc4
Root Directory en Vercel
GMNAPI Dec 12, 2025
3aee7e7
hop
GMNAPI Dec 12, 2025
8d10d15
hip
GMNAPI Dec 12, 2025
eaecc8f
hip
GMNAPI Dec 12, 2025
4997157
hop
GMNAPI Dec 12, 2025
d2d151e
hip
GMNAPI Dec 12, 2025
de72ce1
hop
GMNAPI Dec 12, 2025
be34e3e
hop
GMNAPI Dec 12, 2025
e6dcdf9
hop
GMNAPI Dec 12, 2025
31940e0
hop
GMNAPI Dec 12, 2025
5e7e0b1
hip
GMNAPI Dec 12, 2025
89c015c
hop
GMNAPI Dec 12, 2025
316eea6
hop
GMNAPI Dec 12, 2025
6b29ddf
hip
GMNAPI Dec 12, 2025
f3038e2
hop
GMNAPI Dec 12, 2025
3a85027
hop
GMNAPI Dec 12, 2025
36b4942
fix(vercel): update pnpm version and regenerate lockfile
GMNAPI Dec 12, 2025
a125d39
fix(vercel): downgrade to pnpm 8.15.9 for Vercel compatibility
GMNAPI Dec 12, 2025
4f4043d
fix(vercel): configure pnpm 8.15.9 and Node.js 18 for Vercel compatib…
GMNAPI Dec 12, 2025
713f674
fix(vercel): configure pnpm 8.15.6 and Node.js 18 for Vercel compatib…
GMNAPI Dec 12, 2025
c1afa9b
fix(vercel): update to pnpm 9.12.0 and Node.js 20 for ERR_INVALID_THI…
GMNAPI Dec 12, 2025
e5180fe
fix(vercel): update to pnpm 10.0.0 and Node.js 24 for ERR_INVALID_THI…
GMNAPI Dec 12, 2025
6be1708
hip
GMNAPI Dec 12, 2025
216c9fa
fix(vercel): downgrade to pnpm 9.12.0 to resolve ERR_INVALID_THIS
GMNAPI Dec 12, 2025
22c966a
fix(vercel): remove --frozen-lockfile to allow lockfile regeneration
GMNAPI Dec 12, 2025
fea03f7
fix(vercel): force pnpm 9.12.0 installation globally
GMNAPI Dec 12, 2025
e548901
fix(vercel): use corepack instead of npm to manage pnpm
GMNAPI Dec 12, 2025
f8cf307
fix(vercel): remove cd ../.. for root directory disabled
GMNAPI Dec 12, 2025
0cb41fe
fix(portfolio): configure vercel.json for monorepo with Root Directory
GMNAPI Dec 12, 2025
25b51d2
fix(vercel): add next as devDep in root for Vercel detection
GMNAPI Dec 12, 2025
da77e68
fix(vercel): simplify portfolio build command without frozen-lockfile
GMNAPI Dec 12, 2025
1831860
fix(vercel): downgrade to pnpm 8.15.9 to avoid ERR_INVALID_THIS bug
GMNAPI Dec 12, 2025
8d1f792
fix(lab): remove frozen-lockfile for pnpm 8.15.9 compatibility
GMNAPI Dec 12, 2025
9126eb2
hip
GMNAPI Dec 12, 2025
35442ce
chore: align pnpm lockfile for vercel
GMNAPI Dec 12, 2025
20c461b
feat(portfolio): add i18n CV download with locale detection
GMNAPI Dec 13, 2025
c4f3f9e
test(portfolio): add locale-specific CV download tests
GMNAPI Dec 13, 2025
e32ac0d
docs(portfolio): add .env.example for SMTP configuration
GMNAPI Dec 15, 2025
f50c22f
fix(portfolio): exclude API routes from i18n middleware matcher
GMNAPI Dec 15, 2025
895c34a
fix(portfolio): update vercel.json for monorepo build compatibility
GMNAPI Dec 15, 2025
cf46bf9
fix(portfolio): use pnpm 10.25.0 via corepack in Vercel build
GMNAPI Dec 15, 2025
5d56f23
fix(portfolio): simplify vercel.json without corepack
GMNAPI Dec 15, 2025
a79bdb2
fix(portfolio): move vercel.json to monorepo root for stable builds
GMNAPI Dec 15, 2025
9823715
fix(ci): remove coverage files and fix gitignore pattern
GMNAPI Dec 15, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 25 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,17 @@ jobs:

- name: Build for Lighthouse
run: pnpm --filter portfolio run build
env:
NEXT_PUBLIC_SITE_URL: https://angelhidalgo.dev

- name: Install wait-on
run: npm install -g wait-on

- name: Start production server
run: |
pnpm --filter portfolio run start &
echo $! > server.pid
wait-on http://localhost:3000 -t 60000

- name: Run Lighthouse CI
uses: treosh/lighthouse-ci-action@v10
Expand All @@ -182,6 +193,15 @@ jobs:
uploadArtifacts: true
temporaryPublicStorage: true

- name: Stop production server
if: always()
run: |
if [ -f server.pid ]; then
kill $(cat server.pid) || true
rm server.pid
fi
pkill -f "next start" || true

# Job 6: Security Audit
security:
name: Security Audit
Expand All @@ -194,16 +214,19 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 8
version: 9

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Run pnpm audit
run: pnpm audit --production
run: pnpm audit --production || echo "Audit failed, continuing..."
continue-on-error: true

# Job 7: Status Check Summary
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
.yarn/install-state.gz

# testing
/coverage
coverage/

# next.js
/.next/
Expand Down
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
24
2 changes: 1 addition & 1 deletion apps/lab/docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const config = {
favicon: 'img/favicon.ico',

url: 'https://desenvolupadormaster.vercel.app',
baseUrl: '/lab/',
baseUrl: '/',

organizationName: 'GMNAPI',
projectName: 'devportfolio-lab',
Expand Down
12 changes: 5 additions & 7 deletions apps/lab/vercel.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
{
"buildCommand": "cd ../.. && pnpm --filter lab build",
"installCommand": "cd ../.. && pnpm install --frozen-lockfile",
"framework": "docusaurus",
"env": {
"NODE_VERSION": "20"
}
}
"buildCommand": "cd ../.. && pnpm install && cd apps/lab && pnpm run build",
"installCommand": "cd ../.. && pnpm install",
"outputDirectory": "build",
"framework": "docusaurus"
}
20 changes: 20 additions & 0 deletions apps/portfolio/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# SMTP Configuration for Contact Form
# Required for the portfolio contact form to send emails
#
# Copy this file to .env.local and fill with your SMTP credentials
# For production, configure these as environment variables in Vercel

EMAIL_HOST=smtp.example.com
EMAIL_PORT=587
EMAIL_USER=your-email@example.com
EMAIL_PASSWORD=your-secure-password
EMAIL_FROM=noreply@example.com
EMAIL_TO=contact@example.com

# Notes:
# - EMAIL_HOST: SMTP server hostname
# - EMAIL_PORT: Usually 587 (STARTTLS) or 465 (SSL)
# - EMAIL_USER: SMTP authentication username
# - EMAIL_PASSWORD: SMTP authentication password
# - EMAIL_FROM: Sender email address
# - EMAIL_TO: Recipient email address (where form submissions are sent)
1 change: 1 addition & 0 deletions apps/portfolio/.nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
24
2 changes: 1 addition & 1 deletion apps/portfolio/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ import { routing } from './src/i18n/routing';
export default createMiddleware(routing);

export const config = {
matcher: ['/', '/(es|en)/:path*', '/((?!_next|_vercel|.*\\..*).*)'],
matcher: ['/', '/(es|en)/:path*', '/((?!api|_next|_vercel|.*\\..*).*)'],
};
Binary file added apps/portfolio/public/cvEn.pdf
Binary file not shown.
Binary file added apps/portfolio/public/cvEs.pdf
Binary file not shown.
6 changes: 4 additions & 2 deletions apps/portfolio/src/features/hero/Hero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
'use client';

import { m } from 'framer-motion';
import { useTranslations } from 'next-intl';
import { useTranslations, useLocale } from 'next-intl';

import { Button } from '@/shared/components/ui/Button';
import { personalInfo, availability } from '@/shared/constants/personal';
Expand All @@ -17,6 +17,7 @@ import { fadeInUp, fadeIn, staggerContainer } from '@/shared/utils/motion';
export function Hero() {
const tHero = useTranslations('hero');
const tPersonal = useTranslations('personal');
const locale = useLocale();

const scrollToProjects = () => {
const projectsSection = document.getElementById('projects');
Expand All @@ -33,7 +34,8 @@ export function Hero() {
};

const downloadCV = () => {
window.open(personalInfo.cvUrl, '_blank', 'noopener,noreferrer');
const cvFileName = locale === 'en' ? 'cvEn.pdf' : 'cvEs.pdf';
window.open(`/${cvFileName}`, '_blank', 'noopener,noreferrer');
};

const asciiLines = [
Expand Down
2 changes: 0 additions & 2 deletions apps/portfolio/src/shared/constants/personal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ export interface PersonalInfo {
full: string;
};
avatar: string;
cvUrl: string;
social: {
email: string;
linkedin: string;
Expand Down Expand Up @@ -53,7 +52,6 @@ export const personalInfo: PersonalInfo = {
},

avatar: '/images/avatar-placeholder.svg',
cvUrl: '/documents/cv-angel-hidalgo-barreiro.pdf',

social: {
email: 'angel@gestionominegocio.es',
Expand Down
34 changes: 32 additions & 2 deletions apps/portfolio/tests/features/hero/Hero.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import userEvent from '@testing-library/user-event';
import { NextIntlClientProvider } from 'next-intl';

import esMessages from '../../../messages/es.json';
import enMessages from '../../../messages/en.json';
import { Hero } from '@/features/hero/Hero';

function renderHero() {
function renderHero(locale = 'es') {
const messages = locale === 'en' ? enMessages : esMessages;
return render(
<NextIntlClientProvider locale="es" messages={esMessages}>
<NextIntlClientProvider locale={locale} messages={messages}>
<Hero />
</NextIntlClientProvider>
);
Expand Down Expand Up @@ -138,6 +140,34 @@ describe('Hero Section', () => {
windowOpenSpy.mockRestore();
});

it('should download Spanish CV when locale is es', async () => {
const user = userEvent.setup();
const windowOpenSpy = vi.spyOn(window, 'open').mockImplementation(() => null);

renderHero('es');

const cvButton = screen.getByRole('button', { name: /descargar cv/i });
await user.click(cvButton);

expect(windowOpenSpy).toHaveBeenCalledWith('/cvEs.pdf', '_blank', 'noopener,noreferrer');

windowOpenSpy.mockRestore();
});

it('should download English CV when locale is en', async () => {
const user = userEvent.setup();
const windowOpenSpy = vi.spyOn(window, 'open').mockImplementation(() => null);

renderHero('en');

const cvButton = screen.getByRole('button', { name: /download cv/i });
await user.click(cvButton);

expect(windowOpenSpy).toHaveBeenCalledWith('/cvEn.pdf', '_blank', 'noopener,noreferrer');

windowOpenSpy.mockRestore();
});

it('should handle missing projects section gracefully', async () => {
const user = userEvent.setup();

Expand Down
8 changes: 0 additions & 8 deletions apps/portfolio/vercel.json

This file was deleted.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
"name": "devportfolio-monorepo",
"version": "1.0.0",
"private": true,
"packageManager": "pnpm@10.25.0",
"engines": { "node": ">=24 <25" },
"workspaces": [
"apps/*",
"packages/*"
Expand All @@ -27,6 +29,7 @@
"format:check": "prettier --check \"**/*.{ts,tsx,js,jsx,json,css,md}\""
},
"devDependencies": {
"next": "15.0.5",
"prettier": "^3.6.2",
"turbo": "^1.11.3"
}
Expand Down
Loading
Loading