diff --git a/frontend/src/App.vue b/frontend/src/App.vue
index e69de29..d687428 100644
--- a/frontend/src/App.vue
+++ b/frontend/src/App.vue
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/env.d.ts b/frontend/src/env.d.ts
new file mode 100644
index 0000000..2b97bd9
--- /dev/null
+++ b/frontend/src/env.d.ts
@@ -0,0 +1,5 @@
+declare module '*.vue' {
+ import type { DefineComponent } from 'vue'
+ const component: DefineComponent<{}, {}, any>
+ export default component
+}
diff --git a/frontend/src/main.ts b/frontend/src/main.ts
index e69de29..501dee0 100644
--- a/frontend/src/main.ts
+++ b/frontend/src/main.ts
@@ -0,0 +1,10 @@
+import { createApp } from 'vue'
+import { createPinia } from 'pinia'
+import App from './App.vue'
+import router from './router'
+import './style.css'
+
+const app = createApp(App)
+app.use(createPinia())
+app.use(router)
+app.mount('#app')
diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts
index e69de29..7c742de 100644
--- a/frontend/src/router/index.ts
+++ b/frontend/src/router/index.ts
@@ -0,0 +1,12 @@
+import { createRouter, createWebHistory } from 'vue-router'
+
+const router = createRouter({
+ history: createWebHistory(),
+ routes: [
+ { path: '/', component: () => import('@/modules/project/components/ProjectList.vue') },
+ { path: '/projects/:id', component: () => import('@/modules/graph/components/GraphPanorama.vue') },
+ { path: '/projects/:id/editor', component: () => import('@/modules/editor/components/EditorPage.vue') },
+ ],
+})
+
+export default router
diff --git a/frontend/src/shared/api.ts b/frontend/src/shared/api.ts
index e69de29..a60e00f 100644
--- a/frontend/src/shared/api.ts
+++ b/frontend/src/shared/api.ts
@@ -0,0 +1,3 @@
+import axios from 'axios'
+const api = axios.create({ baseURL: '/api' })
+export default api
diff --git a/frontend/src/shared/types/api.ts b/frontend/src/shared/types/api.ts
index e69de29..43fa19d 100644
--- a/frontend/src/shared/types/api.ts
+++ b/frontend/src/shared/types/api.ts
@@ -0,0 +1,198 @@
+export interface Project {
+ id: string
+ name: string
+ design_dir: string
+ code_dir: string | null
+ created_at: string
+}
+
+export interface FileStatusEntry {
+ path: string
+ status: string
+ content_lines: number
+}
+
+export interface ScanSummary {
+ total_files: number
+ ok: number
+ sparse: number
+ missing: number
+ placeholder_heavy: number
+ template_residue: number
+}
+
+export interface ScanResult {
+ project_id: string
+ scanned_at: string
+ file_statuses: FileStatusEntry[]
+ summary: ScanSummary
+}
+
+export interface GraphNode {
+ id: string
+ type: string
+ label: string
+ status: string
+ group_id: string
+}
+
+export interface GraphEdge {
+ source: string
+ target: string
+ relation: string
+}
+
+export interface GraphGroup {
+ id: string
+ label: string
+ layer: string
+}
+
+export interface GraphView {
+ nodes: GraphNode[]
+ edges: GraphEdge[]
+ groups: GraphGroup[]
+}
+
+export interface Capability {
+ capability_id: string
+ name: string
+ description: string
+ priority: string
+ phase: string
+ related_value_flows: string[]
+}
+
+export interface Module {
+ module_id: string
+ name: string
+ layer: string
+ description: string
+ phase: string
+ depends_on: string[]
+ capabilities: string[]
+}
+
+export interface Entity {
+ entity_id: string
+ name: string
+ domain: string
+ owner_module: string
+ description: string
+ phase: string
+ source_file: string
+}
+
+export interface Integration {
+ integration_id: string
+ source: string
+ target: string
+ target_type: string
+ direction: string
+ protocol: string
+ trigger: string
+ phase: string
+ description: string
+}
+
+export interface ValueFlow {
+ value_flow_id: string
+ name: string
+ trigger: string
+ actor: string
+ steps: string
+ outcome: string
+ phase: string
+ related_capabilities: string[]
+}
+
+export interface UserJourney {
+ journey_id: string
+ name: string
+ actor: string
+ precondition: string
+ steps: string
+ postcondition: string
+ phase: string
+ related_value_flows: string[]
+}
+
+export interface DataFlow {
+ data_flow_id: string
+ source: string
+ target: string
+ data_content: string
+ trigger: string
+ protocol: string
+ phase: string
+ description: string
+}
+
+export interface ExternalSystem {
+ system_id: string
+ name: string
+ type: string
+ protocol: string
+ direction: string
+ phase: string
+ description: string
+}
+
+export interface TraceabilityLink {
+ trace_id: string
+ capability_id: string
+ module_id: string
+ entity_ids: string[]
+ value_flow_ids: string[]
+ notes: string
+}
+
+export interface RuntimeComponent {
+ component_id: string
+ name: string
+ type: string
+ technology: string
+ port: string
+}
+
+export interface EditableFile {
+ path: string
+ format: string
+ content: string
+ last_modified: string
+}
+
+export interface AffectedFile {
+ path: string
+ reason: string
+}
+
+export interface ImpactResult {
+ source_file: string
+ affected_files: AffectedFile[]
+}
+
+export interface ImplProgress {
+ module_id: string
+ percentage: number
+ source: string
+ evaluated_at: string
+}
+
+export interface CapabilityDetail {
+ capability: Capability
+ modules: Module[]
+ value_flows: ValueFlow[]
+}
+
+export interface ModuleDetail {
+ module: Module
+ entities: Entity[]
+ integrations: Integration[]
+ codebase_alignment: Record | null
+}
+
+export interface EntityDetail {
+ entity: Entity
+ data_flows: DataFlow[]
+}
diff --git a/frontend/src/style.css b/frontend/src/style.css
new file mode 100644
index 0000000..ef40b86
--- /dev/null
+++ b/frontend/src/style.css
@@ -0,0 +1,83 @@
+:root {
+ --sidebar-width: 260px;
+ --color-primary: #1976D2;
+ --color-bg: #f5f5f5;
+ --color-sidebar: #fff;
+ --color-border: #e0e0e0;
+ --color-ok: #4CAF50;
+ --color-sparse: #FFC107;
+ --color-missing: #F44336;
+ --color-template-residue: #FF9800;
+ --color-placeholder-heavy: #9C27B0;
+ --color-unknown: #9E9E9E;
+}
+
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+body {
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
+ background: var(--color-bg);
+ color: #333;
+}
+
+.app-layout {
+ display: grid;
+ grid-template-columns: var(--sidebar-width) 1fr;
+ min-height: 100vh;
+}
+
+.sidebar {
+ background: var(--color-sidebar);
+ border-right: 1px solid var(--color-border);
+ padding: 16px;
+ overflow-y: auto;
+}
+
+.sidebar h2 {
+ font-size: 16px;
+ margin-bottom: 16px;
+ color: var(--color-primary);
+}
+
+.content {
+ padding: 24px;
+ overflow-y: auto;
+}
+
+button {
+ cursor: pointer;
+ border: none;
+ border-radius: 4px;
+ padding: 8px 16px;
+ font-size: 14px;
+}
+
+button.primary {
+ background: var(--color-primary);
+ color: white;
+}
+
+button.danger {
+ background: var(--color-missing);
+ color: white;
+}
+
+input, textarea {
+ border: 1px solid var(--color-border);
+ border-radius: 4px;
+ padding: 8px;
+ font-size: 14px;
+ width: 100%;
+}
+
+.card {
+ background: white;
+ border: 1px solid var(--color-border);
+ border-radius: 8px;
+ padding: 16px;
+ margin-bottom: 12px;
+}
diff --git a/frontend/src/vite-env.d.ts b/frontend/src/vite-env.d.ts
new file mode 100644
index 0000000..11f02fe
--- /dev/null
+++ b/frontend/src/vite-env.d.ts
@@ -0,0 +1 @@
+///