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: - Presentation - Thin controllers that just validate input and send responses. - Application - The actual logic, like CreateNoteCommand orGetUserQuery , each in its own small file. - Domain - Pure business rules. No frameworks, no database code, just logic. - 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 anai_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 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 | | 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 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)
Comments
No comments yet. Start the discussion.