fix: handle empty filter param and add created/updated fields for PB 0.25 compat

This commit is contained in:
2026-07-19 15:03:15 +00:00
parent a45a2a0bb2
commit 327c5bf733
48 changed files with 49 additions and 1684 deletions
@@ -1,39 +0,0 @@
exports = {
up: async (app) => {
const collection = new app.models.Collection({
name: 'domains',
type: 'base',
schema: app.models.NewSchema([
app.models.NewSchemaField({
name: 'name',
type: 'text',
required: true,
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'color',
type: 'text',
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'icon',
type: 'text',
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'sort_order',
type: 'number',
options: {}
})
]),
indexes: [
'CREATE UNIQUE INDEX idx_domains_name ON domains (name)'
]
});
return app.save(collection);
},
down: async (app) => {
const collection = await app.findCollectionByNameOrId('domains');
return app.delete(collection);
}
};
@@ -1,29 +0,0 @@
exports = {
up: async (app) => {
const collection = new app.models.Collection({
name: 'tags',
type: 'base',
schema: app.models.NewSchema([
app.models.NewSchemaField({
name: 'name',
type: 'text',
required: true,
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'color',
type: 'text',
options: { maxSize: 255 }
})
]),
indexes: [
'CREATE UNIQUE INDEX idx_tags_name ON tags (name)'
]
});
return app.save(collection);
},
down: async (app) => {
const collection = await app.findCollectionByNameOrId('tags');
return app.delete(collection);
}
};
@@ -1,72 +0,0 @@
exports = {
up: async (app) => {
const collection = new app.models.Collection({
name: 'projects',
type: 'base',
schema: app.models.NewSchema([
app.models.NewSchemaField({
name: 'name',
type: 'text',
required: true,
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'description',
type: 'text',
options: {}
}),
app.models.NewSchemaField({
name: 'color',
type: 'text',
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'icon',
type: 'text',
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'domain',
type: 'relation',
options: { collectionId: 'domains', maxSelect: 1, cascadeDelete: false }
}),
app.models.NewSchemaField({
name: 'status',
type: 'select',
options: { values: ['active', 'paused', 'archived'], maxSelect: 1 }
}),
app.models.NewSchemaField({
name: 'tags',
type: 'relation',
options: { collectionId: 'tags', maxSelect: 10, cascadeDelete: false }
}),
app.models.NewSchemaField({
name: 'goal',
type: 'text',
options: {}
}),
app.models.NewSchemaField({
name: 'deadline',
type: 'date',
options: {}
}),
app.models.NewSchemaField({
name: 'progress',
type: 'number',
options: { min: 0, max: 100 }
}),
app.models.NewSchemaField({
name: 'members',
type: 'json',
options: {}
})
]),
indexes: []
});
return app.save(collection);
},
down: async (app) => {
const collection = await app.findCollectionByNameOrId('projects');
return app.delete(collection);
}
};
@@ -1,79 +0,0 @@
exports = {
up: async (app) => {
const collection = new app.models.Collection({
name: 'project_settings',
type: 'base',
schema: app.models.NewSchema([
app.models.NewSchemaField({
name: 'project_id',
type: 'relation',
required: true,
options: { collectionId: 'projects', maxSelect: 1, cascadeDelete: true }
}),
app.models.NewSchemaField({
name: 'default_priority',
type: 'select',
options: { values: ['low', 'medium', 'high', 'urgent'], maxSelect: 1 }
}),
app.models.NewSchemaField({
name: 'default_domain',
type: 'relation',
options: { collectionId: 'domains', maxSelect: 1, cascadeDelete: false }
}),
app.models.NewSchemaField({
name: 'default_tags',
type: 'relation',
options: { collectionId: 'tags', maxSelect: 10, cascadeDelete: false }
}),
app.models.NewSchemaField({
name: 'auto_archive_completed_after_days',
type: 'number',
options: {}
}),
app.models.NewSchemaField({
name: 'default_view',
type: 'select',
options: { values: ['kanban', 'list'], maxSelect: 1 }
}),
app.models.NewSchemaField({
name: 'habit_reminder_time_default',
type: 'text',
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'pomodoro_focus_minutes',
type: 'number',
options: { min: 1, max: 120 }
}),
app.models.NewSchemaField({
name: 'pomodoro_break_minutes',
type: 'number',
options: { min: 1, max: 60 }
}),
app.models.NewSchemaField({
name: 'accent_color_override',
type: 'text',
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'milestone_dependency_enforcement',
type: 'bool',
options: {}
}),
app.models.NewSchemaField({
name: 'custom_fields',
type: 'json',
options: {}
})
]),
indexes: [
'CREATE UNIQUE INDEX idx_project_settings_project_id ON project_settings (project_id)'
]
});
return app.save(collection);
},
down: async (app) => {
const collection = await app.findCollectionByNameOrId('project_settings');
return app.delete(collection);
}
};
@@ -1,50 +0,0 @@
exports = {
up: async (app) => {
const collection = new app.models.Collection({
name: 'milestones',
type: 'base',
schema: app.models.NewSchema([
app.models.NewSchemaField({
name: 'title',
type: 'text',
required: true,
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'description',
type: 'text',
options: {}
}),
app.models.NewSchemaField({
name: 'project_id',
type: 'relation',
required: true,
options: { collectionId: 'projects', maxSelect: 1, cascadeDelete: true }
}),
app.models.NewSchemaField({
name: 'status',
type: 'select',
options: { values: ['planned', 'in_progress', 'complete'], maxSelect: 1 }
}),
app.models.NewSchemaField({
name: 'due_date',
type: 'date',
options: {}
}),
app.models.NewSchemaField({
name: 'sort_order',
type: 'number',
options: {}
})
]),
indexes: [
'CREATE INDEX idx_milestones_project_id ON milestones (project_id)'
]
});
return app.save(collection);
},
down: async (app) => {
const collection = await app.findCollectionByNameOrId('milestones');
return app.delete(collection);
}
};
@@ -1,31 +0,0 @@
exports = {
up: async (app) => {
const collection = new app.models.Collection({
name: 'milestone_dependencies',
type: 'base',
schema: app.models.NewSchema([
app.models.NewSchemaField({
name: 'milestone_id',
type: 'relation',
required: true,
options: { collectionId: 'milestones', maxSelect: 1, cascadeDelete: true }
}),
app.models.NewSchemaField({
name: 'depends_on_milestone_id',
type: 'relation',
required: true,
options: { collectionId: 'milestones', maxSelect: 1, cascadeDelete: true }
})
]),
indexes: [
'CREATE INDEX idx_milestone_dependencies_milestone_id ON milestone_dependencies (milestone_id)',
'CREATE INDEX idx_milestone_dependencies_depends_on ON milestone_dependencies (depends_on_milestone_id)'
]
});
return app.save(collection);
},
down: async (app) => {
const collection = await app.findCollectionByNameOrId('milestone_dependencies');
return app.delete(collection);
}
};
@@ -1,32 +0,0 @@
exports = {
up: async (app) => {
const collection = new app.models.Collection({
name: 'milestone_templates',
type: 'base',
schema: app.models.NewSchema([
app.models.NewSchemaField({
name: 'name',
type: 'text',
required: true,
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'description',
type: 'text',
options: {}
}),
app.models.NewSchemaField({
name: 'milestones',
type: 'json',
options: {}
})
]),
indexes: []
});
return app.save(collection);
},
down: async (app) => {
const collection = await app.findCollectionByNameOrId('milestone_templates');
return app.delete(collection);
}
};
@@ -1,44 +0,0 @@
exports = {
up: async (app) => {
const collection = new app.models.Collection({
name: 'milestone_history',
type: 'base',
schema: app.models.NewSchema([
app.models.NewSchemaField({
name: 'milestone_id',
type: 'relation',
required: true,
options: { collectionId: 'milestones', maxSelect: 1, cascadeDelete: true }
}),
app.models.NewSchemaField({
name: 'old_status',
type: 'text',
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'new_status',
type: 'text',
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'changed_by',
type: 'text',
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'changed_at',
type: 'date',
options: {}
})
]),
indexes: [
'CREATE INDEX idx_milestone_history_milestone_id ON milestone_history (milestone_id)'
]
});
return app.save(collection);
},
down: async (app) => {
const collection = await app.findCollectionByNameOrId('milestone_history');
return app.delete(collection);
}
};
@@ -1,112 +0,0 @@
exports = {
up: async (app) => {
const collection = new app.models.Collection({
name: 'tasks',
type: 'base',
schema: app.models.NewSchema([
app.models.NewSchemaField({
name: 'title',
type: 'text',
required: true,
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'description',
type: 'text',
options: {}
}),
app.models.NewSchemaField({
name: 'status',
type: 'select',
options: { values: ['todo', 'in_progress', 'done', 'cancelled'], maxSelect: 1 }
}),
app.models.NewSchemaField({
name: 'priority',
type: 'select',
options: { values: ['low', 'medium', 'high', 'urgent'], maxSelect: 1 }
}),
app.models.NewSchemaField({
name: 'due_date',
type: 'date',
options: {}
}),
app.models.NewSchemaField({
name: 'project_id',
type: 'relation',
options: { collectionId: 'projects', maxSelect: 1, cascadeDelete: false }
}),
app.models.NewSchemaField({
name: 'milestone_id',
type: 'relation',
options: { collectionId: 'milestones', maxSelect: 1, cascadeDelete: false }
}),
app.models.NewSchemaField({
name: 'tags',
type: 'relation',
options: { collectionId: 'tags', maxSelect: 10, cascadeDelete: false }
}),
app.models.NewSchemaField({
name: 'domain',
type: 'relation',
options: { collectionId: 'domains', maxSelect: 1, cascadeDelete: false }
}),
app.models.NewSchemaField({
name: 'assignee',
type: 'text',
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'estimate',
type: 'number',
options: { min: 0 }
}),
app.models.NewSchemaField({
name: 'time_spent',
type: 'number',
options: { min: 0 }
}),
app.models.NewSchemaField({
name: 'recurring_config',
type: 'json',
options: {}
}),
app.models.NewSchemaField({
name: 'attachments',
type: 'json',
options: {}
}),
app.models.NewSchemaField({
name: 'dependencies',
type: 'json',
options: {}
}),
app.models.NewSchemaField({
name: 'subtasks',
type: 'json',
options: {}
}),
app.models.NewSchemaField({
name: 'custom_fields',
type: 'json',
options: {}
}),
app.models.NewSchemaField({
name: 'completed_at',
type: 'date',
options: {}
})
]),
indexes: [
'CREATE INDEX idx_tasks_project_id ON tasks (project_id)',
'CREATE INDEX idx_tasks_milestone_id ON tasks (milestone_id)',
'CREATE INDEX idx_tasks_status ON tasks (status)',
'CREATE INDEX idx_tasks_priority ON tasks (priority)'
]
});
return app.save(collection);
},
down: async (app) => {
const collection = await app.findCollectionByNameOrId('tasks');
return app.delete(collection);
}
};
@@ -1,40 +0,0 @@
exports = {
up: async (app) => {
const collection = new app.models.Collection({
name: 'task_subtasks',
type: 'base',
schema: app.models.NewSchema([
app.models.NewSchemaField({
name: 'task_id',
type: 'relation',
required: true,
options: { collectionId: 'tasks', maxSelect: 1, cascadeDelete: true }
}),
app.models.NewSchemaField({
name: 'title',
type: 'text',
required: true,
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'done',
type: 'bool',
options: {}
}),
app.models.NewSchemaField({
name: 'sort_order',
type: 'number',
options: {}
})
]),
indexes: [
'CREATE INDEX idx_task_subtasks_task_id ON task_subtasks (task_id)'
]
});
return app.save(collection);
},
down: async (app) => {
const collection = await app.findCollectionByNameOrId('task_subtasks');
return app.delete(collection);
}
};
@@ -1,31 +0,0 @@
exports = {
up: async (app) => {
const collection = new app.models.Collection({
name: 'task_dependencies',
type: 'base',
schema: app.models.NewSchema([
app.models.NewSchemaField({
name: 'task_id',
type: 'relation',
required: true,
options: { collectionId: 'tasks', maxSelect: 1, cascadeDelete: true }
}),
app.models.NewSchemaField({
name: 'depends_on_task_id',
type: 'relation',
required: true,
options: { collectionId: 'tasks', maxSelect: 1, cascadeDelete: true }
})
]),
indexes: [
'CREATE INDEX idx_task_dependencies_task_id ON task_dependencies (task_id)',
'CREATE INDEX idx_task_dependencies_depends_on ON task_dependencies (depends_on_task_id)'
]
});
return app.save(collection);
},
down: async (app) => {
const collection = await app.findCollectionByNameOrId('task_dependencies');
return app.delete(collection);
}
};
@@ -1,45 +0,0 @@
exports = {
up: async (app) => {
const collection = new app.models.Collection({
name: 'task_attachments',
type: 'base',
schema: app.models.NewSchema([
app.models.NewSchemaField({
name: 'task_id',
type: 'relation',
required: true,
options: { collectionId: 'tasks', maxSelect: 1, cascadeDelete: true }
}),
app.models.NewSchemaField({
name: 'file',
type: 'file',
required: true,
options: { maxSelect: 1, maxSize: 5242880, mimeTypes: [] }
}),
app.models.NewSchemaField({
name: 'filename',
type: 'text',
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'mime_type',
type: 'text',
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'size',
type: 'number',
options: { min: 0 }
})
]),
indexes: [
'CREATE INDEX idx_task_attachments_task_id ON task_attachments (task_id)'
]
});
return app.save(collection);
},
down: async (app) => {
const collection = await app.findCollectionByNameOrId('task_attachments');
return app.delete(collection);
}
};
@@ -1,50 +0,0 @@
exports = {
up: async (app) => {
const collection = new app.models.Collection({
name: 'task_time_entries',
type: 'base',
schema: app.models.NewSchema([
app.models.NewSchemaField({
name: 'task_id',
type: 'relation',
required: true,
options: { collectionId: 'tasks', maxSelect: 1, cascadeDelete: true }
}),
app.models.NewSchemaField({
name: 'duration',
type: 'number',
required: true,
options: { min: 0 }
}),
app.models.NewSchemaField({
name: 'started_at',
type: 'date',
options: {}
}),
app.models.NewSchemaField({
name: 'ended_at',
type: 'date',
options: {}
}),
app.models.NewSchemaField({
name: 'source',
type: 'select',
options: { values: ['manual', 'timer', 'pomodoro'], maxSelect: 1 }
}),
app.models.NewSchemaField({
name: 'notes',
type: 'text',
options: {}
})
]),
indexes: [
'CREATE INDEX idx_task_time_entries_task_id ON task_time_entries (task_id)'
]
});
return app.save(collection);
},
down: async (app) => {
const collection = await app.findCollectionByNameOrId('task_time_entries');
return app.delete(collection);
}
};
@@ -1,119 +0,0 @@
exports = {
up: async (app) => {
const collection = new app.models.Collection({
name: 'habits',
type: 'base',
schema: app.models.NewSchema([
app.models.NewSchemaField({
name: 'title',
type: 'text',
required: true,
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'description',
type: 'text',
options: {}
}),
app.models.NewSchemaField({
name: 'frequency',
type: 'select',
options: { values: ['daily', 'weekly', 'custom'], maxSelect: 1 }
}),
app.models.NewSchemaField({
name: 'cron_expression',
type: 'text',
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'target_count',
type: 'number',
options: { min: 1 }
}),
app.models.NewSchemaField({
name: 'streak_current',
type: 'number',
options: { min: 0 }
}),
app.models.NewSchemaField({
name: 'streak_best',
type: 'number',
options: { min: 0 }
}),
app.models.NewSchemaField({
name: 'last_completed_at',
type: 'date',
options: {}
}),
app.models.NewSchemaField({
name: 'project_id',
type: 'relation',
options: { collectionId: 'projects', maxSelect: 1, cascadeDelete: false }
}),
app.models.NewSchemaField({
name: 'tags',
type: 'relation',
options: { collectionId: 'tags', maxSelect: 10, cascadeDelete: false }
}),
app.models.NewSchemaField({
name: 'domain',
type: 'relation',
options: { collectionId: 'domains', maxSelect: 1, cascadeDelete: false }
}),
app.models.NewSchemaField({
name: 'difficulty',
type: 'select',
options: { values: ['easy', 'medium', 'hard'], maxSelect: 1 }
}),
app.models.NewSchemaField({
name: 'mood_tracking',
type: 'bool',
options: {}
}),
app.models.NewSchemaField({
name: 'reminder_times',
type: 'json',
options: {}
}),
app.models.NewSchemaField({
name: 'skip_days',
type: 'json',
options: {}
}),
app.models.NewSchemaField({
name: 'unit',
type: 'text',
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'goal_per_period',
type: 'number',
options: { min: 0 }
}),
app.models.NewSchemaField({
name: 'score',
type: 'number',
options: { min: 0 }
}),
app.models.NewSchemaField({
name: 'score_config',
type: 'json',
options: {}
}),
app.models.NewSchemaField({
name: 'completion_mode',
type: 'select',
options: { values: ['quick', 'detailed'], maxSelect: 1 }
})
]),
indexes: [
'CREATE INDEX idx_habits_project_id ON habits (project_id)'
]
});
return app.save(collection);
},
down: async (app) => {
const collection = await app.findCollectionByNameOrId('habits');
return app.delete(collection);
}
};
@@ -1,46 +0,0 @@
exports = {
up: async (app) => {
const collection = new app.models.Collection({
name: 'habit_logs',
type: 'base',
schema: app.models.NewSchema([
app.models.NewSchemaField({
name: 'habit_id',
type: 'relation',
required: true,
options: { collectionId: 'habits', maxSelect: 1, cascadeDelete: true }
}),
app.models.NewSchemaField({
name: 'date',
type: 'date',
required: true,
options: {}
}),
app.models.NewSchemaField({
name: 'mood',
type: 'text',
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'quantity',
type: 'number',
options: { min: 0 }
}),
app.models.NewSchemaField({
name: 'notes',
type: 'text',
options: {}
})
]),
indexes: [
'CREATE INDEX idx_habit_logs_habit_id ON habit_logs (habit_id)',
'CREATE INDEX idx_habit_logs_date ON habit_logs (date)'
]
});
return app.save(collection);
},
down: async (app) => {
const collection = await app.findCollectionByNameOrId('habit_logs');
return app.delete(collection);
}
};
@@ -1,36 +0,0 @@
exports = {
up: async (app) => {
const collection = new app.models.Collection({
name: 'habit_skip_days',
type: 'base',
schema: app.models.NewSchema([
app.models.NewSchemaField({
name: 'habit_id',
type: 'relation',
required: true,
options: { collectionId: 'habits', maxSelect: 1, cascadeDelete: true }
}),
app.models.NewSchemaField({
name: 'date',
type: 'date',
required: true,
options: {}
}),
app.models.NewSchemaField({
name: 'reason',
type: 'text',
options: {}
})
]),
indexes: [
'CREATE INDEX idx_habit_skip_days_habit_id ON habit_skip_days (habit_id)',
'CREATE INDEX idx_habit_skip_days_date ON habit_skip_days (date)'
]
});
return app.save(collection);
},
down: async (app) => {
const collection = await app.findCollectionByNameOrId('habit_skip_days');
return app.delete(collection);
}
};
@@ -1,72 +0,0 @@
exports = {
up: async (app) => {
const collection = new app.models.Collection({
name: 'notes',
type: 'base',
schema: app.models.NewSchema([
app.models.NewSchemaField({
name: 'title',
type: 'text',
required: true,
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'content',
type: 'text',
options: {}
}),
app.models.NewSchemaField({
name: 'domain',
type: 'relation',
options: { collectionId: 'domains', maxSelect: 1, cascadeDelete: false }
}),
app.models.NewSchemaField({
name: 'tags',
type: 'relation',
options: { collectionId: 'tags', maxSelect: 10, cascadeDelete: false }
}),
app.models.NewSchemaField({
name: 'linked_entities',
type: 'json',
options: {}
}),
app.models.NewSchemaField({
name: 'created_by',
type: 'text',
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'ai_generated',
type: 'bool',
options: {}
}),
app.models.NewSchemaField({
name: 'bookmarked',
type: 'bool',
options: {}
}),
app.models.NewSchemaField({
name: 'pinned',
type: 'bool',
options: {}
}),
app.models.NewSchemaField({
name: 'frontmatter',
type: 'json',
options: {}
}),
app.models.NewSchemaField({
name: 'wikilinks',
type: 'json',
options: {}
})
]),
indexes: []
});
return app.save(collection);
},
down: async (app) => {
const collection = await app.findCollectionByNameOrId('notes');
return app.delete(collection);
}
};
@@ -1,36 +0,0 @@
exports = {
up: async (app) => {
const collection = new app.models.Collection({
name: 'note_links',
type: 'base',
schema: app.models.NewSchema([
app.models.NewSchemaField({
name: 'source_note_id',
type: 'relation',
required: true,
options: { collectionId: 'notes', maxSelect: 1, cascadeDelete: true }
}),
app.models.NewSchemaField({
name: 'target_note_id',
type: 'relation',
required: true,
options: { collectionId: 'notes', maxSelect: 1, cascadeDelete: true }
}),
app.models.NewSchemaField({
name: 'link_text',
type: 'text',
options: { maxSize: 255 }
})
]),
indexes: [
'CREATE INDEX idx_note_links_source ON note_links (source_note_id)',
'CREATE INDEX idx_note_links_target ON note_links (target_note_id)'
]
});
return app.save(collection);
},
down: async (app) => {
const collection = await app.findCollectionByNameOrId('note_links');
return app.delete(collection);
}
};
@@ -1,36 +0,0 @@
exports = {
up: async (app) => {
const collection = new app.models.Collection({
name: 'note_task_links',
type: 'base',
schema: app.models.NewSchema([
app.models.NewSchemaField({
name: 'note_id',
type: 'relation',
required: true,
options: { collectionId: 'notes', maxSelect: 1, cascadeDelete: true }
}),
app.models.NewSchemaField({
name: 'task_id',
type: 'relation',
required: true,
options: { collectionId: 'tasks', maxSelect: 1, cascadeDelete: true }
}),
app.models.NewSchemaField({
name: 'checkbox_position',
type: 'number',
options: {}
})
]),
indexes: [
'CREATE INDEX idx_note_task_links_note_id ON note_task_links (note_id)',
'CREATE INDEX idx_note_task_links_task_id ON note_task_links (task_id)'
]
});
return app.save(collection);
},
down: async (app) => {
const collection = await app.findCollectionByNameOrId('note_task_links');
return app.delete(collection);
}
};
@@ -1,42 +0,0 @@
exports = {
up: async (app) => {
const collection = new app.models.Collection({
name: 'report_templates',
type: 'base',
schema: app.models.NewSchema([
app.models.NewSchemaField({
name: 'name',
type: 'text',
required: true,
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'description',
type: 'text',
options: {}
}),
app.models.NewSchemaField({
name: 'report_type',
type: 'select',
options: { values: ['weekly', 'monthly', 'project', 'habit', 'custom'], maxSelect: 1 }
}),
app.models.NewSchemaField({
name: 'content_template',
type: 'text',
options: {}
}),
app.models.NewSchemaField({
name: 'is_builtin',
type: 'bool',
options: {}
})
]),
indexes: []
});
return app.save(collection);
},
down: async (app) => {
const collection = await app.findCollectionByNameOrId('report_templates');
return app.delete(collection);
}
};
@@ -1,72 +0,0 @@
exports = {
up: async (app) => {
const collection = new app.models.Collection({
name: 'reports',
type: 'base',
schema: app.models.NewSchema([
app.models.NewSchemaField({
name: 'title',
type: 'text',
required: true,
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'content',
type: 'text',
options: {}
}),
app.models.NewSchemaField({
name: 'report_type',
type: 'select',
options: { values: ['weekly', 'monthly', 'project', 'habit', 'custom'], maxSelect: 1 }
}),
app.models.NewSchemaField({
name: 'date_range_start',
type: 'date',
options: {}
}),
app.models.NewSchemaField({
name: 'date_range_end',
type: 'date',
options: {}
}),
app.models.NewSchemaField({
name: 'generated_by',
type: 'text',
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'ai_generated',
type: 'bool',
options: {}
}),
app.models.NewSchemaField({
name: 'linked_entities',
type: 'json',
options: {}
}),
app.models.NewSchemaField({
name: 'domain',
type: 'relation',
options: { collectionId: 'domains', maxSelect: 1, cascadeDelete: false }
}),
app.models.NewSchemaField({
name: 'tags',
type: 'relation',
options: { collectionId: 'tags', maxSelect: 10, cascadeDelete: false }
}),
app.models.NewSchemaField({
name: 'template_id',
type: 'relation',
options: { collectionId: 'report_templates', maxSelect: 1, cascadeDelete: false }
})
]),
indexes: []
});
return app.save(collection);
},
down: async (app) => {
const collection = await app.findCollectionByNameOrId('reports');
return app.delete(collection);
}
};
@@ -1,39 +0,0 @@
exports = {
up: async (app) => {
const collection = new app.models.Collection({
name: 'canvases',
type: 'base',
schema: app.models.NewSchema([
app.models.NewSchemaField({
name: 'name',
type: 'text',
required: true,
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'mode',
type: 'select',
options: { values: ['freeform', 'graph'], maxSelect: 1 }
}),
app.models.NewSchemaField({
name: 'project_id',
type: 'relation',
options: { collectionId: 'projects', maxSelect: 1, cascadeDelete: false }
}),
app.models.NewSchemaField({
name: 'state',
type: 'json',
options: {}
})
]),
indexes: [
'CREATE INDEX idx_canvases_project_id ON canvases (project_id)'
]
});
return app.save(collection);
},
down: async (app) => {
const collection = await app.findCollectionByNameOrId('canvases');
return app.delete(collection);
}
};
@@ -1,64 +0,0 @@
exports = {
up: async (app) => {
const collection = new app.models.Collection({
name: 'canvas_cards',
type: 'base',
schema: app.models.NewSchema([
app.models.NewSchemaField({
name: 'canvas_id',
type: 'relation',
required: true,
options: { collectionId: 'canvases', maxSelect: 1, cascadeDelete: true }
}),
app.models.NewSchemaField({
name: 'card_type',
type: 'select',
options: { values: ['note', 'task', 'image', 'entity'], maxSelect: 1 }
}),
app.models.NewSchemaField({
name: 'entity_id',
type: 'text',
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'entity_type',
type: 'text',
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'position_x',
type: 'number',
options: {}
}),
app.models.NewSchemaField({
name: 'position_y',
type: 'number',
options: {}
}),
app.models.NewSchemaField({
name: 'width',
type: 'number',
options: { min: 1 }
}),
app.models.NewSchemaField({
name: 'height',
type: 'number',
options: { min: 1 }
}),
app.models.NewSchemaField({
name: 'content',
type: 'json',
options: {}
})
]),
indexes: [
'CREATE INDEX idx_canvas_cards_canvas_id ON canvas_cards (canvas_id)'
]
});
return app.save(collection);
},
down: async (app) => {
const collection = await app.findCollectionByNameOrId('canvas_cards');
return app.delete(collection);
}
};
@@ -1,65 +0,0 @@
exports = {
up: async (app) => {
const collection = new app.models.Collection({
name: 'agents',
type: 'base',
schema: app.models.NewSchema([
app.models.NewSchemaField({
name: 'name',
type: 'text',
required: true,
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'api_key',
type: 'text',
required: true,
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'avatar',
type: 'text',
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'description',
type: 'text',
options: {}
}),
app.models.NewSchemaField({
name: 'permission_tier',
type: 'select',
options: { values: ['full_access', 'read_only', 'content_creator', 'task_manager', 'custom'], maxSelect: 1 }
}),
app.models.NewSchemaField({
name: 'custom_permissions',
type: 'json',
options: {}
}),
app.models.NewSchemaField({
name: 'webhook_url',
type: 'text',
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'last_activity_at',
type: 'date',
options: {}
}),
app.models.NewSchemaField({
name: 'status',
type: 'select',
options: { values: ['active', 'disabled'], maxSelect: 1 }
})
]),
indexes: [
'CREATE UNIQUE INDEX idx_agents_api_key ON agents (api_key)'
]
});
return app.save(collection);
},
down: async (app) => {
const collection = await app.findCollectionByNameOrId('agents');
return app.delete(collection);
}
};
@@ -1,59 +0,0 @@
exports = {
up: async (app) => {
const collection = new app.models.Collection({
name: 'agent_activity',
type: 'base',
schema: app.models.NewSchema([
app.models.NewSchemaField({
name: 'agent_id',
type: 'relation',
required: true,
options: { collectionId: 'agents', maxSelect: 1, cascadeDelete: true }
}),
app.models.NewSchemaField({
name: 'action',
type: 'text',
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'entity_type',
type: 'text',
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'entity_id',
type: 'text',
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'before_state',
type: 'json',
options: {}
}),
app.models.NewSchemaField({
name: 'after_state',
type: 'json',
options: {}
}),
app.models.NewSchemaField({
name: 'prompt',
type: 'text',
options: {}
}),
app.models.NewSchemaField({
name: 'response',
type: 'text',
options: {}
})
]),
indexes: [
'CREATE INDEX idx_agent_activity_agent_id ON agent_activity (agent_id)'
]
});
return app.save(collection);
},
down: async (app) => {
const collection = await app.findCollectionByNameOrId('agent_activity');
return app.delete(collection);
}
};
@@ -1,43 +0,0 @@
exports = {
up: async (app) => {
const collection = new app.models.Collection({
name: 'webhooks',
type: 'base',
schema: app.models.NewSchema([
app.models.NewSchemaField({
name: 'name',
type: 'text',
required: true,
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'url',
type: 'text',
required: true,
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'events',
type: 'json',
options: {}
}),
app.models.NewSchemaField({
name: 'secret',
type: 'text',
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'active',
type: 'bool',
options: {}
})
]),
indexes: []
});
return app.save(collection);
},
down: async (app) => {
const collection = await app.findCollectionByNameOrId('webhooks');
return app.delete(collection);
}
};
@@ -1,54 +0,0 @@
exports = {
up: async (app) => {
const collection = new app.models.Collection({
name: 'webhook_deliveries',
type: 'base',
schema: app.models.NewSchema([
app.models.NewSchemaField({
name: 'webhook_id',
type: 'relation',
required: true,
options: { collectionId: 'webhooks', maxSelect: 1, cascadeDelete: true }
}),
app.models.NewSchemaField({
name: 'event_type',
type: 'text',
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'payload',
type: 'json',
options: {}
}),
app.models.NewSchemaField({
name: 'response_status',
type: 'number',
options: {}
}),
app.models.NewSchemaField({
name: 'response_body',
type: 'text',
options: {}
}),
app.models.NewSchemaField({
name: 'success',
type: 'bool',
options: {}
}),
app.models.NewSchemaField({
name: 'attempts',
type: 'number',
options: { min: 0 }
})
]),
indexes: [
'CREATE INDEX idx_webhook_deliveries_webhook_id ON webhook_deliveries (webhook_id)'
]
});
return app.save(collection);
},
down: async (app) => {
const collection = await app.findCollectionByNameOrId('webhook_deliveries');
return app.delete(collection);
}
};
@@ -1,50 +0,0 @@
exports = {
up: async (app) => {
const collection = new app.models.Collection({
name: 'agent_tasks',
type: 'base',
schema: app.models.NewSchema([
app.models.NewSchemaField({
name: 'agent_id',
type: 'relation',
required: true,
options: { collectionId: 'agents', maxSelect: 1, cascadeDelete: true }
}),
app.models.NewSchemaField({
name: 'entity_type',
type: 'text',
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'entity_id',
type: 'text',
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'instruction',
type: 'text',
options: {}
}),
app.models.NewSchemaField({
name: 'status',
type: 'select',
options: { values: ['pending', 'in_progress', 'completed', 'failed', 'delivery_failed'], maxSelect: 1 }
}),
app.models.NewSchemaField({
name: 'result',
type: 'json',
options: {}
})
]),
indexes: [
'CREATE INDEX idx_agent_tasks_agent_id ON agent_tasks (agent_id)',
'CREATE INDEX idx_agent_tasks_status ON agent_tasks (status)'
]
});
return app.save(collection);
},
down: async (app) => {
const collection = await app.findCollectionByNameOrId('agent_tasks');
return app.delete(collection);
}
};
@@ -1,49 +0,0 @@
exports = {
up: async (app) => {
const collection = new app.models.Collection({
name: 'notifications',
type: 'base',
schema: app.models.NewSchema([
app.models.NewSchemaField({
name: 'title',
type: 'text',
required: true,
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'message',
type: 'text',
options: {}
}),
app.models.NewSchemaField({
name: 'type',
type: 'select',
options: { values: ['info', 'success', 'warning', 'error'], maxSelect: 1 }
}),
app.models.NewSchemaField({
name: 'entity_type',
type: 'text',
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'entity_id',
type: 'text',
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'read',
type: 'bool',
options: {}
})
]),
indexes: [
'CREATE INDEX idx_notifications_read ON notifications (read)'
]
});
return app.save(collection);
},
down: async (app) => {
const collection = await app.findCollectionByNameOrId('notifications');
return app.delete(collection);
}
};
@@ -1,44 +0,0 @@
exports = {
up: async (app) => {
const collection = new app.models.Collection({
name: 'error_logs',
type: 'base',
schema: app.models.NewSchema([
app.models.NewSchemaField({
name: 'code',
type: 'text',
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'message',
type: 'text',
options: {}
}),
app.models.NewSchemaField({
name: 'details',
type: 'json',
options: {}
}),
app.models.NewSchemaField({
name: 'stack_trace',
type: 'text',
options: {}
}),
app.models.NewSchemaField({
name: 'source',
type: 'text',
options: { maxSize: 255 }
})
]),
indexes: [
'CREATE INDEX idx_error_logs_code ON error_logs (code)',
'CREATE INDEX idx_error_logs_source ON error_logs (source)'
]
});
return app.save(collection);
},
down: async (app) => {
const collection = await app.findCollectionByNameOrId('error_logs');
return app.delete(collection);
}
};
@@ -1,66 +0,0 @@
exports = {
up: async (app) => {
const collection = new app.models.Collection({
name: 'queue_jobs',
type: 'base',
schema: app.models.NewSchema([
app.models.NewSchemaField({
name: 'job_type',
type: 'text',
required: true,
options: { maxSize: 255 }
}),
app.models.NewSchemaField({
name: 'payload',
type: 'json',
options: {}
}),
app.models.NewSchemaField({
name: 'status',
type: 'select',
options: { values: ['pending', 'in_progress', 'completed', 'failed'], maxSelect: 1 }
}),
app.models.NewSchemaField({
name: 'attempts',
type: 'number',
options: { min: 0 }
}),
app.models.NewSchemaField({
name: 'max_attempts',
type: 'number',
options: { min: 1 }
}),
app.models.NewSchemaField({
name: 'error',
type: 'text',
options: {}
}),
app.models.NewSchemaField({
name: 'scheduled_at',
type: 'date',
options: {}
}),
app.models.NewSchemaField({
name: 'started_at',
type: 'date',
options: {}
}),
app.models.NewSchemaField({
name: 'completed_at',
type: 'date',
options: {}
})
]),
indexes: [
'CREATE INDEX idx_queue_jobs_status ON queue_jobs (status)',
'CREATE INDEX idx_queue_jobs_scheduled_at ON queue_jobs (scheduled_at)',
'CREATE INDEX idx_queue_jobs_job_type ON queue_jobs (job_type)'
]
});
return app.save(collection);
},
down: async (app) => {
const collection = await app.findCollectionByNameOrId('queue_jobs');
return app.delete(collection);
}
};