Complete platform for a construction company with a dedicated Node.js/Fastify API, client dashboard with project progress, magic link system built from scratch, and dynamic filters via searchParams.
DesignAgência Ade!
↗ View live project01
Overview
M3H Construtora is a construction company that needed a centralized platform for project tracking — serving both clients and administrators. The public site presents each development with progress information; the client area displays completion percentage, pending invoices, observations, and documents; the admin panel allows creating developments, issuing invoices, scheduling visits, and linking them to specific clients.
The platform was built with Next.js, React, and TypeScript on the front end, with a dedicated API in Node.js and Fastify on the back end. The database is PostgreSQL via Supabase, with Prisma as the ORM. Files and documents are stored in a Supabase bucket. The dashboard uses shadcn/ui, with forms validated by Zod and React Hook Form.
02
Challenge
Building and deploying a dedicated API from scratch — separate from the front end — was the first significant out-of-comfort-zone challenge. It required learning how to deploy Node.js APIs on Vercel, configure production and staging environments, and integrate with the Supabase bucket for storing images, invoices, and documents for clients and construction projects.
The forms for creating developments and clients were complex: multiple related fields, file uploads, and cross-validation between front end and back end using the same Zod schemas on both sides. Keeping the validation rules consistent across both layers without duplication required constant attention.
The magic link password recovery system was implemented from scratch, without third-party libraries: UUID token generated per request, stored in the database with a one-hour expiration, sent by email, and validated on access. Any gap in that chain — reused token, expired token, or invalid user — needed to be detected and rejected before granting access.
Both the public area and the admin panel featured dynamic filters for listing developments, clients, invoices, and visits. All search and pagination logic was structured via searchParams, keeping filter state in the URL and enabling direct sharing of filtered listings.
03
Solution
I deployed the Node.js/Fastify API on Vercel with environment variables separated by context and direct integration with Supabase Storage for uploads. Prisma centralized database access and made modeling the relationships between developments, clients, invoices, and visits straightforward.
Using the same Zod schemas on the front end and back end eliminated the need to maintain two independent validation layers — any rule change propagated automatically to both sides. React Hook Form managed complex form state without unnecessary rerenders, including file upload fields.
The magic link system was built with a UUID token generated per request, stored in the database with an expiration timestamp, and invalidated after use. Dynamic filters were implemented via searchParams in Next.js, reading and updating URL parameters without losing state during navigation — both in the public area and in the admin panel.


















