Logo
Back
Personal Portfolio repository on GitHub

Personal Portfolio

A full-stack portfolio built with Next.js, DDD, and Clean Architecture in a Turborepo monorepo.

  • TypeScript
  • React
  • Next.js
  • Node.js
  • PostgreSQL
  • Docker
  • Tailwind CSS
Period
2024

Most developer portfolios are static pages with hardcoded text and a list of GitHub links. I wanted to build something that reflects how I actually work — with proper architecture, tests, and a real content management workflow.

This portfolio is a production-grade full-stack monorepo built with Next.js 16 App Router, TypeScript, Prisma, and Supabase. The architecture follows Domain-Driven Design and Clean Architecture principles across five packages: core, application, infra, ui, and utils. The frontend site and the admin app are isolated Next.js applications that communicate exclusively through a versioned REST API — no cross-boundary imports.

Monorepo package structure showing five layers: core, application, infra, ui, and utils


Architecture decisions

The strictest constraint I enforced was the dependency rule: core has zero framework dependencies (no React, no Prisma, no Next.js). application depends only on core and defines port interfaces. infra implements those ports. The site and admin consume only the REST API. This boundary is enforced by custom ESLint rules that fail the build if violated.

Domain errors follow the Either pattern — no exceptions are thrown for business rule violations. Every use case returns Either<DomainError, T>, and the HTTP layer maps lefts to structured error responses with consistent { code, message } payloads.

// Use case result — no throws, no surprises
const result = await getProjectBySlug.execute({ slug });
if (result.isLeft()) return apiError(result.value);
return apiSuccess(result.value);

Authentication

Auth is handled via Supabase Auth with JWT tokens stored in httpOnly cookies. The site's middleware validates the session on every protected request, and the admin app has a dedicated proxy auth layer that re-validates tokens server-side before rendering any admin page.

Admin panel login screen with email and password fields on a dark background


Testing strategy

The test suite runs across all five packages with Vitest. Domain logic is covered by pure unit tests — no mocks, just value objects and entities in isolation. Use cases are tested against in-memory repositories and fake gateways that implement the same port interfaces as the real infra. The site package has component tests with Testing Library and integration tests for API route handlers.

LayerStrategyTools
corePure unit testsVitest
applicationIn-memory repos + fake gatewaysVitest
infraIntegration tests against real DBVitest + Prisma
siteComponent + API route testsVitest + Testing Library

Internationalization

Content is available in English and Portuguese using next-intl. The language preference persists via a locale segment in the URL (/en-US/..., /pt-BR/...), and the middleware negotiates the default locale from the Accept-Language header on first visit.

Side-by-side view of the portfolio in English and Portuguese showing the language switcher


Infrastructure

The monorepo is managed by Turborepo with remote caching. CI runs lint, typecheck, and all tests on every pull request. The database is a Supabase PostgreSQL instance with Prisma migrations applied per environment through a separate migration script that runs before deployment.

Other projects

  • B2B e-commerce platform for construction materials

    B2B E-Commerce Platform

    Full-stack B2B platform for construction materials built with DDD, Clean Architecture, NestJS, and React.

    • TypeScript
    • React
    • Node.js
    View Project