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
242 lines
5.7 KiB
JavaScript
242 lines
5.7 KiB
JavaScript
/**
|
|
* Design System Server (DSS) - Team Service
|
|
*
|
|
* Multi-team management with RBAC handling team operations,
|
|
* role management, and permissions.
|
|
*/
|
|
|
|
// Role definitions with permissions
|
|
const ROLES = {
|
|
SUPER_ADMIN: {
|
|
name: 'Super Admin',
|
|
description: 'Full system access',
|
|
permissions: ['*'],
|
|
level: 100
|
|
},
|
|
TEAM_LEAD: {
|
|
name: 'Team Lead',
|
|
description: 'Full team access, can manage members',
|
|
permissions: [
|
|
'read', 'write', 'delete',
|
|
'sync_tokens', 'sync_components',
|
|
'manage_team_members', 'invite_users',
|
|
'configure_figma', 'run_visual_diff',
|
|
'generate_code', 'export_tokens'
|
|
],
|
|
level: 80
|
|
},
|
|
DEVELOPER: {
|
|
name: 'Developer',
|
|
description: 'Read/write access, can sync and generate',
|
|
permissions: [
|
|
'read', 'write',
|
|
'sync_tokens', 'sync_components',
|
|
'generate_code', 'export_tokens',
|
|
'run_visual_diff'
|
|
],
|
|
level: 50
|
|
},
|
|
VIEWER: {
|
|
name: 'Viewer',
|
|
description: 'Read-only access',
|
|
permissions: ['read', 'export_tokens'],
|
|
level: 10
|
|
}
|
|
};
|
|
|
|
class TeamService {
|
|
constructor() {
|
|
this.apiBase = '/api/teams';
|
|
this.useMock = false;
|
|
this.currentUser = null;
|
|
this.currentTeam = null;
|
|
}
|
|
|
|
// === Role Management ===
|
|
|
|
getRoles() {
|
|
return ROLES;
|
|
}
|
|
|
|
getRole(roleKey) {
|
|
return ROLES[roleKey];
|
|
}
|
|
|
|
hasPermission(userRole, permission) {
|
|
const role = ROLES[userRole];
|
|
if (!role) return false;
|
|
if (role.permissions.includes('*')) return true;
|
|
return role.permissions.includes(permission);
|
|
}
|
|
|
|
canManage(managerRole, targetRole) {
|
|
const manager = ROLES[managerRole];
|
|
const target = ROLES[targetRole];
|
|
if (!manager || !target) return false;
|
|
return manager.level > target.level;
|
|
}
|
|
|
|
// === Team Operations ===
|
|
|
|
async getTeams() {
|
|
if (this.useMock) {
|
|
await this._delay(300);
|
|
return this._getMockTeams();
|
|
}
|
|
|
|
const response = await fetch(`${this.apiBase}`);
|
|
return response.json();
|
|
}
|
|
|
|
async getTeam(teamId) {
|
|
if (this.useMock) {
|
|
await this._delay(200);
|
|
const teams = this._getMockTeams();
|
|
return teams.find(t => t.id === teamId);
|
|
}
|
|
|
|
const response = await fetch(`${this.apiBase}/${teamId}`);
|
|
return response.json();
|
|
}
|
|
|
|
async createTeam(data) {
|
|
if (this.useMock) {
|
|
await this._delay(400);
|
|
return {
|
|
id: `team-${Date.now()}`,
|
|
...data,
|
|
createdAt: new Date().toISOString(),
|
|
members: []
|
|
};
|
|
}
|
|
|
|
const response = await fetch(`${this.apiBase}`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(data)
|
|
});
|
|
return response.json();
|
|
}
|
|
|
|
async updateTeam(teamId, data) {
|
|
if (this.useMock) {
|
|
await this._delay(300);
|
|
return { id: teamId, ...data, updatedAt: new Date().toISOString() };
|
|
}
|
|
|
|
const response = await fetch(`${this.apiBase}/${teamId}`, {
|
|
method: 'PUT',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(data)
|
|
});
|
|
return response.json();
|
|
}
|
|
|
|
// === Member Management ===
|
|
|
|
async getTeamMembers(teamId) {
|
|
if (this.useMock) {
|
|
await this._delay(200);
|
|
return this._getMockMembers(teamId);
|
|
}
|
|
|
|
const response = await fetch(`${this.apiBase}/${teamId}/members`);
|
|
return response.json();
|
|
}
|
|
|
|
async addTeamMember(teamId, email, role) {
|
|
if (this.useMock) {
|
|
await this._delay(400);
|
|
return {
|
|
id: `member-${Date.now()}`,
|
|
email,
|
|
role,
|
|
teamId,
|
|
status: 'pending',
|
|
invitedAt: new Date().toISOString()
|
|
};
|
|
}
|
|
|
|
const response = await fetch(`${this.apiBase}/${teamId}/members`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ email, role })
|
|
});
|
|
return response.json();
|
|
}
|
|
|
|
async updateMemberRole(teamId, memberId, role) {
|
|
if (this.useMock) {
|
|
await this._delay(300);
|
|
return { id: memberId, role, updatedAt: new Date().toISOString() };
|
|
}
|
|
|
|
const response = await fetch(`${this.apiBase}/${teamId}/members/${memberId}`, {
|
|
method: 'PUT',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ role })
|
|
});
|
|
return response.json();
|
|
}
|
|
|
|
async removeMember(teamId, memberId) {
|
|
if (this.useMock) {
|
|
await this._delay(300);
|
|
return { success: true };
|
|
}
|
|
|
|
const response = await fetch(`${this.apiBase}/${teamId}/members/${memberId}`, {
|
|
method: 'DELETE'
|
|
});
|
|
return response.json();
|
|
}
|
|
|
|
// === Team Settings ===
|
|
|
|
async getTeamSettings(teamId) {
|
|
if (this.useMock) {
|
|
await this._delay(200);
|
|
return this._getMockTeamSettings(teamId);
|
|
}
|
|
|
|
const response = await fetch(`${this.apiBase}/${teamId}/settings`);
|
|
return response.json();
|
|
}
|
|
|
|
async updateTeamSettings(teamId, settings) {
|
|
if (this.useMock) {
|
|
await this._delay(300);
|
|
return { ...settings, updatedAt: new Date().toISOString() };
|
|
}
|
|
|
|
const response = await fetch(`${this.apiBase}/${teamId}/settings`, {
|
|
method: 'PUT',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(settings)
|
|
});
|
|
return response.json();
|
|
}
|
|
|
|
// === Dashboard Data ===
|
|
|
|
async getTeamDashboard(teamId) {
|
|
if (this.useMock) {
|
|
await this._delay(400);
|
|
return this._getMockDashboard(teamId);
|
|
}
|
|
|
|
const response = await fetch(`${this.apiBase}/${teamId}/dashboard`);
|
|
return response.json();
|
|
}
|
|
|
|
async getAdminDashboard() {
|
|
if (this.useMock) {
|
|
await this._delay(500);
|
|
return this._getMockAdminDashboard();
|
|
}
|
|
|
|
const response = await fetch(`${this.apiBase}/admin/dashboard`);
|
|
return response.json();
|
|
}
|
|
}
|