**ARCH VISUALIZER v1.0** - '아키텍처', '구조', '시각화', '다이어그램', '문서화', 'codebase_graph.md', '프로젝트 구조' 요청 시 자동 발동. codebase-graph 기반 자동 아키텍처 문서/다이어그램 생성. Mermaid/PlantUML/ASCII 다이어그램, 자동 갱신 지원.
Scanned 2/12/2026
Install to Claude Code
npx -y skills add majiayu000/claude-skill-registry --skill arch-visualizer-monicajeon28-gmcruise --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Arch Visualizer?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/majiayu000-arch-visualizer)More formats (shields.io, HTML) on the badges page.
---
name: arch-visualizer
description: "**ARCH VISUALIZER v1.0** - '아키텍처', '구조', '시각화', '다이어그램', '문서화', 'codebase_graph.md', '프로젝트 구조' 요청 시 자동 발동. codebase-graph 기반 자동 아키텍처 문서/다이어그램 생성. Mermaid/PlantUML/ASCII 다이어그램, 자동 갱신 지원."
allowed-tools:
- Read
- Glob
- Grep
- Write
---
# Arch Visualizer Skill v1.0
**아키텍처 자동 문서화** - codebase-graph를 시각적 다이어그램과 문서로 자동 변환
## 핵심 컨셉
```yaml
Problem:
Manual_Documentation:
- "아키텍처 문서가 코드와 동기화 안 됨"
- "다이어그램 수동 업데이트 번거로움"
- "신규 개발자 온보딩 지연"
Solution:
Auto_Visualization:
- "codebase-graph 데이터로 자동 생성"
- "코드 변경 시 자동 갱신"
- "다양한 포맷 지원 (Mermaid, PlantUML, ASCII)"
Output_Types:
- "codebase_graph.md: 전체 아키텍처 문서"
- "모듈 의존성 다이어그램"
- "클래스 다이어그램"
- "호출 흐름 다이어그램"
- "레이어 다이어그램"
```
## 자동 발동 조건
```yaml
Auto_Trigger_Conditions:
Keywords_KO:
- "아키텍처 문서, 구조 문서"
- "다이어그램 생성, 시각화"
- "프로젝트 구조, 코드 구조"
- "codebase_graph.md 생성"
- "의존성 다이어그램, 클래스 다이어그램"
- "온보딩 문서, 신규 개발자 문서"
Keywords_EN:
- "architecture document, structure doc"
- "generate diagram, visualize"
- "project structure, code structure"
- "dependency diagram, class diagram"
- "onboarding document"
Events:
- "프로젝트 초기 분석 완료 후"
- "대규모 리팩토링 후"
- "/arch 명령어 실행 시"
Scheduled:
- "주요 변경사항 커밋 후 자동 갱신"
```
## 생성 가능한 다이어그램
### 1. 모듈 의존성 다이어그램
```yaml
Module_Dependency:
purpose: "모듈/패키지 간 의존 관계"
format: "Mermaid flowchart"
shows:
- "폴더/패키지 단위"
- "import 방향"
- "순환 참조 표시"
```
### 2. 클래스 다이어그램
```yaml
Class_Diagram:
purpose: "클래스 간 상속/구현 관계"
format: "Mermaid classDiagram"
shows:
- "클래스/인터페이스"
- "상속 관계"
- "구현 관계"
- "주요 메서드"
```
### 3. 시퀀스 다이어그램
```yaml
Sequence_Diagram:
purpose: "특정 기능의 호출 흐름"
format: "Mermaid sequenceDiagram"
shows:
- "함수 호출 순서"
- "비동기 호출"
- "에러 핸들링 흐름"
```
### 4. 레이어 다이어그램
```yaml
Layer_Diagram:
purpose: "계층 구조 (Controller→Service→Repository)"
format: "Mermaid flowchart TB"
shows:
- "계층 분리"
- "계층 간 통신"
- "위반 사항 강조"
```
### 5. 컴포넌트 다이어그램
```yaml
Component_Diagram:
purpose: "고수준 시스템 구조"
format: "Mermaid/C4Model"
shows:
- "주요 컴포넌트"
- "외부 시스템"
- "데이터 흐름"
```
## codebase_graph.md 템플릿
```markdown
# {{projectName}} Architecture
> Auto-generated on {{generatedAt}}
> Based on codebase-graph analysis
## Overview
| Metric | Value |
|--------|-------|
| Total Files | {{totalFiles}} |
| Total Functions | {{totalFunctions}} |
| Total Classes | {{totalClasses}} |
| Total Types | {{totalTypes}} |
| Languages | {{languages}} |
| Framework | {{framework}} |
---
## Project Structure
```
{{projectTree}}
```
---
## Module Dependency Graph
```mermaid
flowchart LR
{{moduleDependencyMermaid}}
```
### Key Modules
| Module | Files | Functions | Complexity | Description |
|--------|-------|-----------|------------|-------------|
{{#each keyModules}}
| {{name}} | {{fileCount}} | {{functionCount}} | {{avgComplexity}} | {{description}} |
{{/each}}
---
## Layer Architecture
```mermaid
flowchart TB
subgraph Presentation["Presentation Layer"]
Controllers
Routes
end
subgraph Business["Business Layer"]
Services
UseCases
end
subgraph Data["Data Layer"]
Repositories
Models
end
subgraph Infrastructure["Infrastructure"]
Database
ExternalAPIs
Cache
end
Presentation --> Business
Business --> Data
Data --> Infrastructure
```
### Layer Distribution
| Layer | Files | % |
|-------|-------|---|
{{#each layers}}
| {{name}} | {{fileCount}} | {{percentage}}% |
{{/each}}
---
## Class Relationships
```mermaid
classDiagram
{{classDiagramMermaid}}
```
### Key Classes
{{#each keyClasses}}
#### {{name}}
- **Path**: `{{path}}`
- **Extends**: {{extends}}
- **Implements**: {{implements}}
- **Methods**: {{methodCount}}
- **Injected Dependencies**: {{dependencies}}
{{/each}}
---
## API Endpoints
| Method | Path | Handler | Description |
|--------|------|---------|-------------|
{{#each endpoints}}
| {{method}} | {{path}} | {{handler}} | {{description}} |
{{/each}}
---
## Entry Points
### Main Entry
- **File**: `{{mainEntry}}`
- **Bootstrap**: `{{bootstrapFunction}}`
### Route Entry Points
{{#each routeEntries}}
- `{{path}}` → {{handler}}
{{/each}}
---
## Hot Spots (High Complexity)
| Function | Complexity | LOC | File |
|----------|------------|-----|------|
{{#each hotSpots}}
| {{name}} | {{complexity}} | {{loc}} | {{file}} |
{{/each}}
---
## Circular Dependencies
{{#if circularDependencies.length}}
**Detected {{circularDependencies.length}} circular dependencies:**
{{#each circularDependencies}}
{{index}}. `{{cycle}}`
{{/each}}
{{else}}
No circular dependencies detected.
{{/if}}
---
## Orphan Code (Unused)
{{#if orphans.length}}
**Found {{orphans.length}} potentially unused exports:**
{{#each orphans}}
- `{{path}}:{{name}}`
{{/each}}
{{else}}
No unused exports detected.
{{/if}}
---
## Quick Navigation
### By Feature
{{#each features}}
- **{{name}}**: {{files}}
{{/each}}
### By Layer
- **Controllers**: {{controllerFiles}}
- **Services**: {{serviceFiles}}
- **Repositories**: {{repositoryFiles}}
- **Types**: {{typeFiles}}
---
## Onboarding Guide
### 1. Where to Start
{{startingPoints}}
### 2. Core Concepts
{{coreConcepts}}
### 3. Common Patterns
{{commonPatterns}}
### 4. Configuration
{{configurationGuide}}
---
*This document is auto-generated and will be updated when the codebase changes.*
*Last updated: {{lastUpdated}}*
```
## Mermaid 다이어그램 생성기
```typescript
class MermaidGenerator {
private graph: CodebaseGraph;
constructor(graph: CodebaseGraph) {
this.graph = graph;
}
/**
* 모듈 의존성 다이어그램 생성
*/
generateModuleDependency(): string {
const modules = this.getModules();
const lines: string[] = ['flowchart LR'];
// 모듈 노드 정의
for (const mod of modules) {
const sanitized = this.sanitizeId(mod.name);
lines.push(` ${sanitized}["${mod.name}"]`);
}
// 의존성 엣지
const edges = this.graph.edges.filter(e => e.type === 'imports');
const moduleEdges = this.aggregateToModules(edges);
for (const { source, target, weight } of moduleEdges) {
const sourceId = this.sanitizeId(source);
const targetId = this.sanitizeId(target);
if (weight > 5) {
lines.push(` ${sourceId} ==> ${targetId}`); // 강한 의존성
} else {
lines.push(` ${sourceId} --> ${targetId}`);
}
}
// 순환 참조 표시
const cycles = this.graph.detectCircularDependencies();
for (const cycle of cycles) {
const cycleNodes = cycle.map(n => this.sanitizeId(n));
lines.push(` %% Circular: ${cycleNodes.join(' -> ')}`);
}
return lines.join('\n');
}
/**
* 클래스 다이어그램 생성
*/
generateClassDiagram(scope?: string): string {
const classes = this.graph.nodes
.filter(n => n.type === 'class')
.filter(n => !scope || n.path.includes(scope));
const lines: string[] = ['classDiagram'];
// 클래스 정의
for (const cls of classes) {
lines.push(` class ${cls.name} {`);
// 프로퍼티
for (const prop of cls.properties?.slice(0, 5) || []) {
const visibility = prop.visibility === 'private' ? '-' :
prop.visibility === 'protected' ? '#' : '+';
lines.push(` ${visibility}${prop.name}: ${this.simplifyType(prop.type)}`);
}
// 메서드
for (const methodId of cls.methods?.slice(0, 5) || []) {
const method = this.graph.findNode(methodId);
if (method) {
lines.push(` +${method.name}()`);
}
}
lines.push(` }`);
}
// 관계
for (const cls of classes) {
if (cls.extends) {
lines.push(` ${cls.extends} <|-- ${cls.name}`);
}
for (const impl of cls.implements || []) {
lines.push(` ${impl} <|.. ${cls.name}`);
}
}
return lines.join('\n');
}
/**
* 시퀀스 다이어그램 생성 (특정 흐름)
*/
generateSequenceDiagram(entryPoint: string, depth: number = 5): string {
const lines: string[] = ['sequenceDiagram'];
const visited = new Set<string>();
const participants = new Set<string>();
const traverse = (nodeId: string, currentDepth: number, caller?: string) => {
if (currentDepth > depth) return;
if (visited.has(`${caller}->${nodeId}`)) return;
visited.add(`${caller}->${nodeId}`);
const node = this.graph.findNode(nodeId);
if (!node) return;
const participant = this.getParticipant(node);
participants.add(participant);
if (caller) {
const callerParticipant = this.getParticipant(this.graph.findNode(caller)!);
if (node.isAsync) {
lines.push(` ${callerParticipant}->>+${participant}: ${node.name}()`);
lines.push(` ${participant}-->>-${callerParticipant}: result`);
} else {
lines.push(` ${callerParticipant}->>+${participant}: ${node.name}()`);
}
}
// 호출하는 함수들 추적
const calls = this.graph.getOutgoingEdges(nodeId, 'calls');
for (const call of calls.slice(0, 5)) {
traverse(call.target, currentDepth + 1, nodeId);
}
};
traverse(entryPoint, 0);
// 참여자 선언 추가
const participantLines = Array.from(participants).map(p =>
` participant ${p}`
);
return [lines[0], ...participantLines, ...lines.slice(1)].join('\n');
}
/**
* 레이어 다이어그램 생성
*/
generateLayerDiagram(): string {
const layers = this.detectLayers();
const lines: string[] = ['flowchart TB'];
// 레이어 서브그래프
for (const layer of layers) {
lines.push(` subgraph ${layer.name}["${layer.displayName}"]`);
for (const node of layer.nodes.slice(0, 10)) {
const id = this.sanitizeId(node.name);
lines.push(` ${id}["${node.name}"]`);
}
lines.push(` end`);
}
// 레이어 간 의존성
for (let i = 0; i < layers.length - 1; i++) {
lines.push(` ${layers[i].name} --> ${layers[i + 1].name}`);
}
// 위반 사항 (아래 레이어가 위 레이어 참조)
const violations = this.detectLayerViolations(layers);
for (const v of violations) {
lines.push(` %% VIOLATION: ${v.from} --> ${v.to}`);
lines.push(` ${v.from} -.->|violation| ${v.to}`);
}
return lines.join('\n');
}
/**
* 레이어 자동 감지
*/
private detectLayers(): Layer[] {
const layerPatterns = [
{ name: 'controllers', displayName: 'Presentation', patterns: ['controller', 'route', 'resolver'] },
{ name: 'services', displayName: 'Business', patterns: ['service', 'usecase', 'handler'] },
{ name: 'repositories', displayName: 'Data', patterns: ['repository', 'dao', 'model'] },
{ name: 'infrastructure', displayName: 'Infrastructure', patterns: ['database', 'cache', 'queue'] },
];
return layerPatterns.map(layer => ({
...layer,
nodes: this.graph.nodes.filter(n =>
layer.patterns.some(p => n.path.toLowerCase().includes(p) || n.name.toLowerCase().includes(p))
),
}));
}
/**
* 레이어 위반 감지
*/
private detectLayerViolations(layers: Layer[]): Violation[] {
const violations: Violation[] = [];
const layerOrder = layers.map(l => l.name);
for (const edge of this.graph.edges.filter(e => e.type === 'imports')) {
const sourceLayer = this.getLayerForNode(edge.source, layers);
const targetLayer = this.getLayerForNode(edge.target, layers);
if (sourceLayer && targetLayer) {
const sourceIndex = layerOrder.indexOf(sourceLayer);
const targetIndex = layerOrder.indexOf(targetLayer);
// 아래 레이어가 위 레이어를 참조하면 위반
if (sourceIndex > targetIndex) {
violations.push({
from: this.graph.findNode(edge.source)?.name || edge.source,
to: this.graph.findNode(edge.target)?.name || edge.target,
fromLayer: sourceLayer,
toLayer: targetLayer,
});
}
}
}
return violations;
}
private sanitizeId(name: string): string {
return name.replace(/[^a-zA-Z0-9]/g, '_');
}
private simplifyType(type: string): string {
if (type.length > 20) return type.substring(0, 17) + '...';
return type;
}
private getParticipant(node: GraphNode): string {
// 클래스 이름 또는 파일 이름
const parts = node.path.split('/');
return parts[parts.length - 1].replace('.ts', '');
}
private getModules(): { name: string; files: string[] }[] {
const modules = new Map<string, string[]>();
for (const node of this.graph.nodes.filter(n => n.type === 'file')) {
const parts = node.path.split('/');
const moduleName = parts.length > 2 ? parts.slice(0, -1).join('/') : parts[0];
if (!modules.has(moduleName)) {
modules.set(moduleName, []);
}
modules.get(moduleName)!.push(node.path);
}
return Array.from(modules.entries()).map(([name, files]) => ({ name, files }));
}
private aggregateToModules(edges: GraphEdge[]): { source: string; target: string; weight: number }[] {
const moduleEdges = new Map<string, number>();
for (const edge of edges) {
const sourceModule = this.getModuleName(edge.source);
const targetModule = this.getModuleName(edge.target);
if (sourceModule !== targetModule) {
const key = `${sourceModule}->${targetModule}`;
moduleEdges.set(key, (moduleEdges.get(key) || 0) + 1);
}
}
return Array.from(moduleEdges.entries()).map(([key, weight]) => {
const [source, target] = key.split('->');
return { source, target, weight };
});
}
private getModuleName(path: string): string {
const parts = path.split('/');
return parts.length > 2 ? parts.slice(0, 2).join('/') : parts[0];
}
private getLayerForNode(nodeId: string, layers: Layer[]): string | null {
for (const layer of layers) {
if (layer.nodes.some(n => n.id === nodeId)) {
return layer.name;
}
}
return null;
}
}
```
## Quick Commands
| Command | Action |
|---------|--------|
| `arch generate` | codebase_graph.md 전체 생성 |
| `arch modules` | 모듈 의존성 다이어그램 |
| `arch classes [scope]` | 클래스 다이어그램 |
| `arch sequence <entry>` | 시퀀스 다이어그램 |
| `arch layers` | 레이어 다이어그램 |
| `arch update` | 기존 문서 갱신 |
| `arch violations` | 레이어 위반 사항 |
| `arch onboarding` | 온보딩 문서 생성 |
## 다른 스킬과의 통합
```yaml
Integration:
codebase-graph:
type: "데이터 소스"
usage: "그래프 데이터 조회"
smart-context:
type: "협력"
usage: "문서화 컨텍스트 생성"
code-reviewer:
type: "소비자"
usage: "리뷰 시 구조 참조"
monorepo-architect:
type: "협력"
usage: "모노레포 구조 시각화"
```
## 문서 구조
```
arch-visualizer/
├── SKILL.md # 이 파일 (메인)
├── core/
│ ├── diagram-types.md # 다이어그램 유형 설명
│ └── layer-detection.md # 레이어 자동 감지
├── generators/
│ ├── mermaid-generator.md # Mermaid 생성기
│ ├── plantuml-generator.md # PlantUML 생성기
│ └── ascii-generator.md # ASCII 생성기
├── templates/
│ ├── codebase-graph-template.md # 메인 문서 템플릿
│ └── onboarding-template.md # 온보딩 문서 템플릿
└── quick-reference/
├── commands.md # 명령어 가이드
└── mermaid-syntax.md # Mermaid 문법 참조
```
---
**Version**: 1.0.0
**Quality Target**: 90%
**Required Skill**: codebase-graph
**Related Skills**: smart-context, monorepo-architect, code-reviewer
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!