Monco Tattoo
A platform for a tattoo studio that replaced booking requests over Instagram and WhatsApp: portfolio, guided booking form and a dashboard where the artist reviews each case.
- Status
- In production
- Type
- Client
- Since
- March 2026
- My role
- End-to-end development: interface design, frontend, backend, database and deployment.
- Stack
- Next.jsTypeScriptTailwind CSSPrismaPostgreSQL (Neon)NextAuthCloudinaryResendVercel
Problems and how I solved them
- 01
ProblemThe artist received booking requests through Instagram and WhatsApp, incomplete and disorganized, and had to ask every client the same questions.
SolutionI turned those questions into a step-by-step form (idea, style, body area, size, availability and reference photos), validated with Zod. Every request reaches the dashboard as a complete case.
- 02
ProblemDuring a code review, I found that editing a booking accepted any submitted field and that searching by WhatsApp number exposed the booking's ticket. Together, they allowed a third party to approve someone else's booking.
SolutionI implemented a Zod allowlist on every endpoint, required both ticket and WhatsApp from guest users and stopped returning internal fields. I verified it with 26 HTTP tests: 16 of them failed against the previous version.
- 03
ProblemThe artist wasn't notified of new requests in time.
SolutionEach request triggers an email notification through Resend. The service is only initialized when a key is configured, so the build doesn't fail when it's missing.
- 04
ProblemMany clients didn't want to create an account, but still needed to know the status of their request.
SolutionEach request generates a ticket. With it plus their WhatsApp number or ID, clients can check and edit their booking without signing up. If the ticket doesn't exist or the details don't match, the response is identical, so valid tickets can't be guessed.
- 05
ProblemThe first version stored bookings and profiles in a local JSON file, an approach that doesn't scale in production.
SolutionI migrated the data to PostgreSQL on Neon with Prisma, using the serverless adapter to ensure it runs reliably on Vercel.
- 06
ProblemClients needed to upload up to five reference photos without exposing the Cloudinary credentials.
SolutionThe server signs each upload and the browser sends the image directly to Cloudinary. The secret key never leaves the server and the backend doesn't process heavy files.
- 07
ProblemWhen a client modified their request, the artist couldn't tell what had changed.
SolutionEach change generates a server-side change log, not a client-side one, which the artist can review on the ticket.
- 08
ProblemUpgrading to Prisma 7 broke schema validation (P1012): the connection URL is no longer allowed in schema.prisma.
SolutionI moved the connection to prisma.config.ts and loaded the environment variables manually, since Prisma 7 no longer reads .env on its own.
- 09
ProblemVercel's serverless functions open many database connections at the same time.
SolutionThe app uses Neon's pooled URL (PgBouncer) and migrations use a direct connection, each with its own environment variable.
- 10
ProblemIn production, NextAuth had nothing to sign session cookies with.
SolutionI set NEXTAUTH_SECRET and passed it explicitly to the auth configuration.
- 11
ProblemOn mobile devices, the home page scrolled horizontally and the cursor fell out of alignment over the interactive canvas elements.
SolutionI removed the canvas layers that got in the way and fixed the overflow until the page had no sideways scroll and the cursor lined up.

