Architecture
Monorepo architecture, designed to help you build scalable and maintainable applications.
Following a monorepo architecture, AI Boilerplate is designed to help you build scalable and maintainable applications.
The boilerplate uses a Turborepo monorepo, making it easy to extend your project with features like a mobile application and share code and configs between applications.
With the modular architecture, you can add or remove features and customize the application to fit your needs.
You can manage code for different projects, like web applications and marketing websites, all in one place.
Folder Structure
In a Turborepo setup, different parts of the project are organized into apps and packages to facilitate modular development, reuse, and maintenance.
Inside apps are the different applications we can deploy. Inside packages are reusable packages shared among multiple applications.
- dashboard: Main SaaS application.
- marketing: Public website, docs, blog, and legal pages.
- api: tRPC routers, services, and repositories.
- auth: Better Auth configuration with server/client exports.
- configs: Shared configurations for ESLint, Prettier, Tailwind CSS, and TypeScript.
- db: Prisma schema, client, and extensions.
- email: Email sending and templates.
- payments: Stripe integration.
- ui: Shared UI components built on shadcn/ui.
- utils: Shared feature flags, helpers, constants, and types.
- validations: Shared Zod schemas.
Feature-Based Folder Structure
The applications use a feature-based folder structure to organize code.
This structure groups related code together, making it easier to manage and scale the project.
We create folders adhering to a specific feature/route inside each route in the app folder. By prefixing the folder name with _ (underscore), we can ensure that the folder is excluded from the Next.js file-system routing.
- _components: Reusable components scoped to the route.
- _contexts: Contexts for the route.
- (auth): Public pages (sign in, sign up).
- (main): Authenticated pages (dashboard, settings).
- api: Route handlers for tRPC, Better Auth, and Stripe.
- lib: Shared libraries and utilities.
You can add more folders as needed for each feature to keep the code organized.
To avoid circular dependencies, use relative paths when importing within the same folder (e.g., the account feature).
Use absolute paths only when importing from different features.
API Architecture
The API follows a three-layer architecture: Router → Service → Repository.
- Router: Thin controller layer that maps procedures to service methods.
- Service: Business logic, feature flag checks, error handling.
- Repository: Pure Prisma queries with explicit field selection.
- Input: Zod schemas for procedure input validation.
Database Schema
The database schema is defined using Prisma in packages/db/prisma/schema.prisma.
This file contains the models that define the database tables and their relationships.
Models
User
The User model stores information such as name, email, role, plan, and credits.
Links to accounts, sessions, subscription, and credit transactions.
Users can have multiple accounts, sessions, credit transactions, and a subscription.
Account
The Account model manages authentication details for various providers. It stores tokens and metadata for third-party authentication, ensuring secure access.
Supports multiple providers for the same user.
Session
The Session model tracks active user sessions. It stores the token, expiration, user agent, and IP address.
Verification
The Verification model stores tokens for email verification and magic links.
Subscription
The Subscription model stores Stripe subscription details linked to a user. It tracks the product, status, billing interval, current period, trial dates, and cancellation state.
CreditTransaction
The CreditTransaction model stores credit history. Each entry records the type, amount, running balance, description, and optional payment reference.
When a new credit transaction is created, the running balance in the User model (User.credits) is automatically updated.
Enums
Role
User roles.
adminuser
SubscriptionStatus
Stripe subscription statuses.
activecanceledincompleteincomplete_expiredpast_duepausedtrialingunpaid
BillingInterval
Billing intervals.
monthlyyearly
CreditTransactionType
Credit transaction types.
grant: Granted by admin or system (e.g., welcome gift, trial grant, renewal grant).purchase: Card purchase.consumption: Consumed by a feature or action.adjustment: Manual or automatic correction.refund: Card refund.
Enums are synced between the Prisma schema and TypeScript types, so changes in one are reflected in the other.
Import Paths
We employ absolute import paths to make it easier to import files and components across the project.
It also makes it easier to move files around without breaking imports.
Root
To import from the root of the project, you can use the ~ (tilde) alias.
import Logo from "~/public/logo.svg";App
To import from the app (or src) folder, you can use the @ (at) alias.
import { api } from "@/lib/trpc/react";Cross-Package
To import from a package, you can use the @package alias.
import { auth } from "@package/auth/server";
import { db } from "@package/db";
import { sendEmail, MagicLink } from "@package/email";
import { Button } from "@package/ui/button";
import { features } from "@package/utils";
import { signInSchema } from "@package/validations";