|
@@ -0,0 +1,205 @@
|
|
|
|
|
+# Enterprise Identity Navigation Move 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:** Move the enterprise identity management entry from Data Research to System Management without changing its URL, component, permission, or runtime behavior.
|
|
|
|
|
+
|
|
|
|
|
+**Architecture:** This is a router-data-only migration. A structural source contract will identify top-level and child route objects by their route names, prove the old parent no longer owns the entry, and prove the System Management parent owns exactly one compatible `企业身份与 SSO` entry.
|
|
|
|
|
+
|
|
|
|
|
+**Tech Stack:** Vue 2 router metadata, Python pytest source contracts, Vue CLI production build, Docker Compose local UAT.
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## File Structure
|
|
|
|
|
+
|
|
|
|
|
+- Create `tests/test_enterprise_identity_navigation_contract.py`: structural parent, compatibility, order, and uniqueness contract.
|
|
|
|
|
+- Modify `frontend/src/router/routes.js`: move and rename the existing navigation object; no page or API changes.
|
|
|
|
|
+
|
|
|
|
|
+### Task 1: Define the failing navigation ownership contract
|
|
|
|
|
+
|
|
|
|
|
+**Files:**
|
|
|
|
|
+- Create: `tests/test_enterprise_identity_navigation_contract.py`
|
|
|
|
|
+- Test: `tests/test_enterprise_identity_navigation_contract.py`
|
|
|
|
|
+
|
|
|
|
|
+- [ ] **Step 1: Write the structural test**
|
|
|
|
|
+
|
|
|
|
|
+```python
|
|
|
|
|
+from pathlib import Path
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ROOT = Path(__file__).resolve().parents[1]
|
|
|
|
|
+ROUTES = ROOT / "frontend/src/router/routes.js"
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def _route_block(source: str, *, indent: int, name: str) -> str:
|
|
|
|
|
+ start_token = " " * indent + "{\n"
|
|
|
|
|
+ end_token = "\n" + " " * indent + "},"
|
|
|
|
|
+ name_token = " " * (indent + 2) + f"name: '{name}'"
|
|
|
|
|
+ name_at = source.index(name_token)
|
|
|
|
|
+ start = source.rfind(start_token, 0, name_at)
|
|
|
|
|
+ end = source.find(end_token, name_at)
|
|
|
|
|
+ assert start >= 0 and end >= 0
|
|
|
|
|
+ return source[start : end + len(end_token)]
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def test_enterprise_identity_is_owned_only_by_system_management():
|
|
|
|
|
+ routes = ROUTES.read_text(encoding="utf-8")
|
|
|
|
|
+ data_research = _route_block(routes, indent=4, name="data-governance")
|
|
|
|
|
+ system = _route_block(routes, indent=4, name="systemManage")
|
|
|
|
|
+
|
|
|
|
|
+ assert "systemEnterpriseIdentity" not in data_research
|
|
|
|
|
+ assert routes.count("name: 'systemEnterpriseIdentity'") == 1
|
|
|
|
|
+
|
|
|
|
|
+ identity = _route_block(system, indent=8, name="systemEnterpriseIdentity")
|
|
|
|
|
+ assert "title: '企业身份与 SSO'" in identity
|
|
|
|
|
+ assert "label: '企业身份与 SSO'" in identity
|
|
|
|
|
+ assert "path: '/systemManage/enterprise-identity'" in identity
|
|
|
|
|
+ assert "component: 'systemManage/enterpriseIdentity'" in identity
|
|
|
|
|
+ assert "permissions: ['identity:manage']" in identity
|
|
|
|
|
+ assert "icon: 'mdi-account-key-outline'" in identity
|
|
|
|
|
+ assert "sort: 2" in identity
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def test_system_management_navigation_order_is_stable():
|
|
|
|
|
+ routes = ROUTES.read_text(encoding="utf-8")
|
|
|
|
|
+ system = _route_block(routes, indent=4, name="systemManage")
|
|
|
|
|
+ names = [
|
|
|
|
|
+ "systemUserManage",
|
|
|
|
|
+ "systemEnterpriseIdentity",
|
|
|
|
|
+ "systemResponsibilityManage",
|
|
|
|
|
+ "systemGovernanceAudit",
|
|
|
|
|
+ "systemAgentGovernance",
|
|
|
|
|
+ ]
|
|
|
|
|
+ positions = [system.index(f"name: '{name}'") for name in names]
|
|
|
|
|
+ assert positions == sorted(positions)
|
|
|
|
|
+ for sort, name in enumerate(names, start=1):
|
|
|
|
|
+ block = _route_block(system, indent=8, name=name)
|
|
|
|
|
+ assert f"sort: {sort}" in block
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+- [ ] **Step 2: Verify RED**
|
|
|
|
|
+
|
|
|
|
|
+Run: `PYTHONPATH=. .venv/bin/pytest -q tests/test_enterprise_identity_navigation_contract.py`
|
|
|
|
|
+
|
|
|
|
|
+Expected: FAIL because `systemEnterpriseIdentity` still belongs to the Data Research route and is absent from System Management.
|
|
|
|
|
+
|
|
|
|
|
+- [ ] **Step 3: Commit the RED contract**
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+git add tests/test_enterprise_identity_navigation_contract.py
|
|
|
|
|
+git commit -m "test: define enterprise identity menu ownership"
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### Task 2: Move the compatible route record
|
|
|
|
|
+
|
|
|
|
|
+**Files:**
|
|
|
|
|
+- Modify: `frontend/src/router/routes.js`
|
|
|
|
|
+- Test: `tests/test_enterprise_identity_navigation_contract.py`
|
|
|
|
|
+
|
|
|
|
|
+- [ ] **Step 1: Remove the existing child from Data Research**
|
|
|
|
|
+
|
|
|
|
|
+Delete only the child object whose route name is `systemEnterpriseIdentity` from the `data-governance` children array. Do not modify the surrounding Data Research routes.
|
|
|
|
|
+
|
|
|
|
|
+- [ ] **Step 2: Insert the compatible child under System Management**
|
|
|
|
|
+
|
|
|
|
|
+Insert this object immediately after `systemUserManage`:
|
|
|
|
|
+
|
|
|
|
|
+```javascript
|
|
|
|
|
+{
|
|
|
|
|
+ hidden: 0,
|
|
|
|
|
+ type: 1,
|
|
|
|
|
+ title: '企业身份与 SSO',
|
|
|
|
|
+ path: '/systemManage/enterprise-identity',
|
|
|
|
|
+ children: [],
|
|
|
|
|
+ label: '企业身份与 SSO',
|
|
|
|
|
+ sort: 2,
|
|
|
|
|
+ component: 'systemManage/enterpriseIdentity',
|
|
|
|
|
+ meta: {
|
|
|
|
|
+ title: '企业身份与 SSO',
|
|
|
|
|
+ icon: 'mdi-account-key-outline',
|
|
|
|
|
+ permissions: ['identity:manage']
|
|
|
|
|
+ },
|
|
|
|
|
+ name: 'systemEnterpriseIdentity',
|
|
|
|
|
+ alwaysShow: 0
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+Change the following System Management sort values:
|
|
|
|
|
+
|
|
|
|
|
+- `systemResponsibilityManage`: `2` to `3`
|
|
|
|
|
+- `systemGovernanceAudit`: `3` to `4`
|
|
|
|
|
+- `systemAgentGovernance`: `4` to `5`
|
|
|
|
|
+
|
|
|
|
|
+- [ ] **Step 3: Verify GREEN and regression scope**
|
|
|
|
|
+
|
|
|
|
|
+Run:
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+PYTHONPATH=. .venv/bin/pytest -q \
|
|
|
|
|
+ tests/test_enterprise_identity_navigation_contract.py \
|
|
|
|
|
+ tests/test_phase3_wp02_enterprise_identity_contract.py \
|
|
|
|
|
+ tests/test_frontend_rbac_contract.py \
|
|
|
|
|
+ tests/test_architecture_artifacts.py
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+Expected: all tests pass; existing path and `identity:manage` assertions remain green.
|
|
|
|
|
+
|
|
|
|
|
+- [ ] **Step 4: Build the frontend**
|
|
|
|
|
+
|
|
|
|
|
+Run: `npm --prefix frontend run build`
|
|
|
|
|
+
|
|
|
|
|
+Expected: exit 0 with no route resolution error.
|
|
|
|
|
+
|
|
|
|
|
+- [ ] **Step 5: Commit the router migration**
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+git add frontend/src/router/routes.js
|
|
|
|
|
+git commit -m "feat: move enterprise identity to system management"
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### Task 3: Deploy and verify the local UAT frontend
|
|
|
|
|
+
|
|
|
|
|
+**Files:**
|
|
|
|
|
+- Verify: `deploy/docker/docker-compose.yml`
|
|
|
|
|
+- Verify: `frontend/src/router/routes.js`
|
|
|
|
|
+
|
|
|
|
|
+- [ ] **Step 1: Rebuild only the frontend**
|
|
|
|
|
+
|
|
|
|
|
+Run: `docker compose -f deploy/docker/docker-compose.yml up -d --build frontend`
|
|
|
|
|
+
|
|
|
|
|
+Expected: the frontend container is recreated and becomes healthy; persisted identity and application data remain unchanged.
|
|
|
|
|
+
|
|
|
|
|
+- [ ] **Step 2: Verify health and compatible deep link**
|
|
|
|
|
+
|
|
|
|
|
+Run:
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+docker compose -f deploy/docker/docker-compose.yml ps
|
|
|
|
|
+curl -fsS http://localhost:18183/systemManage/enterprise-identity >/dev/null
|
|
|
|
|
+curl -fsS http://localhost:15500/api/system/health >/dev/null
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+Expected: frontend, backend, Kestra, n8n, runner, and storage services remain healthy; both HTTP checks succeed.
|
|
|
|
|
+
|
|
|
|
|
+- [ ] **Step 3: Verify the visible menu after authentication**
|
|
|
|
|
+
|
|
|
|
|
+Confirm that:
|
|
|
|
|
+
|
|
|
|
|
+1. `数据研发` no longer displays `企业身份`.
|
|
|
|
|
+2. `系统管理` displays `企业身份与 SSO` after `用户管理`.
|
|
|
|
|
+3. Opening it preserves `/systemManage/enterprise-identity` and shows the existing `企业身份与 SSO` page with `待企业 IdP UAT`.
|
|
|
|
|
+
|
|
|
|
|
+- [ ] **Step 4: Final checks**
|
|
|
|
|
+
|
|
|
|
|
+Run:
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+git diff --check
|
|
|
|
|
+PYTHONPATH=. .venv/bin/pytest -q \
|
|
|
|
|
+ tests/test_enterprise_identity_navigation_contract.py \
|
|
|
|
|
+ tests/test_phase3_wp02_enterprise_identity_contract.py \
|
|
|
|
|
+ tests/test_frontend_rbac_contract.py \
|
|
|
|
|
+ tests/test_architecture_artifacts.py
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+Expected: all focused tests pass and `git diff --check` emits no output.
|