690 lines
24 KiB
JavaScript
690 lines
24 KiB
JavaScript
/**
|
||
* Create All Directus Collections
|
||
* Main script to create all 10 core collections for the Task Management Suite
|
||
*/
|
||
|
||
const { getAuthenticatedClient } = require('../utils/directus-client');
|
||
const { createCollection, createFields, FIELD_TYPES, getSystemFields } = require('../utils/schema-helpers');
|
||
|
||
/**
|
||
* Create Projects Collection
|
||
*/
|
||
async function createProjectsCollection(client) {
|
||
console.log('\n📦 Creating Projects Collection...');
|
||
|
||
// Create collection
|
||
await createCollection(client, {
|
||
collection: 'projects',
|
||
meta: {
|
||
collection: 'projects',
|
||
icon: 'folder',
|
||
note: 'Project hierarchy and organization',
|
||
display_template: '{{name}}',
|
||
archive_field: 'status',
|
||
archive_value: 'archived',
|
||
sort_field: 'sort',
|
||
accountability: 'all',
|
||
color: '#6366F1'
|
||
},
|
||
schema: {
|
||
name: 'projects'
|
||
}
|
||
});
|
||
|
||
// Create fields
|
||
const fields = [
|
||
FIELD_TYPES.uuid('id', { primary_key: true, hidden: true }),
|
||
FIELD_TYPES.string('name', { required: true, width: 'half' }),
|
||
FIELD_TYPES.text('description', { interface: 'input-rich-text-html' }),
|
||
FIELD_TYPES.dropdown('status', [
|
||
{ text: 'Active', value: 'active' },
|
||
{ text: 'On Hold', value: 'on_hold' },
|
||
{ text: 'Completed', value: 'completed' },
|
||
{ text: 'Archived', value: 'archived' }
|
||
], { default: 'active', width: 'half' }),
|
||
FIELD_TYPES.m2o('parent_project', 'projects', { nullable: true }),
|
||
FIELD_TYPES.string('repository_url', { nullable: true, interface: 'input', meta: { placeholder: 'https://github.com/...' } }),
|
||
FIELD_TYPES.dropdown('bmad_workflow_type', [
|
||
{ text: 'Greenfield', value: 'greenfield' },
|
||
{ text: 'Brownfield', value: 'brownfield' },
|
||
{ text: 'Maintenance', value: 'maintenance' }
|
||
], { nullable: true, width: 'half' }),
|
||
FIELD_TYPES.string('task_master_project_id', { nullable: true, width: 'half' }),
|
||
FIELD_TYPES.dropdown('priority', [
|
||
{ text: 'Low', value: 'low' },
|
||
{ text: 'Medium', value: 'medium' },
|
||
{ text: 'High', value: 'high' },
|
||
{ text: 'Critical', value: 'critical' }
|
||
], { default: 'medium', width: 'half' }),
|
||
FIELD_TYPES.date('start_date', { nullable: true, width: 'half' }),
|
||
FIELD_TYPES.date('due_date', { nullable: true, width: 'half' }),
|
||
FIELD_TYPES.integer('completion_percentage', {
|
||
default: 0,
|
||
width: 'half',
|
||
interface: 'slider',
|
||
options: { min: 0, max: 100, step: 1 }
|
||
}),
|
||
FIELD_TYPES.m2o('created_by', 'directus_users', { width: 'half' }),
|
||
FIELD_TYPES.m2o('assigned_to', 'directus_users', { nullable: true, width: 'half' }),
|
||
FIELD_TYPES.json('metadata', { nullable: true }),
|
||
FIELD_TYPES.integer('sort', { hidden: true, interface: 'input' }),
|
||
...getSystemFields()
|
||
];
|
||
|
||
await createFields(client, 'projects', fields);
|
||
}
|
||
|
||
/**
|
||
* Create Task Statuses Collection
|
||
*/
|
||
async function createTaskStatusesCollection(client) {
|
||
console.log('\n📦 Creating Task Statuses Collection...');
|
||
|
||
await createCollection(client, {
|
||
collection: 'task_statuses',
|
||
meta: {
|
||
collection: 'task_statuses',
|
||
icon: 'assignment_turned_in',
|
||
note: 'Customizable status definitions aligned with workflows',
|
||
display_template: '{{name}}',
|
||
sort_field: 'sort_order',
|
||
accountability: 'all',
|
||
color: '#10B981'
|
||
},
|
||
schema: {
|
||
name: 'task_statuses'
|
||
}
|
||
});
|
||
|
||
const fields = [
|
||
FIELD_TYPES.uuid('id', { primary_key: true, hidden: true }),
|
||
FIELD_TYPES.string('name', { required: true, width: 'half' }),
|
||
FIELD_TYPES.string('slug', { required: true, width: 'half' }),
|
||
FIELD_TYPES.text('description'),
|
||
FIELD_TYPES.string('color', {
|
||
default: '#6366f1',
|
||
interface: 'select-color',
|
||
width: 'half'
|
||
}),
|
||
FIELD_TYPES.string('icon', {
|
||
interface: 'select-icon',
|
||
width: 'half'
|
||
}),
|
||
FIELD_TYPES.dropdown('category', [
|
||
{ text: 'To Do', value: 'todo' },
|
||
{ text: 'In Progress', value: 'in_progress' },
|
||
{ text: 'Review', value: 'review' },
|
||
{ text: 'Done', value: 'done' },
|
||
{ text: 'Blocked', value: 'blocked' }
|
||
], { width: 'half' }),
|
||
FIELD_TYPES.boolean('is_final', { default: false, width: 'half' }),
|
||
FIELD_TYPES.json('auto_transition_rules', { nullable: true }),
|
||
FIELD_TYPES.dropdown('workflow_type', [
|
||
{ text: 'BMad', value: 'bmad' },
|
||
{ text: 'Task Master', value: 'task_master' },
|
||
{ text: 'GitHub', value: 'github' },
|
||
{ text: 'Custom', value: 'custom' }
|
||
], { width: 'half', nullable: true }),
|
||
FIELD_TYPES.integer('sort_order', { default: 0, width: 'half' }),
|
||
FIELD_TYPES.boolean('active', { default: true, width: 'half' }),
|
||
...getSystemFields()
|
||
];
|
||
|
||
await createFields(client, 'task_statuses', fields);
|
||
}
|
||
|
||
/**
|
||
* Create Tasks Collection
|
||
*/
|
||
async function createTasksCollection(client) {
|
||
console.log('\n📦 Creating Tasks Collection...');
|
||
|
||
await createCollection(client, {
|
||
collection: 'tasks',
|
||
meta: {
|
||
collection: 'tasks',
|
||
icon: 'task_alt',
|
||
note: 'Core task entity with rich metadata',
|
||
display_template: '{{title}}',
|
||
archive_field: 'status',
|
||
sort_field: 'sort',
|
||
accountability: 'all',
|
||
color: '#3B82F6'
|
||
},
|
||
schema: {
|
||
name: 'tasks'
|
||
}
|
||
});
|
||
|
||
const fields = [
|
||
FIELD_TYPES.uuid('id', { primary_key: true, hidden: true }),
|
||
FIELD_TYPES.string('title', { required: true }),
|
||
FIELD_TYPES.text('description', { interface: 'input-rich-text-html' }),
|
||
FIELD_TYPES.m2o('status', 'task_statuses', { width: 'half' }),
|
||
FIELD_TYPES.dropdown('priority', [
|
||
{ text: 'Lowest', value: 'lowest' },
|
||
{ text: 'Low', value: 'low' },
|
||
{ text: 'Medium', value: 'medium' },
|
||
{ text: 'High', value: 'high' },
|
||
{ text: 'Highest', value: 'highest' }
|
||
], { default: 'medium', width: 'half' }),
|
||
FIELD_TYPES.dropdown('task_type', [
|
||
{ text: 'Feature', value: 'feature' },
|
||
{ text: 'Bug', value: 'bug' },
|
||
{ text: 'Enhancement', value: 'enhancement' },
|
||
{ text: 'Research', value: 'research' },
|
||
{ text: 'Maintenance', value: 'maintenance' }
|
||
], { width: 'half' }),
|
||
FIELD_TYPES.dropdown('complexity', [
|
||
{ text: 'Trivial', value: 'trivial' },
|
||
{ text: 'Minor', value: 'minor' },
|
||
{ text: 'Major', value: 'major' },
|
||
{ text: 'Critical', value: 'critical' }
|
||
], { width: 'half', nullable: true }),
|
||
FIELD_TYPES.integer('story_points', {
|
||
width: 'half',
|
||
nullable: true,
|
||
interface: 'select-dropdown',
|
||
options: {
|
||
choices: [
|
||
{ text: '1', value: 1 },
|
||
{ text: '2', value: 2 },
|
||
{ text: '3', value: 3 },
|
||
{ text: '5', value: 5 },
|
||
{ text: '8', value: 8 },
|
||
{ text: '13', value: 13 },
|
||
{ text: '21', value: 21 }
|
||
]
|
||
}
|
||
}),
|
||
|
||
// Project relationships
|
||
FIELD_TYPES.m2o('project', 'projects', { required: true, width: 'half' }),
|
||
FIELD_TYPES.m2o('parent_task', 'tasks', { nullable: true, width: 'half' }),
|
||
FIELD_TYPES.m2o('epic', 'tasks', { nullable: true, width: 'half' }),
|
||
|
||
// Assignment and ownership
|
||
FIELD_TYPES.m2o('created_by', 'directus_users', { width: 'half' }),
|
||
FIELD_TYPES.m2o('assigned_to', 'directus_users', { nullable: true, width: 'half' }),
|
||
FIELD_TYPES.string('ai_agent_assigned', { nullable: true, width: 'half' }),
|
||
FIELD_TYPES.m2o('reviewer', 'directus_users', { nullable: true, width: 'half' }),
|
||
|
||
// Time and progress
|
||
FIELD_TYPES.decimal('estimated_hours', { nullable: true, width: 'half', precision: 10, scale: 2 }),
|
||
FIELD_TYPES.decimal('actual_hours', { nullable: true, width: 'half', precision: 10, scale: 2, readonly: true }),
|
||
FIELD_TYPES.integer('progress_percentage', {
|
||
default: 0,
|
||
width: 'half',
|
||
interface: 'slider',
|
||
options: { min: 0, max: 100, step: 5 }
|
||
}),
|
||
FIELD_TYPES.date('start_date', { nullable: true, width: 'half' }),
|
||
FIELD_TYPES.date('due_date', { nullable: true, width: 'half' }),
|
||
FIELD_TYPES.datetime('completed_at', { nullable: true, width: 'half' }),
|
||
|
||
// Integration fields
|
||
FIELD_TYPES.string('task_master_id', { nullable: true, width: 'half' }),
|
||
FIELD_TYPES.string('github_issue_url', { nullable: true }),
|
||
FIELD_TYPES.string('bmad_story_id', { nullable: true, width: 'half' }),
|
||
FIELD_TYPES.json('external_refs', { nullable: true }),
|
||
|
||
// AI and automation
|
||
FIELD_TYPES.boolean('ai_generated', { default: false, width: 'half' }),
|
||
FIELD_TYPES.json('ai_context', { nullable: true }),
|
||
FIELD_TYPES.boolean('auto_status_updates', { default: false, width: 'half' }),
|
||
|
||
// Metadata
|
||
FIELD_TYPES.text('acceptance_criteria', { interface: 'input-rich-text-html', nullable: true }),
|
||
FIELD_TYPES.text('definition_of_done', { interface: 'input-rich-text-html', nullable: true }),
|
||
FIELD_TYPES.text('notes', { interface: 'input-rich-text-html', nullable: true }),
|
||
FIELD_TYPES.integer('sort', { hidden: true, interface: 'input' }),
|
||
...getSystemFields()
|
||
];
|
||
|
||
await createFields(client, 'tasks', fields);
|
||
}
|
||
|
||
/**
|
||
* Create Task Dependencies Collection
|
||
*/
|
||
async function createTaskDependenciesCollection(client) {
|
||
console.log('\n📦 Creating Task Dependencies Collection...');
|
||
|
||
await createCollection(client, {
|
||
collection: 'task_dependencies',
|
||
meta: {
|
||
collection: 'task_dependencies',
|
||
icon: 'device_hub',
|
||
note: 'Task relationship and dependency management',
|
||
display_template: '{{dependent_task}} -> {{dependency_task}}',
|
||
accountability: 'all',
|
||
color: '#F59E0B'
|
||
},
|
||
schema: {
|
||
name: 'task_dependencies'
|
||
}
|
||
});
|
||
|
||
const fields = [
|
||
FIELD_TYPES.uuid('id', { primary_key: true, hidden: true }),
|
||
FIELD_TYPES.m2o('dependent_task', 'tasks', { required: true, width: 'half' }),
|
||
FIELD_TYPES.m2o('dependency_task', 'tasks', { required: true, width: 'half' }),
|
||
FIELD_TYPES.dropdown('dependency_type', [
|
||
{ text: 'Blocks', value: 'blocks' },
|
||
{ text: 'Relates To', value: 'relates_to' },
|
||
{ text: 'Duplicates', value: 'duplicates' },
|
||
{ text: 'Subtask Of', value: 'subtask_of' }
|
||
], { default: 'blocks', width: 'half' }),
|
||
FIELD_TYPES.boolean('is_hard_dependency', { default: true, width: 'half' }),
|
||
FIELD_TYPES.m2o('created_by', 'directus_users'),
|
||
...getSystemFields()
|
||
];
|
||
|
||
await createFields(client, 'task_dependencies', fields);
|
||
}
|
||
|
||
/**
|
||
* Create Task Time Entries Collection
|
||
*/
|
||
async function createTaskTimeEntriesCollection(client) {
|
||
console.log('\n📦 Creating Task Time Entries Collection...');
|
||
|
||
await createCollection(client, {
|
||
collection: 'task_time_entries',
|
||
meta: {
|
||
collection: 'task_time_entries',
|
||
icon: 'schedule',
|
||
note: 'Time tracking and progress data',
|
||
display_template: '{{hours}}h - {{description}}',
|
||
accountability: 'all',
|
||
color: '#8B5CF6'
|
||
},
|
||
schema: {
|
||
name: 'task_time_entries'
|
||
}
|
||
});
|
||
|
||
const fields = [
|
||
FIELD_TYPES.uuid('id', { primary_key: true, hidden: true }),
|
||
FIELD_TYPES.m2o('task', 'tasks', { required: true }),
|
||
FIELD_TYPES.m2o('user', 'directus_users', { nullable: true, width: 'half' }),
|
||
FIELD_TYPES.string('ai_agent', { nullable: true, width: 'half' }),
|
||
FIELD_TYPES.text('description'),
|
||
FIELD_TYPES.decimal('hours', { required: true, width: 'half', precision: 10, scale: 2 }),
|
||
FIELD_TYPES.dropdown('entry_type', [
|
||
{ text: 'Manual', value: 'manual' },
|
||
{ text: 'Automatic', value: 'automatic' },
|
||
{ text: 'Estimated', value: 'estimated' },
|
||
{ text: 'Actual', value: 'actual' }
|
||
], { width: 'half' }),
|
||
FIELD_TYPES.dropdown('work_type', [
|
||
{ text: 'Development', value: 'development' },
|
||
{ text: 'Testing', value: 'testing' },
|
||
{ text: 'Review', value: 'review' },
|
||
{ text: 'Research', value: 'research' },
|
||
{ text: 'Meeting', value: 'meeting' }
|
||
], { width: 'half' }),
|
||
FIELD_TYPES.boolean('billable', { default: false, width: 'half' }),
|
||
FIELD_TYPES.datetime('started_at', { nullable: true, width: 'half' }),
|
||
FIELD_TYPES.datetime('ended_at', { nullable: true, width: 'half' }),
|
||
...getSystemFields()
|
||
];
|
||
|
||
await createFields(client, 'task_time_entries', fields);
|
||
}
|
||
|
||
/**
|
||
* Create Task Templates Collection
|
||
*/
|
||
async function createTaskTemplatesCollection(client) {
|
||
console.log('\n📦 Creating Task Templates Collection...');
|
||
|
||
await createCollection(client, {
|
||
collection: 'task_templates',
|
||
meta: {
|
||
collection: 'task_templates',
|
||
icon: 'content_copy',
|
||
note: 'Reusable task patterns for BMad methodology',
|
||
display_template: '{{name}}',
|
||
accountability: 'all',
|
||
color: '#EC4899'
|
||
},
|
||
schema: {
|
||
name: 'task_templates'
|
||
}
|
||
});
|
||
|
||
const fields = [
|
||
FIELD_TYPES.uuid('id', { primary_key: true, hidden: true }),
|
||
FIELD_TYPES.string('name', { required: true }),
|
||
FIELD_TYPES.text('description'),
|
||
FIELD_TYPES.dropdown('template_type', [
|
||
{ text: 'BMad Epic', value: 'bmad_epic' },
|
||
{ text: 'BMad Story', value: 'bmad_story' },
|
||
{ text: 'Feature', value: 'feature' },
|
||
{ text: 'Bug Fix', value: 'bug_fix' },
|
||
{ text: 'Maintenance', value: 'maintenance' }
|
||
], { width: 'half' }),
|
||
FIELD_TYPES.dropdown('workflow_stage', [
|
||
{ text: 'Planning', value: 'planning' },
|
||
{ text: 'Development', value: 'development' },
|
||
{ text: 'Testing', value: 'testing' },
|
||
{ text: 'Deployment', value: 'deployment' }
|
||
], { width: 'half' }),
|
||
|
||
// Template data
|
||
FIELD_TYPES.string('title_template'),
|
||
FIELD_TYPES.text('description_template'),
|
||
FIELD_TYPES.text('acceptance_criteria_template'),
|
||
FIELD_TYPES.dropdown('default_priority', [
|
||
{ text: 'Lowest', value: 'lowest' },
|
||
{ text: 'Low', value: 'low' },
|
||
{ text: 'Medium', value: 'medium' },
|
||
{ text: 'High', value: 'high' },
|
||
{ text: 'Highest', value: 'highest' }
|
||
], { width: 'half' }),
|
||
FIELD_TYPES.dropdown('default_complexity', [
|
||
{ text: 'Trivial', value: 'trivial' },
|
||
{ text: 'Minor', value: 'minor' },
|
||
{ text: 'Major', value: 'major' },
|
||
{ text: 'Critical', value: 'critical' }
|
||
], { width: 'half', nullable: true }),
|
||
FIELD_TYPES.decimal('estimated_hours', { nullable: true, width: 'half', precision: 10, scale: 2 }),
|
||
|
||
// BMad integration
|
||
FIELD_TYPES.string('bmad_agent_assignment', { nullable: true, width: 'half' }),
|
||
FIELD_TYPES.json('required_skills', { nullable: true }),
|
||
FIELD_TYPES.json('checklist_items', { nullable: true }),
|
||
|
||
// Usage tracking
|
||
FIELD_TYPES.integer('usage_count', { default: 0, width: 'half', readonly: true }),
|
||
FIELD_TYPES.datetime('last_used', { nullable: true, width: 'half', readonly: true }),
|
||
|
||
FIELD_TYPES.m2o('created_by', 'directus_users'),
|
||
...getSystemFields()
|
||
];
|
||
|
||
await createFields(client, 'task_templates', fields);
|
||
}
|
||
|
||
/**
|
||
* Create Task AI Contexts Collection
|
||
*/
|
||
async function createTaskAIContextsCollection(client) {
|
||
console.log('\n📦 Creating Task AI Contexts Collection...');
|
||
|
||
await createCollection(client, {
|
||
collection: 'task_ai_contexts',
|
||
meta: {
|
||
collection: 'task_ai_contexts',
|
||
icon: 'psychology',
|
||
note: 'AI agent context and prompt data',
|
||
display_template: '{{ai_agent_type}} - {{context_type}}',
|
||
accountability: 'all',
|
||
color: '#06B6D4'
|
||
},
|
||
schema: {
|
||
name: 'task_ai_contexts'
|
||
}
|
||
});
|
||
|
||
const fields = [
|
||
FIELD_TYPES.uuid('id', { primary_key: true, hidden: true }),
|
||
FIELD_TYPES.m2o('task', 'tasks', { required: true }),
|
||
FIELD_TYPES.string('ai_agent_type', { width: 'half' }),
|
||
FIELD_TYPES.dropdown('context_type', [
|
||
{ text: 'Prompt', value: 'prompt' },
|
||
{ text: 'Result', value: 'result' },
|
||
{ text: 'Feedback', value: 'feedback' },
|
||
{ text: 'Error', value: 'error' }
|
||
], { width: 'half' }),
|
||
FIELD_TYPES.json('context_data'),
|
||
FIELD_TYPES.datetime('execution_timestamp'),
|
||
FIELD_TYPES.boolean('success', { width: 'half' }),
|
||
FIELD_TYPES.integer('tokens_used', { nullable: true, width: 'half' }),
|
||
FIELD_TYPES.integer('execution_time_ms', { nullable: true, width: 'half' }),
|
||
...getSystemFields()
|
||
];
|
||
|
||
await createFields(client, 'task_ai_contexts', fields);
|
||
}
|
||
|
||
/**
|
||
* Create Task BMad Workflows Collection
|
||
*/
|
||
async function createTaskBMadWorkflowsCollection(client) {
|
||
console.log('\n📦 Creating Task BMad Workflows Collection...');
|
||
|
||
await createCollection(client, {
|
||
collection: 'task_bmad_workflows',
|
||
meta: {
|
||
collection: 'task_bmad_workflows',
|
||
icon: 'account_tree',
|
||
note: 'BMad methodology integration',
|
||
display_template: '{{workflow_stage}} - {{agent_type}}',
|
||
accountability: 'all',
|
||
color: '#14B8A6'
|
||
},
|
||
schema: {
|
||
name: 'task_bmad_workflows'
|
||
}
|
||
});
|
||
|
||
const fields = [
|
||
FIELD_TYPES.uuid('id', { primary_key: true, hidden: true }),
|
||
FIELD_TYPES.m2o('task', 'tasks', { required: true }),
|
||
FIELD_TYPES.dropdown('workflow_stage', [
|
||
{ text: 'Project Manager', value: 'pm' },
|
||
{ text: 'Analyst', value: 'analyst' },
|
||
{ text: 'Architect', value: 'architect' },
|
||
{ text: 'Product Owner', value: 'po' },
|
||
{ text: 'Scrum Master', value: 'sm' },
|
||
{ text: 'Developer', value: 'dev' },
|
||
{ text: 'QA', value: 'qa' },
|
||
{ text: 'UX Expert', value: 'ux' }
|
||
], { width: 'half' }),
|
||
FIELD_TYPES.string('agent_type', { width: 'half' }),
|
||
FIELD_TYPES.json('agent_context'),
|
||
FIELD_TYPES.dropdown('status', [
|
||
{ text: 'Not Started', value: 'not_started' },
|
||
{ text: 'In Progress', value: 'in_progress' },
|
||
{ text: 'Completed', value: 'completed' },
|
||
{ text: 'Skipped', value: 'skipped' }
|
||
], { default: 'not_started', width: 'half' }),
|
||
FIELD_TYPES.json('deliverables'),
|
||
FIELD_TYPES.text('notes'),
|
||
FIELD_TYPES.datetime('started_at', { nullable: true, width: 'half' }),
|
||
FIELD_TYPES.datetime('completed_at', { nullable: true, width: 'half' }),
|
||
...getSystemFields()
|
||
];
|
||
|
||
await createFields(client, 'task_bmad_workflows', fields);
|
||
}
|
||
|
||
/**
|
||
* Create Task Assignments Collection
|
||
*/
|
||
async function createTaskAssignmentsCollection(client) {
|
||
console.log('\n📦 Creating Task Assignments Collection...');
|
||
|
||
await createCollection(client, {
|
||
collection: 'task_assignments',
|
||
meta: {
|
||
collection: 'task_assignments',
|
||
icon: 'group',
|
||
note: 'Team assignments and collaboration',
|
||
display_template: '{{user}} - {{role}}',
|
||
accountability: 'all',
|
||
color: '#F97316'
|
||
},
|
||
schema: {
|
||
name: 'task_assignments'
|
||
}
|
||
});
|
||
|
||
const fields = [
|
||
FIELD_TYPES.uuid('id', { primary_key: true, hidden: true }),
|
||
FIELD_TYPES.m2o('task', 'tasks', { required: true }),
|
||
FIELD_TYPES.m2o('user', 'directus_users', { nullable: true, width: 'half' }),
|
||
FIELD_TYPES.string('ai_agent', { nullable: true, width: 'half' }),
|
||
FIELD_TYPES.dropdown('role', [
|
||
{ text: 'Owner', value: 'owner' },
|
||
{ text: 'Assignee', value: 'assignee' },
|
||
{ text: 'Reviewer', value: 'reviewer' },
|
||
{ text: 'Watcher', value: 'watcher' },
|
||
{ text: 'Contributor', value: 'contributor' }
|
||
], { width: 'half' }),
|
||
FIELD_TYPES.decimal('capacity_percentage', {
|
||
nullable: true,
|
||
width: 'half',
|
||
precision: 5,
|
||
scale: 2,
|
||
interface: 'slider',
|
||
options: { min: 0, max: 100, step: 5 }
|
||
}),
|
||
FIELD_TYPES.datetime('assigned_at', { width: 'half' }),
|
||
FIELD_TYPES.datetime('started_at', { nullable: true, width: 'half' }),
|
||
FIELD_TYPES.datetime('completed_at', { nullable: true, width: 'half' }),
|
||
FIELD_TYPES.text('notes', { nullable: true }),
|
||
...getSystemFields()
|
||
];
|
||
|
||
await createFields(client, 'task_assignments', fields);
|
||
}
|
||
|
||
/**
|
||
* Create Task External References Collection
|
||
*/
|
||
async function createTaskExternalRefsCollection(client) {
|
||
console.log('\n📦 Creating Task External References Collection...');
|
||
|
||
await createCollection(client, {
|
||
collection: 'task_external_refs',
|
||
meta: {
|
||
collection: 'task_external_refs',
|
||
icon: 'link',
|
||
note: 'External system references and integrations',
|
||
display_template: '{{ref_type}}: {{ref_id}}',
|
||
accountability: 'all',
|
||
color: '#64748B'
|
||
},
|
||
schema: {
|
||
name: 'task_external_refs'
|
||
}
|
||
});
|
||
|
||
const fields = [
|
||
FIELD_TYPES.uuid('id', { primary_key: true, hidden: true }),
|
||
FIELD_TYPES.m2o('task', 'tasks', { required: true }),
|
||
FIELD_TYPES.dropdown('ref_type', [
|
||
{ text: 'GitHub Issue', value: 'github_issue' },
|
||
{ text: 'GitHub PR', value: 'github_pr' },
|
||
{ text: 'Task Master', value: 'task_master' },
|
||
{ text: 'Jira', value: 'jira' },
|
||
{ text: 'Slack Thread', value: 'slack_thread' },
|
||
{ text: 'Google Doc', value: 'google_doc' },
|
||
{ text: 'Figma', value: 'figma' },
|
||
{ text: 'Other', value: 'other' }
|
||
], { width: 'half' }),
|
||
FIELD_TYPES.string('ref_id', { required: true, width: 'half' }),
|
||
FIELD_TYPES.string('ref_url', { nullable: true }),
|
||
FIELD_TYPES.json('metadata', { nullable: true }),
|
||
FIELD_TYPES.boolean('auto_sync', { default: false, width: 'half' }),
|
||
FIELD_TYPES.datetime('last_synced', { nullable: true, width: 'half' }),
|
||
...getSystemFields()
|
||
];
|
||
|
||
await createFields(client, 'task_external_refs', fields);
|
||
}
|
||
|
||
/**
|
||
* Main function to create all collections
|
||
*/
|
||
async function main() {
|
||
console.log('🚀 Starting Directus Collections Creation...\n');
|
||
|
||
const summary = {
|
||
collections: { created: 0, existing: 0, errors: 0 },
|
||
fields: { created: 0, existing: 0, errors: 0 }
|
||
};
|
||
|
||
try {
|
||
// Get authenticated client
|
||
const client = await getAuthenticatedClient();
|
||
|
||
// Track results for each collection
|
||
const collectionFunctions = [
|
||
{ name: 'Projects', fn: createProjectsCollection },
|
||
{ name: 'Task Statuses', fn: createTaskStatusesCollection },
|
||
{ name: 'Tasks', fn: createTasksCollection },
|
||
{ name: 'Task Dependencies', fn: createTaskDependenciesCollection },
|
||
{ name: 'Task Time Entries', fn: createTaskTimeEntriesCollection },
|
||
{ name: 'Task Templates', fn: createTaskTemplatesCollection },
|
||
{ name: 'Task AI Contexts', fn: createTaskAIContextsCollection },
|
||
{ name: 'Task BMad Workflows', fn: createTaskBMadWorkflowsCollection },
|
||
{ name: 'Task Assignments', fn: createTaskAssignmentsCollection },
|
||
{ name: 'Task External Refs', fn: createTaskExternalRefsCollection }
|
||
];
|
||
|
||
// Create all collections
|
||
for (const { name, fn } of collectionFunctions) {
|
||
try {
|
||
await fn(client);
|
||
summary.collections.created++;
|
||
} catch (error) {
|
||
console.error(` ❌ Error with ${name} collection:`, error.message);
|
||
summary.collections.errors++;
|
||
}
|
||
}
|
||
|
||
console.log('\n' + '='.repeat(60));
|
||
console.log('📊 FINAL SUMMARY');
|
||
console.log('='.repeat(60));
|
||
|
||
console.log('\n📦 Collections:');
|
||
console.log(` ✅ Processed: ${summary.collections.created + summary.collections.existing}`);
|
||
console.log(` ⚠️ Errors: ${summary.collections.errors}`);
|
||
|
||
console.log('\n✨ Status:');
|
||
if (summary.collections.errors === 0) {
|
||
console.log(' ✅ All collections processed successfully!');
|
||
console.log(' ✅ Ready for relationship setup');
|
||
console.log(' ✅ Ready for validation and indexing');
|
||
} else {
|
||
console.log(' ⚠️ Some collections had issues, but system is functional');
|
||
console.log(' ℹ️ Run script again to retry failed operations');
|
||
}
|
||
|
||
console.log('\n📝 Next Steps:');
|
||
console.log(' 1. Run: npm run setup-relationships');
|
||
console.log(' 2. Run: npm run setup-validation');
|
||
console.log(' 3. Run: npm run create-indexes');
|
||
console.log('='.repeat(60));
|
||
|
||
} catch (error) {
|
||
console.error('\n❌ Critical error:', error.message);
|
||
if (error.response) {
|
||
console.error('Response data:', error.response.data);
|
||
}
|
||
process.exit(1);
|
||
}
|
||
}
|
||
|
||
// Run if called directly
|
||
if (require.main === module) {
|
||
main();
|
||
}
|
||
|
||
module.exports = {
|
||
createProjectsCollection,
|
||
createTaskStatusesCollection,
|
||
createTasksCollection,
|
||
createTaskDependenciesCollection,
|
||
createTaskTimeEntriesCollection,
|
||
createTaskTemplatesCollection,
|
||
createTaskAIContextsCollection,
|
||
createTaskBMadWorkflowsCollection,
|
||
createTaskAssignmentsCollection,
|
||
createTaskExternalRefsCollection,
|
||
main
|
||
}; |