DEV Community

Cover image for I Wired the Boring 80% So You Can Build the Interesting 20% 🚀
Mohamed Ismail
Mohamed Ismail

Posted on AI-assisted

I Wired the Boring 80% So You Can Build the Interesting 20% 🚀

A ready-to-use fullstack boilerplate built for speed, clarity, and smooth AI-assisted coding.

🔗 Repo: github.com/ihssmaheel-dev/modular-monolith-starter


Why I Built This

We're in a strange, exciting era. Thanks to AI coding tools, a single developer can now attempt projects that used to take a whole team years to build. But there's a catch — most people don't spend weeks stuck on the hard part. They spend weeks stuck on the boring part: wiring up auth, picking the right architecture, connecting the database, configuring queues, and just... getting to a point where they can start building the actual idea.

I've felt that pain myself. So I built this starter to remove it.

The goal is simple: give a solo developer (or a small team) a clean, production-ready foundation on day one — so the setup grind doesn't eat the weeks you should be spending on your actual product.


A Quick, Honest Note Before You Dive In

No two developers build the same way, and that's completely fine. This starter isn't the "one true way" to structure a project — it's my way, shaped by research into other boilerplates, a lot of blog posts, and more than a few conversations with AI tools along the way.

If something here doesn't match how you like to work, change it. Rip out what you don't need, rename what bugs you, restructure what feels off — do it before you start building on top of it, while it's still cheap to change. I'm not asking anyone to use this exactly as-is. I just believe it's a solid, well-thought-out starting point — and I'd rather you shape it to fit you than fight it the whole way through.


The Idea: Clean Modules, One Codebase

Instead of piling everything into one giant folder, this starter splits your app into separate modules — like auth, users, notes, tenancy, files, notifications, and privacy.

Each module follows the same four simple layers:

  1. Presentation – Thin controllers that just validate input and send responses.
  2. Application – The actual logic, like CreateNoteCommand or GetUserQuery, each in its own small file.
  3. Domain – Pure business rules. No frameworks, no database code, just logic.
  4. Infrastructure – Database tables (Drizzle ORM) and repositories that talk to PostgreSQL.

No More Surprise Crashes

Most apps throw errors when something goes wrong — a bad password, a missing user — and one missed try/catch can crash your server.

This starter uses the Result pattern (via neverthrow) instead. Every function returns either ok(data) or err(error). Errors become normal values you handle on purpose, not surprises that break things.


Built for AI Coding Tools

If you use tools like Cursor, Claude Code, GitHub Copilot, or Antigravity, you already know they work best on clean code — and struggle once files get long or types get messy.

This starter is designed with that in mind:

  • Small files. Routes stay under 150 lines, and use cases stay under 400 — short enough for an AI tool to read in one go.
  • One source of truth. Every API request and response is defined with Zod schemas in @repo/contracts, so nothing is left to guesswork.
  • Built-in guardrails. The build catches common mistakes automatically — like a UI component accidentally importing a database model.
  • Clear instructions. An AGENTS.md file and an ai_instructions/ folder spell out the project's conventions for any AI assistant working in the codebase.

What You Get Out of the Box

API, Two Ways

Use oRPC for fast, type-safe calls with auto-generated TanStack Query hooks, or plain REST for webhooks and third-party integrations. Both share the same underlying logic, so you never write it twice.

Multi-Tenancy, Done Right

Switch between single-tenant and multi-tenant modes with one environment variable. In multi-tenant mode, PostgreSQL's Row-Level Security enforces data isolation at the database level — so even a buggy query can't leak another organization's data.

Roles & Permissions

A full authorization system with roles, ownership checks, and custom policies. Protecting a route is as simple as adding @RequirePermission('notes:read').

Solid Authentication

  • JWTs with automatic key rotation
  • Single-use refresh tokens tracked in Redis to stop replay attacks
  • "Log out everywhere" support
  • CSRF protection and account lockout against brute-force attempts

No Double Charges

Add @Idempotent() and Redis will catch duplicate requests — so a double-clicked "Submit" button doesn't create two orders.

Reliable Background Jobs

Using the Transactional Outbox pattern, state changes and their events save in the same database transaction. A background worker then pushes them to BullMQ, so nothing gets lost even if the server restarts.

Direct-to-S3 Uploads

Files go straight from the client to S3 or MinIO using a presigned URL — never through your API server. Unused files are cleaned up automatically after 7 days.

GDPR Ready

Users can export all their data in one click, or request full account erasure — profiles are anonymized immediately and data is cleared after a 30-day grace period.

Realtime Updates

WebSockets and Server-Sent Events, backed by Redis Streams, so realtime features scale across multiple servers without missing events.

Shared Design Tokens & i18n

Edit colors, spacing, and fonts once in active.json, and it updates your web CSS, mobile styles, and email templates together. Comes with English, Spanish, and French translations, plus checks that catch missing translation keys.

Built-In Observability

Tracing, metrics, and structured logs are wired in from the start, with ready-made dashboards for viewing traces and logs locally — so you can actually see what your app is doing instead of guessing.


Add a New Feature in Seconds

pnpm generate:feature invoices invoice
Enter fullscreen mode Exit fullscreen mode

This one command scaffolds everything you need:

  • Validation schemas and API contracts
  • Domain entities and error types
  • Database tables and repositories
  • CQRS commands and queries
  • REST and oRPC controllers
  • Frontend API client methods
  • TanStack Query hooks and UI components
  • Unit and integration tests

The Stack

I picked every tool here deliberately — modern, open source, and battle-tested. This isn't the full list (that would be a very long table), just the pieces most worth knowing about:

Layer Technology
Monorepo Turborepo + pnpm workspaces, TypeScript throughout
Backend NestJS on Fastify
Validation Zod (schemas) + neverthrow (Result pattern for errors)
API oRPC (type-safe RPC) with REST as a compatibility layer, docs via Scalar
Database PostgreSQL with Row-Level Security + Drizzle ORM
Cache & Jobs Redis + BullMQ
Auth & Security Argon2 hashing, JWT with key rotation, CSRF protection, rate limiting
Authorization Custom hybrid engine (roles + ownership + policies)
File Storage S3 / MinIO with direct-to-client presigned uploads
Email React Email, with Resend or plain SMTP
Realtime WebSockets + Server-Sent Events over Redis Streams
Web Frontend TanStack Start (React 19, Router, Query, Zustand)
Mobile Expo + Expo Router + NativeWind
UI Base UI primitives + Tailwind CSS + shadcn-style theming
i18n react-i18next, with English, Spanish, and French out of the box
Testing Vitest + Playwright, with architectural boundary checks
Observability OpenTelemetry, Prometheus, Pino, with Grafana/Jaeger/Loki for local dashboards

All open source, with no vendor lock-in — and every piece here can be swapped out if it's not your taste.


Get Started in 3 Minutes

# 1. Clone the repository
git clone https://github.com/ihssmaheel-dev/modular-monolith-starter.git
cd modular-monolith-starter

# 2. Install dependencies
pnpm install

# 3. Start local services (Postgres, Redis, MinIO, Mailpit)
pnpm docker:up
pnpm docker:init

# 4. Run database migrations
pnpm db:migrate

# 5. Start development servers
pnpm dev
Enter fullscreen mode Exit fullscreen mode

Your API runs at http://localhost:3000 (docs at /api/docs), and the web app runs at http://localhost:5173.


Star It, Try It, Help Shape It

This project is still growing, and I'd love your feedback — bug reports, feature ideas, or just thoughts on what could be better. And remember: if a piece of this doesn't fit how you work, that's completely fine — unwire it, swap it, make it yours before you build on top.

Star the repo on GitHub
💬 Open an issue to share your thoughts.

Let's build something great together.

Top comments (0)