Tutorial 5: Building a SaaS with MakerKit
Commercial License Required
MakerKit requires a commercial license. While Orchestre can help you build with it, you must obtain a valid license from MakerKit for commercial use.
In this comprehensive tutorial, you'll build a complete SaaS application using the MakerKit template. We'll create a project management tool with teams, subscriptions, and real features that you could actually ship.
Learning Objectives
By the end of this tutorial, you'll:
- ✅ Build a production-ready SaaS
- ✅ Implement multi-tenant architecture
- ✅ Set up subscription billing
- ✅ Add team collaboration features
- ✅ Deploy to production
Prerequisites
- Completed beginner tutorials
- Basic Next.js knowledge
- Stripe account (free)
- 2-3 hours of time
Project Overview
We're building TaskFlow - a team project management SaaS with:
- User authentication
- Team workspaces
- Project and task management
- Subscription tiers
- Admin dashboard
Part 1: Project Setup
Initialize the Project
/orchestre:create (MCP) taskflow makerkit-nextjsConfigure Environment
cd taskflow
cp .env.example .env.localUpdate .env.local:
# Database (use local PostgreSQL or Supabase)
DATABASE_URL=postgresql://...
# Authentication
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=your-secret-here
# Stripe (from your Stripe dashboard)
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
STRIPE_PUBLISHABLE_KEY=pk_test_...Initial Orchestration
/orchestre:orchestrate (MCP) "Build a project management SaaS where teams can create projects, manage tasks, and collaborate. Include three subscription tiers: Free (1 project), Pro (10 projects), and Enterprise (unlimited)."Part 2: Data Model
Execute the Data Model
/orchestre:execute-task (MCP) "Create data model for projects and tasks with team ownership"This creates:
model Project {
id String @id @default(cuid())
name String
description String?
organizationId String
organization Organization @relation(...)
tasks Task[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Task {
id String @id @default(cuid())
title String
description String?
status TaskStatus @default(TODO)
projectId String
project Project @relation(...)
assigneeId String?
assignee User? @relation(...)
dueDate DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
enum TaskStatus {
TODO
IN_PROGRESS
DONE
}Run Migrations
npm run db:migratePart 3: Subscription Setup
Configure Stripe Plans
/setup-stripeAdd Subscription Plans
/add-subscription-plan "Free plan: 1 project, 2 team members"
/add-subscription-plan "Pro plan: 10 projects, 10 team members, $29/month"
/add-subscription-plan "Enterprise plan: Unlimited projects and members, $99/month"Implement Feature Gates
/orchestre:execute-task (MCP) "Add subscription-based feature gates for project limits"Part 4: Core Features
Project Management
/add-feature "Project CRUD with team access control"This creates:
app/(app)/projects/page.tsx- Project listapp/(app)/projects/[id]/page.tsx- Project detailsapp/api/projects/route.ts- API endpoints- Components for project UI
Task Management
/add-feature "Task management within projects with status tracking"Team Features
/add-team-feature "Team member invitation system"
/add-team-feature "Role-based permissions (owner, admin, member)"Part 5: User Interface
Dashboard
/orchestre:execute-task (MCP) "Create dashboard showing user's projects and recent tasks"The dashboard will include:
- Project overview cards
- Recent tasks list
- Team activity feed
- Quick actions
Project View
/orchestre:execute-task (MCP) "Create Kanban board view for tasks"This implements:
- Drag-and-drop functionality
- Status columns
- Task cards with assignees
- Real-time updates
Part 6: Advanced Features
Real-time Collaboration
/orchestre:orchestrate (MCP) "Add real-time updates when team members modify tasks"Search and Filtering
/implement-search "Global search across projects and tasks"Email Notifications
/implement-email-template "Task assignment notification"
/implement-email-template "Project invitation"Part 7: Testing the SaaS
Create Test Scenarios
/orchestre:execute-task (MCP) "Create test scenarios for subscription upgrades and downgrades"Manual Testing Flow
Sign Up Flow
- Register new account
- Verify email (if configured)
- Complete onboarding
Team Creation
- Create organization
- Invite team members
- Set permissions
Subscription Flow
- View pricing page
- Select plan
- Complete Stripe checkout
- Verify features enabled
Feature Usage
- Create projects (check limits)
- Add tasks
- Invite members (check limits)
- Test real-time updates
Part 8: Production Deployment
Pre-deployment Checklist
/validate-implementation "production readiness"Security Audit
/orchestre:security-audit (MCP) --productionPerformance Check
/performance-check --web-vitalsDeploy to Production
/deploy-productionComplete Code Example
Here's a key component - the Project List with subscription limits:
// app/(app)/projects/page.tsx
export default async function ProjectsPage() {
const { organization, subscription } = await getOrgAndSubscription()
const projects = await getProjects(organization.id)
const canCreateMore = await canCreateProject(organization.id, subscription)
return (
<div>
<PageHeader
title="Projects"
action={
canCreateMore ? (
<CreateProjectButton />
) : (
<UpgradePrompt plan={subscription.plan} />
)
}
/>
<ProjectGrid projects={projects} />
{!canCreateMore && (
<LimitReachedBanner
current={projects.length}
limit={subscription.projectLimit}
/>
)}
</div>
)
}Advanced Patterns
1. Subscription Middleware
// middleware/subscription-check.ts
export async function requiresPlan(minPlan: PlanLevel) {
return async (req: Request) => {
const subscription = await getUserSubscription(req)
if (subscription.level < minPlan) {
return redirectToUpgrade()
}
}
}2. Team Context Hook
// hooks/use-team-context.ts
export function useTeamContext() {
const { organization, membership } = useAuth()
const can = (permission: Permission) => {
return hasPermission(membership.role, permission)
}
return { organization, membership, can }
}3. Real-time Updates
// components/task-board.tsx
export function TaskBoard({ projectId }) {
const tasks = useLiveQuery(
db.tasks.where({ projectId }).orderBy('position')
)
const moveTask = async (taskId, newStatus) => {
await updateTask(taskId, { status: newStatus })
// Optimistic update handled by useLiveQuery
}
return <KanbanBoard tasks={tasks} onMove={moveTask} />
}Common Challenges
1. Subscription State
Problem: Subscription state not updating after payment Solution: Implement Stripe webhooks properly
/orchestre:execute-task (MCP) "Debug Stripe webhook handling for subscription updates"2. Multi-tenant Data Isolation
Problem: Users seeing data from other organizations Solution: Always filter by organizationId
/orchestre:security-audit (MCP) --focus "data isolation"3. Performance with Many Teams
Problem: Slow queries with many organizations Solution: Add proper indexes
/performance-check --databaseBest Practices
1. Always Use Organization Context
// ❌ Bad
const projects = await db.projects.findMany()
// ✅ Good
const projects = await db.projects.findMany({
where: { organizationId: ctx.organizationId }
})2. Feature Flag Everything
// Check features before showing UI
if (subscription.features.includes('advanced-analytics')) {
return <AnalyticsDashboard />
}3. Handle Subscription Limits Gracefully
// Show upgrade prompts contextually
if (isApproachingLimit) {
return <SoftUpgradePrompt />
}Practice Exercises
1. Add Comments Feature
/orchestre:orchestrate (MCP) "Add commenting system to tasks with mentions"2. Implement Audit Logs
/orchestre:add-enterprise-feature (MCP) "Audit logging for all actions"3. Add API Access
/add-feature "Public API with key authentication"4. Mobile App Integration
/orchestre:orchestrate (MCP) "Plan mobile app that connects to this SaaS backend"Production Checklist
- [ ] Environment variables configured
- [ ] Database migrations run
- [ ] Stripe products created
- [ ] Email service configured
- [ ] Error tracking setup
- [ ] Analytics configured
- [ ] Security headers added
- [ ] Performance optimized
- [ ] Backup strategy defined
- [ ] Monitoring established
What You've Learned
✅ Built a complete multi-tenant SaaS ✅ Implemented subscription billing ✅ Added team collaboration ✅ Created production-ready features ✅ Deployed to production
Next Steps
You've built a real SaaS that you could launch! Consider:
Continue learning: Parallel Workflows →
Enhance your SaaS:
- Add more features with
/orchestre:orchestrate (MCP) - Implement mobile app
- Add enterprise features
- Optimize performance
Launch it:
- Set up marketing site
- Configure production Stripe
- Add terms of service
- Start getting customers!
Remember: You've just built something people pay for. That's powerful!
