The challenge
Developers need quick access to various utility tools scattered across different websites.
The approach
Built a pnpm + Turborepo monorepo of three apps.
What shipped- A Next.js 15 frontend whose tool catalogue is generated at build time from per-tool folders
- A React + Vite admin dashboard
- An Express 5 API with Prisma on PostgreSQL
- MongoDB for the blog
- A Typesense search index
- Google sign-in
- Per-route rate limiting
- Sharp image conversion and a Socket.IO gateway for collaborative whiteboard and sharing tools
The outcome
235 tools across converters, formatters, encoders, calculators, image and sharing utilities, most running entirely in the browser, with accounts, favourites, history and usage analytics behind them.
How WebUtility is put together
A pnpm + Turborepo monorepo of three deployables. The tool catalogue is a build-time registry in the Next.js frontend and most tools run entirely in the browser; an Express 5 API handles accounts, Google sign-in, uploads, server-side image conversion, search and the blog, and a Socket.IO gateway powers the collaborative tools.
- tools in the registry
- 235
- apps in one monorepo
- 3
- Prisma models
- 13
- processing requests per IP
- 10/min
01 · Clients
client
Visitors
client
Admins
02 · Frontends
service
User frontend
Next.js · Zustand
generated tool registry, in-browser tools
service
Admin dashboard
React · Vite · Recharts
users, blog, analytics
03 · Backend
service
REST API
Express 5 · TypeScript
JWT, per-route rate limits, uploads
service
Realtime gateway
Socket.IO
whiteboard, ShareBro rooms
04 · Data
database
PostgreSQL
Prisma
users, favorites, history, analytics
database
MongoDB
Mongoose
blog posts & categories
database
Typesense
search index
object store
Object storage
OCI · local disk
uploads, blog media
05 · Third-party
third-party
Google OAuth
third-party
SMTP
Nodemailer
third-party
Rates APIs
currency & metal prices
12 connections
- Visitors→User frontendHTTPS
- Admins→Admin dashboardHTTPS
- User frontend→REST APIREST
- User frontend→Realtime gatewayWebSocket · async
- Admin dashboard→REST APIREST
- REST API→PostgreSQLSQL
- REST API→MongoDBblog CRUD
- REST API→Typesensequery
- REST API→Object storageput object
- REST API→Google OAuthverify sign-in
- REST API→SMTPadmin alerts · async
- REST API→Rates APIslive rates
Request flow · Converting an image on the server
- 1The tool page posts the file to /api/process/image/convert with the target format and quality.
- 2The processing router applies its rate limit (10 requests per minute per IP) and multer enforces size and type before the handler runs.
- 3Sharp re-encodes the image in-process and the converted file is returned to the browser.
- 4Lighter tools such as formatters, encoders and calculators never reach the API; they run client-side from the registry.
Design decisions
- Tools as a generated registry
- Each tool is a folder with config.json and tool.tsx; a build step generates the registry and search index, so adding a tool never touches routing.
- Stateless JWT
- Short-lived access and refresh tokens carry user id and role, so the auth middleware verifies without a database round trip.
- Store per data shape
- Relational user data lives in Postgres through Prisma; free-form blog documents live in MongoDB; search is a dedicated Typesense index.
- Pluggable storage
- Uploads go through a storage-provider interface, with OCI Object Storage and local disk implemented behind it.
Trade-offs & known limits
- Queue workers and the Redis cache are scaffolded but not implemented, so server-side processing runs synchronously in the request.
- Logout is client-side: there is no token blacklist, so revocation relies on short token lifetimes.
Have something similar in mind?
I'm open for freelance and contract work — let's talk about what you're building.