Initial commit: Clean DSS implementation

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
This commit is contained in:
Digital Production Factory
2025-12-09 18:45:48 -03:00
commit 276ed71f31
884 changed files with 373737 additions and 0 deletions

View File

@@ -0,0 +1,185 @@
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;
}
}
};

View File

@@ -0,0 +1,97 @@
import { DataTypes, Op } from 'sequelize';
export default {
up: async (queryInterface) => {
const transaction = await queryInterface.sequelize.transaction();
try {
await queryInterface.createTable('config_settings', {
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true
},
scope: {
type: DataTypes.ENUM('SYSTEM', 'PROJECT', 'USER'),
allowNull: false
},
scopeId: {
type: DataTypes.UUID,
allowNull: true,
field: 'scope_id'
},
key: {
type: DataTypes.STRING,
allowNull: false
},
value: {
type: DataTypes.JSONB,
allowNull: false
},
isSecret: {
type: DataTypes.BOOLEAN,
defaultValue: false,
field: 'is_secret'
},
schemaVersion: {
type: DataTypes.INTEGER,
defaultValue: 1,
field: 'schema_version'
},
createdAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW,
field: 'created_at'
},
updatedAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW,
field: 'updated_at'
}
}, { transaction });
// Create a unique index that handles the NULL scope_id for SYSTEM scope correctly
// In Postgres 15+ we could use NULLS NOT DISTINCT, but for compatibility we use a partial index
// for the NULL case and a standard unique index for the non-NULL case.
// 1. Standard unique constraint for non-null scope_id (Project/User)
await queryInterface.addIndex('config_settings', ['scope', 'scope_id', 'key'], {
unique: true,
where: {
scope_id: { [Op.ne]: null }
},
name: 'config_settings_scope_scope_id_key_unique',
transaction
});
// 2. Unique constraint for SYSTEM scope (where scope_id is NULL)
await queryInterface.addIndex('config_settings', ['scope', 'key'], {
unique: true,
where: {
scope_id: null
},
name: 'config_settings_system_scope_key_unique',
transaction
});
await transaction.commit();
} catch (err) {
await transaction.rollback();
throw err;
}
},
down: async (queryInterface) => {
const transaction = await queryInterface.sequelize.transaction();
try {
await queryInterface.dropTable('config_settings', { transaction });
await queryInterface.sequelize.query('DROP TYPE IF EXISTS "enum_config_settings_scope";', { transaction });
await transaction.commit();
} catch (err) {
await transaction.rollback();
throw err;
}
}
};

View File

@@ -0,0 +1,78 @@
import { DataTypes } from 'sequelize';
export default {
up: async (queryInterface) => {
const transaction = await queryInterface.sequelize.transaction();
try {
await queryInterface.createTable('config_audit_logs', {
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true
},
configId: {
type: DataTypes.UUID,
allowNull: false,
field: 'config_id',
references: {
model: 'config_settings',
key: 'id'
},
onDelete: 'CASCADE'
},
actorId: {
type: DataTypes.UUID,
allowNull: false,
field: 'actor_id',
references: {
model: 'users', // Note: User table name usually lowercase in Postgres if created via Sequelize defaults, or "Users" if strictly quoted
key: 'id'
}
},
action: {
type: DataTypes.ENUM('CREATE', 'UPDATE', 'DELETE'),
allowNull: false
},
previousValue: {
type: DataTypes.JSONB,
allowNull: true,
field: 'previous_value'
},
newValue: {
type: DataTypes.JSONB,
allowNull: true,
field: 'new_value'
},
createdAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW,
field: 'created_at'
}
}, { transaction });
// Add indexes for common query patterns
await queryInterface.addIndex('config_audit_logs', ['config_id'], { transaction });
await queryInterface.addIndex('config_audit_logs', ['actor_id'], { transaction });
await queryInterface.addIndex('config_audit_logs', ['created_at'], { transaction });
await transaction.commit();
} catch (err) {
await transaction.rollback();
throw err;
}
},
down: async (queryInterface) => {
const transaction = await queryInterface.sequelize.transaction();
try {
await queryInterface.dropTable('config_audit_logs', { transaction });
await queryInterface.sequelize.query('DROP TYPE IF EXISTS "enum_config_audit_logs_action";', { transaction });
await transaction.commit();
} catch (err) {
await transaction.rollback();
throw err;
}
}
};

View File

@@ -0,0 +1,69 @@
import { v4 as uuidv4 } from 'uuid';
export default {
up: async (queryInterface) => {
const transaction = await queryInterface.sequelize.transaction();
try {
const now = new Date();
const defaultConfigs = [
{
key: 'figma.api_timeout',
value: JSON.stringify(30000),
is_secret: false,
scope: 'SYSTEM',
scope_id: null
},
{
key: 'storybook.default_port',
value: JSON.stringify(6006),
is_secret: false,
scope: 'SYSTEM',
scope_id: null
},
{
key: 'rate_limit.requests_per_minute',
value: JSON.stringify(60),
is_secret: false,
scope: 'SYSTEM',
scope_id: null
},
{
key: 'theme',
value: JSON.stringify('auto'),
is_secret: false,
scope: 'SYSTEM',
scope_id: null
}
];
const records = defaultConfigs.map(config => ({
id: uuidv4(),
...config,
schema_version: 1,
created_at: now,
updated_at: now
}));
await queryInterface.bulkInsert('config_settings', records, { transaction });
await transaction.commit();
} catch (err) {
await transaction.rollback();
console.error('Failed to seed default configs:', err);
throw err;
}
},
down: async (queryInterface) => {
const transaction = await queryInterface.sequelize.transaction();
try {
await queryInterface.bulkDelete('config_settings', { scope: 'SYSTEM' }, { transaction });
await transaction.commit();
} catch (err) {
await transaction.rollback();
throw err;
}
}
};