exports.up = async function (knex) { await knex.schema.createTable('ai_processes', (table) => { table.uuid('id').primary(); table.string('tenant_id').notNullable(); table.string('name').notNullable(); table.text('description'); table.integer('latest_version').notNullable().defaultTo(1); table.string('created_by').notNullable(); table.timestamp('created_at').defaultTo(knex.fn.now()); table.timestamp('updated_at').defaultTo(knex.fn.now()); table.index(['tenant_id']); }); await knex.schema.createTable('ai_process_versions', (table) => { table.uuid('id').primary(); table.string('tenant_id').notNullable(); table.uuid('process_id').notNullable(); table.integer('version').notNullable(); table.json('graph_json').notNullable(); table.json('compiled_json').notNullable(); table.string('created_by').notNullable(); table.timestamp('created_at').defaultTo(knex.fn.now()); table.unique(['process_id', 'version']); table.index(['tenant_id']); table.index(['process_id']); }); await knex.schema.createTable('ai_process_runs', (table) => { table.uuid('id').primary(); table.string('tenant_id').notNullable(); table.uuid('process_id').notNullable(); table.integer('version').notNullable(); table.string('status').notNullable(); table.json('input_json').notNullable(); table.json('output_json'); table.json('error_json'); table.json('state_json'); table.string('current_node_id'); table.timestamp('started_at').defaultTo(knex.fn.now()); table.timestamp('ended_at'); table.index(['tenant_id']); table.index(['process_id']); }); await knex.schema.createTable('ai_chat_sessions', (table) => { table.uuid('id').primary(); table.string('tenant_id').notNullable(); table.string('user_id').notNullable(); table.timestamp('created_at').defaultTo(knex.fn.now()); table.index(['tenant_id']); table.index(['user_id']); }); await knex.schema.createTable('ai_chat_messages', (table) => { table.uuid('id').primary(); table.uuid('session_id').notNullable(); table.string('role').notNullable(); table.text('content').notNullable(); table.timestamp('created_at').defaultTo(knex.fn.now()); table.index(['session_id']); }); await knex.schema.createTable('ai_audit_events', (table) => { table.uuid('id').primary(); table.string('tenant_id').notNullable(); table.uuid('run_id').notNullable(); table.string('event_type').notNullable(); table.json('payload_json').notNullable(); table.timestamp('created_at').defaultTo(knex.fn.now()); table.index(['tenant_id']); table.index(['run_id']); }); }; exports.down = async function (knex) { await knex.schema.dropTableIfExists('ai_audit_events'); await knex.schema.dropTableIfExists('ai_chat_messages'); await knex.schema.dropTableIfExists('ai_chat_sessions'); await knex.schema.dropTableIfExists('ai_process_runs'); await knex.schema.dropTableIfExists('ai_process_versions'); await knex.schema.dropTableIfExists('ai_processes'); };