# Directus Task Management Suite - Implementation Guides ## Implementation Overview This document provides detailed technical implementation guides for building the Directus Task Management Suite, organized by development phase with specific code examples, configuration steps, and best practices. ## Phase 1: Foundation Implementation Guide ### 1.1 Directus Collections Setup #### Core Collections Schema Implementation **Step 1: Create Projects Collection** ```sql -- Execute via Directus API or admin interface { "collection": "projects", "schema": { "id": { "type": "uuid", "default": "$GENERATE_UUID", "primary_key": true }, "name": { "type": "string", "required": true, "max_length": 255 }, "description": { "type": "text", "nullable": true }, "status": { "type": "string", "default": "active", "options": { "choices": [ {"text": "Active", "value": "active"}, {"text": "On Hold", "value": "on_hold"}, {"text": "Completed", "value": "completed"}, {"text": "Archived", "value": "archived"} ] } }, "parent_project": { "type": "uuid", "foreign_key": "projects.id", "nullable": true }, "repository_url": { "type": "string", "nullable": true }, "bmad_workflow_type": { "type": "string", "options": { "choices": [ {"text": "Greenfield", "value": "greenfield"}, {"text": "Brownfield", "value": "brownfield"}, {"text": "Maintenance", "value": "maintenance"} ] } }, "task_master_project_id": { "type": "string", "nullable": true }, "priority": { "type": "string", "default": "medium", "options": { "choices": [ {"text": "Low", "value": "low"}, {"text": "Medium", "value": "medium"}, {"text": "High", "value": "high"}, {"text": "Critical", "value": "critical"} ] } }, "start_date": { "type": "date", "nullable": true }, "due_date": { "type": "date", "nullable": true }, "completion_percentage": { "type": "integer", "default": 0, "validation": { "min": 0, "max": 100 } }, "created_by": { "type": "uuid", "foreign_key": "directus_users.id" }, "assigned_to": { "type": "uuid", "foreign_key": "directus_users.id", "nullable": true }, "metadata": { "type": "json", "nullable": true }, "created_at": { "type": "timestamp", "auto_create": true }, "updated_at": { "type": "timestamp", "auto_update": true } } } ``` **Step 2: Create Task Statuses Collection** ```sql { "collection": "task_statuses", "schema": { "id": { "type": "uuid", "default": "$GENERATE_UUID", "primary_key": true }, "name": { "type": "string", "required": true, "unique": true }, "slug": { "type": "string", "required": true, "unique": true }, "description": { "type": "text", "nullable": true }, "color": { "type": "string", "default": "#6366f1", "validation": { "pattern": "^#[0-9A-Fa-f]{6}$" } }, "icon": { "type": "string", "default": "circle" }, "category": { "type": "string", "required": true, "options": { "choices": [ {"text": "To Do", "value": "todo"}, {"text": "In Progress", "value": "in_progress"}, {"text": "Review", "value": "review"}, {"text": "Done", "value": "done"}, {"text": "Blocked", "value": "blocked"} ] } }, "is_final": { "type": "boolean", "default": false }, "auto_transition_rules": { "type": "json", "nullable": true }, "workflow_type": { "type": "string", "options": { "choices": [ {"text": "BMad", "value": "bmad"}, {"text": "Task Master", "value": "task_master"}, {"text": "GitHub", "value": "github"}, {"text": "Custom", "value": "custom"} ] } }, "sort_order": { "type": "integer", "default": 0 }, "active": { "type": "boolean", "default": true }, "created_at": { "type": "timestamp", "auto_create": true }, "updated_at": { "type": "timestamp", "auto_update": true } } } ``` **Step 3: Create Tasks Collection** ```sql { "collection": "tasks", "schema": { "id": { "type": "uuid", "default": "$GENERATE_UUID", "primary_key": true }, "title": { "type": "string", "required": true, "max_length": 255 }, "description": { "type": "text", "nullable": true }, "status": { "type": "uuid", "foreign_key": "task_statuses.id", "required": true }, "priority": { "type": "string", "default": "medium", "options": { "choices": [ {"text": "Lowest", "value": "lowest"}, {"text": "Low", "value": "low"}, {"text": "Medium", "value": "medium"}, {"text": "High", "value": "high"}, {"text": "Highest", "value": "highest"} ] } }, "task_type": { "type": "string", "default": "feature", "options": { "choices": [ {"text": "Feature", "value": "feature"}, {"text": "Bug", "value": "bug"}, {"text": "Enhancement", "value": "enhancement"}, {"text": "Research", "value": "research"}, {"text": "Maintenance", "value": "maintenance"} ] } }, "complexity": { "type": "string", "options": { "choices": [ {"text": "Trivial", "value": "trivial"}, {"text": "Minor", "value": "minor"}, {"text": "Major", "value": "major"}, {"text": "Critical", "value": "critical"} ] } }, "story_points": { "type": "integer", "nullable": true, "validation": { "min": 1, "max": 21 } }, "project": { "type": "uuid", "foreign_key": "projects.id", "required": true }, "parent_task": { "type": "uuid", "foreign_key": "tasks.id", "nullable": true }, "epic": { "type": "uuid", "foreign_key": "tasks.id", "nullable": true }, "created_by": { "type": "uuid", "foreign_key": "directus_users.id" }, "assigned_to": { "type": "uuid", "foreign_key": "directus_users.id", "nullable": true }, "ai_agent_assigned": { "type": "string", "nullable": true }, "reviewer": { "type": "uuid", "foreign_key": "directus_users.id", "nullable": true }, "estimated_hours": { "type": "decimal", "precision": 5, "scale": 2, "nullable": true }, "actual_hours": { "type": "decimal", "precision": 5, "scale": 2, "computed": "SUM(task_time_entries.hours)" }, "progress_percentage": { "type": "integer", "default": 0, "validation": { "min": 0, "max": 100 } }, "start_date": { "type": "date", "nullable": true }, "due_date": { "type": "date", "nullable": true }, "completed_at": { "type": "timestamp", "nullable": true }, "task_master_id": { "type": "string", "nullable": true, "unique": true }, "github_issue_url": { "type": "string", "nullable": true }, "bmad_story_id": { "type": "string", "nullable": true }, "external_refs": { "type": "json", "nullable": true }, "ai_generated": { "type": "boolean", "default": false }, "ai_context": { "type": "json", "nullable": true }, "auto_status_updates": { "type": "boolean", "default": false }, "acceptance_criteria": { "type": "text", "nullable": true }, "definition_of_done": { "type": "text", "nullable": true }, "notes": { "type": "text", "nullable": true }, "created_at": { "type": "timestamp", "auto_create": true }, "updated_at": { "type": "timestamp", "auto_update": true } } } ``` #### Database Optimization Setup **Step 4: Create Strategic Indexes** ```sql -- Composite indexes for common query patterns CREATE INDEX idx_tasks_project_status ON tasks(project, status); CREATE INDEX idx_tasks_assigned_status ON tasks(assigned_to, status) WHERE assigned_to IS NOT NULL; CREATE INDEX idx_tasks_due_date ON tasks(due_date) WHERE due_date IS NOT NULL; -- Partial indexes for active data CREATE INDEX idx_active_tasks ON tasks(project, status) WHERE status NOT IN ( SELECT id FROM task_statuses WHERE is_final = true ); -- Full-text search optimization CREATE INDEX idx_tasks_search ON tasks USING gin(to_tsvector('english', title || ' ' || COALESCE(description, ''))); -- Project hierarchy optimization CREATE INDEX idx_projects_parent ON projects(parent_project) WHERE parent_project IS NOT NULL; CREATE INDEX idx_tasks_parent ON tasks(parent_task) WHERE parent_task IS NOT NULL; ``` ### 1.2 MCP Tools Implementation #### MCP Server Extension Setup **Step 1: Project Structure Setup** ```bash # Create MCP extension directory mkdir -p tools/directus-task-management-mcp cd tools/directus-task-management-mcp # Initialize package.json npm init -y npm install @modelcontextprotocol/sdk-typescript npm install @types/node typescript --save-dev # Create source structure mkdir -p src/{tools,types,utils} ``` **Step 2: Core MCP Tools Implementation** **`src/tools/task-crud.ts`** ```typescript import { Tool } from "@modelcontextprotocol/sdk-typescript"; import { DirectusClient } from "../utils/directus-client"; import { Task, TaskCreateData, TaskUpdateData, TaskFilters } from "../types/task-types"; export const createTaskTool: Tool = { name: "mcp__directus__create_task", description: "Create a new task in Directus with full metadata support", inputSchema: { type: "object", properties: { data: { type: "object", properties: { title: { type: "string" }, description: { type: "string" }, project: { type: "string", format: "uuid" }, priority: { type: "string", enum: ["lowest", "low", "medium", "high", "highest"] }, task_type: { type: "string", enum: ["feature", "bug", "enhancement", "research", "maintenance"] }, complexity: { type: "string", enum: ["trivial", "minor", "major", "critical"] }, assigned_to: { type: "string", format: "uuid" }, estimated_hours: { type: "number" }, due_date: { type: "string", format: "date" }, acceptance_criteria: { type: "string" }, definition_of_done: { type: "string" }, tags: { type: "array", items: { type: "string" } } }, required: ["title", "project"] } }, required: ["data"] } }; export async function handleCreateTask(args: any): Promise { const client = new DirectusClient(); try { // Validate project exists await client.validateProject(args.data.project); // Get default status for new tasks const defaultStatus = await client.getDefaultTaskStatus(); // Prepare task data with defaults const taskData: TaskCreateData = { ...args.data, status: defaultStatus.id, progress_percentage: 0, ai_generated: args.data.ai_context ? true : false, created_at: new Date().toISOString() }; // Create task const task = await client.createItem('tasks', taskData); // Handle tags if provided if (args.data.tags?.length > 0) { await client.manageTags(task.id, args.data.tags); } return task; } catch (error) { throw new Error(`Failed to create task: ${error.message}`); } } ``` **`src/tools/task-queries.ts`** ```typescript export const getTaskTool: Tool = { name: "mcp__directus__get_task", description: "Get detailed task information with optional relations", inputSchema: { type: "object", properties: { id: { type: "string", format: "uuid" }, include_relations: { type: "boolean", default: false } }, required: ["id"] } }; export async function handleGetTask(args: any): Promise { const client = new DirectusClient(); const fields = args.include_relations ? [ '*', 'status.*', 'project.*', 'assigned_to.*', 'parent_task.*', 'dependencies.dependency_task.*', 'time_entries.*', 'ai_contexts.*' ] : ['*', 'status.*', 'project.name', 'assigned_to.first_name', 'assigned_to.last_name']; try { const task = await client.readItem('tasks', args.id, { fields }); if (!task) { throw new Error(`Task with ID ${args.id} not found`); } return task; } catch (error) { throw new Error(`Failed to get task: ${error.message}`); } } export const listTasksTool: Tool = { name: "mcp__directus__list_tasks", description: "List tasks with filtering, sorting, and pagination", inputSchema: { type: "object", properties: { filters: { type: "object", properties: { project: { type: "string", format: "uuid" }, status: { type: "string" }, assigned_to: { type: "string", format: "uuid" }, priority: { type: "string" }, task_type: { type: "string" }, search: { type: "string" }, due_before: { type: "string", format: "date" }, created_after: { type: "string", format: "date-time" } } }, pagination: { type: "object", properties: { limit: { type: "integer", minimum: 1, maximum: 100, default: 25 }, offset: { type: "integer", minimum: 0, default: 0 }, page: { type: "integer", minimum: 1 } } }, sort: { type: "array", items: { type: "string" }, default: ["-created_at"] } } } }; export async function handleListTasks(args: any): Promise<{ data: Task[], meta: any }> { const client = new DirectusClient(); const query: any = { fields: ['*', 'status.*', 'project.name', 'assigned_to.first_name', 'assigned_to.last_name'], limit: args.pagination?.limit || 25, sort: args.sort || ['-created_at'] }; // Handle pagination if (args.pagination?.offset) { query.offset = args.pagination.offset; } else if (args.pagination?.page) { query.offset = (args.pagination.page - 1) * query.limit; } // Build filter conditions const filter: any = {}; if (args.filters) { if (args.filters.project) filter.project = { _eq: args.filters.project }; if (args.filters.status) filter.status = { _eq: args.filters.status }; if (args.filters.assigned_to) filter.assigned_to = { _eq: args.filters.assigned_to }; if (args.filters.priority) filter.priority = { _eq: args.filters.priority }; if (args.filters.task_type) filter.task_type = { _eq: args.filters.task_type }; if (args.filters.due_before) filter.due_date = { _lte: args.filters.due_before }; if (args.filters.created_after) filter.created_at = { _gte: args.filters.created_after }; // Full-text search if (args.filters.search) { filter._or = [ { title: { _icontains: args.filters.search } }, { description: { _icontains: args.filters.search } } ]; } } if (Object.keys(filter).length > 0) { query.filter = filter; } try { const result = await client.readItems('tasks', query); return result; } catch (error) { throw new Error(`Failed to list tasks: ${error.message}`); } } ``` **Step 3: AI Integration Tools** **`src/tools/ai-integration.ts`** ```typescript export const createAITaskTool: Tool = { name: "mcp__directus__create_ai_task", description: "Create a task using AI prompt processing with context awareness", inputSchema: { type: "object", properties: { prompt: { type: "string", minLength: 10 }, context: { type: "object", properties: { project_id: { type: "string", format: "uuid" }, current_tasks: { type: "array", items: { type: "string" } }, agent_type: { type: "string" }, workflow_stage: { type: "string" } } } }, required: ["prompt"] } }; export async function handleCreateAITask(args: any): Promise { const client = new DirectusClient(); const aiService = new AITaskProcessor(); try { // Get context information let projectContext = null; if (args.context?.project_id) { projectContext = await client.readItem('projects', args.context.project_id); } // Process prompt with AI const taskData = await aiService.processTaskPrompt(args.prompt, { project: projectContext, existingTasks: args.context?.current_tasks || [], agentType: args.context?.agent_type, workflowStage: args.context?.workflow_stage }); // Enhance with AI context taskData.ai_generated = true; taskData.ai_context = { original_prompt: args.prompt, processing_timestamp: new Date().toISOString(), agent_type: args.context?.agent_type, confidence_score: taskData.confidence_score || 0.8 }; // Create task using standard creation flow return await handleCreateTask({ data: taskData }); } catch (error) { throw new Error(`Failed to create AI task: ${error.message}`); } } export const updateTaskAIContextTool: Tool = { name: "mcp__directus__update_task_ai_context", description: "Update task AI context with agent activity and results", inputSchema: { type: "object", properties: { task_id: { type: "string", format: "uuid" }, context_data: { type: "object", properties: { agent_type: { type: "string" }, operation: { type: "string" }, result: { type: "string" }, files_modified: { type: "array", items: { type: "string" } }, time_spent: { type: "number" }, success: { type: "boolean" }, next_steps: { type: "string" } }, required: ["agent_type", "operation", "success"] } }, required: ["task_id", "context_data"] } }; export async function handleUpdateTaskAIContext(args: any): Promise { const client = new DirectusClient(); try { // Create AI context entry await client.createItem('task_ai_contexts', { task: args.task_id, ai_agent_type: args.context_data.agent_type, context_type: 'feedback', context_data: args.context_data, execution_timestamp: new Date().toISOString(), success: args.context_data.success }); // Update task progress if specified if (args.context_data.progress_update) { await client.updateItem('tasks', args.task_id, { progress_percentage: args.context_data.progress_update, updated_at: new Date().toISOString() }); } } catch (error) { throw new Error(`Failed to update task AI context: ${error.message}`); } } ``` ### 1.3 Frontend Interface Setup #### Directus Admin Interface Customization **Step 1: Collection Interface Configuration** **`collections/tasks.yaml`** (via API or admin interface) ```yaml collection: tasks meta: icon: check_box note: "Task management with full project integration" display_template: "{{title}} - {{project.name}}" fields: title: interface: input options: placeholder: "Enter task title..." display_options: tabular: true required: true description: interface: input-rich-text-html options: toolbar: ['bold', 'italic', 'underline', 'link', 'code'] status: interface: select-dropdown-m2o options: template: "{{name}}" display: labels display_options: choices: - background: "{{color}}" foreground: "#ffffff" value: "{{id}}" text: "{{name}}" priority: interface: select-dropdown display: labels display_options: choices: - { text: "Lowest", value: "lowest", background: "#64748b" } - { text: "Low", value: "low", background: "#10b981" } - { text: "Medium", value: "medium", background: "#f59e0b" } - { text: "High", value: "high", background: "#ef4444" } - { text: "Highest", value: "highest", background: "#dc2626" } project: interface: select-dropdown-m2o options: template: "{{name}}" required: true assigned_to: interface: select-dropdown-m2o options: template: "{{first_name}} {{last_name}}" progress_percentage: interface: slider options: min: 0 max: 100 step: 5 display: progress-bar estimated_hours: interface: input options: type: number step: 0.25 min: 0 due_date: interface: datetime options: type: date ``` **Step 2: Custom Layout Configuration** **`layouts/tasks-detail.vue`** ```vue ``` ## Phase 2: Integration Implementation Guide ### 2.1 Task Master Sync Integration #### Bidirectional Sync Service **`src/services/task-master-sync.ts`** ```typescript import { EventEmitter } from 'events'; import { spawn } from 'child_process'; import { DirectusClient } from '../utils/directus-client'; export class TaskMasterSyncService extends EventEmitter { private directus: DirectusClient; private syncInterval: NodeJS.Timer | null = null; private isRunning: boolean = false; constructor() { super(); this.directus = new DirectusClient(); } async startSync(intervalMinutes: number = 5): Promise { if (this.isRunning) return; this.isRunning = true; console.log('Starting Task Master sync service...'); // Initial sync await this.performSync(); // Set up recurring sync this.syncInterval = setInterval(async () => { try { await this.performSync(); } catch (error) { console.error('Sync error:', error); this.emit('sync-error', error); } }, intervalMinutes * 60 * 1000); this.emit('sync-started'); } async stopSync(): Promise { if (this.syncInterval) { clearInterval(this.syncInterval); this.syncInterval = null; } this.isRunning = false; this.emit('sync-stopped'); } async performSync(): Promise { console.log('Starting bidirectional sync...'); const syncResult = { timestamp: new Date().toISOString(), taskMasterToDirectus: 0, directusToTaskMaster: 0, conflicts: 0, errors: [] }; try { // Phase 1: Task Master → Directus const tmUpdates = await this.syncFromTaskMaster(); syncResult.taskMasterToDirectus = tmUpdates.length; // Phase 2: Directus → Task Master const directusUpdates = await this.syncToTaskMaster(); syncResult.directusToTaskMaster = directusUpdates.length; // Phase 3: Conflict Resolution const conflicts = await this.resolveConflicts(); syncResult.conflicts = conflicts.length; console.log('Sync completed:', syncResult); this.emit('sync-completed', syncResult); } catch (error) { syncResult.errors.push(error.message); this.emit('sync-error', error); throw error; } } private async syncFromTaskMaster(): Promise { // Export from Task Master const tmData = await this.executeTaskMasterCommand(['export', '--format=json', '--since-sync']); if (!tmData.tasks || tmData.tasks.length === 0) { return []; } const updates: any[] = []; for (const tmTask of tmData.tasks) { try { // Check if task exists in Directus const existingTask = await this.directus.readItems('tasks', { filter: { task_master_id: { _eq: tmTask.id } }, limit: 1 }); if (existingTask.data.length > 0) { // Update existing task const directusTask = existingTask.data[0]; const updateData = this.mapTaskMasterToDirectus(tmTask); // Check for conflicts if (this.hasConflict(directusTask, updateData, tmTask)) { await this.recordConflict(directusTask.id, tmTask, updateData); continue; } await this.directus.updateItem('tasks', directusTask.id, updateData); updates.push({ type: 'update', taskMasterId: tmTask.id, directusId: directusTask.id }); } else { // Create new task const newTaskData = this.mapTaskMasterToDirectus(tmTask); newTaskData.task_master_id = tmTask.id; const newTask = await this.directus.createItem('tasks', newTaskData); updates.push({ type: 'create', taskMasterId: tmTask.id, directusId: newTask.id }); } } catch (error) { console.error(`Error syncing task ${tmTask.id}:`, error); continue; } } return updates; } private async syncToTaskMaster(): Promise { // Get tasks modified since last sync const lastSync = await this.getLastSyncTimestamp(); const modifiedTasks = await this.directus.readItems('tasks', { filter: { _and: [ { updated_at: { _gt: lastSync } }, { task_master_id: { _nnull: true } } ] } }); const updates: any[] = []; for (const directusTask of modifiedTasks.data) { try { const tmData = this.mapDirectusToTaskMaster(directusTask); // Update in Task Master await this.executeTaskMasterCommand([ 'update-task', '--id', directusTask.task_master_id, '--data', JSON.stringify(tmData) ]); updates.push({ type: 'update', directusId: directusTask.id, taskMasterId: directusTask.task_master_id }); } catch (error) { console.error(`Error syncing to Task Master ${directusTask.task_master_id}:`, error); continue; } } return updates; } private mapTaskMasterToDirectus(tmTask: any): any { return { title: tmTask.title, description: tmTask.description, // Map Task Master status to Directus status status: this.mapStatus(tmTask.status, 'tm_to_directus'), priority: this.mapPriority(tmTask.priority, 'tm_to_directus'), estimated_hours: tmTask.estimated_hours, progress_percentage: tmTask.progress || 0, due_date: tmTask.due_date, acceptance_criteria: tmTask.acceptance_criteria, definition_of_done: tmTask.definition_of_done, updated_at: new Date().toISOString(), // Preserve sync metadata external_refs: { ...tmTask.external_refs, last_tm_sync: new Date().toISOString() } }; } private mapDirectusToTaskMaster(directusTask: any): any { return { title: directusTask.title, description: directusTask.description, status: this.mapStatus(directusTask.status.slug, 'directus_to_tm'), priority: this.mapPriority(directusTask.priority, 'directus_to_tm'), estimated_hours: directusTask.estimated_hours, progress: directusTask.progress_percentage, due_date: directusTask.due_date, acceptance_criteria: directusTask.acceptance_criteria, definition_of_done: directusTask.definition_of_done }; } private async executeTaskMasterCommand(args: string[]): Promise { return new Promise((resolve, reject) => { const process = spawn('task-master', args, { stdio: 'pipe' }); let output = ''; process.stdout.on('data', (data) => { output += data.toString(); }); process.on('close', (code) => { if (code === 0) { try { resolve(JSON.parse(output)); } catch (error) { resolve({ output }); } } else { reject(new Error(`Task Master command failed with code ${code}`)); } }); }); } private hasConflict(directusTask: any, updateData: any, tmTask: any): boolean { // Simple timestamp-based conflict detection const directusModified = new Date(directusTask.updated_at); const tmModified = new Date(tmTask.updated_at); const lastSync = new Date(directusTask.external_refs?.last_tm_sync || 0); // Conflict if both have been modified since last sync return directusModified > lastSync && tmModified > lastSync; } private async recordConflict(directusTaskId: string, tmTask: any, updateData: any): Promise { await this.directus.createItem('task_sync_conflicts', { task: directusTaskId, conflict_type: 'bidirectional_update', directus_data: updateData, task_master_data: tmTask, detected_at: new Date().toISOString(), resolution_status: 'pending' }); } private mapStatus(status: string, direction: 'tm_to_directus' | 'directus_to_tm'): string { const statusMap = { tm_to_directus: { 'pending': 'todo', 'in-progress': 'in_progress', 'done': 'completed', 'blocked': 'blocked' }, directus_to_tm: { 'todo': 'pending', 'in_progress': 'in-progress', 'completed': 'done', 'blocked': 'blocked' } }; return statusMap[direction][status] || status; } private async getLastSyncTimestamp(): Promise { const syncRecord = await this.directus.readItems('sync_metadata', { filter: { sync_type: { _eq: 'task_master' } }, sort: ['-created_at'], limit: 1 }); return syncRecord.data[0]?.last_sync_time || new Date(0).toISOString(); } } ``` ### 2.2 BMad Integration Implementation #### BMad Workflow Templates **`src/services/bmad-integration.ts`** ```typescript export class BMadIntegrationService { private directus: DirectusClient; constructor() { this.directus = new DirectusClient(); } async createBMadEpic(epicData: BMadEpicData): Promise { // Create epic task const epic = await this.directus.createItem('tasks', { title: epicData.title, description: epicData.description, task_type: 'feature', priority: 'high', complexity: 'major', project: epicData.project_id, bmad_story_id: epicData.bmad_id, ai_generated: true, ai_context: { bmad_workflow: 'epic_creation', planning_phase: epicData.planning_phase, methodology: 'bmad' } }); // Create workflow tracking entries await this.initializeBMadWorkflow(epic.id, epicData.workflow_type); return epic; } async generateUserStories(epicId: string, storyCount: number = 3): Promise { const epic = await this.directus.readItem('tasks', epicId); if (!epic) throw new Error('Epic not found'); const stories: Task[] = []; for (let i = 1; i <= storyCount; i++) { const story = await this.directus.createItem('tasks', { title: `${epic.title} - User Story ${i}`, description: `User story derived from epic: ${epic.title}`, task_type: 'feature', priority: epic.priority, complexity: 'minor', project: epic.project, parent_task: epic.id, epic: epic.id, bmad_story_id: `${epic.bmad_story_id}-story-${i}`, ai_generated: true, ai_context: { bmad_workflow: 'story_generation', parent_epic: epic.id, story_number: i } }); stories.push(story); } return stories; } private async initializeBMadWorkflow(taskId: string, workflowType: string): Promise { const workflows = this.getBMadWorkflowSteps(workflowType); for (const [index, step] of workflows.entries()) { await this.directus.createItem('task_bmad_workflows', { task: taskId, bmad_phase: step.phase, bmad_agent: step.agent, workflow_step: step.step, step_status: 'pending', execution_order: index + 1, step_data: step.default_data || {} }); } } private getBMadWorkflowSteps(workflowType: string): BMadWorkflowStep[] { const workflows = { greenfield: [ { phase: 'analysis', agent: 'pm', step: 'requirements_gathering', default_data: { templates: ['prd', 'user_stories'] } }, { phase: 'analysis', agent: 'architect', step: 'system_design', default_data: { deliverables: ['architecture_diagram', 'tech_stack'] } }, { phase: 'planning', agent: 'analyst', step: 'research_analysis', default_data: { research_areas: ['market', 'technical', 'competitive'] } }, { phase: 'development', agent: 'dev', step: 'implementation', default_data: { coding_standards: true, tdd_required: true } }, { phase: 'review', agent: 'qa', step: 'quality_assurance', default_data: { test_coverage_min: 80, security_review: true } } ], brownfield: [ { phase: 'analysis', agent: 'architect', step: 'system_assessment', default_data: { legacy_analysis: true, impact_assessment: true } }, { phase: 'planning', agent: 'pm', step: 'enhancement_planning', default_data: { risk_assessment: true, rollback_plan: true } }, { phase: 'development', agent: 'dev', step: 'incremental_implementation', default_data: { backwards_compatibility: true, feature_flags: true } }, { phase: 'review', agent: 'qa', step: 'regression_testing', default_data: { full_regression: true, performance_testing: true } } ] }; return workflows[workflowType] || workflows.greenfield; } async updateWorkflowStep(taskId: string, stepId: string, stepData: any): Promise { await this.directus.updateItem('task_bmad_workflows', stepId, { step_status: stepData.status, step_data: { ...stepData.data }, completed_at: stepData.status === 'completed' ? new Date().toISOString() : null }); // Check if all steps are complete if (stepData.status === 'completed') { const allSteps = await this.directus.readItems('task_bmad_workflows', { filter: { task: { _eq: taskId } } }); const allComplete = allSteps.data.every(step => step.step_status === 'completed'); if (allComplete) { await this.directus.updateItem('tasks', taskId, { status: await this.getStatusId('completed'), progress_percentage: 100, completed_at: new Date().toISOString() }); } } } } ``` This implementation guide provides comprehensive code examples and setup instructions for the first two phases of the Directus Task Management Suite. The remaining phases would follow similar patterns with additional features like analytics dashboards, advanced AI integration, and performance optimizations. The key to successful implementation is: 1. **Start with solid foundations** - proper database design and API patterns 2. **Build incrementally** - each phase delivers working functionality 3. **Test thoroughly** - especially integration points with existing systems 4. **Document extensively** - enable future maintenance and enhancement 5. **Monitor performance** - ensure scalability as usage grows Each code example includes error handling, validation, and integration patterns that align with the existing project architecture and established development practices.