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.
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.
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.
| Layer | Strategy | Tools |
|---|---|---|
core | Pure unit tests | Vitest |
application | In-memory repos + fake gateways | Vitest |
infra | Integration tests against real DB | Vitest + Prisma |
site | Component + API route tests | Vitest + 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.
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
Full-stack B2B platform for construction materials built with DDD, Clean Architecture, NestJS, and React.
- TypeScript
- React
- Node.js