Pepanimal

April 21, 2026

Pepanimal

A full-stack, multilingual (ES/EN/FR/PT) platform for responsible dog and cat adoption. It connects shelters with adopters and digitizes the whole process — from publishing an animal to selecting the final adopter — with a public catalog, a shelter management dashboard, integrated chat and notifications.

Built solo, end to end: architecture, frontend, backend, database, component library and infrastructure.

Contents

The problem

Animal adoption is usually handled in a scattered, informal way: one-off posts on social media, conversations over WhatsApp or Instagram, spreadsheets, and no structured tracking of requests. This creates two concrete pain points:

  • For shelters: it's hard to give their animals visibility, receive requests in an orderly way, evaluate candidates properly, coordinate the team (several volunteers and staff) and track the status of each adoption. Information lives spread across several tools.
  • For adopters: there is no central place to browse animals from different shelters, each animal's information is incomplete, and the request process is opaque — they don't know the status of their request or how to talk to the shelter.

The solution

Pepanimal centralizes and digitizes the entire adoption flow in a single platform:

  • A public catalog where anyone can browse dogs and cats up for adoption, with detailed profiles (temperament, compatibility with other pets and children, health status, location and responsible shelter).
  • A shelter management dashboard to register animals with photos and video, publish adoptions, manage the team via roles and invitations, and coordinate foster homes.
  • A structured request flow: the adopter fills in a pre-adoption questionnaire and submits the request; the shelter reviews it on a board with statuses (Under review → In progress → Validated / Discarded), adds internal comments, chats with the candidate and finally selects the definitive adopter.
  • A notification system that keeps the adopter informed on every status change and when they are picked as the final candidate.

The result is a transparent, traceable process with built-in communication, with no reliance on external tools.

Pepanimal landing page with the hero, shelter sign-up and steps to adopt

Key features

  • Multilingual public catalog of animals by species, with sorting and filters (breed, size, location) and slug-localized routes (/animals/perros in ES, /animals/dogs in EN).
  • Detailed animal profile: image and video gallery, temperament (energy and independence levels, compatibility with cats/dogs/children/people), health status (vaccinated, dewormed, neutered, special medical condition) and shelter details.
  • Authentication with email/password and Google OAuth (Better Auth).
  • Shelter dashboard with metrics (available animals, in foster care, adoptions this month, average time in the shelter) and charts.
  • Animal management: create, edit, upload images and video, assign caretakers and foster homes.
  • Kanban board of adoption requests with statuses, internal team comments and final candidate selection.
  • Integrated chat between shelter and adopter, tied to each request.
  • Configurable pre-adoption questionnaire with multilingual questions.
  • Shelter team management: email invitations with roles (ADMIN / WORKER).
  • Foster homes: register and assign animals to temporary homes.
  • Content blog about adoption and pet care (52 articles in each of the 4 languages), rendered with MDX.
  • Technical SEO: dynamic metadata, JSON-LD structured data, dynamic sitemap and robots, and multilingual hreflang.
  • AI image moderation: every uploaded photo is analyzed with OpenAI's moderation API to block disallowed content.

Public catalog of dogs up for adoption with per-animal cards and sort/filter controls

Detailed animal profile with photo, key data, adoption conditions, behavior, health and responsible shelter

Content blog about adoption and pet care, with per-article cards and pagination

Tech stack

A monorepo using npm workspaces (apps/*, packages/*), Node ≥ 24, deployed on Vercel with a separate project per app and per-folder conditional builds.

Frontend (apps/web) — Next.js 16 (App Router) · React 19 · TypeScript · Tailwind CSS 4 · TanStack Query · Zustand · react-hook-form + Zod · next-intl (4 languages) · Better Auth · MDX for the blog · FFmpeg (WASM) for in-browser video compression.

Backend (apps/api) — Hono on Node · 4-layer clean architecture (domain → application → infra → presentation) · InversifyJS (dependency injection) · Prisma 7 · Better Auth (email + Google OAuth) · Zod · OpenAI (image moderation) · sharp (WebP optimization) · Nodemailer + React Email · AWS SDK S3 · Pino.

Database — PostgreSQL with Prisma (~25 models), Neon (serverless) in production. A data-level translation system via a Multilang model that stores all four language variants.

Component library (packages/react-ui) — a local library with Vite + Storybook, Atomic Design architecture, Recharts for the charts and drag & drop for the kanban board.

Technical challenges

True data-level multilingualism, not just UI. i18n isn't limited to interface text (handled with next-intl): the domain's dynamic content — breeds, countries, provinces and questionnaire questions — also exists in all four languages. This was solved with a Multilang model in the database that translatable entities point to, so switching languages returns consistent data across the whole app. Routes are even slug-localized.

Client- and server-side media pipeline. Shelters upload heavy photos (often iPhone HEIC) and videos from mobile. A two-stage pipeline was built: on the client, HEIC conversion, image compression and video compression with FFmpeg compiled to WASM before uploading; on the server, re-optimization with sharp (rescaling and WebP re-encoding). Each image also goes through OpenAI AI moderation before being published.

Clean-architecture API with dependency injection. The backend is organized into domain modules (animal, adoption, shelter, chat…), each with its own layers and a strict dependency flow. Repositories are defined as abstract contracts injected with InversifyJS, so business logic never touches Prisma. Layer boundaries are enforced with file-scoped lint rules.

Monorepo with a shared UI library and independent deployments. Two apps (web, api) and a locally consumed component library. Each app deploys separately on Vercel without rebuilding everything on each push, using Ignored Build Steps based on per-folder git diff and custom vercel.json files.

Shelter dashboard — Summary with key metrics and adoptions chart

Shelter dashboard — Card-based list of the shelter's animals with search and filters

My role

Built solo (full-stack) over ~5 months. End-to-end work: monorepo architecture, frontend (Next.js), backend (Hono with clean architecture + DI), component library with Storybook, data modeling with Prisma and the translation system, integrations (Better Auth with Google OAuth, OpenAI, S3 storage, transactional email), technical SEO, i18n in 4 languages, blog and deployment and quality tooling setup.