Migrated from design-system-swarm with fresh git history.
Old project history preserved in /home/overbits/apps/design-system-swarm
Core components:
- MCP Server (Python FastAPI with mcp 1.23.1)
- Claude Plugin (agents, commands, skills, strategies, hooks, core)
- DSS Backend (dss-mvp1 - token translation, Figma sync)
- Admin UI (Node.js/React)
- Server (Node.js/Express)
- Storybook integration (dss-mvp1/.storybook)
Self-contained configuration:
- All paths relative or use DSS_BASE_PATH=/home/overbits/dss
- PYTHONPATH configured for dss-mvp1 and dss-claude-plugin
- .env file with all configuration
- Claude plugin uses ${CLAUDE_PLUGIN_ROOT} for portability
Migration completed: $(date)
🤖 Clean migration with full functionality preserved
186 lines
6.8 KiB
JavaScript
186 lines
6.8 KiB
JavaScript
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;
|
|
}
|
|
}
|
|
};
|