# Data Factory Kestra / n8n Navigation Separation Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Give governed Kestra production deployment and legacy n8n management independent Data Factory navigation and page lifecycles. **Architecture:** Move the Kestra deployment component out of the n8n workflow directory and expose it through a dedicated internal route. Keep the two n8n surfaces explicitly marked as legacy, preserve their current adapters, and protect the separation with source-level navigation contracts plus a production frontend build and Docker smoke test. **Tech Stack:** Vue 2, Vue Router, Vuetify, Python pytest contract tests, Docker Compose. --- ## File Structure - Create `tests/test_data_factory_orchestration_navigation_contract.py`: owns the engine-separation navigation contract. - Modify `tests/test_data_rule_frontend_contract.py`: points the existing governed deployment assertions at the new Kestra page. - Modify `frontend/src/router/routes.js`: defines independent Kestra and legacy n8n menu entries. - Create `frontend/src/views/dataFactory/productionLineDeployment/index.vue`: dedicated Kestra production deployment page, moved from the n8n directory. - Modify `frontend/src/views/dataFactory/workflow/index.vue`: retains only n8n workflow list, executions, and health. - Remove `frontend/src/views/dataFactory/workflow/ProductionLineDeployment.vue`: eliminates the physical page coupling. ### Task 1: Add the failing navigation-separation contract **Files:** - Create: `tests/test_data_factory_orchestration_navigation_contract.py` - Test: `tests/test_data_factory_orchestration_navigation_contract.py` - [ ] **Step 1: Write the failing contract** ```python from pathlib import Path ROOT = Path(__file__).resolve().parents[1] ROUTES = ROOT / "frontend/src/router/routes.js" N8N_PAGE = ROOT / "frontend/src/views/dataFactory/workflow/index.vue" KESTRA_PAGE = ROOT / "frontend/src/views/dataFactory/productionLineDeployment/index.vue" def test_data_factory_exposes_independent_kestra_and_legacy_n8n_navigation(): routes = ROUTES.read_text(encoding="utf-8") assert "数据生产线投产" in routes assert "'/dataFactory/production-line-deployment'" in routes assert "dataFactory/productionLineDeployment" in routes assert "n8n 生产线管理(待下线)" in routes assert "n8n 工作流管理(待下线)" in routes assert routes.index("数据生产线投产") < routes.index("n8n 生产线管理(待下线)") def test_kestra_page_is_not_owned_by_the_n8n_workflow_page(): legacy = N8N_PAGE.read_text(encoding="utf-8") kestra = KESTRA_PAGE.read_text(encoding="utf-8") assert "ProductionLineDeployment" not in legacy assert "数据生产线投产" not in legacy assert "工作流列表" in legacy assert "执行记录" in legacy assert "健康检查" in legacy assert "DATA FACTORY · GOVERNED RELEASE" in kestra assert "Kestra revision" in kestra ``` - [ ] **Step 2: Run the contract and verify RED** Run: `PYTHONPATH=. .venv/bin/pytest -q tests/test_data_factory_orchestration_navigation_contract.py` Expected: FAIL because the dedicated Kestra route/page does not exist and the n8n page still imports `ProductionLineDeployment`. - [ ] **Step 3: Commit the RED contract** ```bash git add tests/test_data_factory_orchestration_navigation_contract.py git commit -m "test: define Kestra and n8n navigation boundary" ``` ### Task 2: Create the dedicated Kestra page and remove the n8n tab coupling **Files:** - Create: `frontend/src/views/dataFactory/productionLineDeployment/index.vue` - Remove: `frontend/src/views/dataFactory/workflow/ProductionLineDeployment.vue` - Modify: `frontend/src/views/dataFactory/workflow/index.vue` - Modify: `tests/test_data_rule_frontend_contract.py` - [ ] **Step 1: Move the governed deployment component** Move `frontend/src/views/dataFactory/workflow/ProductionLineDeployment.vue` byte-for-byte to `frontend/src/views/dataFactory/productionLineDeployment/index.vue`. Its imports use the `@/api/dataRules` alias, so the move does not change runtime dependencies. - [ ] **Step 2: Remove the Kestra tab from the legacy n8n page** Make `frontend/src/views/dataFactory/workflow/index.vue` contain only: ```vue 工作流列表 执行记录 健康检查 ``` Remove the `ProductionLineDeployment` import, component registration, and tab item. Keep `ExecutionRecord :tab="tab"` aligned with the new three-tab index. - [ ] **Step 3: Point the existing governed frontend contract at the new page** Change the constants in `tests/test_data_rule_frontend_contract.py` to: ```python FACTORY = Path( "frontend/src/views/dataFactory/productionLineDeployment/index.vue" ) FACTORY_INDEX = FACTORY ``` The existing assertions continue to prove deployment, canary, activation, rollback, evidence, and readiness behavior. - [ ] **Step 4: Run focused tests** Run: ```bash PYTHONPATH=. .venv/bin/pytest -q \ tests/test_data_factory_orchestration_navigation_contract.py \ tests/test_data_rule_frontend_contract.py ``` Expected: navigation test still fails only because the new router entry is absent; existing governed deployment assertions pass at the new location. ### Task 3: Add independent router entries and legacy labels **Files:** - Modify: `frontend/src/router/routes.js` - Test: `tests/test_data_factory_orchestration_navigation_contract.py` - [ ] **Step 1: Insert the Kestra entry before the legacy entries** Add a Data Factory child with this contract: ```javascript { meun: '', code: '', hidden: 0, rootId: 972, icon: '', remark: '', type: 1, title: '数据生产线投产', local: '', path: '/dataFactory/production-line-deployment', urls: '', children: [], enName: 'Kestra Production Deployment', id: 979, redirect: '', level: 2, openPath: '', active: '', label: '数据生产线投产', sort: 5, parentId: 972, effectiveStatus: true, parentName: 'dataFactory', component: 'dataFactory/productionLineDeployment', meta: { keepAlive: false, allowClick: false, roles: [], enName: 'Kestra Production Deployment', icon: '', editModules: false, title: '数据生产线投产', fullScreen: false, target: false, effectiveStatus: true }, name: 'productionLineDeployment', style: '', alwaysShow: 0, metastr: '{"keepAlive":false,"allowClick":false,"enName":"Kestra Production Deployment","editModules":false,"title":"数据生产线投产","fullScreen":false,"target":false}', open: null } ``` - [ ] **Step 2: Rename the two n8n entries without changing behavior** Update the current external entry label/title to `n8n 生产线管理(待下线)` while retaining `process.env.VUE_APP_N8N_URL` and `target: true`. Update the current internal workflow entry label/title to `n8n 工作流管理(待下线)` while retaining `/dataFactory/workflow`, component `dataFactory/workflow`, and `target: false`. - [ ] **Step 3: Run RED-to-GREEN contract tests** Run: ```bash PYTHONPATH=. .venv/bin/pytest -q \ tests/test_data_factory_orchestration_navigation_contract.py \ tests/test_data_rule_frontend_contract.py \ tests/test_cleanup_contract.py \ tests/test_architecture_artifacts.py ``` Expected: PASS. - [ ] **Step 4: Commit the implementation** ```bash git add \ frontend/src/router/routes.js \ frontend/src/views/dataFactory/workflow/index.vue \ frontend/src/views/dataFactory/productionLineDeployment/index.vue \ frontend/src/views/dataFactory/workflow/ProductionLineDeployment.vue \ tests/test_data_rule_frontend_contract.py git commit -m "feat: separate Kestra and legacy n8n navigation" ``` ### Task 4: Build, deploy, and verify the local UAT frontend **Files:** - Verify: `frontend/` - Verify: `deploy/docker/docker-compose.yml` - [ ] **Step 1: Build the production frontend** Run: `npm --prefix frontend run build` Expected: exit 0 with a generated production bundle and no route-resolution error. - [ ] **Step 2: Rebuild and restart only the frontend service** Run: `docker compose -f deploy/docker/docker-compose.yml up -d --build frontend` Expected: frontend and its dependencies remain healthy; backend, Kestra, and n8n state are preserved. - [ ] **Step 3: Verify service health and deep links** Run: ```bash docker compose -f deploy/docker/docker-compose.yml ps curl -fsS http://localhost:18183/dataFactory/production-line-deployment >/dev/null curl -fsS http://localhost:18183/dataFactory/workflow >/dev/null ``` Expected: frontend is healthy and both internal routes return the SPA document. - [ ] **Step 4: Browser acceptance** Verify in the local UAT UI: 1. `数据工厂 > 数据生产线投产` opens the governed Kestra page. 2. `数据工厂 > n8n 生产线管理(待下线)` opens the current n8n URL. 3. `数据工厂 > n8n 工作流管理(待下线)` shows only three n8n tabs. 4. Refreshing either internal deep link does not produce a 404. - [ ] **Step 5: Run final source checks and commit any generated contract update** Run: ```bash git diff --check PYTHONPATH=. .venv/bin/pytest -q \ tests/test_data_factory_orchestration_navigation_contract.py \ tests/test_data_rule_frontend_contract.py \ tests/test_cleanup_contract.py \ tests/test_architecture_artifacts.py ``` Expected: all tests pass and `git diff --check` emits no output.