Tutorial: Building a Task Management System
Learn how to build a complete task management application using Mosaic Builder. This step-by-step guide will take you from initial concept to deployed application.
What We'll Build
A full-featured task management system with:
Prerequisites
Part 1: Starting the Conversation
Step 1: Initial Description
Start with a clear, high-level description:
I need to build a task management system for my software development team.
We work on multiple projects and need to track tasks, bugs, and features.
Team members should be able to collaborate on tasks.
AI Response Analysis
The AI will identify initial entities:
Step 2: Answer Clarifying Questions
The AI asks: > "Should tasks have different types like bugs and features? Do you need user roles and permissions?"
Your response:
Yes, tasks should have types: feature, bug, improvement, and documentation.
We need two roles: project managers who can create projects and assign tasks,
and developers who work on tasks. Tasks should have priority levels
(low, medium, high, critical) and status tracking.
entities: {
User: { role: 'manager' | 'developer' },
Project: { name, description },
Task: {
type: 'feature' | 'bug' | 'improvement' | 'documentation',
priority: 'low' | 'medium' | 'high' | 'critical',
status: string
}
}
Part 2: Defining the Structure
Step 3: Add Detailed Requirements
Continue with specifics:
Each task needs:
- Title and detailed description
- Assignee (one team member)
- Reporter (who created it)
- Due date and time estimates
- Status: todo, in_progress, review, testing, done
- Comments for discussion
- File attachments
- Activity log for changes
Projects should have:
- Start and end dates
- Project manager
- Team members
- Progress tracking
DSL Structure Emerges
Entities:
User:
- id: uuid
- email: string (unique)
- name: string
- role: enum [manager, developer]
- avatar: string (optional)
Project:
- id: uuid
- name: string
- description: text
- managerId: uuid (ref: User)
- startDate: date
- endDate: date
- status: enum [planning, active, completed]
Task:
- id: uuid
- projectId: uuid (ref: Project)
- title: string
- description: text
- type: enum [feature, bug, improvement, documentation]
- priority: enum [low, medium, high, critical]
- status: enum [todo, in_progress, review, testing, done]
- assigneeId: uuid (ref: User)
- reporterId: uuid (ref: User)
- dueDate: datetime
- estimatedHours: number
- actualHours: number (optional)
Comment:
- id: uuid
- taskId: uuid (ref: Task)
- userId: uuid (ref: User)
- content: text
- createdAt: datetime
Attachment:
- id: uuid
- taskId: uuid (ref: Task)
- fileName: string
- fileUrl: string
- uploadedBy: uuid (ref: User)
Step 4: Relationships and Business Logic
Specify how entities connect:
Relationships:
- One project has many tasks
- Users can be assigned to multiple projects
- Each task has one assignee but many can comment
- Tasks can have dependencies on other tasks
- Projects have multiple team members
Business rules:
- Only managers can create/delete projects
- Task assignee gets notified of new comments
- Tasks can't be closed with open subtasks
- Overdue tasks trigger notifications
Part 3: Refining the Model
Step 5: AI Proposes Complete Structure
The AI presents its understanding:
> I've mapped out your task management system: > > Core Entities: User, Project, Task, Comment, Attachment, ProjectMember, TaskDependency > > Key Features: > - Role-based access (Manager/Developer) > - Task dependencies and subtasks > - Real-time notifications > - Activity tracking > - File attachments > > Suggested Additions: > - Sprint/Milestone grouping? > - Time tracking integration? > - Task templates? > - Recurring tasks? > > Should I add any of these features?
Step 6: Confirm and Enhance
Yes, add:
- Sprints for agile development (2-week cycles)
- Time tracking with daily logs
- Task templates for common tasks
- Email notifications for important events
- Dashboard showing team workload and project progress
Final DSL Structure
Phase: Confirming 🟢 Readiness: 85%interface FinalDSL {
entities: {
User: { /* complete */ },
Project: { /* complete */ },
Sprint: {
projectId: uuid,
name: string,
startDate: date,
endDate: date,
goal: text
},
Task: {
/* previous fields plus: */
sprintId?: uuid,
templateId?: uuid,
isRecurring: boolean
},
TimeLog: {
taskId: uuid,
userId: uuid,
date: date,
hours: decimal,
description: text
},
TaskTemplate: {
name: string,
defaultFields: json
},
Notification: {
userId: uuid,
type: string,
message: text,
read: boolean
}
},
pages: {
dashboard: {
components: ['MetricsGrid', 'TaskChart', 'TeamWorkload']
},
projects: {
components: ['ProjectList', 'ProjectForm']
},
tasks: {
components: ['TaskBoard', 'TaskList', 'TaskDetail']
},
sprints: {
components: ['SprintPlanning', 'SprintBoard']
}
},
workflows: {
createTask: ['validate', 'notify', 'log'],
completeTask: ['checkDependencies', 'updateProgress', 'notify'],
startSprint: ['moveTasks', 'notifyTeam']
}
}
Part 4: Generating Code
Step 7: Click Generate Code
With readiness at 85%, the "Generate Code" button appears.
Generation Options:📦 What to Generate:
├── ✅ Database Schema (Prisma)
├── ✅ API Routes
├── ✅ Authentication
├── ✅ React Components
├── ✅ Dashboard
└── ✅ Email Templates
🎨 Styling:
└── ✅ Tailwind CSS + shadcn/ui
🔧 Additional:
├── ✅ TypeScript types
├── ✅ Validation schemas
└── ✅ Test stubs
Step 8: Review Generated Code
#### Prisma Schema (Excerpt)
model Task {
id String @id @default(uuid())
projectId String
project Project @relation(fields: [projectId], references: [id])
sprintId String?
sprint Sprint? @relation(fields: [sprintId], references: [id])
title String
description String @db.Text
type TaskType
priority Priority
status TaskStatus
assigneeId String
assignee User @relation("TaskAssignee", fields: [assigneeId], references: [id])
reporterId String
reporter User @relation("TaskReporter", fields: [reporterId], references: [id])
dueDate DateTime?
estimatedHours Float?
actualHours Float?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
comments Comment[]
attachments Attachment[]
timeLogs TimeLog[]
dependencies TaskDependency[] @relation("DependentTask")
dependents TaskDependency[] @relation("DependsOnTask")
@@index([projectId, status])
@@index([assigneeId])
@@index([sprintId])
}
enum TaskType {
FEATURE
BUG
IMPROVEMENT
DOCUMENTATION
}
enum Priority {
LOW
MEDIUM
HIGH
CRITICAL
}
enum TaskStatus {
TODO
IN_PROGRESS
REVIEW
TESTING
DONE
}
#### API Route Example
// app/api/tasks/route.ts
export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url)
const projectId = searchParams.get('projectId')
const status = searchParams.get('status')
const assigneeId = searchParams.get('assigneeId')
const tasks = await prisma.task.findMany({
where: {
...(projectId && { projectId }),
...(status && { status }),
...(assigneeId && { assigneeId })
},
include: {
assignee: {
select: { id: true, name: true, avatar: true }
},
project: {
select: { id: true, name: true }
},
_count: {
select: { comments: true, attachments: true }
}
},
orderBy: [
{ priority: 'desc' },
{ dueDate: 'asc' }
]
})
return NextResponse.json(tasks)
}
#### React Component Example
// components/tasks/TaskBoard.tsx
export function TaskBoard({ projectId }: { projectId: string }) {
const { data: tasks, isLoading } = useQuery({
queryKey: ['tasks', projectId],
queryFn: () => fetchTasks(projectId)
})
const columns = ['TODO', 'IN_PROGRESS', 'REVIEW', 'TESTING', 'DONE']
return (
<div className="grid grid-cols-5 gap-4">
{columns.map(status => (
<div key={status} className="bg-gray-50 rounded-lg p-4">
<h3 className="font-semibold mb-4">{status.replace('_', ' ')}</h3>
<div className="space-y-2">
{tasks
?.filter(task => task.status === status)
.map(task => (
<TaskCard key={task.id} task={task} />
))}
</div>
</div>
))}
</div>
)
}
Part 5: Customization
Step 9: Iterate on Generated Code
Continue the conversation to refine:
Add these features to the task board:
1. Drag and drop to change status
2. Quick filters for "My Tasks" and "Overdue"
3. Color coding by priority
4. Real-time updates when others make changes
The AI generates additional code:
// Enhanced TaskBoard with drag-and-drop
import { DragDropContext, Droppable, Draggable } from '@hello-pangea/dnd'
export function TaskBoard({ projectId }: { projectId: string }) {
// ... existing code ...
const handleDragEnd = async (result: DropResult) => {
if (!result.destination) return
const taskId = result.draggableId
const newStatus = result.destination.droppableId
await updateTask(taskId, { status: newStatus })
// Optimistic update
queryClient.setQueryData(['tasks', projectId], (old) => {
// Update task status locally
})
}
// Real-time updates with WebSocket
useEffect(() => {
const ws = new WebSocket('/api/ws')
ws.on('task:updated', (task) => {
queryClient.invalidateQueries(['tasks', projectId])
})
return () => ws.close()
}, [projectId])
return (
<DragDropContext onDragEnd={handleDragEnd}>
{/* Draggable columns */}
</DragDropContext>
)
}
Step 10: Add Custom Features
Request specific functionality:
Create a dashboard that shows:
- Tasks due this week
- Team member workload (tasks per person)
- Project completion percentage
- Burndown chart for current sprint
- Recent activity feed
Generated Dashboard:
// app/(app)/dashboard/page.tsx
export default function Dashboard() {
return (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<MetricCard
title="Tasks Due This Week"
value={tasksDueThisWeek}
icon={<Calendar />}
/>
<WorkloadChart
data={teamWorkload}
title="Team Workload"
/>
<ProgressRing
value={projectCompletion}
title="Project Progress"
/>
<BurndownChart
sprint={currentSprint}
className="col-span-2"
/>
<ActivityFeed
activities={recentActivities}
className="col-span-1"
/>
</div>
)
}
Part 6: Deployment
Step 11: Prepare for Production
Final conversation:
Prepare the application for production deployment on Vercel with:
- Environment configuration
- Database migrations
- Authentication setup
- Email service integration
Generated configuration files:
#### .env.production
# Database
DATABASE_URL=postgresql://...
# Authentication
AUTH_SECRET=generated-secret
NEXTAUTH_URL=https://tasks.yourdomain.com
# Email
SMTP_HOST=smtp.sendgrid.net
SMTP_PORT=587
SMTP_USER=apikey
SMTP_PASS=your-sendgrid-api-key
# OpenRouter (for AI features)
OPENROUTER_API_KEY=sk-or-v1-...
#### Deploy Script
// package.json
{
"scripts": {
"build": "prisma generate && prisma migrate deploy && next build",
"start": "next start",
"postinstall": "prisma generate"
}
}
Part 7: Testing & Launch
Generated Test Suite
// __tests__/tasks.test.ts
describe('Task Management', () => {
test('creates task with required fields', async () => {
const task = await createTask({
title: 'Test Task',
projectId: testProject.id,
assigneeId: testUser.id,
type: 'FEATURE',
priority: 'HIGH'
})
expect(task).toHaveProperty('id')
expect(task.title).toBe('Test Task')
})
test('enforces permissions', async () => {
const developer = await createUser({ role: 'DEVELOPER' })
await expect(
deleteProject(testProject.id, developer)
).rejects.toThrow('Unauthorized')
})
})
Step 12: Deploy to Production
# Deploy to Vercel
vercel --prod
# Run migrations
pnpm prisma migrate deploy
# Seed initial data
pnpm prisma db seed
Complete Application Features
What You've Built
✅ Complete task management system ✅ Role-based authentication ✅ Real-time updates ✅ Drag-and-drop interface ✅ Email notifications ✅ Time tracking ✅ Sprint management ✅ File attachments ✅ Activity logging ✅ Dashboard with metricsProject Statistics
Advanced Customizations
Continue Building
You can extend further by asking: Generate a React Native mobile app that connects to the same API
Add Slack integration to notify channels about task updates
Add AI to suggest task assignments based on team member skills
Create advanced analytics dashboard with productivity metrics
Lessons Learned
Best Practices
Tips for Success
Next Steps
Enhance Your Application
Learn More
Summary
In this tutorial, you've learned how to:
The entire process took less than 30 minutes and resulted in a fully functional task management system ready for your team to use.