Task Manager Tutorial
Build a complete task management application using Synap SDK. This tutorial covers all core features: creating entities, managing relationships, and tracking history.
What You’ll Build
A task manager with:
- ✅ Create, update, delete tasks
- 👥 Assign tasks to people
- 🔗 Task dependencies
- 📊 Task statistics
- 📜 Complete audit trail
- 🔍 Search functionality
Prerequisites
pnpm add @synap/sdkInitialize SDK:
import { SynapSDK } from '@synap/sdk'
const synap = new SynapSDK({
url: process.env.SYNAP_URL!,
apiKey: process.env.SYNAP_API_KEY!
})Step 1: Create Tasks
Basic Task Creation
async function createTask(title: string, priority: 'low' | 'medium' | 'high') {
const { entityId } = await synap.entities.create({
type: 'task',
title,
preview: `Priority: ${priority}`,
metadata: {
priority,
status: 'todo',
createdAt: new Date().toISOString()
}
})
console.log('✅ Task created:', entityId)
return entityId
}
// Usage
const taskId = await createTask('Review PR #123', 'high')Task with Due Date
async function createTaskWithDueDate(
title: string,
dueDate: string,
priority: 'low' | 'medium' | 'high' = 'medium'
) {
const { entityId } = await synap.entities.create({
type: 'task',
title,
metadata: {
priority,
status: 'todo',
dueDate,
estimatedHours: 2
}
})
return entityId
}
// Create task due tomorrow
const tomorrow = new Date()
tomorrow.setDate(tomorrow.getDate() + 1)
await createTaskWithDueDate(
'Prepare quarterly report',
tomorrow.toISOString().split('T')[0],
'high'
)Step 2: Assign Tasks to People
Create Person
async function createPerson(name: string, email: string) {
const { entityId } = await synap.entities.create({
type: 'person',
title: name,
metadata: {
email,
role: 'developer'
}
})
return entityId
}
const marie = await createPerson('Marie Johnson', 'marie@example.com')
const john = await createPerson('John Smith', 'john@example.com')Assign Task
async function assignTask(taskId: string, personId: string) {
await synap.relations.create(taskId, personId, 'assigned_to')
console.log('✅ Task assigned')
}
// Assign task to Marie
await assignTask(taskId, marie)Get Task Assignees
async function getTaskAssignees(taskId: string) {
const people = await synap.relations.getRelated(taskId, {
type: 'assigned_to',
direction: 'source'
})
return people
}
// Check who is assigned
const assignees = await getTaskAssignees(taskId)
console.log('Assigned to:', assignees.map(p => p.title).join(', '))Step 3: Task Dependencies
Create Dependent Tasks
async function createDependentTask(
title: string,
dependsOnTaskId: string
) {
// Create new task
const { entityId } = await synap.entities.create({
type: 'task',
title,
metadata: {
priority: 'medium',
status: 'blocked' // Can't start until dependency completes
}
})
// Create dependency relationship
await synap.relations.create(entityId, dependsOnTaskId, 'depends_on')
return entityId
}
// Create task that depends on another
const designTask = await createTask('Design new feature', 'high')
const implementTask = await createDependentTask(
'Implement new feature',
designTask
)Check Dependencies
async function getTaskDependencies(taskId: string) {
const dependencies = await synap.relations.getRelated(taskId, {
type: 'depends_on',
direction: 'source'
})
return dependencies
}
// Check what task depends on
const deps = await getTaskDependencies(implementTask)
console.log('Depends on:', deps.map(t => t.title))Find Blocked Tasks
async function getBlockedTasks() {
const allTasks = await synap.entities.list({ type: 'task' })
return allTasks.filter(task =>
task.metadata.status === 'blocked'
)
}
const blocked = await getBlockedTasks()
console.log(`${blocked.length} tasks are blocked`)Step 4: Update Tasks
Mark Task as In Progress
async function startTask(taskId: string) {
await synap.entities.update(taskId, {
metadata: {
status: 'in_progress',
startedAt: new Date().toISOString()
}
})
console.log('✅ Task started')
}
await startTask(taskId)Complete Task
async function completeTask(taskId: string) {
await synap.entities.update(taskId, {
metadata: {
status: 'done',
completedAt: new Date().toISOString()
}
})
console.log('✅ Task completed')
}
await completeTask(designTask)
// Unblock dependent tasks
const dependents = await synap.relations.getRelated(designTask, {
type: 'depends_on',
direction: 'target' // Tasks that depend ON this one
})
for (const task of dependents) {
await synap.entities.update(task.id, {
metadata: { status: 'todo' }
})
}Update Priority
async function updateTaskPriority(
taskId: string,
priority: 'low' | 'medium' | 'high'
) {
await synap.entities.update(taskId, {
metadata: { priority }
})
}
await updateTaskPriority(taskId, 'urgent')Step 5: Query Tasks
Get All Tasks
async function getAllTasks() {
const tasks = await synap.entities.list({
type: 'task',
limit: 100
})
return tasks
}
const allTasks = await getAllTasks()
console.log(`Total tasks: ${allTasks.length}`)Filter by Status
function filterByStatus(tasks: Entity[], status: string) {
return tasks.filter(task => task.metadata.status === status)
}
const allTasks = await getAllTasks()
const todoTasks = filterByStatus(allTasks, 'todo')
const inProgress = filterByStatus(allTasks, 'in_progress')
const done = filterByStatus(allTasks, 'done')
console.log(`Todo: ${todoTasks.length}`)
console.log(`In Progress: ${inProgress.length}`)
console.log(`Done: ${done.length}`)Get Overdue Tasks
function getOverdueTasks(tasks: Entity[]) {
const now = new Date()
return tasks.filter(task => {
if (!task.metadata.dueDate || task.metadata.status === 'done') {
return false
}
const dueDate = new Date(task.metadata.dueDate)
return dueDate < now
})
}
const overdue = getOverdueTasks(allTasks)
console.log(`⚠️ ${overdue.length} overdue tasks`)Search Tasks
async function searchTasks(query: string) {
const results = await synap.entities.search({
query,
types: ['task'],
limit: 20
})
return results
}
// Search for tasks
const results = await searchTasks('review code')
console.log(`Found ${results.length} tasks`)Step 6: Task Statistics
Get User’s Task Stats
async function getTaskStats() {
const tasks = await getAllTasks()
const stats = {
total: tasks.length,
todo: filterByStatus(tasks, 'todo').length,
inProgress: filterByStatus(tasks, 'in_progress').length,
done: filterByStatus(tasks, 'done').length,
overdue: getOverdueTasks(tasks).length,
byPriority: {
high: tasks.filter(t => t.metadata.priority === 'high').length,
medium: tasks.filter(t => t.metadata.priority === 'medium').length,
low: tasks.filter(t => t.metadata.priority === 'low').length
}
}
return stats
}
const stats = await getTaskStats()
console.log('Task Statistics:', stats)Get Person’s Tasks
async function getPersonTasks(personId: string) {
const tasks = await synap.relations.getRelated(personId, {
type: 'assigned_to',
direction: 'target' // Person is target of assignment
})
return tasks
}
const marieTasks = await getPersonTasks(marie)
console.log(`Marie has ${marieTasks.length} tasks`)Step 7: Audit Trail
View Task History
async function getTaskHistory(taskId: string) {
const history = await synap.events.getHistory(taskId)
console.log(`\nTask History (${history.length} events):`)
history.forEach(event => {
console.log(`${event.createdAt}: ${event.eventType}`)
console.log(' Data:', event.data)
})
return history
}
await getTaskHistory(taskId)Track Changes
async function getTaskChanges(taskId: string) {
const history = await synap.events.getHistory(taskId)
const updates = history.filter(e =>
e.eventType === 'entities.update.validated'
)
console.log('\nTask Changes:')
updates.forEach(update => {
console.log(`\n${update.createdAt}:`)
Object.entries(update.data.metadata || {}).forEach(([key, value]) => {
console.log(` ${key}: ${value}`)
})
})
return updates
}
await getTaskChanges(taskId)Step 8: Delete Tasks
Soft Delete
async function deleteTask(taskId: string) {
// Delete task
await synap.entities.delete(taskId)
// Relationships are automatically handled
console.log('✅ Task deleted')
}
await deleteTask(taskId)Complete Example: Task Dashboard
async function buildTaskDashboard() {
// Get all tasks
const tasks = await getAllTasks()
// Get statistics
const stats = await getTaskStats()
// Get overdue tasks
const overdue = getOverdueTasks(tasks)
// Get high priority tasks
const highPriority = tasks.filter(t =>
t.metadata.priority === 'high' &&
t.metadata.status !== 'done'
)
return {
stats,
overdue: overdue.map(t => ({
id: t.id,
title: t.title,
dueDate: t.metadata.dueDate,
daysOverdue: Math.floor(
(Date.now() - new Date(t.metadata.dueDate).getTime()) /
(1000 * 60 * 60 * 24)
)
})),
highPriority: highPriority.map(t => ({
id: t.id,
title: t.title,
status: t.metadata.status,
assignees: [] // Fetch separately
})),
recentActivity: tasks
.sort((a, b) =>
new Date(b.updatedAt).getTime() -
new Date(a.updatedAt).getTime()
)
.slice(0, 5)
}
}
// Use it
const dashboard = await buildTaskDashboard()
console.log('Dashboard:', dashboard)Next Steps
Enhance Your Task Manager:
- Add Comments - Create note entities linked to tasks
- Task Templates - Create reusable task structures
- Notifications - Use event webhooks for real-time updates
- Time Tracking - Add start/end times, calculate duration
- Sub-tasks - Use
parent_ofrelationships - Tags - Create tag entities and link with
tagged_with - Projects - Group tasks under project entities
Related Documentation:
- Entities API → - Full entity operations
- Relations API → - Relationship patterns
- Events API → - Event history
- Next.js Integration → - Build the UI
Full Code
Complete task manager implementation
import { SynapSDK } from '@synap/sdk'
const synap = new SynapSDK({
url: process.env.SYNAP_URL!,
apiKey: process.env.SYNAP_API_KEY!
})
// Create task
async function createTask(title: string, priority: 'low' | 'medium' | 'high') {
const { entityId } = await synap.entities.create({
type: 'task',
title,
metadata: { priority, status: 'todo' }
})
return entityId
}
// Assign task
async function assignTask(taskId: string, personId: string) {
await synap.relations.create(taskId, personId, 'assigned_to')
}
// Update status
async function updateStatus(taskId: string, status: string) {
await synap.entities.update(taskId, {
metadata: { status }
})
}
// Get all tasks
async function getAllTasks() {
return await synap.entities.list({ type: 'task' })
}
// Get statistics
async function getStats() {
const tasks = await getAllTasks()
return {
total: tasks.length,
todo: tasks.filter(t => t.metadata.status === 'todo').length,
done: tasks.filter(t => t.metadata.status === 'done').length
}
}
// Main
async function main() {
// Create person
const { entityId: personId } = await synap.entities.create({
type: 'person',
title: 'Marie Johnson',
metadata: { email: 'marie@example.com' }
})
// Create and assign task
const taskId = await createTask('Review code', 'high')
await assignTask(taskId, personId)
// Complete task
await updateStatus(taskId, 'done')
// Show stats
const stats = await getStats()
console.log('Stats:', stats)
}
main()Congratulations! 🎉 You’ve built a complete task management system with Synap SDK!
Last updated on