Work / Diin Associations
Sleek Interio
A lead engine for a luxury interior design firm. An interactive cost calculator qualifies visitors step by step, saves their progress before they can abandon it, and hands the sales team scored, routable leads.
- Draft recovery window
- 24h
- Rate-limit layers
- 3
- Monorepo packages
- 6
- Engineer
- 1
01 / The problem
Interior design quotes are complicated. Area, rooms, service scope, budget tier, timeline. A plain contact form collects junk, and a long form loses people halfway through. Every abandoned form is a lead the firm paid marketing money to attract and then silently lost.
The firm needed three things: a form people actually finish, a way to recover the ones who do not, and enough signal on each lead for the sales team to know who to call first.
02 / What I built
Sleek Interio is a Turborepo monorepo: a Next.js site, an Express API in TypeScript with a controller, service and repository structure, and shared packages for UI, types and config. Prisma models the lead pipeline in Neon Postgres. Upstash Redis sits in front for everything transient.
The calculator computes an internal complexity score and an estimated revenue range for every submission. The sales team sees the full picture in an admin dashboard with audit-logged status changes. The visitor only ever sees a clean public summary.
03 / Deep dive
Drafts live in Redis, leads live in Postgres
Half-finished forms are valuable but they are not records. Writing them to the primary database pollutes it with noise and lock contention.
So the calculator autosaves every step to Redis with a 24 hour TTL. Close the tab at step four, come back tomorrow, and the form resumes where you left it. Only a completed, validated submission graduates into Postgres. The primary database only ever contains real leads.
- Autosave on every step, sub-second Redis writes
- 24h TTL expires abandoned drafts on its own
- Postgres receives only completed submissions
04 / Deep dive
The browser never sees a secret
The pricing logic is the firm's competitive edge, and API keys in browser code are a breach waiting to happen. Both problems have the same answer: the client talks only to the Next.js server.
Server Actions proxy every request to the Express API and attach the bearer key server-side. On the way back, a serializer strips the internal fields, complexity score, revenue estimate, budget tier, before anything reaches the client. Admins see the full record; visitors see only their own quote.
- Server Actions as a backend-for-frontend gateway
- Bearer-key middleware guards every protected route
- Public serializer masks internal scoring fields
05 / Deep dive
Spam hits a sliding window
A public lead form is a magnet for bots. Validation alone does not stop a script submitting plausible data a thousand times.
Every endpoint sits behind Redis sliding-window rate limits: a general 10 requests per minute per IP, and a strict 3 submissions per 10 minutes keyed on IP plus email for lead creation. Zod validates every payload at the boundary, Helmet sets the security headers, and every admin action lands in an audit log.
- 10 req/min general, 3 per 10 min for submissions
- Window keyed on IP plus email, not IP alone
- Zod-validated DTOs, audit trail on every status change
06 / Outcomes
- Live lead engine for a real firm, built and shipped solo
- Mid-funnel drop-offs come back to a saved form instead of starting over
- Sales works from scored leads with a full audit history
- Pricing logic never leaves the server
Stack
- Frontend
- Next.js 15, React 19, Zustand, React Hook Form, Framer Motion
- API
- Node.js, Express, TypeScript, Zod, Prisma
- Data
- Neon Postgres, Upstash Redis
- Ops
- Turborepo, Clerk, Resend, Helmet, Husky
Next case study
Wheelness