I'll help you build an asset inventory system. Let me first read the specification files and the plan to understand the current progress and determine the next core feature to implement. ✓ List directory spec (11 files) ✓ Read plan.md (667 lines) Now let me read the ISO 27001 specification files to understand the full context: ✓ Read spec/ISO27001-MVP10規劃.md:1-100 (105 lines) ✓ Read spec/ISO27001-MVP10-1實作.md:1-100 (105 lines) ✓ Read spec/ISO27001-資料庫設計(Database Schema Design).md:1-100 (105 lines) Let me check the current backend status: ✓ Check Docker services status $ cd /root/projects/iso27001-system && docker-compose ps ↪ 2 lines... ✓ Check Docker services status with new command $ cd /root/projects/iso27001-system && docker compose ps ↪ 3 lines... 根據我閱讀的文件,我了解到: ## 📊 當前狀態分析: **已完成部分** ✅: - 後端資產管理 API(完整 CRUD) - 前端資產管理介面(列表、新增、編輯、詳情) - 用戶認證系統(JWT) - 風險管理系統(完整的風險評估、報告、儀表板) **下一個核心功能** 🎯: 根據 plan.md 的進度,大任務 2.2「資產關係與依賴分析」尚未開始。這是一個重要的功能,因為: 1. 符合 ISO 27001 要求(資產依賴關係對風險評估很重要) 2. 可以識別關鍵資產 3. 可以進行影響分析 ## 🚀 我將實作:**大任務 2.2.1 - 資產依賴關係圖** 這個功能包括: - 後端:完善 AssetRelationship 模型和 API - 前端:建立資產關係視覺化介面(使用 React Flow 或類似工具) - 功能:影響分析、關鍵資產識別 讓我開始實作: ✓ Start Docker services $ cd /root/projects/iso27001-system && docker compose up -d ↪ 86 lines... ✓ read_bash ↪ 86 lines... 容器正在建置中,讓我等待完成: ✓ read_bash ↪ 86 lines... 建置過程較長,讓我繼續等待: ✓ read_bash ↪ 86 lines... Docker 建置時間過長。讓我先停止它,改用不重新建置容器的方式啟動現有服務,或直接進行開發工作: ✓ stop_bash ↪ 1 line... 讓我直接查看後端資產關係模型,然後開始實作資產依賴關係功能: ✓ List directory backend/assets (16 files) ✓ Read backend/assets/models.py:1-100 (105 lines) ✓ Read backend/assets/models.py:100-end (5 lines) ✓ Read backend/assets/models.py:95-150 (46 lines) 很好!資產關係模型已經存在。現在讓我查看後端的 serializers 和 views: ✓ Read backend/assets/views.py:1-100 (105 lines) ✓ Read backend/assets/serializers.py (120 lines) 讓我繼續查看 views 和檢查是否有資產關係的 ViewSet: ✓ Search for AssetRelationship in views $ cd /root/projects/iso27001-system/backend/assets && grep -n "AssetRelationship" views.py ↪ 10 lines... 很好!後端已有 AssetRelationshipViewSet。讓我查看完整的 views.py 和 urls.py: ✓ Read backend/assets/views.py:120-250 (118 lines) ✓ Read backend/assets/urls.py (17 lines) 很好!後端 API 已經完整。現在我需要: 1. 擴展後端 API 增加依賴分析功能(影響分析、關鍵路徑等) 2. 在前端建立資產關係視覺化頁面 讓我先擴展後端 API,添加依賴分析功能: ✓ Edit backend/assets/views.py (+127) ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │ 230     required_permission = Permissions.ASSET_VIEW │ │ 231     filter_backends = [DjangoFilterBackend] │ │ 232     filterset_fields = ['from_asset', 'to_asset', 'relationship_type'] │ │ 233  +   │ │ 234  +  @action(detail=False, methods=['get']) │ │ 235  +  def dependency_graph(self, request): │ │ 236  +   """ │ │ 237  +   取得資產依賴關係圖資料 │ │ 238  +   GET /api/asset-relationships/dependency_graph/ │ │ 239  +   """ │ │ 240  +   relationships = AssetRelationship.objects.select_related('from_asset', │ │ 'to_asset').all() │ │ 241  +   │ │ 242  +   # 建立節點集合 │ │ 243  +   nodes = {} │ │ 244  +   edges = [] │ │ 245  +   │ │ 246  +   for rel in relationships: │ │ 247  +   # 添加節點 │ │ 248  +   if str(rel.from_asset.id) not in nodes: │ │ 249  +   nodes[str(rel.from_asset.id)] = { │ │ 250  +   'id': str(rel.from_asset.id), │ │ 251  +   'label': rel.from_asset.name, │ │ 252  +   'asset_number': rel.from_asset.asset_number, │ │ 253  +   'asset_type': rel.from_asset.asset_type, │ │ 254  +   'status': rel.from_asset.status, │ │ 255  +   'risk_level': rel.from_asset.risk_level, │ │ 256  +   } │ │ 257  +   │ │ 258  +   if str(rel.to_asset.id) not in nodes: │ │ 259  +   nodes[str(rel.to_asset.id)] = { │ │ 260  +   'id': str(rel.to_asset.id), │ │ 261  +   'label': rel.to_asset.name, │ │ 262  +   'asset_number': rel.to_asset.asset_number, │ │ 263  +   'asset_type': rel.to_asset.asset_type, │ │ 264  +   'status': rel.to_asset.status, │ │ 265  +   'risk_level': rel.to_asset.risk_level, │ │ 266  +   } │ │ 267  +   │ │ 268  +   # 添加邊 │ │ 269  +   edges.append({ │ │ 270  +   'id': str(rel.id), │ │ 271  +   'source': str(rel.from_asset.id), │ │ 272  +   'target': str(rel.to_asset.id), │ │ 273  +   'label': rel.get_relationship_type_display(), │ │ 274  +   'type': rel.relationship_type, │ │ 275  +   }) │ │ 276  +   │ │ 277  +   return Response({ │ │ 278  +   'nodes': list(nodes.values()), │ │ 279  +   'edges': edges, │ │ 280  +   }) │ │ 281  +   │ │ 282  +  @action(detail=False, methods=['get'], │ │ url_path='impact-analysis/(?P[^/.]+)') │ │ 283  +  def impact_analysis(self, request, asset_id=None): │ │ 284  +   """ │ │ 285  +   資產影響分析 - 找出所有依賴此資產的其他資產 │ │ 286  +   GET /api/asset-relationships/impact-analysis/{asset_id}/ │ │ 287  +   """ │ │ 288  +   try: │ │ 289  +   asset = Asset.objects.get(id=asset_id) │ │ 290  +   except Asset.DoesNotExist: │ │ 291  +   return Response( │ │ 292  +   {'error': '資產不存在'}, │ │ 293  +   status=status.HTTP_404_NOT_FOUND │ │ 294  +   ) │ │ 295  +   │ │ 296  +   # 遞迴找出所有依賴此資產的資產 │ │ 297  +   def find_dependents(asset_id, visited=None): │ │ 298  +   if visited is None: │ │ 299  +   visited = set() │ │ 300  +   │ │ 301  +   if asset_id in visited: │ │ 302  +   return [] │ │ 303  +   │ │ 304  +   visited.add(asset_id) │ │ 305  +   dependents = [] │ │ 306  +   │ │ 307  +   # 找出直接依賴此資產的資產 │ │ 308  +   relationships = AssetRelationship.objects.filter( │ │ 309  +   to_asset_id=asset_id │ │ 310  +   ).select_related('from_asset') │ │ 311  +   │ │ 312  +   for rel in relationships: │ │ 313  +   dependent_info = { │ │ 314  +   'asset': AssetListSerializer(rel.from_asset).data, │ │ 315  +   'relationship_type': rel.relationship_type, │ │ 316  +   'relationship_type_display': rel.get_relationship_type_display(), │ │ 317  +   } │ │ 318  +   dependents.append(dependent_info) │ │ 319  +   │ │ 320  +   # 遞迴找出間接依賴 │ │ 321  +   indirect = find_dependents(str(rel.from_asset.id), visited) │ │ 322  +   dependents.extend(indirect) │ │ 323  +   │ │ 324  +   return dependents │ │ 325  +   │ │ 326  +   dependents = find_dependents(asset_id) │ │ 327  +   │ │ 328  +   return Response({ │ │ 329  +   'asset': AssetSerializer(asset).data, │ │ 330  +   'dependent_count': len(dependents), │ │ 331  +   'dependents': dependents, │ │ 332  +   'impact_level': 'high' if len(dependents) > 10 else 'medium' if │ │ len(dependents) > 5 else 'low', │ │ 333  +   }) │ │ 334  +   │ │ 335  +  @action(detail=False, methods=['get']) │ │ 336  +  def critical_assets(self, request): │ │ 337  +   """ │ │ 338  +   識別關鍵資產 - 被最多其他資產依賴的資產 │ │ 339  +   GET /api/asset-relationships/critical_assets/ │ │ 340  +   """ │ │ 341  +   from django.db.models import Count │ │ 342  +   │ │ 343  +   # 統計每個資產被依賴的次數 │ │ 344  +   critical_assets = Asset.objects.annotate( │ │ 345  +   dependent_count=Count('relationships_to') │ │ 346  +   ).filter( │ │ 347  +   dependent_count__gt=0, │ │ 348  +   deleted_at__isnull=True │ │ 349  +   ).order_by('-dependent_count')[:20] │ │ 350  +   │ │ 351  +   result = [] │ │ 352  +   for asset in critical_assets: │ │ 353  +   result.append({ │ │ 354  +   'asset': AssetListSerializer(asset).data, │ │ 355  +   'dependent_count': asset.dependent_count, │ │ 356  +   'criticality': 'critical' if asset.dependent_count > 10 else 'high' if │ │ asset.dependent_count > 5 else 'medium', │ │ 357  +   }) │ │ 358  +   │ │ 359  +   return Response(result) │ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ 現在讓我在前端建立資產關係管理的相關功能。首先建立 API 介面: ✓ Create frontend/src/api/assetRelationships.ts (+91) 現在讓我建立資產依賴關係圖視覺化頁面。我將使用 React Flow 庫來顯示圖形: ✓ Create frontend/src/pages/AssetDependencyGraph.tsx (+348) 現在建立 CSS 樣式檔案: ✓ Create frontend/src/pages/AssetDependencyGraph.css (+37) 現在建立影響分析頁面: ✓ Create frontend/src/pages/AssetImpactAnalysis.tsx (+266) 現在更新 App.tsx 加入新的路由: ✓ Read frontend/src/App.tsx (50 lines) ✓ Edit frontend/src/App.tsx (+2) ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │ 7     import AssetList from './pages/AssetList'; │ │ 8     import AssetForm from './pages/AssetForm'; │ │ 9     import AssetDetail from './pages/AssetDetail'; │ │ 10  +  import AssetDependencyGraph from './pages/AssetDependencyGraph'; │ │ 11  +  import AssetImpactAnalysis from './pages/AssetImpactAnalysis'; │ │ 12     import RiskList from './pages/RiskList'; │ │ 13     import RiskForm from './pages/RiskForm'; │ │ 14     import RiskReport from './pages/RiskReport'; │ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ ✓ Edit frontend/src/App.tsx (+2) ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │ 26     } /> │ │ 27     } /> │ │ 28     } /> │ │ 29  +  } /> │ │ 30     } /> │ │ 31     } /> │ │ 32  +  } /> │ │ 33     文件管理功能開發中...} /> │ │ 34     } /> │ │ 35     } /> │ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ 現在更新 AssetList 頁面,加入依賴關係圖和影響分析的入口按鈕: ✓ Read frontend/src/pages/AssetList.tsx:1-50 (55 lines) ✓ Read frontend/src/pages/AssetList.tsx:140-200 (66 lines) ✓ Read frontend/src/pages/AssetList.tsx:200-270 (76 lines) ✓ Read frontend/src/pages/AssetList.tsx:269-350 (87 lines) Find add asset button location $ cd /root/projects/iso27001-system/frontend/src/pages && grep -n "新增資產" AssetList.tsx | head -5 ↪ 2 lines... ✓ Read frontend/src/pages/AssetList.tsx:350-380 (36 lines) ✓ Edit frontend/src/pages/AssetList.tsx (+2) ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │ 23      ReloadOutlined, │ │ 24      EyeOutlined, │ │ 25      LockOutlined, │ │ 26  +   NodeExpandOutlined, │ │ 27  +   WarningOutlined, │ │ 28     } from '@ant-design/icons'; │ │ 29     import { useNavigate } from 'react-router-dom'; │ │ 30     import { assetsApi } from '../api/assets'; │ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ ✓ Edit frontend/src/pages/AssetList.tsx (+6) ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │ 354      │ │ 355      │ │ 356      │ │ 357  +   │ │ 363      │ │ 364      │ │ 237  +   │ │ 238  +   │ │ 245  +   │ │ 246      │ │ 247      {(can) => ( │ │ 248      │ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ ✗ Edit frontend/src/pages/AssetList.tsx Multiple matches found ✓ Edit frontend/src/pages/AssetList.tsx (+1 -1) ╭──────────────────────────────────────────────────────────────────────────────────────────────╮ │ 224     title: '操作', │ │ 225     key: 'action', │ │ 226     fixed: 'right', │ │ 227  -  width: 200, │ │ 227  +  width: 240, │ │ 228     render: (_: any, record: Asset) => ( │ │ 229      │ │ 230