Maria Babo

Maria Babo — Portfolio and shop-and-photos platform

The portfolio of a photographer, architect and web designer: three fields, IMAGE, SPACE and WEB, on a site that reads like an archive, with large type and no ornament. The same repository holds a platform of its own with a ceramics shop, custom orders, payment, and photo-session delivery behind a paywall.

YEAR
2026 — present
TYPE
Real client · Partly in production
ROLE
Full-Stack Developer
MARIA BABO: o site no computador e no celular
4
apps in the monorepo: landing, ceramics, photography and API
12
published portfolio projects
15
URLs in the landing's sitemap

Problem.

A professional working across three disciplines needs a portfolio that joins them without looking like three sites. Beyond the showcase, she had two possible businesses, selling ceramics and delivering session photos to clients, which call for a catalog, orders, confirmed payment and protection of the original files.

Solution.

A monorepo with four applications: the portfolio landing (Next.js 14), the ceramics shop with cart and custom orders, the photo-session site with a paid area, and an Express API with Prisma and Postgres. The API handles Mercado Pago payments with webhooks, JWT login, email, Cloudflare R2 storage and photo watermarking. A shared design system provides the visual base of the apps.

Result.

The landing is live at www.mariababo.com.br, with 12 published projects and 15 URLs in the sitemap. The shop, the session site and the API also respond on their own subdomains, but still with sample data and no real products or sessions registered.

The hard part.

Every project has a point where the obvious solution doesn't cut it. Here, it was these.

Selling a photo without handing over the original

Someone viewing a session needs to see enough to want to buy, but can't walk away with the file for free. Locked photos become a blurred preview with a repeated watermark, stored in a public bucket. Originals sit in a private R2 bucket that is never served directly: every read goes through a short-lived signed URL, generated only after the server checks that the photo was unlocked or paid for.

Confirming payment without trusting the browser

The amount never comes from the client: the server computes it from the configured price. Confirmation arrives as a Mercado Pago webhook, which the API validates by recomputing the HMAC-SHA256 signature over the id, request-id and timestamp, with a constant-time comparison. Only then does the API query the payment on Mercado Pago's own API instead of accepting the status in the notification body, and ties it to the shop order or the session payment through the external_reference.

A site that behaves like an archive, built from a design

The reference is a design export, not the previous site. Scripts normalize each export into a versioned snapshot and produce a diff report between versions before any code is written. Images become WebP and the grid pages are generated from files that aren't edited by hand. Each project's content is data, and the pipeline runs types, lint, build and end-to-end tests on every landing change.

Four deploys in one repository

The frontends ship to Vercel on every push to master. The API is only redeployed when its paths or the database and storage packages change: the Action enters the VPS over SSH, rebuilds the image, applies the Prisma migrations and brings the container up. The API's rate limit is in memory, per IP, enough for a single process, and the code notes that it would need to become something shared if the API scaled out.

What I did.

  • An npm workspaces monorepo, with Next.js 14 apps, an Express API and shared packages for database, storage and design system
  • The portfolio landing, built from a design export supplied by Maria, with each project's content written as data
  • A ceramics shop with cart, orders, custom-order requests and an admin panel
  • A photo-session site with access codes, locked and unlocked photos, payment and an admin panel
  • An API with Mercado Pago and webhooks, JWT, email delivery, Cloudflare R2, rate limiting and photo watermarking
  • API deploy to a VPS with Docker and GitHub Actions over SSH, and app deploys on Vercel
  • Playwright smoke tests in the landing pipeline, SEO, sitemap and a share image per project

Stack.

Next.js 14ExpressPrismaPostgreSQLMercado PagoCloudflare R2Docker

Have a similar project?

Tell me the problem — I answer personally.