InfoGrab DocsInfoGrab Docs

GitLab Duo Agent Platform

요약

이 가이드는 GitLab Duo Agent Platform으로 작업하는 방법을 설명합니다. GitLab Duo Agent Platform은 Vue.js로 만든 단일 페이지 애플리케이션(Single Page Application, SPA)으로, AI 기반 자동화 기능을 위한 통합 인터페이스를 제공합니다.

이 가이드는 GitLab Duo Agent Platform으로 작업하는 방법을 설명합니다.

개요#

GitLab Duo Agent Platform은 Vue.js로 만든 단일 페이지 애플리케이션(Single Page Application, SPA)으로, AI 기반 자동화 기능을 위한 통합 인터페이스를 제공합니다. 이 플랫폼은 여러 내비게이션 항목이 /automate 경로 아래에 함께 존재할 수 있게 하는 스코프 라우팅 시스템을 사용합니다.

이 플랫폼은 유연한 네임스페이스 시스템으로 설계되어, 동일한 프론트엔드 인프라를 서로 다른 컨텍스트(프로젝트, 그룹 등)에서 재사용하면서도 컴포넌트 매핑 시스템으로 컨텍스트별 기능을 제공합니다.

네임스페이스 아키텍처#

네임스페이스 시스템은 다음과 같은 중앙 매핑 메커니즘을 중심으로 구성됩니다.

  1. 네임스페이스를 확인합니다 - 플랫폼이 어느 컨텍스트에서 실행되는지 판별합니다
  2. Vue 컴포넌트에 매핑합니다 - 해당 네임스페이스에 맞는 Vue 컴포넌트로 라우팅합니다
  3. GraphQL 쿼리를 props로 전달합니다 - 의존성 주입으로 네임스페이스별 데이터를 제공합니다

진입점#

주 진입점의 위치는 다음과 같습니다.

ee/app/assets/javascripts/pages/projects/duo_agents_platform/index.js

이 파일이 플랫폼을 가져와 초기화합니다.

import { initDuoAgentsPlatformProjectPage } from 'ee/ai/duo_agents_platform/namespace/project';

initDuoAgentsPlatformProjectPage();

앱 구조#

Mermaid 다이어그램 (12줄)
소스 코드 보기
graph TD
    A[Entry Point] --> B[initDuoAgentsPlatformPage]
    B --> C[Extract Namespace Data]
    C --> D[Create Router with Namespace]
    D --> E[Component Mapping]
    E --> F[Namespace-Specific Component]
    F --> G[GraphQL Query with Props]
    G --> H[Rendered UI]
I[Dataset Properties] --> C
J[Namespace Constant] --> E
K[Component Mappings] --&gt; E</code></pre></details></div>

새 내비게이션 항목 추가#

GitLab Duo Agent Platform은 Vue Router 구성이 브레드크럼 내비게이션을 직접 구동하는 라우터 기반 내비게이션 시스템을 사용합니다. 핵심은 ee/app/assets/javascripts/ai/duo_agents_platform/router/index.js의 라우터 구조가 URL 구조와 브레드크럼 계층 구조를 모두 결정한다는 점입니다.

라우터 기반 내비게이션 동작 방식#

이 시스템은 서로 연결된 다음 구성 요소로 동작합니다.

  1. 라우터 구조: meta.text 속성을 가진 중첩 라우트가 브레드크럼 레이블을 정의합니다
  2. 브레드크럼 컴포넌트: duo_agents_platform_breadcrumbs.vue가 일치한 라우트에서 브레드크럼을 자동으로 생성합니다
  3. 라우트 주입: index.js의 injectVueAppBreadcrumbs()가 라우터를 브레드크럼 시스템에 연결합니다

라우터 분석#

ee/app/assets/javascripts/ai/duo_agents_platform/router/index.js의 현재 라우터 구조는 다음과 같습니다.

routes: [
  {
    component: NestedRouteApp, // Simple <router-view /> wrapper
    path: '/agent-sessions',
    meta: {
      text: s__('DuoAgentsPlatform|Sessions'), // This becomes a breadcrumb
    },
    children: [
      {
        name: AGENTS_PLATFORM_INDEX_ROUTE,
        path: '', // Matches /agent-sessions exactly
        component: AgentsPlatformIndex,
      },
      {
        name: AGENTS_PLATFORM_NEW_ROUTE,
        path: 'new', // Matches /agent-sessions/new
        component: AgentsPlatformNew,
        meta: {
          text: s__('DuoAgentsPlatform|New'), // This becomes a breadcrumb
        },
      },
      // ...
    ],
  },
];

브레드크럼 생성#

브레드크럼 컴포넌트(duo_agents_platform_breadcrumbs.vue)는 다음과 같이 동작합니다.

  1. this.$route.matched에서 일치한 모든 라우트를 가져옵니다
  2. 일치한 각 라우트에서 meta.text를 추출합니다
  3. 해당 텍스트와 라우트 경로로 브레드크럼 항목을 만듭니다
  4. 정적 브레드크럼("Automate" 등)과 결합합니다
// From duo_agents_platform_breadcrumbs.vue
const matchedRoutes = (this.$route?.matched || [])
  .map((route) => {
    return {
      text: route.meta?.text, // Uses meta.text for breadcrumb label
      to: { path: route.path },
    };
  })
  .filter((r) => r.text); // Only routes with meta.text become breadcrumbs

새 내비게이션 항목 추가#

새 최상위 내비게이션 항목("Your Feature" 같은)을 추가하려면 라우터에 새 라우트 트리를 추가해야 합니다.

1단계: 라우트 상수 추가#

파일: ee/app/assets/javascripts/ai/duo_agents_platform/router/constants.js

// Add route name constants for your feature
export const AGENTS_PLATFORM_YOUR_FEATURE_INDEX = 'your_feature_index';
export const AGENTS_PLATFORM_YOUR_FEATURE_NEW = 'your_feature_new';
export const AGENTS_PLATFORM_YOUR_FEATURE_SHOW = 'your_feature_show';

2단계: 라우터에 라우트 추가#

파일: ee/app/assets/javascripts/ai/duo_agents_platform/router/index.js

import YourFeatureIndex from '../pages/your_feature/your_feature_index.vue';
import YourFeatureNew from '../pages/your_feature/your_feature_new.vue';
import YourFeatureShow from '../pages/your_feature/your_feature_show.vue';

export const createRouter = (base, namespace) => {
  return new VueRouter({
    base,
    mode: 'history',
    routes: [
      // Existing agent-sessions routes
      {
        component: NestedRouteApp,
        path: '/agent-sessions',
        meta: {
          text: s__('DuoAgentsPlatform|Sessions'),
        },
        children: [
          {
            name: AGENTS_PLATFORM_INDEX_ROUTE,
            path: '',
            component: getNamespaceIndexComponent(namespace),
          },
          // ... existing children
        ],
      },

      // NEW: Your feature routes
      {
        component: NestedRouteApp,
        path: '/your-feature', // This becomes the URL path
        meta: {
          text: s__('DuoAgentsPlatform|Your Feature'), // This becomes the breadcrumb
        },
        children: [
          {
            name: AGENTS_PLATFORM_YOUR_FEATURE_INDEX,
            path: '', // Matches /your-feature exactly
            component: YourFeatureIndex,
          },
          {
            name: AGENTS_PLATFORM_YOUR_FEATURE_NEW,
            path: 'new', // Matches /your-feature/new
            component: YourFeatureNew,
            meta: {
              text: s__('DuoAgentsPlatform|New'), // Breadcrumb: "Your Feature > New"
            },
          },
          {
            name: AGENTS_PLATFORM_YOUR_FEATURE_SHOW,
            path: ':id(\\d+)', // Matches /your-feature/123
            component: YourFeatureShow,
            // No meta.text - will use route param as breadcrumb
          },
        ],
      },

      { path: '*', redirect: '/agent-sessions' },
    ],
  });
};

3단계: 백엔드 라우트 추가(필요한 경우)#

ee/config/routes/project.rb의 기존 와일드카드 라우트가 새 경로를 처리합니다.

scope :automate do
  get '/(*vueroute)' => 'duo_agents_platform#show', as: :automate, format: false
end

중요: 사이드바 메뉴 항목을 추가하는 경우(4단계)에는 이름이 지정된 라우트 헬퍼를 추가해야 합니다.

scope :automate do
  get '/(*vueroute)' => 'duo_agents_platform#show', as: :automate, format: false
  # Named routes for sidebar menu helpers
  get 'agent-sessions', to: 'duo_agents_platform#show', as: :automate_agent_sessions, format: false
  get 'your-feature', to: 'duo_agents_platform#show', as: :automate_your_features, format: false
end
Note

기존 패턴과 맞추고 Rails 경로 헬퍼가 올바르게 생성되도록 라우트 이름에는 복수형(예: automate_your_features)을 사용합니다.

4단계: 사이드바 메뉴 항목 추가#

파일: ee/lib/sidebars/projects/super_sidebar_menus/duo_agents_menu.rb

configure_menu_items 메서드에 메뉴 항목을 추가하고 그에 대응하는 메뉴 항목 메서드를 만듭니다.

override :configure_menu_items
def configure_menu_items
  add_item(duo_agents_runs_menu_item)
  add_item(duo_agents_your_feature_menu_item)  # Add your new menu item
  true
end

private

def duo_agents_your_feature_menu_item
  ::Sidebars::MenuItem.new(
    title: s_('Your Feature'),
    link: project_automate_your_features_path(context.project),  # Note: plural 'features'
    active_routes: { controller: :duo_agents_platform },
    item_id: :agents_your_feature
  )
end

5단계: Vue 컴포넌트 생성#

파일: ee/app/assets/javascripts/ai/duo_agents_platform/pages/your_feature/your_feature_index.vue

<script>
export default {
  name: 'YourFeatureIndex',
};
</script>

<template>
  <div>
    <h1>Your Feature</h1>
  </div>

</template>

새 네임스페이스 추가#

새 네임스페이스(예: 그룹용)를 추가하는 방법은 다음과 같습니다.

1. 네임스페이스 상수 정의#

// ee/app/assets/javascripts/ai/duo_agents_platform/constants.js
export const AGENT_PLATFORM_GROUP_PAGE = 'group';

2. 네임스페이스 디렉터리 구조 생성#

ee/app/assets/javascripts/ai/duo_agents_platform/namespace/group/
├── index.js
├── group_agents_platform_index.vue
└── graphql/
    └── queries/
        └── get_group_agent_flows.query.graphql

3. 네임스페이스 초기화 구현#

// ee/app/assets/javascripts/ai/duo_agents_platform/namespace/group/index.js
import { initDuoAgentsPlatformPage } from '../../index';
import { AGENT_PLATFORM_GROUP_PAGE } from '../../constants';

export const initDuoAgentsPlatformGroupPage = () => {
  initDuoAgentsPlatformPage({
    namespace: AGENT_PLATFORM_GROUP_PAGE,
    namespaceDatasetProperties: ['groupPath', 'groupId'],
  });
};

4. 네임스페이스별 컴포넌트 생성#

<!-- ee/app/assets/javascripts/ai/duo_agents_platform/namespace/group/group_agents_platform_index.vue -->
<script>
import getGroupAgentFlows from './graphql/queries/get_group_agent_flows.query.graphql';
import DuoAgentsPlatformIndex from '../../pages/index/duo_agents_platform_index.vue';

export default {
  components: { DuoAgentsPlatformIndex },
  inject: ['groupPath'], // Group-specific injection
  apollo: {
    workflows: {
      query: getGroupAgentFlows, // Group-specific query
      variables() {
        return {
          groupPath: this.groupPath,
          // ...
        };
      },
      // ...
    },
  },
};
</script>

<template>
  <duo-agents-platform-index
    :is-loading-workflows="isLoadingWorkflows"
    :workflows="workflows"
    :workflows-page-info="workflowsPageInfo"
    :workflow-query="$apollo.queries.workflows"
  />
</template>

5. 컴포넌트 매핑 업데이트#

// ee/app/assets/javascripts/ai/duo_agents_platform/router/utils.js
import { AGENT_PLATFORM_PROJECT_PAGE, AGENT_PLATFORM_GROUP_PAGE } from '../constants';
import ProjectAgentsPlatformIndex from '../namespace/project/project_agents_platform_index.vue';
import GroupAgentsPlatformIndex from '../namespace/group/group_agents_platform_index.vue';

export const getNamespaceIndexComponent = (namespace) => {
  const componentMappings = {
    [AGENT_PLATFORM_PROJECT_PAGE]: ProjectAgentsPlatformIndex,
    [AGENT_PLATFORM_GROUP_PAGE]: GroupAgentsPlatformIndex, // New mapping
  };

  return componentMappings[namespace];
};

6. 진입점 생성#

// ee/app/assets/javascripts/pages/groups/duo_agents_platform/index.js
import { initDuoAgentsPlatformGroupPage } from 'ee/ai/duo_agents_platform/namespace/group';

initDuoAgentsPlatformGroupPage();

이 아키텍처의 장점#

  1. 코드 재사용: 동일한 프론트엔드 인프라가 서로 다른 컨텍스트에서 동작합니다
  2. 관심사의 분리: 각 네임스페이스가 자체 데이터 페칭과 비즈니스 로직을 처리합니다
  3. 확장성: 기존 코드를 수정하지 않고 새 네임스페이스를 쉽게 추가할 수 있습니다
  4. 타입 안전성: 네임스페이스 상수와 필수 속성으로 계약이 명확합니다
  5. 유지 관리성: 네임스페이스 구현이 서로 격리되어 결합도가 낮아집니다

주요 구현 세부 사항#

라우터 기반 브레드크럼#

브레드크럼 시스템은 라우터 구조에서 내비게이션을 자동으로 생성합니다.

  • meta.text가 있는 상위 라우트는 브레드크럼 구간이 됩니다
  • meta.text가 있는 하위 라우트는 브레드크럼 체인을 확장합니다
  • meta.text가 없는 라우트는 라우트 파라미터(:id 등)를 브레드크럼 텍스트로 사용합니다
  • 정적 브레드크럼("Automate" 등)은 모든 라우트 앞에 붙습니다

URL 구조#

최상위 내비게이션 항목마다 자체 URL 네임스페이스를 가집니다.

  • Sessions: /automate/agent-sessions, /automate/agent-sessions/new, /automate/agent-sessions/123
  • Your Feature: /automate/your-feature, /automate/your-feature/new, /automate/your-feature/456

중첩 라우트 패턴#

이 플랫폼은 일관된 중첩 라우트 패턴을 사용합니다.

  1. 상위 라우트: URL 경로와 최상위 브레드크럼을 정의합니다
  2. NestedRouteApp 컴포넌트: 하위 라우트를 위한 단순한 <router-view /> 래퍼입니다
  3. 하위 라우트: 개별 페이지와 추가 브레드크럼 구간을 정의합니다

예시: 현재 에이전트 세션 구현#

기존 에이전트 세션 기능이 이 패턴을 보여 줍니다.

{
  component: NestedRouteApp,           // Renders child routes
  path: '/agent-sessions',             // URL: /automate/agent-sessions
  meta: {
    text: s__('DuoAgentsPlatform|Sessions'),  // Breadcrumb: "Sessions"
  },
  children: [
    {
      name: AGENTS_PLATFORM_INDEX_ROUTE,
      path: '',                        // URL: /automate/agent-sessions
      component: AgentsPlatformIndex,  // No additional breadcrumb
    },
    {
      name: AGENTS_PLATFORM_NEW_ROUTE,
      path: 'new',                     // URL: /automate/agent-sessions/new
      component: AgentsPlatformNew,
      meta: {
        text: s__('DuoAgentsPlatform|New'),  // Breadcrumb: "Sessions > New"
      },
    },
    {
      name: AGENTS_PLATFORM_SHOW_ROUTE,
      path: ':id(\\d+)',               // URL: /automate/agent-sessions/123
      component: AgentsPlatformShow,   // Breadcrumb: "Sessions > 123"
      // No meta.text - uses :id parameter as breadcrumb
    },
  ],
}

이렇게 하면 다음 브레드크럼 계층 구조가 만들어집니다.

  • /automate/agent-sessions → "Automate > Sessions"
  • /automate/agent-sessions/new → "Automate > Sessions > New"
  • /automate/agent-sessions/123 → "Automate > Sessions > 123"

주요 파일 참조#

  • 진입점: ee/app/assets/javascripts/pages/projects/duo_agents_platform/index.js
  • 주 초기화: ee/app/assets/javascripts/ai/duo_agents_platform/index.js
  • 라우터: ee/app/assets/javascripts/ai/duo_agents_platform/router/index.js
  • 컴포넌트 매핑: ee/app/assets/javascripts/ai/duo_agents_platform/router/utils.js
  • 상수: ee/app/assets/javascripts/ai/duo_agents_platform/constants.js
  • 유틸리티: ee/app/assets/javascripts/ai/duo_agents_platform/utils.js
  • 프로젝트 네임스페이스: ee/app/assets/javascripts/ai/duo_agents_platform/namespace/project/

모범 사례#

  1. 라우터 구조: meta.text 속성을 가진 중첩 라우트로 브레드크럼 계층 구조를 정의합니다
  2. URL 이름 지정: URL 경로에는 kebab-case를 사용합니다(/yourFeature가 아니라 /your-feature)
  3. 라우트 이름: 라우트 이름에는 의미가 분명한 상수를 사용합니다(AGENTS_PLATFORM_YOUR_FEATURE_INDEX)
  4. 컴포넌트 구성: 기능 컴포넌트는 pages/[feature]/ 디렉터리에 둡니다
  5. 브레드크럼 텍스트: 모든 meta.text 값에는 국제화 문자열(s__())을 사용합니다
  6. 일관된 패턴: NestedRouteApp을 사용하는 기존 중첩 라우트 패턴을 따릅니다
  7. 네임스페이스 분리: 네임스페이스별 로직은 namespace/ 아래의 전용 디렉터리에 둡니다
  8. 컴포넌트 매핑: 컴포넌트 매핑 시스템으로 네임스페이스별 컴포넌트에 라우팅합니다
  9. 데이터 주입: 네임스페이스별 데이터에는 Vue의 provide/inject 패턴을 사용합니다

문제 해결#

일반적인 문제#

  1. 브레드크럼이 표시되지 않음: 상위 라우트에 meta.text 속성이 있는지 확인합니다
  2. 라우트가 동작하지 않음: ee/config/routes/project.rb에 와일드카드 라우트가 있는지 확인합니다
  3. 사이드바가 강조되지 않음: 사이드바 메뉴 항목의 active_routes가 올바른지 확인합니다
  4. 404 오류: 라우트 경로가 기존 라우트와 충돌하지 않는지 확인합니다

디버깅 팁#

  1. Vue DevTools: $route.matched를 검사해 어떤 라우트가 일치하는지 확인합니다
  2. 라우터 상태: Vue DevTools에서 라우터 구성을 확인합니다
  3. 브레드크럼 디버그: 브레드크럼 컴포넌트에 console.log(this.$route.matched)를 추가합니다
  4. URL 테스트: 브라우저에서 URL로 직접 이동해 라우트를 테스트합니다

가짜 플로 생성#

플랫폼을 시험해 볼 가짜 플로를 생성하려면 ee/lib/tasks/gitlab/duo_workflow/duo_workflow.rake Rake 태스크를 실행할 수 있습니다.

특정 프로젝트에서 플로 50 개를 만들고 그중 20 개는 지정한 사용자가 만들도록 하는 예

bundle exec rake "gitlab:duo_workflow:populate[50,20,user@example.com,gitlab-org/gitlab-test]

GitLab Duo Agent Platform

GitLab v19.5
원문 보기

요약

이 가이드는 GitLab Duo Agent Platform으로 작업하는 방법을 설명합니다. GitLab Duo Agent Platform은 Vue.js로 만든 단일 페이지 애플리케이션(Single Page Application, SPA)으로, AI 기반 자동화 기능을 위한 통합 인터페이스를 제공합니다.

이 가이드는 GitLab Duo Agent Platform으로 작업하는 방법을 설명합니다.

개요#

GitLab Duo Agent Platform은 Vue.js로 만든 단일 페이지 애플리케이션(Single Page Application, SPA)으로, AI 기반 자동화 기능을 위한 통합 인터페이스를 제공합니다. 이 플랫폼은 여러 내비게이션 항목이 /automate 경로 아래에 함께 존재할 수 있게 하는 스코프 라우팅 시스템을 사용합니다.

이 플랫폼은 유연한 네임스페이스 시스템으로 설계되어, 동일한 프론트엔드 인프라를 서로 다른 컨텍스트(프로젝트, 그룹 등)에서 재사용하면서도 컴포넌트 매핑 시스템으로 컨텍스트별 기능을 제공합니다.

네임스페이스 아키텍처#

네임스페이스 시스템은 다음과 같은 중앙 매핑 메커니즘을 중심으로 구성됩니다.

  1. 네임스페이스를 확인합니다 - 플랫폼이 어느 컨텍스트에서 실행되는지 판별합니다
  2. Vue 컴포넌트에 매핑합니다 - 해당 네임스페이스에 맞는 Vue 컴포넌트로 라우팅합니다
  3. GraphQL 쿼리를 props로 전달합니다 - 의존성 주입으로 네임스페이스별 데이터를 제공합니다

진입점#

주 진입점의 위치는 다음과 같습니다.

ee/app/assets/javascripts/pages/projects/duo_agents_platform/index.js

이 파일이 플랫폼을 가져와 초기화합니다.

import { initDuoAgentsPlatformProjectPage } from 'ee/ai/duo_agents_platform/namespace/project';

initDuoAgentsPlatformProjectPage();

앱 구조#

Mermaid 다이어그램 (12줄)
소스 코드 보기
graph TD
    A[Entry Point] --> B[initDuoAgentsPlatformPage]
    B --> C[Extract Namespace Data]
    C --> D[Create Router with Namespace]
    D --> E[Component Mapping]
    E --> F[Namespace-Specific Component]
    F --> G[GraphQL Query with Props]
    G --> H[Rendered UI]
I[Dataset Properties] --&gt; C
J[Namespace Constant] --&gt; E
K[Component Mappings] --&gt; E</code></pre></details></div>

새 내비게이션 항목 추가#

GitLab Duo Agent Platform은 Vue Router 구성이 브레드크럼 내비게이션을 직접 구동하는 라우터 기반 내비게이션 시스템을 사용합니다. 핵심은 ee/app/assets/javascripts/ai/duo_agents_platform/router/index.js의 라우터 구조가 URL 구조와 브레드크럼 계층 구조를 모두 결정한다는 점입니다.

라우터 기반 내비게이션 동작 방식#

이 시스템은 서로 연결된 다음 구성 요소로 동작합니다.

  1. 라우터 구조: meta.text 속성을 가진 중첩 라우트가 브레드크럼 레이블을 정의합니다
  2. 브레드크럼 컴포넌트: duo_agents_platform_breadcrumbs.vue가 일치한 라우트에서 브레드크럼을 자동으로 생성합니다
  3. 라우트 주입: index.js의 injectVueAppBreadcrumbs()가 라우터를 브레드크럼 시스템에 연결합니다

라우터 분석#

ee/app/assets/javascripts/ai/duo_agents_platform/router/index.js의 현재 라우터 구조는 다음과 같습니다.

routes: [
  {
    component: NestedRouteApp, // Simple <router-view /> wrapper
    path: '/agent-sessions',
    meta: {
      text: s__('DuoAgentsPlatform|Sessions'), // This becomes a breadcrumb
    },
    children: [
      {
        name: AGENTS_PLATFORM_INDEX_ROUTE,
        path: '', // Matches /agent-sessions exactly
        component: AgentsPlatformIndex,
      },
      {
        name: AGENTS_PLATFORM_NEW_ROUTE,
        path: 'new', // Matches /agent-sessions/new
        component: AgentsPlatformNew,
        meta: {
          text: s__('DuoAgentsPlatform|New'), // This becomes a breadcrumb
        },
      },
      // ...
    ],
  },
];

브레드크럼 생성#

브레드크럼 컴포넌트(duo_agents_platform_breadcrumbs.vue)는 다음과 같이 동작합니다.

  1. this.$route.matched에서 일치한 모든 라우트를 가져옵니다
  2. 일치한 각 라우트에서 meta.text를 추출합니다
  3. 해당 텍스트와 라우트 경로로 브레드크럼 항목을 만듭니다
  4. 정적 브레드크럼("Automate" 등)과 결합합니다
// From duo_agents_platform_breadcrumbs.vue
const matchedRoutes = (this.$route?.matched || [])
  .map((route) => {
    return {
      text: route.meta?.text, // Uses meta.text for breadcrumb label
      to: { path: route.path },
    };
  })
  .filter((r) => r.text); // Only routes with meta.text become breadcrumbs

새 내비게이션 항목 추가#

새 최상위 내비게이션 항목("Your Feature" 같은)을 추가하려면 라우터에 새 라우트 트리를 추가해야 합니다.

1단계: 라우트 상수 추가#

파일: ee/app/assets/javascripts/ai/duo_agents_platform/router/constants.js

// Add route name constants for your feature
export const AGENTS_PLATFORM_YOUR_FEATURE_INDEX = 'your_feature_index';
export const AGENTS_PLATFORM_YOUR_FEATURE_NEW = 'your_feature_new';
export const AGENTS_PLATFORM_YOUR_FEATURE_SHOW = 'your_feature_show';

2단계: 라우터에 라우트 추가#

파일: ee/app/assets/javascripts/ai/duo_agents_platform/router/index.js

import YourFeatureIndex from '../pages/your_feature/your_feature_index.vue';
import YourFeatureNew from '../pages/your_feature/your_feature_new.vue';
import YourFeatureShow from '../pages/your_feature/your_feature_show.vue';

export const createRouter = (base, namespace) => {
  return new VueRouter({
    base,
    mode: 'history',
    routes: [
      // Existing agent-sessions routes
      {
        component: NestedRouteApp,
        path: '/agent-sessions',
        meta: {
          text: s__('DuoAgentsPlatform|Sessions'),
        },
        children: [
          {
            name: AGENTS_PLATFORM_INDEX_ROUTE,
            path: '',
            component: getNamespaceIndexComponent(namespace),
          },
          // ... existing children
        ],
      },

      // NEW: Your feature routes
      {
        component: NestedRouteApp,
        path: '/your-feature', // This becomes the URL path
        meta: {
          text: s__('DuoAgentsPlatform|Your Feature'), // This becomes the breadcrumb
        },
        children: [
          {
            name: AGENTS_PLATFORM_YOUR_FEATURE_INDEX,
            path: '', // Matches /your-feature exactly
            component: YourFeatureIndex,
          },
          {
            name: AGENTS_PLATFORM_YOUR_FEATURE_NEW,
            path: 'new', // Matches /your-feature/new
            component: YourFeatureNew,
            meta: {
              text: s__('DuoAgentsPlatform|New'), // Breadcrumb: "Your Feature > New"
            },
          },
          {
            name: AGENTS_PLATFORM_YOUR_FEATURE_SHOW,
            path: ':id(\\d+)', // Matches /your-feature/123
            component: YourFeatureShow,
            // No meta.text - will use route param as breadcrumb
          },
        ],
      },

      { path: '*', redirect: '/agent-sessions' },
    ],
  });
};

3단계: 백엔드 라우트 추가(필요한 경우)#

ee/config/routes/project.rb의 기존 와일드카드 라우트가 새 경로를 처리합니다.

scope :automate do
  get '/(*vueroute)' => 'duo_agents_platform#show', as: :automate, format: false
end

중요: 사이드바 메뉴 항목을 추가하는 경우(4단계)에는 이름이 지정된 라우트 헬퍼를 추가해야 합니다.

scope :automate do
  get '/(*vueroute)' => 'duo_agents_platform#show', as: :automate, format: false
  # Named routes for sidebar menu helpers
  get 'agent-sessions', to: 'duo_agents_platform#show', as: :automate_agent_sessions, format: false
  get 'your-feature', to: 'duo_agents_platform#show', as: :automate_your_features, format: false
end
Note

기존 패턴과 맞추고 Rails 경로 헬퍼가 올바르게 생성되도록 라우트 이름에는 복수형(예: automate_your_features)을 사용합니다.

4단계: 사이드바 메뉴 항목 추가#

파일: ee/lib/sidebars/projects/super_sidebar_menus/duo_agents_menu.rb

configure_menu_items 메서드에 메뉴 항목을 추가하고 그에 대응하는 메뉴 항목 메서드를 만듭니다.

override :configure_menu_items
def configure_menu_items
  add_item(duo_agents_runs_menu_item)
  add_item(duo_agents_your_feature_menu_item)  # Add your new menu item
  true
end

private

def duo_agents_your_feature_menu_item
  ::Sidebars::MenuItem.new(
    title: s_('Your Feature'),
    link: project_automate_your_features_path(context.project),  # Note: plural 'features'
    active_routes: { controller: :duo_agents_platform },
    item_id: :agents_your_feature
  )
end

5단계: Vue 컴포넌트 생성#

파일: ee/app/assets/javascripts/ai/duo_agents_platform/pages/your_feature/your_feature_index.vue

<script>
export default {
  name: 'YourFeatureIndex',
};
</script>

<template>
  <div>
    <h1>Your Feature</h1>
  </div>

</template>

새 네임스페이스 추가#

새 네임스페이스(예: 그룹용)를 추가하는 방법은 다음과 같습니다.

1. 네임스페이스 상수 정의#

// ee/app/assets/javascripts/ai/duo_agents_platform/constants.js
export const AGENT_PLATFORM_GROUP_PAGE = 'group';

2. 네임스페이스 디렉터리 구조 생성#

ee/app/assets/javascripts/ai/duo_agents_platform/namespace/group/
├── index.js
├── group_agents_platform_index.vue
└── graphql/
    └── queries/
        └── get_group_agent_flows.query.graphql

3. 네임스페이스 초기화 구현#

// ee/app/assets/javascripts/ai/duo_agents_platform/namespace/group/index.js
import { initDuoAgentsPlatformPage } from '../../index';
import { AGENT_PLATFORM_GROUP_PAGE } from '../../constants';

export const initDuoAgentsPlatformGroupPage = () => {
  initDuoAgentsPlatformPage({
    namespace: AGENT_PLATFORM_GROUP_PAGE,
    namespaceDatasetProperties: ['groupPath', 'groupId'],
  });
};

4. 네임스페이스별 컴포넌트 생성#

<!-- ee/app/assets/javascripts/ai/duo_agents_platform/namespace/group/group_agents_platform_index.vue -->
<script>
import getGroupAgentFlows from './graphql/queries/get_group_agent_flows.query.graphql';
import DuoAgentsPlatformIndex from '../../pages/index/duo_agents_platform_index.vue';

export default {
  components: { DuoAgentsPlatformIndex },
  inject: ['groupPath'], // Group-specific injection
  apollo: {
    workflows: {
      query: getGroupAgentFlows, // Group-specific query
      variables() {
        return {
          groupPath: this.groupPath,
          // ...
        };
      },
      // ...
    },
  },
};
</script>

<template>
  <duo-agents-platform-index
    :is-loading-workflows="isLoadingWorkflows"
    :workflows="workflows"
    :workflows-page-info="workflowsPageInfo"
    :workflow-query="$apollo.queries.workflows"
  />
</template>

5. 컴포넌트 매핑 업데이트#

// ee/app/assets/javascripts/ai/duo_agents_platform/router/utils.js
import { AGENT_PLATFORM_PROJECT_PAGE, AGENT_PLATFORM_GROUP_PAGE } from '../constants';
import ProjectAgentsPlatformIndex from '../namespace/project/project_agents_platform_index.vue';
import GroupAgentsPlatformIndex from '../namespace/group/group_agents_platform_index.vue';

export const getNamespaceIndexComponent = (namespace) => {
  const componentMappings = {
    [AGENT_PLATFORM_PROJECT_PAGE]: ProjectAgentsPlatformIndex,
    [AGENT_PLATFORM_GROUP_PAGE]: GroupAgentsPlatformIndex, // New mapping
  };

  return componentMappings[namespace];
};

6. 진입점 생성#

// ee/app/assets/javascripts/pages/groups/duo_agents_platform/index.js
import { initDuoAgentsPlatformGroupPage } from 'ee/ai/duo_agents_platform/namespace/group';

initDuoAgentsPlatformGroupPage();

이 아키텍처의 장점#

  1. 코드 재사용: 동일한 프론트엔드 인프라가 서로 다른 컨텍스트에서 동작합니다
  2. 관심사의 분리: 각 네임스페이스가 자체 데이터 페칭과 비즈니스 로직을 처리합니다
  3. 확장성: 기존 코드를 수정하지 않고 새 네임스페이스를 쉽게 추가할 수 있습니다
  4. 타입 안전성: 네임스페이스 상수와 필수 속성으로 계약이 명확합니다
  5. 유지 관리성: 네임스페이스 구현이 서로 격리되어 결합도가 낮아집니다

주요 구현 세부 사항#

라우터 기반 브레드크럼#

브레드크럼 시스템은 라우터 구조에서 내비게이션을 자동으로 생성합니다.

  • meta.text가 있는 상위 라우트는 브레드크럼 구간이 됩니다
  • meta.text가 있는 하위 라우트는 브레드크럼 체인을 확장합니다
  • meta.text가 없는 라우트는 라우트 파라미터(:id 등)를 브레드크럼 텍스트로 사용합니다
  • 정적 브레드크럼("Automate" 등)은 모든 라우트 앞에 붙습니다

URL 구조#

최상위 내비게이션 항목마다 자체 URL 네임스페이스를 가집니다.

  • Sessions: /automate/agent-sessions, /automate/agent-sessions/new, /automate/agent-sessions/123
  • Your Feature: /automate/your-feature, /automate/your-feature/new, /automate/your-feature/456

중첩 라우트 패턴#

이 플랫폼은 일관된 중첩 라우트 패턴을 사용합니다.

  1. 상위 라우트: URL 경로와 최상위 브레드크럼을 정의합니다
  2. NestedRouteApp 컴포넌트: 하위 라우트를 위한 단순한 <router-view /> 래퍼입니다
  3. 하위 라우트: 개별 페이지와 추가 브레드크럼 구간을 정의합니다

예시: 현재 에이전트 세션 구현#

기존 에이전트 세션 기능이 이 패턴을 보여 줍니다.

{
  component: NestedRouteApp,           // Renders child routes
  path: '/agent-sessions',             // URL: /automate/agent-sessions
  meta: {
    text: s__('DuoAgentsPlatform|Sessions'),  // Breadcrumb: "Sessions"
  },
  children: [
    {
      name: AGENTS_PLATFORM_INDEX_ROUTE,
      path: '',                        // URL: /automate/agent-sessions
      component: AgentsPlatformIndex,  // No additional breadcrumb
    },
    {
      name: AGENTS_PLATFORM_NEW_ROUTE,
      path: 'new',                     // URL: /automate/agent-sessions/new
      component: AgentsPlatformNew,
      meta: {
        text: s__('DuoAgentsPlatform|New'),  // Breadcrumb: "Sessions > New"
      },
    },
    {
      name: AGENTS_PLATFORM_SHOW_ROUTE,
      path: ':id(\\d+)',               // URL: /automate/agent-sessions/123
      component: AgentsPlatformShow,   // Breadcrumb: "Sessions > 123"
      // No meta.text - uses :id parameter as breadcrumb
    },
  ],
}

이렇게 하면 다음 브레드크럼 계층 구조가 만들어집니다.

  • /automate/agent-sessions → "Automate > Sessions"
  • /automate/agent-sessions/new → "Automate > Sessions > New"
  • /automate/agent-sessions/123 → "Automate > Sessions > 123"

주요 파일 참조#

  • 진입점: ee/app/assets/javascripts/pages/projects/duo_agents_platform/index.js
  • 주 초기화: ee/app/assets/javascripts/ai/duo_agents_platform/index.js
  • 라우터: ee/app/assets/javascripts/ai/duo_agents_platform/router/index.js
  • 컴포넌트 매핑: ee/app/assets/javascripts/ai/duo_agents_platform/router/utils.js
  • 상수: ee/app/assets/javascripts/ai/duo_agents_platform/constants.js
  • 유틸리티: ee/app/assets/javascripts/ai/duo_agents_platform/utils.js
  • 프로젝트 네임스페이스: ee/app/assets/javascripts/ai/duo_agents_platform/namespace/project/

모범 사례#

  1. 라우터 구조: meta.text 속성을 가진 중첩 라우트로 브레드크럼 계층 구조를 정의합니다
  2. URL 이름 지정: URL 경로에는 kebab-case를 사용합니다(/yourFeature가 아니라 /your-feature)
  3. 라우트 이름: 라우트 이름에는 의미가 분명한 상수를 사용합니다(AGENTS_PLATFORM_YOUR_FEATURE_INDEX)
  4. 컴포넌트 구성: 기능 컴포넌트는 pages/[feature]/ 디렉터리에 둡니다
  5. 브레드크럼 텍스트: 모든 meta.text 값에는 국제화 문자열(s__())을 사용합니다
  6. 일관된 패턴: NestedRouteApp을 사용하는 기존 중첩 라우트 패턴을 따릅니다
  7. 네임스페이스 분리: 네임스페이스별 로직은 namespace/ 아래의 전용 디렉터리에 둡니다
  8. 컴포넌트 매핑: 컴포넌트 매핑 시스템으로 네임스페이스별 컴포넌트에 라우팅합니다
  9. 데이터 주입: 네임스페이스별 데이터에는 Vue의 provide/inject 패턴을 사용합니다

문제 해결#

일반적인 문제#

  1. 브레드크럼이 표시되지 않음: 상위 라우트에 meta.text 속성이 있는지 확인합니다
  2. 라우트가 동작하지 않음: ee/config/routes/project.rb에 와일드카드 라우트가 있는지 확인합니다
  3. 사이드바가 강조되지 않음: 사이드바 메뉴 항목의 active_routes가 올바른지 확인합니다
  4. 404 오류: 라우트 경로가 기존 라우트와 충돌하지 않는지 확인합니다

디버깅 팁#

  1. Vue DevTools: $route.matched를 검사해 어떤 라우트가 일치하는지 확인합니다
  2. 라우터 상태: Vue DevTools에서 라우터 구성을 확인합니다
  3. 브레드크럼 디버그: 브레드크럼 컴포넌트에 console.log(this.$route.matched)를 추가합니다
  4. URL 테스트: 브라우저에서 URL로 직접 이동해 라우트를 테스트합니다

가짜 플로 생성#

플랫폼을 시험해 볼 가짜 플로를 생성하려면 ee/lib/tasks/gitlab/duo_workflow/duo_workflow.rake Rake 태스크를 실행할 수 있습니다.

특정 프로젝트에서 플로 50 개를 만들고 그중 20 개는 지정한 사용자가 만들도록 하는 예

bundle exec rake "gitlab:duo_workflow:populate[50,20,user@example.com,gitlab-org/gitlab-test]