WIP - scaffold approvals
This commit is contained in:
@@ -0,0 +1,190 @@
|
||||
exports.up = async function (knex) {
|
||||
await knex.schema.createTable('approval_definitions', (table) => {
|
||||
table.string('id', 191).primary().defaultTo(knex.raw('(UUID())'));
|
||||
table.string('name', 191).notNullable();
|
||||
table.text('description');
|
||||
table.string('triggerType', 191).notNullable();
|
||||
table.string('targetObjectType', 191);
|
||||
table.json('entryCriteria');
|
||||
table.json('steps');
|
||||
table.json('votingPolicy');
|
||||
table.string('rejectionRule', 191);
|
||||
table.string('materialChangePolicy', 191);
|
||||
table.integer('version').notNullable().defaultTo(1);
|
||||
table.boolean('isActive').notNullable().defaultTo(true);
|
||||
table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now());
|
||||
table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now());
|
||||
});
|
||||
|
||||
await knex.schema.createTable('approval_requests', (table) => {
|
||||
table.string('id', 191).primary().defaultTo(knex.raw('(UUID())'));
|
||||
table.string('definitionId', 191).notNullable();
|
||||
table.string('status', 191).notNullable().defaultTo('pending');
|
||||
table.string('targetObjectType', 191).notNullable();
|
||||
table.string('targetObjectId', 191).notNullable();
|
||||
table.string('action', 191);
|
||||
table.string('stateFrom', 191);
|
||||
table.string('stateTo', 191);
|
||||
table.json('fieldChanges');
|
||||
table.json('snapshot');
|
||||
table.string('versionHash', 191);
|
||||
table.string('submittedById', 191);
|
||||
table.timestamp('submittedAt');
|
||||
table.string('currentStepKey', 191);
|
||||
table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now());
|
||||
table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now());
|
||||
|
||||
table.index(['definitionId']);
|
||||
table.index(['targetObjectType', 'targetObjectId']);
|
||||
table.index(['submittedById']);
|
||||
table
|
||||
.foreign('definitionId')
|
||||
.references('id')
|
||||
.inTable('approval_definitions')
|
||||
.onDelete('CASCADE')
|
||||
.onUpdate('CASCADE');
|
||||
table
|
||||
.foreign('submittedById')
|
||||
.references('id')
|
||||
.inTable('users')
|
||||
.onDelete('SET NULL')
|
||||
.onUpdate('CASCADE');
|
||||
});
|
||||
|
||||
await knex.schema.createTable('approval_steps', (table) => {
|
||||
table.string('id', 191).primary().defaultTo(knex.raw('(UUID())'));
|
||||
table.string('requestId', 191).notNullable();
|
||||
table.string('stepKey', 191).notNullable();
|
||||
table.string('name', 191).notNullable();
|
||||
table.integer('stepOrder').notNullable();
|
||||
table.string('status', 191).notNullable().defaultTo('pending');
|
||||
table.json('routing');
|
||||
table.json('voting');
|
||||
table.timestamp('dueAt');
|
||||
table.timestamp('completedAt');
|
||||
table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now());
|
||||
table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now());
|
||||
|
||||
table.index(['requestId']);
|
||||
table.index(['status']);
|
||||
table
|
||||
.foreign('requestId')
|
||||
.references('id')
|
||||
.inTable('approval_requests')
|
||||
.onDelete('CASCADE')
|
||||
.onUpdate('CASCADE');
|
||||
});
|
||||
|
||||
await knex.schema.createTable('approval_assignments', (table) => {
|
||||
table.string('id', 191).primary().defaultTo(knex.raw('(UUID())'));
|
||||
table.string('stepId', 191).notNullable();
|
||||
table.string('assigneeId', 191).notNullable();
|
||||
table.string('status', 191).notNullable().defaultTo('pending');
|
||||
table.text('response');
|
||||
table.timestamp('respondedAt');
|
||||
table.timestamp('dueAt');
|
||||
table.string('reassignedFromId', 191);
|
||||
table.string('delegatedById', 191);
|
||||
table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now());
|
||||
table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now());
|
||||
|
||||
table.index(['stepId']);
|
||||
table.index(['assigneeId']);
|
||||
table.index(['status']);
|
||||
table
|
||||
.foreign('stepId')
|
||||
.references('id')
|
||||
.inTable('approval_steps')
|
||||
.onDelete('CASCADE')
|
||||
.onUpdate('CASCADE');
|
||||
table
|
||||
.foreign('assigneeId')
|
||||
.references('id')
|
||||
.inTable('users')
|
||||
.onDelete('RESTRICT')
|
||||
.onUpdate('CASCADE');
|
||||
table
|
||||
.foreign('reassignedFromId')
|
||||
.references('id')
|
||||
.inTable('users')
|
||||
.onDelete('SET NULL')
|
||||
.onUpdate('CASCADE');
|
||||
table
|
||||
.foreign('delegatedById')
|
||||
.references('id')
|
||||
.inTable('users')
|
||||
.onDelete('SET NULL')
|
||||
.onUpdate('CASCADE');
|
||||
});
|
||||
|
||||
await knex.schema.createTable('approval_effect_logs', (table) => {
|
||||
table.string('id', 191).primary().defaultTo(knex.raw('(UUID())'));
|
||||
table.string('requestId', 191).notNullable();
|
||||
table.string('effectKey', 191).notNullable();
|
||||
table.string('status', 191).notNullable().defaultTo('success');
|
||||
table.json('response');
|
||||
table.timestamp('executedAt').notNullable().defaultTo(knex.fn.now());
|
||||
|
||||
table.unique(['requestId', 'effectKey']);
|
||||
table.index(['requestId']);
|
||||
table
|
||||
.foreign('requestId')
|
||||
.references('id')
|
||||
.inTable('approval_requests')
|
||||
.onDelete('CASCADE')
|
||||
.onUpdate('CASCADE');
|
||||
});
|
||||
|
||||
await knex.schema.createTable('tasks', (table) => {
|
||||
table.string('id', 191).primary().defaultTo(knex.raw('(UUID())'));
|
||||
table.string('title', 191).notNullable();
|
||||
table.text('description');
|
||||
table.string('status', 191).notNullable().defaultTo('open');
|
||||
table.string('priority', 191);
|
||||
table.timestamp('dueAt');
|
||||
table.string('assignedToId', 191);
|
||||
table.string('relatedObjectType', 191);
|
||||
table.string('relatedObjectId', 191);
|
||||
table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now());
|
||||
table.timestamp('updatedAt').notNullable().defaultTo(knex.fn.now());
|
||||
|
||||
table.index(['assignedToId']);
|
||||
table.index(['relatedObjectType', 'relatedObjectId']);
|
||||
table
|
||||
.foreign('assignedToId')
|
||||
.references('id')
|
||||
.inTable('users')
|
||||
.onDelete('SET NULL')
|
||||
.onUpdate('CASCADE');
|
||||
});
|
||||
|
||||
await knex.schema.createTable('activity_logs', (table) => {
|
||||
table.string('id', 191).primary().defaultTo(knex.raw('(UUID())'));
|
||||
table.string('action', 191).notNullable();
|
||||
table.string('subjectType', 191).notNullable();
|
||||
table.string('subjectId', 191).notNullable();
|
||||
table.text('description');
|
||||
table.json('properties');
|
||||
table.string('causerId', 191);
|
||||
table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now());
|
||||
|
||||
table.index(['subjectType', 'subjectId']);
|
||||
table.index(['causerId']);
|
||||
table
|
||||
.foreign('causerId')
|
||||
.references('id')
|
||||
.inTable('users')
|
||||
.onDelete('SET NULL')
|
||||
.onUpdate('CASCADE');
|
||||
});
|
||||
};
|
||||
|
||||
exports.down = async function (knex) {
|
||||
await knex.schema.dropTableIfExists('activity_logs');
|
||||
await knex.schema.dropTableIfExists('tasks');
|
||||
await knex.schema.dropTableIfExists('approval_effect_logs');
|
||||
await knex.schema.dropTableIfExists('approval_assignments');
|
||||
await knex.schema.dropTableIfExists('approval_steps');
|
||||
await knex.schema.dropTableIfExists('approval_requests');
|
||||
await knex.schema.dropTableIfExists('approval_definitions');
|
||||
};
|
||||
Reference in New Issue
Block a user