import { DataTypes } from 'sequelize'; import { v4 as uuidv4 } from 'uuid'; const ROLES = ['admin', 'ui_team', 'ux_team', 'qa_team']; const ACTIONS = ['create', 'read', 'update', 'delete']; export default { up: async (queryInterface) => { const transaction = await queryInterface.sequelize.transaction(); try { // 1. Add role and team_id columns to Users table await queryInterface.addColumn('Users', 'team_id', { type: DataTypes.STRING, allowNull: true }, { transaction }); // Update existing users to use new role enum values // First, add a temporary column await queryInterface.addColumn('Users', 'role_new', { type: DataTypes.ENUM(...ROLES), allowNull: true }, { transaction }); // Map old roles to new roles (if Users table exists with old roles) await queryInterface.sequelize.query(` UPDATE "Users" SET role_new = CASE WHEN role = 'admin' THEN 'admin' WHEN role = 'designer' THEN 'ux_team' WHEN role = 'developer' THEN 'ui_team' WHEN role = 'viewer' THEN 'qa_team' ELSE 'ui_team' END `, { transaction }); // Drop old role column await queryInterface.removeColumn('Users', 'role', { transaction }); // Rename new role column to role await queryInterface.renameColumn('Users', 'role_new', 'role', { transaction }); // Set default value for role await queryInterface.changeColumn('Users', 'role', { type: DataTypes.ENUM(...ROLES), allowNull: false, defaultValue: 'ui_team' }, { transaction }); // 2. Create Team Permissions table await queryInterface.createTable('TeamPermissions', { id: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4, primaryKey: true }, role: { type: DataTypes.ENUM(...ROLES), allowNull: false }, permission: { type: DataTypes.STRING, allowNull: false }, resource: { type: DataTypes.STRING, allowNull: false }, action: { type: DataTypes.ENUM(...ACTIONS), allowNull: false }, createdAt: { type: DataTypes.DATE, allowNull: false, defaultValue: DataTypes.NOW }, updatedAt: { type: DataTypes.DATE, allowNull: false, defaultValue: DataTypes.NOW } }, { transaction }); // 3. Add Unique Constraint await queryInterface.addConstraint('TeamPermissions', { fields: ['role', 'resource', 'action'], type: 'unique', name: 'unique_role_resource_action', transaction }); // 4. Seed Default Permissions const timestamp = new Date(); const seeds = [ // UI Team Permissions { role: 'ui_team', permission: 'sync_figma', resource: 'figma', action: 'create' }, { role: 'ui_team', permission: 'view_figma', resource: 'figma', action: 'read' }, { role: 'ui_team', permission: 'quickwins', resource: 'analysis', action: 'read' }, { role: 'ui_team', permission: 'regression', resource: 'analysis', action: 'create' }, { role: 'ui_team', permission: 'view_metrics', resource: 'metrics', action: 'read' }, // UX Team Permissions { role: 'ux_team', permission: 'view_components', resource: 'components', action: 'read' }, { role: 'ux_team', permission: 'update_components', resource: 'components', action: 'update' }, { role: 'ux_team', permission: 'view_tokens', resource: 'tokens', action: 'read' }, { role: 'ux_team', permission: 'update_tokens', resource: 'tokens', action: 'update' }, { role: 'ux_team', permission: 'view_icons', resource: 'icons', action: 'read' }, { role: 'ux_team', permission: 'update_icons', resource: 'icons', action: 'update' }, { role: 'ux_team', permission: 'customize_figma_plugin', resource: 'figma', action: 'update' }, { role: 'ux_team', permission: 'view_metrics', resource: 'metrics', action: 'read' }, // QA Team Permissions { role: 'qa_team', permission: 'test_components', resource: 'components', action: 'read' }, { role: 'qa_team', permission: 'create_issue', resource: 'issues', action: 'create' }, { role: 'qa_team', permission: 'view_metrics', resource: 'metrics', action: 'read' }, { role: 'qa_team', permission: 'run_esre', resource: 'testing', action: 'create' } ].map(s => ({ ...s, id: uuidv4(), createdAt: timestamp, updatedAt: timestamp })); if (seeds.length > 0) { await queryInterface.bulkInsert('TeamPermissions', seeds, { transaction }); } await transaction.commit(); console.log('✓ RBAC migration completed successfully'); } catch (err) { await transaction.rollback(); console.error('✗ RBAC migration failed:', err); throw err; } }, down: async (queryInterface) => { const transaction = await queryInterface.sequelize.transaction(); try { // Drop team_permissions table await queryInterface.dropTable('TeamPermissions', { transaction }); // Remove team_id column await queryInterface.removeColumn('Users', 'team_id', { transaction }); // Restore old role enum await queryInterface.addColumn('Users', 'role_old', { type: DataTypes.ENUM('admin', 'designer', 'developer', 'viewer'), allowNull: true }, { transaction }); // Map new roles back to old roles await queryInterface.sequelize.query(` UPDATE "Users" SET role_old = CASE WHEN role = 'admin' THEN 'admin' WHEN role = 'ux_team' THEN 'designer' WHEN role = 'ui_team' THEN 'developer' WHEN role = 'qa_team' THEN 'viewer' ELSE 'designer' END `, { transaction }); await queryInterface.removeColumn('Users', 'role', { transaction }); await queryInterface.renameColumn('Users', 'role_old', 'role', { transaction }); await queryInterface.changeColumn('Users', 'role', { type: DataTypes.ENUM('admin', 'designer', 'developer', 'viewer'), allowNull: false, defaultValue: 'designer' }, { transaction }); // Cleanup Enums await queryInterface.sequelize.query('DROP TYPE IF EXISTS "enum_Users_role_new";', { transaction }); await queryInterface.sequelize.query('DROP TYPE IF EXISTS "enum_TeamPermissions_role";', { transaction }); await queryInterface.sequelize.query('DROP TYPE IF EXISTS "enum_TeamPermissions_action";', { transaction }); await transaction.commit(); console.log('✓ RBAC migration rolled back successfully'); } catch (err) { await transaction.rollback(); console.error('✗ RBAC migration rollback failed:', err); throw err; } } };