diff --git a/backend/app/alembic/versions/0007_add_agent_type_category_fields.py b/backend/app/alembic/versions/0007_add_agent_type_category_fields.py new file mode 100644 index 0000000..953b06d --- /dev/null +++ b/backend/app/alembic/versions/0007_add_agent_type_category_fields.py @@ -0,0 +1,90 @@ +"""Add category and display fields to agent_types table + +Revision ID: 0007 +Revises: 0006 +Create Date: 2026-01-06 + +This migration adds: +- category: String(50) for grouping agents by role type +- icon: String(50) for Lucide icon identifier +- color: String(7) for hex color code +- sort_order: Integer for display ordering within categories +- typical_tasks: JSONB list of tasks this agent excels at +- collaboration_hints: JSONB list of agent slugs that work well together +""" + +from collections.abc import Sequence + +import sqlalchemy as sa +from alembic import op +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision: str = "0007" +down_revision: str | None = "0006" +branch_labels: str | Sequence[str] | None = None +depends_on: str | Sequence[str] | None = None + + +def upgrade() -> None: + """Add category and display fields to agent_types table.""" + # Add new columns + op.add_column( + "agent_types", + sa.Column("category", sa.String(length=50), nullable=True), + ) + op.add_column( + "agent_types", + sa.Column("icon", sa.String(length=50), nullable=True, server_default="bot"), + ) + op.add_column( + "agent_types", + sa.Column( + "color", sa.String(length=7), nullable=True, server_default="#3B82F6" + ), + ) + op.add_column( + "agent_types", + sa.Column("sort_order", sa.Integer(), nullable=False, server_default="0"), + ) + op.add_column( + "agent_types", + sa.Column( + "typical_tasks", + postgresql.JSONB(astext_type=sa.Text()), + nullable=False, + server_default="[]", + ), + ) + op.add_column( + "agent_types", + sa.Column( + "collaboration_hints", + postgresql.JSONB(astext_type=sa.Text()), + nullable=False, + server_default="[]", + ), + ) + + # Add indexes for category and sort_order + op.create_index("ix_agent_types_category", "agent_types", ["category"]) + op.create_index("ix_agent_types_sort_order", "agent_types", ["sort_order"]) + op.create_index( + "ix_agent_types_category_sort", "agent_types", ["category", "sort_order"] + ) + + +def downgrade() -> None: + """Remove category and display fields from agent_types table.""" + # Drop indexes + op.drop_index("ix_agent_types_category_sort", table_name="agent_types") + op.drop_index("ix_agent_types_sort_order", table_name="agent_types") + op.drop_index("ix_agent_types_category", table_name="agent_types") + + # Drop columns + op.drop_column("agent_types", "collaboration_hints") + op.drop_column("agent_types", "typical_tasks") + op.drop_column("agent_types", "sort_order") + op.drop_column("agent_types", "color") + op.drop_column("agent_types", "icon") + op.drop_column("agent_types", "category") diff --git a/backend/app/api/routes/agent_types.py b/backend/app/api/routes/agent_types.py index 5280993..9695d30 100644 --- a/backend/app/api/routes/agent_types.py +++ b/backend/app/api/routes/agent_types.py @@ -81,6 +81,13 @@ def _build_agent_type_response( mcp_servers=agent_type.mcp_servers, tool_permissions=agent_type.tool_permissions, is_active=agent_type.is_active, + # Category and display fields + category=agent_type.category, + icon=agent_type.icon, + color=agent_type.color, + sort_order=agent_type.sort_order, + typical_tasks=agent_type.typical_tasks or [], + collaboration_hints=agent_type.collaboration_hints or [], created_at=agent_type.created_at, updated_at=agent_type.updated_at, instance_count=instance_count, @@ -300,6 +307,7 @@ async def list_agent_types( request: Request, pagination: PaginationParams = Depends(), is_active: bool = Query(True, description="Filter by active status"), + category: str | None = Query(None, description="Filter by category"), search: str | None = Query(None, description="Search by name, slug, description"), current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), @@ -314,6 +322,7 @@ async def list_agent_types( request: FastAPI request object pagination: Pagination parameters (page, limit) is_active: Filter by active status (default: True) + category: Filter by category (e.g., "development", "design") search: Optional search term for name, slug, description current_user: Authenticated user db: Database session @@ -328,6 +337,7 @@ async def list_agent_types( skip=pagination.offset, limit=pagination.limit, is_active=is_active, + category=category, search=search, ) @@ -354,6 +364,51 @@ async def list_agent_types( raise +@router.get( + "/grouped", + response_model=dict[str, list[AgentTypeResponse]], + summary="List Agent Types Grouped by Category", + description="Get all agent types organized by category", + operation_id="list_agent_types_grouped", +) +@limiter.limit(f"{60 * RATE_MULTIPLIER}/minute") +async def list_agent_types_grouped( + request: Request, + is_active: bool = Query(True, description="Filter by active status"), + current_user: User = Depends(get_current_user), + db: AsyncSession = Depends(get_db), +) -> Any: + """ + Get agent types grouped by category. + + Returns a dictionary where keys are category names and values + are lists of agent types, sorted by sort_order within each category. + + Args: + request: FastAPI request object + is_active: Filter by active status (default: True) + current_user: Authenticated user + db: Database session + + Returns: + Dictionary mapping category to list of agent types + """ + try: + grouped = await agent_type_crud.get_grouped_by_category(db, is_active=is_active) + + # Transform to response objects + result: dict[str, list[AgentTypeResponse]] = {} + for category, types in grouped.items(): + result[category] = [ + _build_agent_type_response(t, instance_count=0) for t in types + ] + + return result + except Exception as e: + logger.error(f"Error getting grouped agent types: {e!s}", exc_info=True) + raise + + @router.get( "/{agent_type_id}", response_model=AgentTypeResponse, diff --git a/backend/app/crud/syndarix/agent_type.py b/backend/app/crud/syndarix/agent_type.py index f01d38d..a091246 100644 --- a/backend/app/crud/syndarix/agent_type.py +++ b/backend/app/crud/syndarix/agent_type.py @@ -43,6 +43,13 @@ class CRUDAgentType(CRUDBase[AgentType, AgentTypeCreate, AgentTypeUpdate]): mcp_servers=obj_in.mcp_servers, tool_permissions=obj_in.tool_permissions, is_active=obj_in.is_active, + # Category and display fields + category=obj_in.category.value if obj_in.category else None, + icon=obj_in.icon, + color=obj_in.color, + sort_order=obj_in.sort_order, + typical_tasks=obj_in.typical_tasks, + collaboration_hints=obj_in.collaboration_hints, ) db.add(db_obj) await db.commit() @@ -68,6 +75,7 @@ class CRUDAgentType(CRUDBase[AgentType, AgentTypeCreate, AgentTypeUpdate]): skip: int = 0, limit: int = 100, is_active: bool | None = None, + category: str | None = None, search: str | None = None, sort_by: str = "created_at", sort_order: str = "desc", @@ -85,6 +93,9 @@ class CRUDAgentType(CRUDBase[AgentType, AgentTypeCreate, AgentTypeUpdate]): if is_active is not None: query = query.where(AgentType.is_active == is_active) + if category: + query = query.where(AgentType.category == category) + if search: search_filter = or_( AgentType.name.ilike(f"%{search}%"), @@ -162,6 +173,7 @@ class CRUDAgentType(CRUDBase[AgentType, AgentTypeCreate, AgentTypeUpdate]): skip: int = 0, limit: int = 100, is_active: bool | None = None, + category: str | None = None, search: str | None = None, ) -> tuple[list[dict[str, Any]], int]: """ @@ -177,6 +189,7 @@ class CRUDAgentType(CRUDBase[AgentType, AgentTypeCreate, AgentTypeUpdate]): skip=skip, limit=limit, is_active=is_active, + category=category, search=search, ) @@ -260,6 +273,44 @@ class CRUDAgentType(CRUDBase[AgentType, AgentTypeCreate, AgentTypeUpdate]): ) raise + async def get_grouped_by_category( + self, + db: AsyncSession, + *, + is_active: bool = True, + ) -> dict[str, list[AgentType]]: + """ + Get agent types grouped by category, sorted by sort_order within each group. + + Args: + db: Database session + is_active: Filter by active status (default: True) + + Returns: + Dictionary mapping category to list of agent types + """ + try: + query = ( + select(AgentType) + .where(AgentType.is_active == is_active) + .order_by(AgentType.category, AgentType.sort_order, AgentType.name) + ) + result = await db.execute(query) + agent_types = list(result.scalars().all()) + + # Group by category + grouped: dict[str, list[AgentType]] = {} + for at in agent_types: + cat: str = str(at.category) if at.category else "uncategorized" + if cat not in grouped: + grouped[cat] = [] + grouped[cat].append(at) + + return grouped + except Exception as e: + logger.error(f"Error getting grouped agent types: {e!s}", exc_info=True) + raise + # Create a singleton instance for use across the application agent_type = CRUDAgentType(AgentType) diff --git a/backend/app/init_db.py b/backend/app/init_db.py index 836cfa5..09e11d5 100644 --- a/backend/app/init_db.py +++ b/backend/app/init_db.py @@ -149,6 +149,13 @@ async def load_default_agent_types(session: AsyncSession) -> None: mcp_servers=agent_type_data.get("mcp_servers", []), tool_permissions=agent_type_data.get("tool_permissions", {}), is_active=agent_type_data.get("is_active", True), + # Category and display fields + category=agent_type_data.get("category"), + icon=agent_type_data.get("icon", "bot"), + color=agent_type_data.get("color", "#3B82F6"), + sort_order=agent_type_data.get("sort_order", 0), + typical_tasks=agent_type_data.get("typical_tasks", []), + collaboration_hints=agent_type_data.get("collaboration_hints", []), ) await agent_type_crud.create(session, obj_in=agent_type_in) diff --git a/backend/app/models/syndarix/agent_type.py b/backend/app/models/syndarix/agent_type.py index 9024aaf..c8faa4c 100644 --- a/backend/app/models/syndarix/agent_type.py +++ b/backend/app/models/syndarix/agent_type.py @@ -6,7 +6,7 @@ An AgentType is a template that defines the capabilities, personality, and model configuration for agent instances. """ -from sqlalchemy import Boolean, Column, Index, String, Text +from sqlalchemy import Boolean, Column, Index, Integer, String, Text from sqlalchemy.dialects.postgresql import JSONB from sqlalchemy.orm import relationship @@ -56,6 +56,24 @@ class AgentType(Base, UUIDMixin, TimestampMixin): # Whether this agent type is available for new instances is_active = Column(Boolean, default=True, nullable=False, index=True) + # Category for grouping agents (development, design, quality, etc.) + category = Column(String(50), nullable=True, index=True) + + # Lucide icon identifier for UI display (e.g., "code", "palette", "shield") + icon = Column(String(50), nullable=True, default="bot") + + # Hex color code for visual distinction (e.g., "#3B82F6") + color = Column(String(7), nullable=True, default="#3B82F6") + + # Display ordering within category (lower = first) + sort_order = Column(Integer, nullable=False, default=0, index=True) + + # List of typical tasks this agent excels at + typical_tasks = Column(JSONB, default=list, nullable=False) + + # List of agent slugs that collaborate well with this type + collaboration_hints = Column(JSONB, default=list, nullable=False) + # Relationships instances = relationship( "AgentInstance", @@ -66,6 +84,7 @@ class AgentType(Base, UUIDMixin, TimestampMixin): __table_args__ = ( Index("ix_agent_types_slug_active", "slug", "is_active"), Index("ix_agent_types_name_active", "name", "is_active"), + Index("ix_agent_types_category_sort", "category", "sort_order"), ) def __repr__(self) -> str: diff --git a/backend/app/models/syndarix/enums.py b/backend/app/models/syndarix/enums.py index fa09e84..0de7046 100644 --- a/backend/app/models/syndarix/enums.py +++ b/backend/app/models/syndarix/enums.py @@ -167,3 +167,29 @@ class SprintStatus(str, PyEnum): IN_REVIEW = "in_review" COMPLETED = "completed" CANCELLED = "cancelled" + + +class AgentTypeCategory(str, PyEnum): + """ + Category classification for agent types. + + Used for grouping and filtering agents in the UI. + + DEVELOPMENT: Product, project, and engineering roles + DESIGN: UI/UX and design research roles + QUALITY: QA and security engineering + OPERATIONS: DevOps and MLOps + AI_ML: Machine learning and AI specialists + DATA: Data science and engineering + LEADERSHIP: Technical leadership roles + DOMAIN_EXPERT: Industry and domain specialists + """ + + DEVELOPMENT = "development" + DESIGN = "design" + QUALITY = "quality" + OPERATIONS = "operations" + AI_ML = "ai_ml" + DATA = "data" + LEADERSHIP = "leadership" + DOMAIN_EXPERT = "domain_expert" diff --git a/backend/app/schemas/syndarix/agent_type.py b/backend/app/schemas/syndarix/agent_type.py index 36750b6..b0d69da 100644 --- a/backend/app/schemas/syndarix/agent_type.py +++ b/backend/app/schemas/syndarix/agent_type.py @@ -10,6 +10,8 @@ from uuid import UUID from pydantic import BaseModel, ConfigDict, Field, field_validator +from app.models.syndarix.enums import AgentTypeCategory + class AgentTypeBase(BaseModel): """Base agent type schema with common fields.""" @@ -26,6 +28,14 @@ class AgentTypeBase(BaseModel): tool_permissions: dict[str, Any] = Field(default_factory=dict) is_active: bool = True + # Category and display fields + category: AgentTypeCategory | None = None + icon: str | None = Field(None, max_length=50) + color: str | None = Field(None, pattern=r"^#[0-9A-Fa-f]{6}$") + sort_order: int = Field(default=0, ge=0, le=1000) + typical_tasks: list[str] = Field(default_factory=list) + collaboration_hints: list[str] = Field(default_factory=list) + @field_validator("slug") @classmethod def validate_slug(cls, v: str | None) -> str | None: @@ -62,6 +72,18 @@ class AgentTypeBase(BaseModel): """Validate MCP server list.""" return [s.strip() for s in v if s.strip()] + @field_validator("typical_tasks") + @classmethod + def validate_typical_tasks(cls, v: list[str]) -> list[str]: + """Validate and normalize typical tasks list.""" + return [t.strip() for t in v if t.strip()] + + @field_validator("collaboration_hints") + @classmethod + def validate_collaboration_hints(cls, v: list[str]) -> list[str]: + """Validate and normalize collaboration hints (agent slugs).""" + return [h.strip().lower() for h in v if h.strip()] + class AgentTypeCreate(AgentTypeBase): """Schema for creating a new agent type.""" @@ -87,6 +109,14 @@ class AgentTypeUpdate(BaseModel): tool_permissions: dict[str, Any] | None = None is_active: bool | None = None + # Category and display fields (all optional for updates) + category: AgentTypeCategory | None = None + icon: str | None = Field(None, max_length=50) + color: str | None = Field(None, pattern=r"^#[0-9A-Fa-f]{6}$") + sort_order: int | None = Field(None, ge=0, le=1000) + typical_tasks: list[str] | None = None + collaboration_hints: list[str] | None = None + @field_validator("slug") @classmethod def validate_slug(cls, v: str | None) -> str | None: @@ -119,6 +149,22 @@ class AgentTypeUpdate(BaseModel): return v return [e.strip().lower() for e in v if e.strip()] + @field_validator("typical_tasks") + @classmethod + def validate_typical_tasks(cls, v: list[str] | None) -> list[str] | None: + """Validate and normalize typical tasks list.""" + if v is None: + return v + return [t.strip() for t in v if t.strip()] + + @field_validator("collaboration_hints") + @classmethod + def validate_collaboration_hints(cls, v: list[str] | None) -> list[str] | None: + """Validate and normalize collaboration hints (agent slugs).""" + if v is None: + return v + return [h.strip().lower() for h in v if h.strip()] + class AgentTypeInDB(AgentTypeBase): """Schema for agent type in database.""" diff --git a/backend/data/default_agent_types.json b/backend/data/default_agent_types.json index 6004cb7..e898307 100644 --- a/backend/data/default_agent_types.json +++ b/backend/data/default_agent_types.json @@ -29,7 +29,13 @@ "denied": [], "require_approval": ["gitea:delete_*"] }, - "is_active": true + "is_active": true, + "category": "development", + "icon": "clipboard-check", + "color": "#3B82F6", + "sort_order": 10, + "typical_tasks": ["Requirements discovery", "User story creation", "Backlog prioritization", "Stakeholder alignment"], + "collaboration_hints": ["business-analyst", "solutions-architect", "scrum-master"] }, { "name": "Project Manager", @@ -61,7 +67,13 @@ "denied": [], "require_approval": [] }, - "is_active": true + "is_active": true, + "category": "development", + "icon": "briefcase", + "color": "#3B82F6", + "sort_order": 20, + "typical_tasks": ["Sprint planning", "Risk management", "Status reporting", "Team coordination"], + "collaboration_hints": ["product-owner", "scrum-master", "technical-lead"] }, { "name": "Business Analyst", @@ -93,7 +105,13 @@ "denied": [], "require_approval": [] }, - "is_active": true + "is_active": true, + "category": "development", + "icon": "file-text", + "color": "#3B82F6", + "sort_order": 30, + "typical_tasks": ["Requirements analysis", "Process modeling", "Gap analysis", "Functional specifications"], + "collaboration_hints": ["product-owner", "solutions-architect", "qa-engineer"] }, { "name": "Solutions Architect", @@ -129,7 +147,13 @@ "denied": [], "require_approval": ["gitea:create_pull_request"] }, - "is_active": true + "is_active": true, + "category": "development", + "icon": "git-branch", + "color": "#3B82F6", + "sort_order": 40, + "typical_tasks": ["System design", "ADR creation", "Technology selection", "Integration patterns"], + "collaboration_hints": ["backend-engineer", "frontend-engineer", "security-engineer"] }, { "name": "Full Stack Engineer", @@ -166,7 +190,13 @@ "denied": [], "require_approval": ["gitea:create_pull_request", "gitea:delete_*"] }, - "is_active": true + "is_active": true, + "category": "development", + "icon": "code", + "color": "#3B82F6", + "sort_order": 50, + "typical_tasks": ["End-to-end feature development", "API design", "UI implementation", "Database operations"], + "collaboration_hints": ["solutions-architect", "qa-engineer", "devops-engineer"] }, { "name": "Backend Engineer", @@ -208,7 +238,13 @@ "denied": [], "require_approval": ["gitea:create_pull_request", "gitea:delete_*"] }, - "is_active": true + "is_active": true, + "category": "development", + "icon": "server", + "color": "#3B82F6", + "sort_order": 60, + "typical_tasks": ["API development", "Database optimization", "System integration", "Performance tuning"], + "collaboration_hints": ["solutions-architect", "frontend-engineer", "data-engineer"] }, { "name": "Frontend Engineer", @@ -249,7 +285,13 @@ "denied": [], "require_approval": ["gitea:create_pull_request", "gitea:delete_*"] }, - "is_active": true + "is_active": true, + "category": "development", + "icon": "layout", + "color": "#3B82F6", + "sort_order": 70, + "typical_tasks": ["UI component development", "State management", "API integration", "Responsive design"], + "collaboration_hints": ["ui-ux-designer", "backend-engineer", "qa-engineer"] }, { "name": "Mobile Engineer", @@ -286,7 +328,13 @@ "denied": [], "require_approval": ["gitea:create_pull_request", "gitea:delete_*"] }, - "is_active": true + "is_active": true, + "category": "development", + "icon": "smartphone", + "color": "#3B82F6", + "sort_order": 80, + "typical_tasks": ["Native app development", "Cross-platform solutions", "Mobile optimization", "App store deployment"], + "collaboration_hints": ["backend-engineer", "ui-ux-designer", "qa-engineer"] }, { "name": "UI/UX Designer", @@ -321,7 +369,13 @@ "denied": [], "require_approval": [] }, - "is_active": true + "is_active": true, + "category": "design", + "icon": "palette", + "color": "#EC4899", + "sort_order": 10, + "typical_tasks": ["Interface design", "User flow creation", "Design system maintenance", "Prototyping"], + "collaboration_hints": ["frontend-engineer", "ux-researcher", "product-owner"] }, { "name": "UX Researcher", @@ -355,7 +409,13 @@ "denied": [], "require_approval": [] }, - "is_active": true + "is_active": true, + "category": "design", + "icon": "search", + "color": "#EC4899", + "sort_order": 20, + "typical_tasks": ["User research", "Usability testing", "Journey mapping", "Research synthesis"], + "collaboration_hints": ["ui-ux-designer", "product-owner", "business-analyst"] }, { "name": "QA Engineer", @@ -391,7 +451,13 @@ "denied": [], "require_approval": [] }, - "is_active": true + "is_active": true, + "category": "quality", + "icon": "shield", + "color": "#10B981", + "sort_order": 10, + "typical_tasks": ["Test strategy development", "Test automation", "Bug verification", "Quality metrics"], + "collaboration_hints": ["backend-engineer", "frontend-engineer", "devops-engineer"] }, { "name": "DevOps Engineer", @@ -431,7 +497,13 @@ "denied": [], "require_approval": ["gitea:create_release", "gitea:delete_*"] }, - "is_active": true + "is_active": true, + "category": "operations", + "icon": "settings", + "color": "#F59E0B", + "sort_order": 10, + "typical_tasks": ["CI/CD pipeline design", "Infrastructure automation", "Monitoring setup", "Deployment optimization"], + "collaboration_hints": ["backend-engineer", "security-engineer", "mlops-engineer"] }, { "name": "Security Engineer", @@ -467,7 +539,13 @@ "denied": [], "require_approval": [] }, - "is_active": true + "is_active": true, + "category": "quality", + "icon": "shield-check", + "color": "#10B981", + "sort_order": 20, + "typical_tasks": ["Security architecture", "Vulnerability assessment", "Compliance validation", "Threat modeling"], + "collaboration_hints": ["solutions-architect", "devops-engineer", "backend-engineer"] }, { "name": "AI/ML Engineer", @@ -503,7 +581,13 @@ "denied": [], "require_approval": ["gitea:create_pull_request"] }, - "is_active": true + "is_active": true, + "category": "ai_ml", + "icon": "brain", + "color": "#8B5CF6", + "sort_order": 10, + "typical_tasks": ["Model development", "Algorithm selection", "Feature engineering", "Model optimization"], + "collaboration_hints": ["data-scientist", "mlops-engineer", "backend-engineer"] }, { "name": "AI Researcher", @@ -537,7 +621,13 @@ "denied": [], "require_approval": [] }, - "is_active": true + "is_active": true, + "category": "ai_ml", + "icon": "microscope", + "color": "#8B5CF6", + "sort_order": 20, + "typical_tasks": ["Research paper analysis", "Novel algorithm design", "Experiment design", "Benchmark evaluation"], + "collaboration_hints": ["ai-ml-engineer", "data-scientist", "scientific-computing-expert"] }, { "name": "Computer Vision Engineer", @@ -573,7 +663,13 @@ "denied": [], "require_approval": ["gitea:create_pull_request"] }, - "is_active": true + "is_active": true, + "category": "ai_ml", + "icon": "eye", + "color": "#8B5CF6", + "sort_order": 30, + "typical_tasks": ["Image processing pipelines", "Object detection models", "Video analysis", "Computer vision deployment"], + "collaboration_hints": ["ai-ml-engineer", "mlops-engineer", "backend-engineer"] }, { "name": "NLP Engineer", @@ -609,7 +705,13 @@ "denied": [], "require_approval": ["gitea:create_pull_request"] }, - "is_active": true + "is_active": true, + "category": "ai_ml", + "icon": "message-square", + "color": "#8B5CF6", + "sort_order": 40, + "typical_tasks": ["Text processing pipelines", "Language model fine-tuning", "Named entity recognition", "Sentiment analysis"], + "collaboration_hints": ["ai-ml-engineer", "data-scientist", "backend-engineer"] }, { "name": "MLOps Engineer", @@ -645,7 +747,13 @@ "denied": [], "require_approval": ["gitea:create_release"] }, - "is_active": true + "is_active": true, + "category": "operations", + "icon": "settings-2", + "color": "#F59E0B", + "sort_order": 20, + "typical_tasks": ["ML pipeline development", "Model deployment", "Feature store management", "Model monitoring"], + "collaboration_hints": ["ai-ml-engineer", "devops-engineer", "data-engineer"] }, { "name": "Data Scientist", @@ -681,7 +789,13 @@ "denied": [], "require_approval": [] }, - "is_active": true + "is_active": true, + "category": "data", + "icon": "chart-bar", + "color": "#06B6D4", + "sort_order": 10, + "typical_tasks": ["Statistical analysis", "Predictive modeling", "Data visualization", "Insight generation"], + "collaboration_hints": ["data-engineer", "ai-ml-engineer", "business-analyst"] }, { "name": "Data Engineer", @@ -717,7 +831,13 @@ "denied": [], "require_approval": ["gitea:create_pull_request"] }, - "is_active": true + "is_active": true, + "category": "data", + "icon": "database", + "color": "#06B6D4", + "sort_order": 20, + "typical_tasks": ["Data pipeline development", "ETL optimization", "Data warehouse design", "Data quality management"], + "collaboration_hints": ["data-scientist", "backend-engineer", "mlops-engineer"] }, { "name": "Technical Lead", @@ -749,7 +869,13 @@ "denied": [], "require_approval": [] }, - "is_active": true + "is_active": true, + "category": "leadership", + "icon": "users", + "color": "#F97316", + "sort_order": 10, + "typical_tasks": ["Technical direction", "Code review leadership", "Team mentoring", "Architecture decisions"], + "collaboration_hints": ["solutions-architect", "backend-engineer", "frontend-engineer"] }, { "name": "Scrum Master", @@ -781,7 +907,13 @@ "denied": [], "require_approval": [] }, - "is_active": true + "is_active": true, + "category": "leadership", + "icon": "target", + "color": "#F97316", + "sort_order": 20, + "typical_tasks": ["Sprint facilitation", "Impediment removal", "Process improvement", "Team coaching"], + "collaboration_hints": ["project-manager", "product-owner", "technical-lead"] }, { "name": "Financial Systems Expert", @@ -816,7 +948,13 @@ "denied": [], "require_approval": [] }, - "is_active": true + "is_active": true, + "category": "domain_expert", + "icon": "calculator", + "color": "#84CC16", + "sort_order": 10, + "typical_tasks": ["Financial system design", "Regulatory compliance", "Transaction processing", "Audit trail implementation"], + "collaboration_hints": ["solutions-architect", "security-engineer", "backend-engineer"] }, { "name": "Healthcare Systems Expert", @@ -850,7 +988,13 @@ "denied": [], "require_approval": [] }, - "is_active": true + "is_active": true, + "category": "domain_expert", + "icon": "heart-pulse", + "color": "#84CC16", + "sort_order": 20, + "typical_tasks": ["Healthcare system design", "HIPAA compliance", "HL7/FHIR integration", "Clinical workflow optimization"], + "collaboration_hints": ["solutions-architect", "security-engineer", "data-engineer"] }, { "name": "Scientific Computing Expert", @@ -886,7 +1030,13 @@ "denied": [], "require_approval": [] }, - "is_active": true + "is_active": true, + "category": "domain_expert", + "icon": "flask", + "color": "#84CC16", + "sort_order": 30, + "typical_tasks": ["HPC architecture", "Scientific algorithm implementation", "Data pipeline optimization", "Numerical computing"], + "collaboration_hints": ["ai-researcher", "data-scientist", "backend-engineer"] }, { "name": "Behavioral Psychology Expert", @@ -919,7 +1069,13 @@ "denied": [], "require_approval": [] }, - "is_active": true + "is_active": true, + "category": "domain_expert", + "icon": "lightbulb", + "color": "#84CC16", + "sort_order": 40, + "typical_tasks": ["Behavioral design", "Engagement optimization", "User motivation analysis", "Ethical AI guidelines"], + "collaboration_hints": ["ux-researcher", "ui-ux-designer", "product-owner"] }, { "name": "Technical Writer", @@ -951,6 +1107,12 @@ "denied": [], "require_approval": [] }, - "is_active": true + "is_active": true, + "category": "domain_expert", + "icon": "book-open", + "color": "#84CC16", + "sort_order": 50, + "typical_tasks": ["API documentation", "User guides", "Technical specifications", "Knowledge base creation"], + "collaboration_hints": ["solutions-architect", "product-owner", "qa-engineer"] } ]