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.
tests/test_data_factory_orchestration_navigation_contract.py: owns the engine-separation navigation contract.tests/test_data_rule_frontend_contract.py: points the existing governed deployment assertions at the new Kestra page.frontend/src/router/routes.js: defines independent Kestra and legacy n8n menu entries.frontend/src/views/dataFactory/productionLineDeployment/index.vue: dedicated Kestra production deployment page, moved from the n8n directory.frontend/src/views/dataFactory/workflow/index.vue: retains only n8n workflow list, executions, and health.frontend/src/views/dataFactory/workflow/ProductionLineDeployment.vue: eliminates the physical page coupling.Files:
tests/test_data_factory_orchestration_navigation_contract.pyTest: tests/test_data_factory_orchestration_navigation_contract.py
[ ] Step 1: Write the failing contract
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
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.
git add tests/test_data_factory_orchestration_navigation_contract.py
git commit -m "test: define Kestra and n8n navigation boundary"
Files:
frontend/src/views/dataFactory/productionLineDeployment/index.vuefrontend/src/views/dataFactory/workflow/ProductionLineDeployment.vuefrontend/src/views/dataFactory/workflow/index.vueModify: 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.
Make frontend/src/views/dataFactory/workflow/index.vue contain only:
<v-tabs v-model="tab" @change="handleTabChange">
<v-tab>工作流列表</v-tab>
<v-tab>执行记录</v-tab>
<v-tab>健康检查</v-tab>
</v-tabs>
Remove the ProductionLineDeployment import, component registration, and tab item. Keep ExecutionRecord :tab="tab" aligned with the new three-tab index.
Change the constants in tests/test_data_rule_frontend_contract.py to:
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.
Run:
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.
Files:
frontend/src/router/routes.jsTest: 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:
{
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
}
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.
Run:
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.
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"
Files:
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.
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.
Run:
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.
Verify in the local UAT UI:
数据工厂 > 数据生产线投产 opens the governed Kestra page.数据工厂 > n8n 生产线管理(待下线) opens the current n8n URL.数据工厂 > n8n 工作流管理(待下线) shows only three n8n tabs.Run:
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.