38418-vm/backend/src/db/migrations/1771037054124.js
2026-02-14 02:45:34 +00:00

3163 lines
100 KiB
JavaScript

module.exports = {
/**
* @param {QueryInterface} queryInterface
* @param {Sequelize} Sequelize
* @returns {Promise<void>}
*/
async up(queryInterface, Sequelize) {
/**
* @type {Transaction}
*/
const transaction = await queryInterface.sequelize.transaction();
try {
await queryInterface.createTable('users', {
id: {
type: Sequelize.DataTypes.UUID,
defaultValue: Sequelize.DataTypes.UUIDV4,
primaryKey: true,
},
createdById: {
type: Sequelize.DataTypes.UUID,
references: {
key: 'id',
model: 'users',
},
},
updatedById: {
type: Sequelize.DataTypes.UUID,
references: {
key: 'id',
model: 'users',
},
},
createdAt: { type: Sequelize.DataTypes.DATE },
updatedAt: { type: Sequelize.DataTypes.DATE },
deletedAt: { type: Sequelize.DataTypes.DATE },
importHash: {
type: Sequelize.DataTypes.STRING(255),
allowNull: true,
unique: true,
},
}, { transaction });
await queryInterface.createTable('roles', {
id: {
type: Sequelize.DataTypes.UUID,
defaultValue: Sequelize.DataTypes.UUIDV4,
primaryKey: true,
},
createdById: {
type: Sequelize.DataTypes.UUID,
references: {
key: 'id',
model: 'users',
},
},
updatedById: {
type: Sequelize.DataTypes.UUID,
references: {
key: 'id',
model: 'users',
},
},
createdAt: { type: Sequelize.DataTypes.DATE },
updatedAt: { type: Sequelize.DataTypes.DATE },
deletedAt: { type: Sequelize.DataTypes.DATE },
importHash: {
type: Sequelize.DataTypes.STRING(255),
allowNull: true,
unique: true,
},
}, { transaction });
await queryInterface.createTable('permissions', {
id: {
type: Sequelize.DataTypes.UUID,
defaultValue: Sequelize.DataTypes.UUIDV4,
primaryKey: true,
},
createdById: {
type: Sequelize.DataTypes.UUID,
references: {
key: 'id',
model: 'users',
},
},
updatedById: {
type: Sequelize.DataTypes.UUID,
references: {
key: 'id',
model: 'users',
},
},
createdAt: { type: Sequelize.DataTypes.DATE },
updatedAt: { type: Sequelize.DataTypes.DATE },
deletedAt: { type: Sequelize.DataTypes.DATE },
importHash: {
type: Sequelize.DataTypes.STRING(255),
allowNull: true,
unique: true,
},
}, { transaction });
await queryInterface.createTable('gamepads', {
id: {
type: Sequelize.DataTypes.UUID,
defaultValue: Sequelize.DataTypes.UUIDV4,
primaryKey: true,
},
createdById: {
type: Sequelize.DataTypes.UUID,
references: {
key: 'id',
model: 'users',
},
},
updatedById: {
type: Sequelize.DataTypes.UUID,
references: {
key: 'id',
model: 'users',
},
},
createdAt: { type: Sequelize.DataTypes.DATE },
updatedAt: { type: Sequelize.DataTypes.DATE },
deletedAt: { type: Sequelize.DataTypes.DATE },
importHash: {
type: Sequelize.DataTypes.STRING(255),
allowNull: true,
unique: true,
},
}, { transaction });
await queryInterface.createTable('device_profiles', {
id: {
type: Sequelize.DataTypes.UUID,
defaultValue: Sequelize.DataTypes.UUIDV4,
primaryKey: true,
},
createdById: {
type: Sequelize.DataTypes.UUID,
references: {
key: 'id',
model: 'users',
},
},
updatedById: {
type: Sequelize.DataTypes.UUID,
references: {
key: 'id',
model: 'users',
},
},
createdAt: { type: Sequelize.DataTypes.DATE },
updatedAt: { type: Sequelize.DataTypes.DATE },
deletedAt: { type: Sequelize.DataTypes.DATE },
importHash: {
type: Sequelize.DataTypes.STRING(255),
allowNull: true,
unique: true,
},
}, { transaction });
await queryInterface.createTable('massage_programs', {
id: {
type: Sequelize.DataTypes.UUID,
defaultValue: Sequelize.DataTypes.UUIDV4,
primaryKey: true,
},
createdById: {
type: Sequelize.DataTypes.UUID,
references: {
key: 'id',
model: 'users',
},
},
updatedById: {
type: Sequelize.DataTypes.UUID,
references: {
key: 'id',
model: 'users',
},
},
createdAt: { type: Sequelize.DataTypes.DATE },
updatedAt: { type: Sequelize.DataTypes.DATE },
deletedAt: { type: Sequelize.DataTypes.DATE },
importHash: {
type: Sequelize.DataTypes.STRING(255),
allowNull: true,
unique: true,
},
}, { transaction });
await queryInterface.createTable('haptic_patterns', {
id: {
type: Sequelize.DataTypes.UUID,
defaultValue: Sequelize.DataTypes.UUIDV4,
primaryKey: true,
},
createdById: {
type: Sequelize.DataTypes.UUID,
references: {
key: 'id',
model: 'users',
},
},
updatedById: {
type: Sequelize.DataTypes.UUID,
references: {
key: 'id',
model: 'users',
},
},
createdAt: { type: Sequelize.DataTypes.DATE },
updatedAt: { type: Sequelize.DataTypes.DATE },
deletedAt: { type: Sequelize.DataTypes.DATE },
importHash: {
type: Sequelize.DataTypes.STRING(255),
allowNull: true,
unique: true,
},
}, { transaction });
await queryInterface.createTable('haptic_steps', {
id: {
type: Sequelize.DataTypes.UUID,
defaultValue: Sequelize.DataTypes.UUIDV4,
primaryKey: true,
},
createdById: {
type: Sequelize.DataTypes.UUID,
references: {
key: 'id',
model: 'users',
},
},
updatedById: {
type: Sequelize.DataTypes.UUID,
references: {
key: 'id',
model: 'users',
},
},
createdAt: { type: Sequelize.DataTypes.DATE },
updatedAt: { type: Sequelize.DataTypes.DATE },
deletedAt: { type: Sequelize.DataTypes.DATE },
importHash: {
type: Sequelize.DataTypes.STRING(255),
allowNull: true,
unique: true,
},
}, { transaction });
await queryInterface.createTable('massage_sessions', {
id: {
type: Sequelize.DataTypes.UUID,
defaultValue: Sequelize.DataTypes.UUIDV4,
primaryKey: true,
},
createdById: {
type: Sequelize.DataTypes.UUID,
references: {
key: 'id',
model: 'users',
},
},
updatedById: {
type: Sequelize.DataTypes.UUID,
references: {
key: 'id',
model: 'users',
},
},
createdAt: { type: Sequelize.DataTypes.DATE },
updatedAt: { type: Sequelize.DataTypes.DATE },
deletedAt: { type: Sequelize.DataTypes.DATE },
importHash: {
type: Sequelize.DataTypes.STRING(255),
allowNull: true,
unique: true,
},
}, { transaction });
await queryInterface.createTable('calibration_runs', {
id: {
type: Sequelize.DataTypes.UUID,
defaultValue: Sequelize.DataTypes.UUIDV4,
primaryKey: true,
},
createdById: {
type: Sequelize.DataTypes.UUID,
references: {
key: 'id',
model: 'users',
},
},
updatedById: {
type: Sequelize.DataTypes.UUID,
references: {
key: 'id',
model: 'users',
},
},
createdAt: { type: Sequelize.DataTypes.DATE },
updatedAt: { type: Sequelize.DataTypes.DATE },
deletedAt: { type: Sequelize.DataTypes.DATE },
importHash: {
type: Sequelize.DataTypes.STRING(255),
allowNull: true,
unique: true,
},
}, { transaction });
await queryInterface.createTable('safety_events', {
id: {
type: Sequelize.DataTypes.UUID,
defaultValue: Sequelize.DataTypes.UUIDV4,
primaryKey: true,
},
createdById: {
type: Sequelize.DataTypes.UUID,
references: {
key: 'id',
model: 'users',
},
},
updatedById: {
type: Sequelize.DataTypes.UUID,
references: {
key: 'id',
model: 'users',
},
},
createdAt: { type: Sequelize.DataTypes.DATE },
updatedAt: { type: Sequelize.DataTypes.DATE },
deletedAt: { type: Sequelize.DataTypes.DATE },
importHash: {
type: Sequelize.DataTypes.STRING(255),
allowNull: true,
unique: true,
},
}, { transaction });
await queryInterface.createTable('user_preferences', {
id: {
type: Sequelize.DataTypes.UUID,
defaultValue: Sequelize.DataTypes.UUIDV4,
primaryKey: true,
},
createdById: {
type: Sequelize.DataTypes.UUID,
references: {
key: 'id',
model: 'users',
},
},
updatedById: {
type: Sequelize.DataTypes.UUID,
references: {
key: 'id',
model: 'users',
},
},
createdAt: { type: Sequelize.DataTypes.DATE },
updatedAt: { type: Sequelize.DataTypes.DATE },
deletedAt: { type: Sequelize.DataTypes.DATE },
importHash: {
type: Sequelize.DataTypes.STRING(255),
allowNull: true,
unique: true,
},
}, { transaction });
await queryInterface.addColumn(
'users',
'firstName',
{
type: Sequelize.DataTypes.TEXT,
},
{ transaction }
);
await queryInterface.addColumn(
'users',
'lastName',
{
type: Sequelize.DataTypes.TEXT,
},
{ transaction }
);
await queryInterface.addColumn(
'users',
'phoneNumber',
{
type: Sequelize.DataTypes.TEXT,
},
{ transaction }
);
await queryInterface.addColumn(
'users',
'email',
{
type: Sequelize.DataTypes.TEXT,
},
{ transaction }
);
await queryInterface.addColumn(
'users',
'disabled',
{
type: Sequelize.DataTypes.BOOLEAN,
defaultValue: false,
allowNull: false,
},
{ transaction }
);
await queryInterface.addColumn(
'users',
'password',
{
type: Sequelize.DataTypes.TEXT,
},
{ transaction }
);
await queryInterface.addColumn(
'users',
'emailVerified',
{
type: Sequelize.DataTypes.BOOLEAN,
defaultValue: false,
allowNull: false,
},
{ transaction }
);
await queryInterface.addColumn(
'users',
'emailVerificationToken',
{
type: Sequelize.DataTypes.TEXT,
},
{ transaction }
);
await queryInterface.addColumn(
'users',
'emailVerificationTokenExpiresAt',
{
type: Sequelize.DataTypes.DATE,
},
{ transaction }
);
await queryInterface.addColumn(
'users',
'passwordResetToken',
{
type: Sequelize.DataTypes.TEXT,
},
{ transaction }
);
await queryInterface.addColumn(
'users',
'passwordResetTokenExpiresAt',
{
type: Sequelize.DataTypes.DATE,
},
{ transaction }
);
await queryInterface.addColumn(
'users',
'provider',
{
type: Sequelize.DataTypes.TEXT,
},
{ transaction }
);
await queryInterface.addColumn(
'users',
'app_roleId',
{
type: Sequelize.DataTypes.UUID,
references: {
model: 'roles',
key: 'id',
},
},
{ transaction }
);
await queryInterface.addColumn(
'roles',
'name',
{
type: Sequelize.DataTypes.TEXT,
},
{ transaction }
);
await queryInterface.addColumn(
'roles',
'role_customization',
{
type: Sequelize.DataTypes.TEXT,
},
{ transaction }
);
await queryInterface.addColumn(
'permissions',
'name',
{
type: Sequelize.DataTypes.TEXT,
},
{ transaction }
);
await queryInterface.addColumn(
'gamepads',
'display_name',
{
type: Sequelize.DataTypes.TEXT,
},
{ transaction }
);
await queryInterface.addColumn(
'gamepads',
'vendor',
{
type: Sequelize.DataTypes.TEXT,
},
{ transaction }
);
await queryInterface.addColumn(
'gamepads',
'product',
{
type: Sequelize.DataTypes.TEXT,
},
{ transaction }
);
await queryInterface.addColumn(
'gamepads',
'mapping',
{
type: Sequelize.DataTypes.TEXT,
},
{ transaction }
);
await queryInterface.addColumn(
'gamepads',
'connection_type',
{
type: Sequelize.DataTypes.TEXT,
},
{ transaction }
);
await queryInterface.addColumn(
'gamepads',
'supports_vibration',
{
type: Sequelize.DataTypes.BOOLEAN,
defaultValue: false,
allowNull: false,
},
{ transaction }
);
await queryInterface.addColumn(
'gamepads',
'axes_count',
{
type: Sequelize.DataTypes.INTEGER,
},
{ transaction }
);
await queryInterface.addColumn(
'gamepads',
'buttons_count',
{
type: Sequelize.DataTypes.INTEGER,
},
{ transaction }
);
await queryInterface.addColumn(
'gamepads',
'notes',
{
type: Sequelize.DataTypes.TEXT,
},
{ transaction }
);
await queryInterface.addColumn(
'device_profiles',
'name',
{
type: Sequelize.DataTypes.TEXT,
},
{ transaction }
);
await queryInterface.addColumn(
'device_profiles',
'description',
{
type: Sequelize.DataTypes.TEXT,
},
{ transaction }
);
await queryInterface.addColumn(
'device_profiles',
'userId',
{
type: Sequelize.DataTypes.UUID,
references: {
model: 'users',
key: 'id',
},
},
{ transaction }
);
await queryInterface.addColumn(
'device_profiles',
'gamepadId',
{
type: Sequelize.DataTypes.UUID,
references: {
model: 'gamepads',
key: 'id',
},
},
{ transaction }
);
await queryInterface.addColumn(
'device_profiles',
'left_motor_gain',
{
type: Sequelize.DataTypes.DECIMAL,
},
{ transaction }
);
await queryInterface.addColumn(
'device_profiles',
'right_motor_gain',
{
type: Sequelize.DataTypes.DECIMAL,
},
{ transaction }
);
await queryInterface.addColumn(
'device_profiles',
'overall_gain',
{
type: Sequelize.DataTypes.DECIMAL,
},
{ transaction }
);
await queryInterface.addColumn(
'device_profiles',
'max_duration_seconds',
{
type: Sequelize.DataTypes.INTEGER,
},
{ transaction }
);
await queryInterface.addColumn(
'device_profiles',
'safety_cutoff_enabled',
{
type: Sequelize.DataTypes.BOOLEAN,
defaultValue: false,
allowNull: false,
},
{ transaction }
);
await queryInterface.addColumn(
'device_profiles',
'deadzone',
{
type: Sequelize.DataTypes.DECIMAL,
},
{ transaction }
);
await queryInterface.addColumn(
'device_profiles',
'intensity_curve',
{
type: Sequelize.DataTypes.ENUM,
values: ['linear','ease_in','ease_out','ease_in_out'],
},
{ transaction }
);
await queryInterface.addColumn(
'massage_programs',
'name',
{
type: Sequelize.DataTypes.TEXT,
},
{ transaction }
);
await queryInterface.addColumn(
'massage_programs',
'summary',
{
type: Sequelize.DataTypes.TEXT,
},
{ transaction }
);
await queryInterface.addColumn(
'massage_programs',
'visibility',
{
type: Sequelize.DataTypes.ENUM,
values: ['public','unlisted','private'],
},
{ transaction }
);
await queryInterface.addColumn(
'massage_programs',
'category',
{
type: Sequelize.DataTypes.ENUM,
values: ['relax','deep_tissue','pulsing','wave','focus_left','focus_right','custom'],
},
{ transaction }
);
await queryInterface.addColumn(
'massage_programs',
'default_duration_seconds',
{
type: Sequelize.DataTypes.INTEGER,
},
{ transaction }
);
await queryInterface.addColumn(
'massage_programs',
'bpm',
{
type: Sequelize.DataTypes.INTEGER,
},
{ transaction }
);
await queryInterface.addColumn(
'massage_programs',
'base_intensity',
{
type: Sequelize.DataTypes.DECIMAL,
},
{ transaction }
);
await queryInterface.addColumn(
'massage_programs',
'left_bias',
{
type: Sequelize.DataTypes.DECIMAL,
},
{ transaction }
);
await queryInterface.addColumn(
'massage_programs',
'right_bias',
{
type: Sequelize.DataTypes.DECIMAL,
},
{ transaction }
);
await queryInterface.addColumn(
'massage_programs',
'authorId',
{
type: Sequelize.DataTypes.UUID,
references: {
model: 'users',
key: 'id',
},
},
{ transaction }
);
await queryInterface.addColumn(
'haptic_patterns',
'name',
{
type: Sequelize.DataTypes.TEXT,
},
{ transaction }
);
await queryInterface.addColumn(
'haptic_patterns',
'description',
{
type: Sequelize.DataTypes.TEXT,
},
{ transaction }
);
await queryInterface.addColumn(
'haptic_patterns',
'pattern_type',
{
type: Sequelize.DataTypes.ENUM,
values: ['timeline','procedural'],
},
{ transaction }
);
await queryInterface.addColumn(
'haptic_patterns',
'ownerId',
{
type: Sequelize.DataTypes.UUID,
references: {
model: 'users',
key: 'id',
},
},
{ transaction }
);
await queryInterface.addColumn(
'haptic_patterns',
'programId',
{
type: Sequelize.DataTypes.UUID,
references: {
model: 'massage_programs',
key: 'id',
},
},
{ transaction }
);
await queryInterface.addColumn(
'haptic_patterns',
'duration_ms',
{
type: Sequelize.DataTypes.INTEGER,
},
{ transaction }
);
await queryInterface.addColumn(
'haptic_patterns',
'default_left_intensity',
{
type: Sequelize.DataTypes.DECIMAL,
},
{ transaction }
);
await queryInterface.addColumn(
'haptic_patterns',
'default_right_intensity',
{
type: Sequelize.DataTypes.DECIMAL,
},
{ transaction }
);
await queryInterface.addColumn(
'haptic_patterns',
'speed_multiplier',
{
type: Sequelize.DataTypes.DECIMAL,
},
{ transaction }
);
await queryInterface.addColumn(
'haptic_patterns',
'loop_enabled',
{
type: Sequelize.DataTypes.BOOLEAN,
defaultValue: false,
allowNull: false,
},
{ transaction }
);
await queryInterface.addColumn(
'haptic_patterns',
'pattern_json',
{
type: Sequelize.DataTypes.TEXT,
},
{ transaction }
);
await queryInterface.addColumn(
'haptic_steps',
'patternId',
{
type: Sequelize.DataTypes.UUID,
references: {
model: 'haptic_patterns',
key: 'id',
},
},
{ transaction }
);
await queryInterface.addColumn(
'haptic_steps',
'sequence_index',
{
type: Sequelize.DataTypes.INTEGER,
},
{ transaction }
);
await queryInterface.addColumn(
'haptic_steps',
'start_offset_ms',
{
type: Sequelize.DataTypes.INTEGER,
},
{ transaction }
);
await queryInterface.addColumn(
'haptic_steps',
'duration_ms',
{
type: Sequelize.DataTypes.INTEGER,
},
{ transaction }
);
await queryInterface.addColumn(
'haptic_steps',
'left_intensity',
{
type: Sequelize.DataTypes.DECIMAL,
},
{ transaction }
);
await queryInterface.addColumn(
'haptic_steps',
'right_intensity',
{
type: Sequelize.DataTypes.DECIMAL,
},
{ transaction }
);
await queryInterface.addColumn(
'haptic_steps',
'shape',
{
type: Sequelize.DataTypes.ENUM,
values: ['constant','ramp_up','ramp_down','pulse','sine'],
},
{ transaction }
);
await queryInterface.addColumn(
'haptic_steps',
'repeat_count',
{
type: Sequelize.DataTypes.INTEGER,
},
{ transaction }
);
await queryInterface.addColumn(
'haptic_steps',
'repeat_interval_ms',
{
type: Sequelize.DataTypes.INTEGER,
},
{ transaction }
);
await queryInterface.addColumn(
'massage_sessions',
'session_name',
{
type: Sequelize.DataTypes.TEXT,
},
{ transaction }
);
await queryInterface.addColumn(
'massage_sessions',
'userId',
{
type: Sequelize.DataTypes.UUID,
references: {
model: 'users',
key: 'id',
},
},
{ transaction }
);
await queryInterface.addColumn(
'massage_sessions',
'programId',
{
type: Sequelize.DataTypes.UUID,
references: {
model: 'massage_programs',
key: 'id',
},
},
{ transaction }
);
await queryInterface.addColumn(
'massage_sessions',
'device_profileId',
{
type: Sequelize.DataTypes.UUID,
references: {
model: 'device_profiles',
key: 'id',
},
},
{ transaction }
);
await queryInterface.addColumn(
'massage_sessions',
'gamepadId',
{
type: Sequelize.DataTypes.UUID,
references: {
model: 'gamepads',
key: 'id',
},
},
{ transaction }
);
await queryInterface.addColumn(
'massage_sessions',
'started_at',
{
type: Sequelize.DataTypes.DATE,
},
{ transaction }
);
await queryInterface.addColumn(
'massage_sessions',
'ended_at',
{
type: Sequelize.DataTypes.DATE,
},
{ transaction }
);
await queryInterface.addColumn(
'massage_sessions',
'state',
{
type: Sequelize.DataTypes.ENUM,
values: ['running','paused','stopped','completed','aborted'],
},
{ transaction }
);
await queryInterface.addColumn(
'massage_sessions',
'stop_reason',
{
type: Sequelize.DataTypes.ENUM,
values: ['user_stop','safety_cutoff','device_disconnected','error','completed'],
},
{ transaction }
);
await queryInterface.addColumn(
'massage_sessions',
'planned_duration_seconds',
{
type: Sequelize.DataTypes.INTEGER,
},
{ transaction }
);
await queryInterface.addColumn(
'massage_sessions',
'actual_duration_seconds',
{
type: Sequelize.DataTypes.INTEGER,
},
{ transaction }
);
await queryInterface.addColumn(
'massage_sessions',
'avg_left_intensity',
{
type: Sequelize.DataTypes.DECIMAL,
},
{ transaction }
);
await queryInterface.addColumn(
'massage_sessions',
'avg_right_intensity',
{
type: Sequelize.DataTypes.DECIMAL,
},
{ transaction }
);
await queryInterface.addColumn(
'massage_sessions',
'safety_cutoff_triggered',
{
type: Sequelize.DataTypes.BOOLEAN,
defaultValue: false,
allowNull: false,
},
{ transaction }
);
await queryInterface.addColumn(
'massage_sessions',
'notes',
{
type: Sequelize.DataTypes.TEXT,
},
{ transaction }
);
await queryInterface.addColumn(
'calibration_runs',
'name',
{
type: Sequelize.DataTypes.TEXT,
},
{ transaction }
);
await queryInterface.addColumn(
'calibration_runs',
'userId',
{
type: Sequelize.DataTypes.UUID,
references: {
model: 'users',
key: 'id',
},
},
{ transaction }
);
await queryInterface.addColumn(
'calibration_runs',
'gamepadId',
{
type: Sequelize.DataTypes.UUID,
references: {
model: 'gamepads',
key: 'id',
},
},
{ transaction }
);
await queryInterface.addColumn(
'calibration_runs',
'device_profileId',
{
type: Sequelize.DataTypes.UUID,
references: {
model: 'device_profiles',
key: 'id',
},
},
{ transaction }
);
await queryInterface.addColumn(
'calibration_runs',
'started_at',
{
type: Sequelize.DataTypes.DATE,
},
{ transaction }
);
await queryInterface.addColumn(
'calibration_runs',
'finished_at',
{
type: Sequelize.DataTypes.DATE,
},
{ transaction }
);
await queryInterface.addColumn(
'calibration_runs',
'mode',
{
type: Sequelize.DataTypes.ENUM,
values: ['motor_test','intensity_sweep','latency_test','left_right_balance'],
},
{ transaction }
);
await queryInterface.addColumn(
'calibration_runs',
'left_motor_gain_result',
{
type: Sequelize.DataTypes.DECIMAL,
},
{ transaction }
);
await queryInterface.addColumn(
'calibration_runs',
'right_motor_gain_result',
{
type: Sequelize.DataTypes.DECIMAL,
},
{ transaction }
);
await queryInterface.addColumn(
'calibration_runs',
'estimated_latency_ms',
{
type: Sequelize.DataTypes.INTEGER,
},
{ transaction }
);
await queryInterface.addColumn(
'calibration_runs',
'result_notes',
{
type: Sequelize.DataTypes.TEXT,
},
{ transaction }
);
await queryInterface.addColumn(
'safety_events',
'sessionId',
{
type: Sequelize.DataTypes.UUID,
references: {
model: 'massage_sessions',
key: 'id',
},
},
{ transaction }
);
await queryInterface.addColumn(
'safety_events',
'userId',
{
type: Sequelize.DataTypes.UUID,
references: {
model: 'users',
key: 'id',
},
},
{ transaction }
);
await queryInterface.addColumn(
'safety_events',
'occurred_at',
{
type: Sequelize.DataTypes.DATE,
},
{ transaction }
);
await queryInterface.addColumn(
'safety_events',
'event_type',
{
type: Sequelize.DataTypes.ENUM,
values: ['cutoff_triggered','device_disconnected','over_intensity','over_duration','manual_emergency_stop'],
},
{ transaction }
);
await queryInterface.addColumn(
'safety_events',
'severity',
{
type: Sequelize.DataTypes.ENUM,
values: ['info','warning','critical'],
},
{ transaction }
);
await queryInterface.addColumn(
'safety_events',
'left_intensity_at_event',
{
type: Sequelize.DataTypes.DECIMAL,
},
{ transaction }
);
await queryInterface.addColumn(
'safety_events',
'right_intensity_at_event',
{
type: Sequelize.DataTypes.DECIMAL,
},
{ transaction }
);
await queryInterface.addColumn(
'safety_events',
'elapsed_ms',
{
type: Sequelize.DataTypes.INTEGER,
},
{ transaction }
);
await queryInterface.addColumn(
'safety_events',
'details',
{
type: Sequelize.DataTypes.TEXT,
},
{ transaction }
);
await queryInterface.addColumn(
'user_preferences',
'userId',
{
type: Sequelize.DataTypes.UUID,
references: {
model: 'users',
key: 'id',
},
},
{ transaction }
);
await queryInterface.addColumn(
'user_preferences',
'theme',
{
type: Sequelize.DataTypes.ENUM,
values: ['system','light','dark'],
},
{ transaction }
);
await queryInterface.addColumn(
'user_preferences',
'default_view',
{
type: Sequelize.DataTypes.ENUM,
values: ['presets','sessions','calibration','builder'],
},
{ transaction }
);
await queryInterface.addColumn(
'user_preferences',
'sound_enabled',
{
type: Sequelize.DataTypes.BOOLEAN,
defaultValue: false,
allowNull: false,
},
{ transaction }
);
await queryInterface.addColumn(
'user_preferences',
'haptics_enabled',
{
type: Sequelize.DataTypes.BOOLEAN,
defaultValue: false,
allowNull: false,
},
{ transaction }
);
await queryInterface.addColumn(
'user_preferences',
'confirm_before_stop',
{
type: Sequelize.DataTypes.BOOLEAN,
defaultValue: false,
allowNull: false,
},
{ transaction }
);
await queryInterface.addColumn(
'user_preferences',
'quick_stop_hold_ms',
{
type: Sequelize.DataTypes.INTEGER,
},
{ transaction }
);
await queryInterface.addColumn(
'user_preferences',
'default_intensity',
{
type: Sequelize.DataTypes.DECIMAL,
},
{ transaction }
);
await queryInterface.addColumn(
'user_preferences',
'default_duration_seconds',
{
type: Sequelize.DataTypes.INTEGER,
},
{ transaction }
);
await transaction.commit();
} catch (err) {
await transaction.rollback();
throw err;
}
},
/**
* @param {QueryInterface} queryInterface
* @param {Sequelize} Sequelize
* @returns {Promise<void>}
*/
async down(queryInterface, Sequelize) {
/**
* @type {Transaction}
*/
const transaction = await queryInterface.sequelize.transaction();
try {
await queryInterface.removeColumn(
'user_preferences',
'default_duration_seconds',
{ transaction }
);
await queryInterface.removeColumn(
'user_preferences',
'default_intensity',
{ transaction }
);
await queryInterface.removeColumn(
'user_preferences',
'quick_stop_hold_ms',
{ transaction }
);
await queryInterface.removeColumn(
'user_preferences',
'confirm_before_stop',
{ transaction }
);
await queryInterface.removeColumn(
'user_preferences',
'haptics_enabled',
{ transaction }
);
await queryInterface.removeColumn(
'user_preferences',
'sound_enabled',
{ transaction }
);
await queryInterface.removeColumn(
'user_preferences',
'default_view',
{ transaction }
);
await queryInterface.removeColumn(
'user_preferences',
'theme',
{ transaction }
);
await queryInterface.removeColumn(
'user_preferences',
'userId',
{ transaction }
);
await queryInterface.removeColumn(
'safety_events',
'details',
{ transaction }
);
await queryInterface.removeColumn(
'safety_events',
'elapsed_ms',
{ transaction }
);
await queryInterface.removeColumn(
'safety_events',
'right_intensity_at_event',
{ transaction }
);
await queryInterface.removeColumn(
'safety_events',
'left_intensity_at_event',
{ transaction }
);
await queryInterface.removeColumn(
'safety_events',
'severity',
{ transaction }
);
await queryInterface.removeColumn(
'safety_events',
'event_type',
{ transaction }
);
await queryInterface.removeColumn(
'safety_events',
'occurred_at',
{ transaction }
);
await queryInterface.removeColumn(
'safety_events',
'userId',
{ transaction }
);
await queryInterface.removeColumn(
'safety_events',
'sessionId',
{ transaction }
);
await queryInterface.removeColumn(
'calibration_runs',
'result_notes',
{ transaction }
);
await queryInterface.removeColumn(
'calibration_runs',
'estimated_latency_ms',
{ transaction }
);
await queryInterface.removeColumn(
'calibration_runs',
'right_motor_gain_result',
{ transaction }
);
await queryInterface.removeColumn(
'calibration_runs',
'left_motor_gain_result',
{ transaction }
);
await queryInterface.removeColumn(
'calibration_runs',
'mode',
{ transaction }
);
await queryInterface.removeColumn(
'calibration_runs',
'finished_at',
{ transaction }
);
await queryInterface.removeColumn(
'calibration_runs',
'started_at',
{ transaction }
);
await queryInterface.removeColumn(
'calibration_runs',
'device_profileId',
{ transaction }
);
await queryInterface.removeColumn(
'calibration_runs',
'gamepadId',
{ transaction }
);
await queryInterface.removeColumn(
'calibration_runs',
'userId',
{ transaction }
);
await queryInterface.removeColumn(
'calibration_runs',
'name',
{ transaction }
);
await queryInterface.removeColumn(
'massage_sessions',
'notes',
{ transaction }
);
await queryInterface.removeColumn(
'massage_sessions',
'safety_cutoff_triggered',
{ transaction }
);
await queryInterface.removeColumn(
'massage_sessions',
'avg_right_intensity',
{ transaction }
);
await queryInterface.removeColumn(
'massage_sessions',
'avg_left_intensity',
{ transaction }
);
await queryInterface.removeColumn(
'massage_sessions',
'actual_duration_seconds',
{ transaction }
);
await queryInterface.removeColumn(
'massage_sessions',
'planned_duration_seconds',
{ transaction }
);
await queryInterface.removeColumn(
'massage_sessions',
'stop_reason',
{ transaction }
);
await queryInterface.removeColumn(
'massage_sessions',
'state',
{ transaction }
);
await queryInterface.removeColumn(
'massage_sessions',
'ended_at',
{ transaction }
);
await queryInterface.removeColumn(
'massage_sessions',
'started_at',
{ transaction }
);
await queryInterface.removeColumn(
'massage_sessions',
'gamepadId',
{ transaction }
);
await queryInterface.removeColumn(
'massage_sessions',
'device_profileId',
{ transaction }
);
await queryInterface.removeColumn(
'massage_sessions',
'programId',
{ transaction }
);
await queryInterface.removeColumn(
'massage_sessions',
'userId',
{ transaction }
);
await queryInterface.removeColumn(
'massage_sessions',
'session_name',
{ transaction }
);
await queryInterface.removeColumn(
'haptic_steps',
'repeat_interval_ms',
{ transaction }
);
await queryInterface.removeColumn(
'haptic_steps',
'repeat_count',
{ transaction }
);
await queryInterface.removeColumn(
'haptic_steps',
'shape',
{ transaction }
);
await queryInterface.removeColumn(
'haptic_steps',
'right_intensity',
{ transaction }
);
await queryInterface.removeColumn(
'haptic_steps',
'left_intensity',
{ transaction }
);
await queryInterface.removeColumn(
'haptic_steps',
'duration_ms',
{ transaction }
);
await queryInterface.removeColumn(
'haptic_steps',
'start_offset_ms',
{ transaction }
);
await queryInterface.removeColumn(
'haptic_steps',
'sequence_index',
{ transaction }
);
await queryInterface.removeColumn(
'haptic_steps',
'patternId',
{ transaction }
);
await queryInterface.removeColumn(
'haptic_patterns',
'pattern_json',
{ transaction }
);
await queryInterface.removeColumn(
'haptic_patterns',
'loop_enabled',
{ transaction }
);
await queryInterface.removeColumn(
'haptic_patterns',
'speed_multiplier',
{ transaction }
);
await queryInterface.removeColumn(
'haptic_patterns',
'default_right_intensity',
{ transaction }
);
await queryInterface.removeColumn(
'haptic_patterns',
'default_left_intensity',
{ transaction }
);
await queryInterface.removeColumn(
'haptic_patterns',
'duration_ms',
{ transaction }
);
await queryInterface.removeColumn(
'haptic_patterns',
'programId',
{ transaction }
);
await queryInterface.removeColumn(
'haptic_patterns',
'ownerId',
{ transaction }
);
await queryInterface.removeColumn(
'haptic_patterns',
'pattern_type',
{ transaction }
);
await queryInterface.removeColumn(
'haptic_patterns',
'description',
{ transaction }
);
await queryInterface.removeColumn(
'haptic_patterns',
'name',
{ transaction }
);
await queryInterface.removeColumn(
'massage_programs',
'authorId',
{ transaction }
);
await queryInterface.removeColumn(
'massage_programs',
'right_bias',
{ transaction }
);
await queryInterface.removeColumn(
'massage_programs',
'left_bias',
{ transaction }
);
await queryInterface.removeColumn(
'massage_programs',
'base_intensity',
{ transaction }
);
await queryInterface.removeColumn(
'massage_programs',
'bpm',
{ transaction }
);
await queryInterface.removeColumn(
'massage_programs',
'default_duration_seconds',
{ transaction }
);
await queryInterface.removeColumn(
'massage_programs',
'category',
{ transaction }
);
await queryInterface.removeColumn(
'massage_programs',
'visibility',
{ transaction }
);
await queryInterface.removeColumn(
'massage_programs',
'summary',
{ transaction }
);
await queryInterface.removeColumn(
'massage_programs',
'name',
{ transaction }
);
await queryInterface.removeColumn(
'device_profiles',
'intensity_curve',
{ transaction }
);
await queryInterface.removeColumn(
'device_profiles',
'deadzone',
{ transaction }
);
await queryInterface.removeColumn(
'device_profiles',
'safety_cutoff_enabled',
{ transaction }
);
await queryInterface.removeColumn(
'device_profiles',
'max_duration_seconds',
{ transaction }
);
await queryInterface.removeColumn(
'device_profiles',
'overall_gain',
{ transaction }
);
await queryInterface.removeColumn(
'device_profiles',
'right_motor_gain',
{ transaction }
);
await queryInterface.removeColumn(
'device_profiles',
'left_motor_gain',
{ transaction }
);
await queryInterface.removeColumn(
'device_profiles',
'gamepadId',
{ transaction }
);
await queryInterface.removeColumn(
'device_profiles',
'userId',
{ transaction }
);
await queryInterface.removeColumn(
'device_profiles',
'description',
{ transaction }
);
await queryInterface.removeColumn(
'device_profiles',
'name',
{ transaction }
);
await queryInterface.removeColumn(
'gamepads',
'notes',
{ transaction }
);
await queryInterface.removeColumn(
'gamepads',
'buttons_count',
{ transaction }
);
await queryInterface.removeColumn(
'gamepads',
'axes_count',
{ transaction }
);
await queryInterface.removeColumn(
'gamepads',
'supports_vibration',
{ transaction }
);
await queryInterface.removeColumn(
'gamepads',
'connection_type',
{ transaction }
);
await queryInterface.removeColumn(
'gamepads',
'mapping',
{ transaction }
);
await queryInterface.removeColumn(
'gamepads',
'product',
{ transaction }
);
await queryInterface.removeColumn(
'gamepads',
'vendor',
{ transaction }
);
await queryInterface.removeColumn(
'gamepads',
'display_name',
{ transaction }
);
await queryInterface.removeColumn(
'permissions',
'name',
{ transaction }
);
await queryInterface.removeColumn(
'roles',
'role_customization',
{ transaction }
);
await queryInterface.removeColumn(
'roles',
'name',
{ transaction }
);
await queryInterface.removeColumn(
'users',
'app_roleId',
{ transaction }
);
await queryInterface.removeColumn(
'users',
'provider',
{ transaction }
);
await queryInterface.removeColumn(
'users',
'passwordResetTokenExpiresAt',
{ transaction }
);
await queryInterface.removeColumn(
'users',
'passwordResetToken',
{ transaction }
);
await queryInterface.removeColumn(
'users',
'emailVerificationTokenExpiresAt',
{ transaction }
);
await queryInterface.removeColumn(
'users',
'emailVerificationToken',
{ transaction }
);
await queryInterface.removeColumn(
'users',
'emailVerified',
{ transaction }
);
await queryInterface.removeColumn(
'users',
'password',
{ transaction }
);
await queryInterface.removeColumn(
'users',
'disabled',
{ transaction }
);
await queryInterface.removeColumn(
'users',
'email',
{ transaction }
);
await queryInterface.removeColumn(
'users',
'phoneNumber',
{ transaction }
);
await queryInterface.removeColumn(
'users',
'lastName',
{ transaction }
);
await queryInterface.removeColumn(
'users',
'firstName',
{ transaction }
);
await queryInterface.dropTable('user_preferences', { transaction });
await queryInterface.dropTable('safety_events', { transaction });
await queryInterface.dropTable('calibration_runs', { transaction });
await queryInterface.dropTable('massage_sessions', { transaction });
await queryInterface.dropTable('haptic_steps', { transaction });
await queryInterface.dropTable('haptic_patterns', { transaction });
await queryInterface.dropTable('massage_programs', { transaction });
await queryInterface.dropTable('device_profiles', { transaction });
await queryInterface.dropTable('gamepads', { transaction });
await queryInterface.dropTable('permissions', { transaction });
await queryInterface.dropTable('roles', { transaction });
await queryInterface.dropTable('users', { transaction });
await transaction.commit();
} catch (err) {
await transaction.rollback();
throw err;
}
}
};