# Module Diagram Editor Design

## Goal

Build the function module diagram experience shown in the reference image while preserving the existing EasyCode project-driven diagram flow.

The feature has two entry points:

- Project diagram center: enhance the existing "功能模块图" tab so it can generate the diagram from the saved project blueprint, then let the user adjust layout and export.
- Standalone module diagram editor: provide a SQL2Doc-style editor with a left-side indented structure input and a right-side live module diagram canvas.

Both entry points must share the same parsing, graph layout, SVG rendering, and export logic.

## Current Context

The frontend already has:

- `easycode-web/src/components/AppModuleDiagramView.vue`
- `easycode-web/src/utils/appModuleGraph.js`
- `easycode-web/src/utils/appModuleExport.js`
- `easycode-web/src/views/DiagramCenterView.vue`
- tests for `appModuleGraph` and `appModuleExport`

The current graph is already close to the target: it renders a root node, two group nodes, vertical leaf nodes, and black right-angle connectors. The new work should evolve this code rather than replace it with a separate diagram implementation.

## User Experience

### Diagram Center

In `DiagramCenterView.vue`, the "功能模块图" view should become a richer workspace:

- Mode switch:
  - `自动蓝图`: convert `appBlueprint` into an editable outline and render it.
  - `缩进结构`: let the user edit the outline directly.
- Layout controls:
  - Density: `标准`, `宽松`, `紧凑`
  - Direction: `横向`, `竖向`
  - Font size: a compact select or segmented control for `小`, `标准`, `大`.
- Export controls:
  - SVG export
  - PNG export
- Save behavior:
  - Save the current outline text, layout options, source mode, and generated graph payload through the existing project diagram save endpoint.

The diagram center remains project-aware. It loads the project name and blueprint, and saving writes back to the project diagram list.

### Standalone Editor

Add an editor page that can work with or without a project:

- With `projectId`: initialize from the project blueprint, allow edits, and save as a project module diagram.
- Without `projectId`: act as a pure local tool that renders and exports from the typed outline.

The page layout follows the reference:

- Header/tool row for density, direction, font size, and export.
- Left panel for the indented outline text.
- Right panel for the live SVG canvas.
- Helpful empty/error states near the editor rather than modal interruptions.

Custom undo/redo controls are out of scope for this phase. The textarea keeps the browser's native undo/redo behavior.

## Input Model

Use a shared outline model as the internal contract:

```js
{
  title: '学生社团管理系统',
  groups: [
    {
      title: '管理员端',
      items: [
        { title: '注册登录' },
        { title: '用户管理' }
      ]
    }
  ]
}
```

### Indented Text Rules

- First non-empty line is the system title.
- Second-level lines are groups/modules.
- Third-level and deeper lines are leaf functions.
- Indentation is counted in spaces. Tabs are normalized to two spaces.
- The editor should accept imperfect input:
  - Blank lines are ignored.
  - A leaf without a group is placed under a fallback group.
  - Deeply nested functions are flattened into leaf titles by default.
- Parsing should return warnings rather than throwing for recoverable issues.

Example:

```text
学生社团管理系统
  管理员端
    注册登录
    用户管理
    社团管理
  普通用户端
    注册登录
    社团浏览
    社团申请
```

### Blueprint Conversion

Convert the existing app blueprint into the same outline model:

- Root title: project name, then `blueprint.projectName`, then default fallback.
- Admin group: `管理员端`, from `adminMenus`.
- Frontend group: `普通用户端`, from `frontendMenus`.
- Menu title: `menu.name`, then `menu.title`, then `menu.code`.

This keeps automatic project generation and manual editing equivalent.

## Graph Layout

Keep a deterministic graph object:

```js
{
  title,
  caption,
  nodes,
  edges,
  groups,
  canvas,
  options
}
```

Node kinds:

- `root`
- `group`
- `module`

Default horizontal layout:

- Root centered at the top.
- Groups arranged in a row below root.
- Leaf functions arranged below each group.
- Leaf nodes use vertical writing like the reference image.
- Connectors use straight right-angle paths with crisp black strokes.

Density controls tune spacing and sizes, not semantic structure:

- `compact`: smaller gaps, lower canvas width.
- `standard`: current default visual balance.
- `relaxed`: wider gaps for export/readability.

Vertical layout can be introduced as a second layout strategy:

- Root at the left/top.
- Groups stacked or arranged vertically.
- Leaf modules arranged to the right or below each group.

If vertical layout becomes too large, keep horizontal as the production default and make vertical a best-effort option with tests around graph validity.

## Components And Utilities

Refactor toward these units:

- `appModuleOutline.js`
  - `parseModuleOutlineText(text)`
  - `moduleOutlineToText(outline)`
  - `blueprintToModuleOutline(blueprint, options)`
  - `normalizeModuleOutline(outline)`
- `appModuleGraph.js`
  - `buildAppModuleGraph(source, options)`
  - Accept either blueprint or normalized outline.
  - Keep backward compatibility with current callers.
- `appModuleExport.js`
  - Build standalone SVG from the graph.
  - Exported SVG must match the visible graph style.
- `AppModuleDiagramView.vue`
  - Pure graph view plus toolbar.
  - Accept blueprint, outline text, and layout options.
  - Emit outline/layout changes when used in editor mode.
- `ModuleDiagramEditorView.vue`
  - Standalone page with the two-pane editor.
- `DiagramCenterView.vue`
  - Project-aware host that loads project data, manages save, and embeds the shared component.

## Data Flow

Diagram center automatic mode:

```text
project.appBlueprint + project.projectName
  -> blueprintToModuleOutline
  -> moduleOutlineToText
  -> parseModuleOutlineText
  -> buildAppModuleGraph
  -> AppModuleDiagramView
  -> export/save
```

Standalone editor:

```text
outline textarea
  -> parseModuleOutlineText
  -> buildAppModuleGraph
  -> AppModuleDiagramView
  -> export/save if projectId exists
```

## Error Handling

- Empty input shows an empty state instead of rendering a broken graph.
- Invalid indentation shows non-blocking warnings.
- Export failures use `ElMessage.warning`.
- Save failures use the existing `ElMessage.error` pattern in `DiagramCenterView.vue`.
- Long labels are truncated in horizontal boxes and clipped/ellipsized in vertical leaf boxes.

## Testing

Add focused frontend tests before implementation:

- `parseModuleOutlineText` parses the reference student club outline.
- Tabs normalize to two spaces.
- Missing root or empty input returns an empty outline with warnings.
- `blueprintToModuleOutline` maps `adminMenus` to `管理员端` and `frontendMenus` to `普通用户端`.
- `buildAppModuleGraph` supports a normalized outline source.
- Density options change canvas or spacing predictably.
- Export SVG contains the expected text, rectangles, and paths without `foreignObject`.

Use existing Node test style in `easycode-web/src/utils/*.test.mjs`.

## Non-Goals

- No drag-and-drop node editing in this phase.
- No AI generation changes in this phase.
- No backend schema change. Store source mode, outline text, layout options, and graph data inside the existing `diagramJson` payload.
- No pixel-perfect clone of SQL2Doc branding; the goal is the same module diagram workflow and thesis-style output inside EasyCode.

## Acceptance Criteria

- Users can open the project diagram center and view a module diagram generated from the project blueprint.
- Users can switch to indented text mode, edit the structure, and see the diagram update.
- Users can open the standalone module diagram editor and build the same style of diagram from text.
- The generated diagram visually matches the reference style: white canvas, black outlined boxes, straight black connectors, vertical leaf labels.
- SVG and PNG exports reflect the current layout settings.
- Saving a project module diagram preserves source mode, outline text, layout options, and graph data.
- Existing module diagram tests continue to pass, and new parser/layout/export tests pass.
