diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 0000000..4d407a3 --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,13 @@ +{ + "name": "figram", + "version": "1.1.0", + "description": "Claude Code skills for Figram - YAML-driven architecture diagrams for FigJam", + "author": "7nohe", + "license": "MIT", + "homepage": "https://figram.7nohe.dev", + "repository": { + "type": "git", + "url": "https://github.com/7nohe/figram" + }, + "keywords": ["figram", "figjam", "architecture", "diagrams", "yaml", "aws", "gcp", "azure"] +} diff --git a/.claude/skills/yaml-authoring/SKILL.md b/.claude/skills/yaml-authoring/SKILL.md index d3de512..33865c2 100644 --- a/.claude/skills/yaml-authoring/SKILL.md +++ b/.claude/skills/yaml-authoring/SKILL.md @@ -5,160 +5,498 @@ description: Create and validate YAML diagram files. Use when writing new diagra # YAML Diagram Authoring -## Basic Structure +## Documentation + +- [YAML Specs](https://figram.7nohe.dev/en/yaml-specs/) - Full DSL specification +- [AWS Icons](https://figram.7nohe.dev/en/icons-aws/) - All available AWS icons +- [Azure Icons](https://figram.7nohe.dev/en/icons-azure/) - All available Azure icons +- [GCP Icons](https://figram.7nohe.dev/en/icons-gcp/) - All available GCP icons + +--- + +## Quick Start ```yaml version: 1 -docId: unique-document-id -title: "My Architecture Diagram" # optional +docId: "my-diagram" +title: "My Architecture" nodes: - - id: unique-id - provider: aws # Provider name (e.g., aws, gcp, azure) - kind: compute.lambda # Service category.type - label: "Display Name" # optional - parent: container-id # optional, for nesting in VPC/Subnet - layout: # optional for child nodes (auto-positioned) - x: 100 # optional for child nodes - y: 200 # optional for child nodes - w: 200 # required for containers (VPC/Subnet) - h: 150 # required for containers + - id: lambda + provider: aws + kind: compute.lambda + label: "Handler" + layout: { x: 100, y: 100 } + + - id: dynamodb + provider: aws + kind: database.dynamodb + label: "Users Table" + layout: { x: 300, y: 100 } edges: - - id: edge-1 - from: source-node-id - to: target-node-id - label: "optional label" # optional + - id: lambda-to-db + from: lambda + to: dynamodb + label: "read/write" +``` + +**Commands:** +```bash +# Validate and build to JSON +npx figram build diagram.yaml + +# Start WebSocket server with live reload +npx figram serve diagram.yaml ``` +--- + +## Document Structure + +### Top-Level Properties + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `version` | number | Yes | Schema version (currently `1`) | +| `docId` | string | Yes | Unique document identifier (used for WebSocket matching) | +| `title` | string | No | Document title (defaults to `docId`) | +| `nodes` | array | Yes | List of node definitions | +| `edges` | array | No | List of edge definitions | +| `icons` | object | No | Custom icon mappings | + +### Node Properties + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `id` | string | Yes | Unique node identifier | +| `provider` | string | Yes | Cloud provider (`aws`, `gcp`, `azure`) | +| `kind` | string | Yes | Resource type (e.g., `compute.lambda`) | +| `label` | string | No | Display label (defaults to `id`) | +| `parent` | string | No | Parent node id for nesting | +| `layout` | object | Conditional | Position and size | + +### Layout Properties + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `x` | number | Conditional* | X position (pixels) | +| `y` | number | Conditional* | Y position (pixels) | +| `w` | number | No** | Width (for containers) | +| `h` | number | No** | Height (for containers) | + +*Required for top-level nodes; optional for child nodes (auto-layout) +**Required for container nodes (VPC, Subnet, VNet) + +### Edge Properties + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `id` | string | Yes | Unique edge identifier | +| `from` | string | Yes | Source node id | +| `to` | string | Yes | Target node id | +| `label` | string | No | Connection label | +| `color` | string | No | Line color in HEX (`#RGB` or `#RRGGBB`). Default: `#666666` | + +--- + ## Auto-Layout -Child nodes (with `parent`) can omit `layout` entirely for automatic positioning: +Child nodes (with `parent`) can omit `layout` for automatic grid positioning. + +**Grid Layout:** +``` ++------------------------------------------+ +| [1] [2] [3] | +| (60,60) (220,60) (380,60) | +| | +| [4] [5] [6] | +| (60,200) (220,200) (380,200) | ++------------------------------------------+ +``` + +**Rules:** +- 3 columns per row +- 60px padding from parent edge +- 160px horizontal spacing, 140px vertical spacing +- Explicit `x`/`y` overrides auto-positioning +- Cannot specify only `x` or only `y` (both or neither) +**Example:** ```yaml nodes: - id: vpc provider: aws kind: network.vpc - layout: { x: 0, y: 0, w: 800, h: 600 } # Container: explicit layout + layout: { x: 0, y: 0, w: 800, h: 600 } # Container: explicit - id: ec2_1 provider: aws kind: compute.ec2 parent: vpc - # No layout - auto-positioned at (40, 40) + # No layout - auto: (60, 60) - id: ec2_2 provider: aws kind: compute.ec2 parent: vpc - # No layout - auto-positioned at (200, 40) + # No layout - auto: (220, 60) + + - id: rds + provider: aws + kind: database.rds + parent: vpc + layout: { x: 500, y: 300 } # Explicit override ``` -**Auto-layout rules:** -- 3 columns per row -- 60px padding, 160px horizontal spacing, 140px vertical spacing -- Explicit `x`/`y` overrides auto-positioning -- Cannot specify only `x` or only `y` (both or neither) +--- -## Node Kind Categories +## Providers & Kinds -The `kind` field uses a hierarchical format: `category.type` or `category.subcategory.type` +### AWS (`provider: aws`) -### Container Types (require w/h in layout) +**Containers** (require `w` and `h`): +| Kind | Description | +|------|-------------| +| `network.vpc` | Virtual Private Cloud | +| `network.subnet` | Subnet | + +**Common Resources:** +| Category | Kind | Description | +|----------|------|-------------| +| Compute | `compute.ec2` | EC2 Instance | +| Compute | `compute.lambda` | Lambda Function | +| Compute | `compute.lb.alb` | Application Load Balancer | +| Compute | `compute.lb.nlb` | Network Load Balancer | +| Compute | `compute.container.ecs` | ECS Cluster | +| Compute | `compute.container.ecs_service` | ECS Service | +| Compute | `compute.container.eks` | EKS Cluster | +| Compute | `compute.container.fargate` | Fargate | +| Compute | `compute.apprunner` | App Runner | +| Database | `database.rds` | RDS Database | +| Database | `database.aurora` | Aurora | +| Database | `database.dynamodb` | DynamoDB Table | +| Database | `database.elasticache` | ElastiCache | +| Database | `database.redshift` | Redshift | +| Storage | `storage.s3` | S3 Bucket | +| Storage | `storage.efs` | EFS File System | +| Storage | `storage.ebs` | EBS Volume | +| Network | `network.cloudfront` | CloudFront CDN | +| Network | `network.route53` | Route 53 DNS | +| Network | `network.apigateway` | API Gateway | +| Network | `network.igw` | Internet Gateway | +| Network | `network.natgateway` | NAT Gateway | +| Integration | `integration.sqs` | SQS Queue | +| Integration | `integration.sns` | SNS Topic | +| Integration | `integration.eventbridge` | EventBridge | +| Integration | `integration.stepfunctions` | Step Functions | +| Security | `security.iam` | IAM | +| Security | `security.cognito` | Cognito | +| Security | `security.secretsmanager` | Secrets Manager | +| Security | `security.kms` | KMS | + +### GCP (`provider: gcp`) + +**Containers** (require `w` and `h`): | Kind | Description | |------|-------------| | `network.vpc` | Virtual Private Cloud | -| `network.subnet` | Subnet within VPC | - -### Resource Types -| Category | Kind Examples | -|----------|---------------| -| `compute` | `compute.lambda`, `compute.ec2`, `compute.ecs`, `compute.eks` | -| `compute.lb` | `compute.lb.alb`, `compute.lb.nlb`, `compute.lb.elb` | -| `database` | `database.dynamodb`, `database.rds`, `database.aurora` | -| `storage` | `storage.s3`, `storage.efs`, `storage.ebs` | -| `integration` | `integration.apiGateway`, `integration.sns`, `integration.sqs`, `integration.eventBridge` | -| `security` | `security.iam`, `security.cognito`, `security.waf` | -| `analytics` | `analytics.kinesis`, `analytics.athena`, `analytics.glue` | -## Examples +**Common Resources:** +| Category | Kind | Description | +|----------|------|-------------| +| Compute | `compute.gce` | Compute Engine | +| Compute | `compute.functions` | Cloud Functions | +| Compute | `compute.cloudrun` | Cloud Run | +| Compute | `compute.container.gke` | GKE Cluster | +| Compute | `compute.appengine` | App Engine | +| Compute | `compute.lb` | Cloud Load Balancing | +| Database | `database.cloudsql` | Cloud SQL | +| Database | `database.spanner` | Cloud Spanner | +| Database | `database.bigtable` | Cloud Bigtable | +| Database | `database.firestore` | Firestore | +| Database | `database.memorystore` | Memorystore | +| Storage | `storage.gcs` | Cloud Storage | +| Storage | `storage.filestore` | Filestore | +| Network | `network.cdn` | Cloud CDN | +| Network | `network.dns` | Cloud DNS | +| Network | `network.armor` | Cloud Armor | +| Network | `network.apigateway` | API Gateway | +| Integration | `integration.pubsub` | Cloud Pub/Sub | +| Integration | `integration.tasks` | Cloud Tasks | +| Integration | `integration.workflows` | Workflows | +| Security | `security.iam` | Cloud IAM | +| Security | `security.kms` | Cloud KMS | +| Security | `security.secretmanager` | Secret Manager | + +### Azure (`provider: azure`) + +**Containers** (require `w` and `h`): +| Kind | Description | +|------|-------------| +| `network.vnet` | Virtual Network | + +**Common Resources:** +| Category | Kind | Description | +|----------|------|-------------| +| Compute | `compute.vm` | Virtual Machine | +| Compute | `compute.functions` | Azure Functions | +| Compute | `compute.container.aci` | Container Instances | +| Compute | `compute.container.aks` | Azure Kubernetes Service | +| Compute | `compute.appservice` | App Service | +| Compute | `compute.lb` | Load Balancer | +| Compute | `compute.lb.appgw` | Application Gateway | +| Database | `database.sql` | SQL Database | +| Database | `database.cosmosdb` | Cosmos DB | +| Database | `database.mysql` | Azure Database for MySQL | +| Database | `database.postgresql` | Azure Database for PostgreSQL | +| Database | `database.redis` | Azure Cache for Redis | +| Storage | `storage.storage` | Storage Account | +| Storage | `storage.blob` | Blob Storage | +| Storage | `storage.files` | File Storage | +| Storage | `storage.datalake` | Data Lake Storage | +| Network | `network.frontdoor` | Azure Front Door | +| Network | `network.cdn` | Azure CDN | +| Network | `network.dns` | Azure DNS | +| Network | `network.firewall` | Azure Firewall | +| Network | `network.apim` | API Management | +| Integration | `integration.servicebus` | Service Bus | +| Integration | `integration.eventhubs` | Event Hubs | +| Integration | `integration.eventgrid` | Event Grid | +| Integration | `integration.logicapps` | Logic Apps | +| Security | `security.aad` | Azure Active Directory | +| Security | `security.keyvault` | Key Vault | +| Security | `security.defender` | Microsoft Defender | + +### Custom Kinds + +Any string is accepted as a `kind`. Icons fall back through the hierarchy: +- `compute.lb.alb` tries: exact match -> `compute.lb` -> `compute` + +```yaml +- id: custom + provider: custom + kind: my.custom.resource + label: "Custom Resource" + layout: { x: 0, y: 0 } +``` + +--- -### Simple Lambda + S3 +## Custom Icons + +Define custom icons when using FigJam Free Plan or needing icons not in the default set. + +### Inline Definition ```yaml version: 1 -docId: lambda-s3-example -title: "Lambda S3 Integration" - +docId: "my-diagram" +icons: + aws: + "compute.ec2": "./icons/server.png" + "database.rds": "./icons/database.png" + gcp: + "compute.gce": "./icons/vm.png" nodes: - - id: fn - provider: aws - kind: compute.lambda - label: "Process Upload" - layout: - x: 100 - y: 100 - - id: bucket - provider: aws - kind: storage.s3 - label: "uploads-bucket" - layout: - x: 300 - y: 100 + # ... +``` + +### External Icons File (figram-icons.yaml) + +Create `figram-icons.yaml` in the same directory as your diagram: + +```yaml +version: 1 +icons: + aws: + "compute.ec2": "./icons/server.png" + "database": "./icons/db-generic.png" +``` + +The CLI automatically discovers this file. + +### Hierarchical Fallback +Define parent kinds as fallbacks: + +```yaml +icons: + aws: + "compute": "./icons/compute-generic.png" # Fallback for all compute.* + "compute.ec2": "./icons/ec2-specific.png" # Specific override +``` + +### Supported Formats + +- PNG, JPG, JPEG, GIF, WebP +- **SVG is NOT supported** by FigJam + +--- + +## Edge Styling + +### Color Format + +- Full HEX: `#RRGGBB` (e.g., `#FF5733`) +- Shorthand: `#RGB` (e.g., `#F53` expands to `#FF5533`) +- Default: `#666666` (gray) + +### Color Conventions + +| Color | HEX | Use For | +|-------|-----|---------| +| Blue | `#3498DB` | HTTP/HTTPS traffic | +| Green | `#27AE60` | Database connections | +| Orange | `#E67E22` | Cache/Redis | +| Red | `#E74C3C` | Critical/Replication | +| Purple | `#9B59B6` | Container/Image pulls | +| Gray | `#666666` | Default/General | + +```yaml edges: - - id: fn-to-bucket - from: fn - to: bucket + - id: http + from: alb + to: ecs + label: "HTTP:80" + color: "#3498DB" + + - id: db + from: ecs + to: rds + label: "PostgreSQL:5432" + color: "#27AE60" ``` -### API with Database +--- + +## Examples + +### AWS: Serverless API ```yaml version: 1 -docId: api-db-example -title: "REST API Architecture" +docId: serverless-api +title: "Serverless REST API" nodes: - - id: api + - id: apigw provider: aws - kind: integration.apiGateway + kind: network.apigateway label: "REST API" - layout: - x: 100 - y: 200 - - id: handler + layout: { x: 100, y: 150 } + + - id: lambda provider: aws kind: compute.lambda label: "Handler" - layout: - x: 300 - y: 200 - - id: db + layout: { x: 300, y: 150 } + + - id: dynamodb provider: aws kind: database.dynamodb label: "Users Table" - layout: - x: 500 - y: 200 + layout: { x: 500, y: 150 } edges: - - id: api-to-handler - from: api - to: handler + - id: api-to-lambda + from: apigw + to: lambda label: "invoke" - - id: handler-to-db - from: handler - to: db + color: "#3498DB" + + - id: lambda-to-db + from: lambda + to: dynamodb label: "read/write" + color: "#27AE60" +``` + +### GCP: Cloud Run + Pub/Sub + +```yaml +version: 1 +docId: gcp-cloudrun +title: "Event-Driven Cloud Run" + +nodes: + - id: pubsub + provider: gcp + kind: integration.pubsub + label: "Events Topic" + layout: { x: 100, y: 150 } + + - id: cloudrun + provider: gcp + kind: compute.cloudrun + label: "Event Handler" + layout: { x: 300, y: 150 } + + - id: firestore + provider: gcp + kind: database.firestore + label: "Events Store" + layout: { x: 500, y: 150 } + +edges: + - id: pubsub-to-run + from: pubsub + to: cloudrun + label: "push" + color: "#9B59B6" + + - id: run-to-db + from: cloudrun + to: firestore + label: "store" + color: "#27AE60" +``` + +### Azure: App Service Architecture + +```yaml +version: 1 +docId: azure-appservice +title: "Azure Web App" + +nodes: + - id: frontdoor + provider: azure + kind: network.frontdoor + label: "Front Door" + layout: { x: 100, y: 150 } + + - id: appservice + provider: azure + kind: compute.appservice + label: "Web App" + layout: { x: 300, y: 150 } + + - id: cosmosdb + provider: azure + kind: database.cosmosdb + label: "Cosmos DB" + layout: { x: 500, y: 150 } + +edges: + - id: fd-to-app + from: frontdoor + to: appservice + label: "HTTPS" + color: "#3498DB" + + - id: app-to-cosmos + from: appservice + to: cosmosdb + label: "API" + color: "#27AE60" ``` ### VPC with Nested Resources ```yaml version: 1 -docId: vpc-example +docId: vpc-nested title: "VPC Architecture" nodes: @@ -166,112 +504,228 @@ nodes: provider: aws kind: network.vpc label: "Production VPC" - layout: - x: 50 - y: 50 - w: 600 - h: 400 - - id: public-subnet + layout: { x: 0, y: 0, w: 700, h: 400 } + + - id: subnet-public provider: aws kind: network.subnet label: "Public Subnet" parent: vpc - layout: - x: 70 - y: 100 - w: 250 - h: 300 + layout: { x: 40, y: 60, w: 280, h: 280 } + + - id: subnet-private + provider: aws + kind: network.subnet + label: "Private Subnet" + parent: vpc + layout: { x: 380, y: 60, w: 280, h: 280 } + - id: alb provider: aws kind: compute.lb.alb - label: "Application LB" - parent: public-subnet - layout: - x: 100 - y: 150 - - id: lambda + label: "ALB" + parent: subnet-public + # Auto-layout: (60, 60) + + - id: ecs provider: aws - kind: compute.lambda - label: "API Handler" - parent: public-subnet - layout: - x: 100 - y: 280 + kind: compute.container.ecs_service + label: "ECS Service" + parent: subnet-private + # Auto-layout: (60, 60) + + - id: rds + provider: aws + kind: database.rds + label: "RDS" + parent: subnet-private + # Auto-layout: (220, 60) edges: - - id: alb-to-lambda + - id: alb-to-ecs from: alb - to: lambda + to: ecs + label: "HTTP:80" + + - id: ecs-to-rds + from: ecs + to: rds + label: "PostgreSQL" +``` + +--- + +## Common Patterns + +### 3-Tier Architecture + +```yaml +nodes: + - id: vpc + provider: aws + kind: network.vpc + layout: { x: 0, y: 0, w: 600, h: 400 } + + - id: alb + provider: aws + kind: compute.lb.alb + label: "Web Tier" + parent: vpc + + - id: ecs + provider: aws + kind: compute.container.ecs_service + label: "App Tier" + parent: vpc + + - id: rds + provider: aws + kind: database.rds + label: "Data Tier" + parent: vpc + +edges: + - id: web-to-app + from: alb + to: ecs + - id: app-to-data + from: ecs + to: rds +``` + +### Microservices Pattern + +```yaml +nodes: + - id: gateway + provider: aws + kind: network.apigateway + layout: { x: 0, y: 200 } + + - id: svc-users + provider: aws + kind: compute.lambda + label: "Users Service" + layout: { x: 200, y: 100 } + + - id: svc-orders + provider: aws + kind: compute.lambda + label: "Orders Service" + layout: { x: 200, y: 300 } + + - id: queue + provider: aws + kind: integration.sqs + label: "Event Queue" + layout: { x: 400, y: 200 } + +edges: + - id: gw-to-users + from: gateway + to: svc-users + - id: gw-to-orders + from: gateway + to: svc-orders + - id: users-to-queue + from: svc-users + to: queue + - id: orders-to-queue + from: svc-orders + to: queue +``` + +--- + +## Validation & Commands + +### Build (Validate) + +```bash +# Validate and output JSON +npx figram build diagram.yaml + +# Specify output file +npx figram build diagram.yaml -o output.json ``` -## Validation +### Serve (Live Sync) ```bash -# Validate and build to JSON -bun run packages/cli/src/index.ts build diagram.yaml +# Start WebSocket server (default: localhost:3456) +npx figram serve diagram.yaml -# Serve with live reload (default port: 3456) -bun run packages/cli/src/index.ts serve diagram.yaml +# Custom port +npx figram serve diagram.yaml -p 8080 + +# With custom icons +npx figram serve diagram.yaml --icons figram-icons.yaml ``` -## Common Errors +--- + +## Troubleshooting -### Missing Required Fields +### Common Errors + +**Missing required field:** ``` Error: Missing required field "version" Error: Missing required field "docId" ``` Ensure `version` and `docId` are at the document root. -### Duplicate IDs +**Duplicate ID:** ``` Error: Duplicate node id: "my-node" ``` Each node and edge must have a unique `id`. -### Missing Edge ID -``` -Error: Edge must have an id -``` -All edges require an `id` field. - -### Missing Layout +**Missing layout for top-level node:** ``` Error: layout is required for top-level nodes Error: layout.x is required for top-level nodes ``` -Top-level nodes (without `parent`) must have a `layout` with `x` and `y`. Child nodes can omit layout for auto-positioning. +Top-level nodes (without `parent`) must have `layout` with `x` and `y`. -### Partial Coordinates +**Partial coordinates:** ``` Error: layout.x and layout.y must be both specified or both omitted ``` -You cannot specify only `x` or only `y`. Either provide both, or omit both for auto-layout. +Provide both `x` and `y`, or omit both for auto-layout. -### Invalid Parent Reference +**Invalid parent reference:** ``` Error: Node "child" references unknown parent: "missing-vpc" ``` Ensure `parent` references an existing container node. -### Missing Edge Target +**Missing edge target:** ``` Error: Edge references unknown node: "missing-id" ``` Ensure `from` and `to` reference existing node IDs. -### YAML Syntax Error +**Cycle detected:** +``` +Error: Cycle detected in parent hierarchy +``` +Parent relationships cannot form cycles. + +**YAML syntax error:** ``` Error: YAML parse error at line 5 ``` Check indentation (2 spaces) and proper quoting. -## Tips +--- + +## Best Practices -- Use descriptive IDs: `user-api` not `n1` -- Labels can include spaces and special characters (use quotes) -- Use `parent` to nest resources inside VPC/Subnet containers -- Container nodes (VPC, Subnet) require `w` and `h` in layout -- Child nodes can omit `layout` entirely for automatic grid positioning -- Use comments with `#` for documentation -- The `kind` field is flexible - use any string that makes sense for your architecture +1. **Use descriptive IDs:** `user-api` not `n1` +2. **Labels for clarity:** Include context like ports or regions +3. **Nest appropriately:** Use `parent` for VPC/Subnet hierarchy +4. **Group edges:** Comment or order edges by connection type +5. **Consistent layout:** Align related resources +6. **Use auto-layout:** For child nodes when possible +7. **Color-code edges:** Follow conventions for readability diff --git a/packages/docs/src/content/docs/en/installation.md b/packages/docs/src/content/docs/en/installation.md index dc6945c..ec5d7b1 100644 --- a/packages/docs/src/content/docs/en/installation.md +++ b/packages/docs/src/content/docs/en/installation.md @@ -183,6 +183,25 @@ You can download official cloud provider icons from: Icons support hierarchical matching. For example, if you define an icon for `compute.ec2`, it will also be used for `compute.ec2.t3` or `compute.ec2.custom` unless more specific icons are defined. +## Claude Code Plugin + +If you use [Claude Code](https://claude.ai/code), you can install the Figram plugin to get AI-assisted diagram authoring with YAML syntax help and troubleshooting guidance. + +### Installation + +```bash +/plugin install 7nohe/figram +``` + +### Available Skills + +| Skill | Description | +|-------|-------------| +| `getting-started` | Setup guide, workflow, plugin connection | +| `yaml-authoring` | YAML syntax, providers, patterns, troubleshooting | + +Once installed, Claude will automatically reference these skills when you work with Figram YAML files. + ## Remote Access By default, the server binds to `127.0.0.1` (localhost only). To allow connections from other machines: diff --git a/packages/docs/src/content/docs/ja/installation.md b/packages/docs/src/content/docs/ja/installation.md index d2a269e..e7ecc3f 100644 --- a/packages/docs/src/content/docs/ja/installation.md +++ b/packages/docs/src/content/docs/ja/installation.md @@ -183,6 +183,25 @@ npx figram serve diagram.yaml --icons path/to/my-icons.yaml アイコンは階層的なマッチングをサポートします。例えば、`compute.ec2`のアイコンを定義すると、より具体的なアイコンが定義されていない限り、`compute.ec2.t3`や`compute.ec2.custom`にも使用されます。 +## Claude Code プラグイン + +[Claude Code](https://claude.ai/code)を使用している場合、FigramプラグインをインストールすることでYAML構文のヘルプやトラブルシューティングガイドなど、AIによるダイアグラム作成支援を受けられます。 + +### インストール + +```bash +/plugin install 7nohe/figram +``` + +### 利用可能なスキル + +| スキル | 説明 | +|--------|------| +| `getting-started` | セットアップガイド、ワークフロー、プラグイン接続 | +| `yaml-authoring` | YAML構文、プロバイダー、パターン、トラブルシューティング | + +インストール後、Figram YAMLファイルで作業する際にClaudeが自動的にこれらのスキルを参照します。 + ## リモートアクセス デフォルトでは、サーバーは`127.0.0.1`(localhost のみ)にバインドされます。他のマシンからの接続を許可するには: diff --git a/skills/getting-started/SKILL.md b/skills/getting-started/SKILL.md new file mode 100644 index 0000000..0d4a1d7 --- /dev/null +++ b/skills/getting-started/SKILL.md @@ -0,0 +1,308 @@ +--- +name: getting-started +description: General usage guide for Figram. Use when setting up Figram, connecting to FigJam plugin, or troubleshooting connection issues. +--- + +# Figram Getting Started + +## Documentation + +- [Quick Start](https://figram.7nohe.dev/en/quick-start/) - 5-minute setup guide +- [Installation](https://figram.7nohe.dev/en/installation/) - Full installation reference +- [YAML Specs](https://figram.7nohe.dev/en/yaml-specs/) - DSL specification + +--- + +## Prerequisites + +- [Node.js](https://nodejs.org/) v18+ (or [Bun](https://bun.sh/)) +- [Figma Desktop](https://www.figma.com/downloads/) (web version not supported) + +--- + +## Complete Workflow + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 1. CREATE 2. SERVE 3. CONNECT │ +│ │ +│ npx figram init npx figram FigJam Plugin │ +│ │ diagram.yaml │ │ +│ ▼ │ ▼ │ +│ diagram.yaml WebSocket ◄────► Enter docId + URL │ +│ Server Click Connect │ +│ │ +│ 4. EDIT & SYNC │ +│ │ +│ Edit YAML ──► Auto-sync ──► FigJam Canvas Updated │ +└─────────────────────────────────────────────────────────────────┘ +``` + +--- + +## Step 1: Install CLI + +**Global install:** +```bash +npm install -g figram +``` + +**Or use npx (no install):** +```bash +npx figram +``` + +--- + +## Step 2: Create Diagram + +```bash +npx figram init +``` + +Creates `diagram.yaml` template: + +```yaml +version: 1 +docId: "my-architecture" +title: "My Architecture Diagram" + +nodes: + - id: vpc + provider: aws + kind: network.vpc + label: "VPC 10.0.0.0/16" + layout: { x: 0, y: 0, w: 800, h: 500 } + + - id: alb + provider: aws + kind: compute.lb.alb + label: "ALB" + parent: vpc + +edges: + - id: alb_to_ecs + from: alb + to: ecs + label: "HTTP:80" +``` + +--- + +## Step 3: Start WebSocket Server + +```bash +npx figram diagram.yaml +``` + +Output: +``` +WebSocket server started on ws://127.0.0.1:3456 +Watching diagram.yaml for changes... +``` + +**CLI Options:** + +| Option | Description | Example | +|--------|-------------|---------| +| `-p, --port` | Custom port | `npx figram diagram.yaml -p 8080` | +| `--allow-remote` | Allow remote connections | For team sharing | +| `--secret` | Require authentication | `--secret my-token` | +| `--icons` | Custom icons file | `--icons figram-icons.yaml` | +| `--no-watch` | Disable file watching | For one-time sync | + +--- + +## Step 4: Install FigJam Plugin + +1. **Install from Figma Community:** + - Open [Figram Plugin](https://www.figma.com/community/plugin/1588833479203267078/figram) + - Click **"Open in..."** and select Figma Desktop + +2. **Or import manually (development):** + - Figma Desktop → Plugins → Development → Import plugin from manifest + - Select `packages/plugin/manifest.json` + +--- + +## Step 5: Connect Plugin to CLI + +1. Open **FigJam** file in Figma Desktop +2. Run **Figram plugin** (Plugins menu or right-click → Plugins) +3. Enter connection details: + +| Field | Value | Notes | +|-------|-------|-------| +| **Doc ID** | `my-architecture` | Must match `docId` in YAML | +| **WebSocket URL** | `ws://127.0.0.1:3456` | Default CLI address | +| **Secret** | (optional) | If `--secret` was used | + +4. Click **Connect** +5. Diagram appears on canvas! + +--- + +## Step 6: Live Edit + +Edit `diagram.yaml` and save → Changes sync automatically to FigJam. + +**Example: Add a new node** + +```yaml + - id: rds + provider: aws + kind: database.rds + label: "PostgreSQL" + parent: vpc +``` + +Save file → Node appears in FigJam instantly. + +--- + +## Plugin UI Reference + +``` +┌─────────────────────────────────────┐ +│ Figram │ +├─────────────────────────────────────┤ +│ Doc ID: [my-architecture ] │ ← Must match YAML docId +│ URL: [ws://127.0.0.1:3456 ] │ ← CLI server address +│ Secret: [ ] │ ← Optional +│ │ +│ [Connect] Status: ● │ +├─────────────────────────────────────┤ +│ JSON Import (optional) │ +│ ┌─────────────────────────────────┐ │ +│ │ Paste JSON here... │ │ ← For offline import +│ └─────────────────────────────────┘ │ +│ [Import] │ +├─────────────────────────────────────┤ +│ Plugin: 1.0.0 CLI: 1.0.0 │ +└─────────────────────────────────────┘ +``` + +**Status indicators:** +- 🔴 Disconnected +- 🟡 Connecting... +- 🟢 Connected + +--- + +## Remote Access (Team Sharing) + +Share diagrams with team members: + +**Server (your machine):** +```bash +npx figram diagram.yaml --allow-remote --secret team-token +``` + +**Team members:** +- URL: `ws://YOUR_IP:3456` +- Secret: `team-token` + +Find your IP: +```bash +# macOS/Linux +ifconfig | grep "inet " + +# Windows +ipconfig +``` + +--- + +## Custom Icons (Free Plan) + +FigJam Free Plan users need custom icons. Create `figram-icons.yaml`: + +```yaml +version: 1 +icons: + aws: + "compute.ec2": "./icons/ec2.png" + "database.rds": "./icons/rds.png" +``` + +Download official icons: +- [AWS Icons](https://aws.amazon.com/architecture/icons/) +- [GCP Icons](https://cloud.google.com/icons) +- [Azure Icons](https://learn.microsoft.com/en-us/azure/architecture/icons/) + +**Note:** SVG not supported. Use PNG, JPG, GIF, or WebP. + +--- + +## JSON Import (Offline Mode) + +Import diagrams without WebSocket connection: + +1. Build JSON: `npx figram build diagram.yaml` +2. Copy contents of `diagram.json` +3. Paste into plugin's JSON Import area +4. Click **Import** + +--- + +## Troubleshooting + +### Connection Issues + +| Problem | Solution | +|---------|----------| +| "Connection error" | Check CLI is running (`npx figram diagram.yaml`) | +| "Connection refused" | Verify port is not in use | +| Plugin not loading | Use Figma Desktop, not web version | +| "Secret mismatch" | Check `--secret` value matches plugin input | +| docId mismatch | Ensure plugin docId matches YAML `docId` exactly | + +### Check CLI Status + +```bash +# Verify server is running +curl -I http://127.0.0.1:3456 +# Should show "Upgrade Required" (WebSocket endpoint) + +# Check port usage +lsof -i :3456 +``` + +### YAML Errors + +```bash +# Validate YAML syntax +npx figram build diagram.yaml +``` + +Common errors: +- Missing `version` or `docId` +- Duplicate node/edge IDs +- Invalid parent reference +- Missing layout for top-level nodes + +### Version Mismatch + +If plugin shows "Version mismatch" warning: + +```bash +# Update CLI +npm update -g figram + +# Check versions +npx figram --version +``` + +--- + +## Quick Reference + +| Task | Command | +|------|---------| +| Create template | `npx figram init` | +| Start server | `npx figram diagram.yaml` | +| Validate YAML | `npx figram build diagram.yaml` | +| Custom port | `npx figram diagram.yaml -p 8080` | +| Remote access | `npx figram diagram.yaml --allow-remote` | +| With auth | `npx figram diagram.yaml --secret token` | +| Custom icons | `npx figram diagram.yaml --icons icons.yaml` | diff --git a/skills/yaml-authoring/SKILL.md b/skills/yaml-authoring/SKILL.md new file mode 100644 index 0000000..33865c2 --- /dev/null +++ b/skills/yaml-authoring/SKILL.md @@ -0,0 +1,731 @@ +--- +name: yaml-authoring +description: Create and validate YAML diagram files. Use when writing new diagrams or troubleshooting YAML syntax. +--- + +# YAML Diagram Authoring + +## Documentation + +- [YAML Specs](https://figram.7nohe.dev/en/yaml-specs/) - Full DSL specification +- [AWS Icons](https://figram.7nohe.dev/en/icons-aws/) - All available AWS icons +- [Azure Icons](https://figram.7nohe.dev/en/icons-azure/) - All available Azure icons +- [GCP Icons](https://figram.7nohe.dev/en/icons-gcp/) - All available GCP icons + +--- + +## Quick Start + +```yaml +version: 1 +docId: "my-diagram" +title: "My Architecture" + +nodes: + - id: lambda + provider: aws + kind: compute.lambda + label: "Handler" + layout: { x: 100, y: 100 } + + - id: dynamodb + provider: aws + kind: database.dynamodb + label: "Users Table" + layout: { x: 300, y: 100 } + +edges: + - id: lambda-to-db + from: lambda + to: dynamodb + label: "read/write" +``` + +**Commands:** +```bash +# Validate and build to JSON +npx figram build diagram.yaml + +# Start WebSocket server with live reload +npx figram serve diagram.yaml +``` + +--- + +## Document Structure + +### Top-Level Properties + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `version` | number | Yes | Schema version (currently `1`) | +| `docId` | string | Yes | Unique document identifier (used for WebSocket matching) | +| `title` | string | No | Document title (defaults to `docId`) | +| `nodes` | array | Yes | List of node definitions | +| `edges` | array | No | List of edge definitions | +| `icons` | object | No | Custom icon mappings | + +### Node Properties + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `id` | string | Yes | Unique node identifier | +| `provider` | string | Yes | Cloud provider (`aws`, `gcp`, `azure`) | +| `kind` | string | Yes | Resource type (e.g., `compute.lambda`) | +| `label` | string | No | Display label (defaults to `id`) | +| `parent` | string | No | Parent node id for nesting | +| `layout` | object | Conditional | Position and size | + +### Layout Properties + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `x` | number | Conditional* | X position (pixels) | +| `y` | number | Conditional* | Y position (pixels) | +| `w` | number | No** | Width (for containers) | +| `h` | number | No** | Height (for containers) | + +*Required for top-level nodes; optional for child nodes (auto-layout) +**Required for container nodes (VPC, Subnet, VNet) + +### Edge Properties + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `id` | string | Yes | Unique edge identifier | +| `from` | string | Yes | Source node id | +| `to` | string | Yes | Target node id | +| `label` | string | No | Connection label | +| `color` | string | No | Line color in HEX (`#RGB` or `#RRGGBB`). Default: `#666666` | + +--- + +## Auto-Layout + +Child nodes (with `parent`) can omit `layout` for automatic grid positioning. + +**Grid Layout:** +``` ++------------------------------------------+ +| [1] [2] [3] | +| (60,60) (220,60) (380,60) | +| | +| [4] [5] [6] | +| (60,200) (220,200) (380,200) | ++------------------------------------------+ +``` + +**Rules:** +- 3 columns per row +- 60px padding from parent edge +- 160px horizontal spacing, 140px vertical spacing +- Explicit `x`/`y` overrides auto-positioning +- Cannot specify only `x` or only `y` (both or neither) + +**Example:** +```yaml +nodes: + - id: vpc + provider: aws + kind: network.vpc + layout: { x: 0, y: 0, w: 800, h: 600 } # Container: explicit + + - id: ec2_1 + provider: aws + kind: compute.ec2 + parent: vpc + # No layout - auto: (60, 60) + + - id: ec2_2 + provider: aws + kind: compute.ec2 + parent: vpc + # No layout - auto: (220, 60) + + - id: rds + provider: aws + kind: database.rds + parent: vpc + layout: { x: 500, y: 300 } # Explicit override +``` + +--- + +## Providers & Kinds + +### AWS (`provider: aws`) + +**Containers** (require `w` and `h`): +| Kind | Description | +|------|-------------| +| `network.vpc` | Virtual Private Cloud | +| `network.subnet` | Subnet | + +**Common Resources:** +| Category | Kind | Description | +|----------|------|-------------| +| Compute | `compute.ec2` | EC2 Instance | +| Compute | `compute.lambda` | Lambda Function | +| Compute | `compute.lb.alb` | Application Load Balancer | +| Compute | `compute.lb.nlb` | Network Load Balancer | +| Compute | `compute.container.ecs` | ECS Cluster | +| Compute | `compute.container.ecs_service` | ECS Service | +| Compute | `compute.container.eks` | EKS Cluster | +| Compute | `compute.container.fargate` | Fargate | +| Compute | `compute.apprunner` | App Runner | +| Database | `database.rds` | RDS Database | +| Database | `database.aurora` | Aurora | +| Database | `database.dynamodb` | DynamoDB Table | +| Database | `database.elasticache` | ElastiCache | +| Database | `database.redshift` | Redshift | +| Storage | `storage.s3` | S3 Bucket | +| Storage | `storage.efs` | EFS File System | +| Storage | `storage.ebs` | EBS Volume | +| Network | `network.cloudfront` | CloudFront CDN | +| Network | `network.route53` | Route 53 DNS | +| Network | `network.apigateway` | API Gateway | +| Network | `network.igw` | Internet Gateway | +| Network | `network.natgateway` | NAT Gateway | +| Integration | `integration.sqs` | SQS Queue | +| Integration | `integration.sns` | SNS Topic | +| Integration | `integration.eventbridge` | EventBridge | +| Integration | `integration.stepfunctions` | Step Functions | +| Security | `security.iam` | IAM | +| Security | `security.cognito` | Cognito | +| Security | `security.secretsmanager` | Secrets Manager | +| Security | `security.kms` | KMS | + +### GCP (`provider: gcp`) + +**Containers** (require `w` and `h`): +| Kind | Description | +|------|-------------| +| `network.vpc` | Virtual Private Cloud | + +**Common Resources:** +| Category | Kind | Description | +|----------|------|-------------| +| Compute | `compute.gce` | Compute Engine | +| Compute | `compute.functions` | Cloud Functions | +| Compute | `compute.cloudrun` | Cloud Run | +| Compute | `compute.container.gke` | GKE Cluster | +| Compute | `compute.appengine` | App Engine | +| Compute | `compute.lb` | Cloud Load Balancing | +| Database | `database.cloudsql` | Cloud SQL | +| Database | `database.spanner` | Cloud Spanner | +| Database | `database.bigtable` | Cloud Bigtable | +| Database | `database.firestore` | Firestore | +| Database | `database.memorystore` | Memorystore | +| Storage | `storage.gcs` | Cloud Storage | +| Storage | `storage.filestore` | Filestore | +| Network | `network.cdn` | Cloud CDN | +| Network | `network.dns` | Cloud DNS | +| Network | `network.armor` | Cloud Armor | +| Network | `network.apigateway` | API Gateway | +| Integration | `integration.pubsub` | Cloud Pub/Sub | +| Integration | `integration.tasks` | Cloud Tasks | +| Integration | `integration.workflows` | Workflows | +| Security | `security.iam` | Cloud IAM | +| Security | `security.kms` | Cloud KMS | +| Security | `security.secretmanager` | Secret Manager | + +### Azure (`provider: azure`) + +**Containers** (require `w` and `h`): +| Kind | Description | +|------|-------------| +| `network.vnet` | Virtual Network | + +**Common Resources:** +| Category | Kind | Description | +|----------|------|-------------| +| Compute | `compute.vm` | Virtual Machine | +| Compute | `compute.functions` | Azure Functions | +| Compute | `compute.container.aci` | Container Instances | +| Compute | `compute.container.aks` | Azure Kubernetes Service | +| Compute | `compute.appservice` | App Service | +| Compute | `compute.lb` | Load Balancer | +| Compute | `compute.lb.appgw` | Application Gateway | +| Database | `database.sql` | SQL Database | +| Database | `database.cosmosdb` | Cosmos DB | +| Database | `database.mysql` | Azure Database for MySQL | +| Database | `database.postgresql` | Azure Database for PostgreSQL | +| Database | `database.redis` | Azure Cache for Redis | +| Storage | `storage.storage` | Storage Account | +| Storage | `storage.blob` | Blob Storage | +| Storage | `storage.files` | File Storage | +| Storage | `storage.datalake` | Data Lake Storage | +| Network | `network.frontdoor` | Azure Front Door | +| Network | `network.cdn` | Azure CDN | +| Network | `network.dns` | Azure DNS | +| Network | `network.firewall` | Azure Firewall | +| Network | `network.apim` | API Management | +| Integration | `integration.servicebus` | Service Bus | +| Integration | `integration.eventhubs` | Event Hubs | +| Integration | `integration.eventgrid` | Event Grid | +| Integration | `integration.logicapps` | Logic Apps | +| Security | `security.aad` | Azure Active Directory | +| Security | `security.keyvault` | Key Vault | +| Security | `security.defender` | Microsoft Defender | + +### Custom Kinds + +Any string is accepted as a `kind`. Icons fall back through the hierarchy: +- `compute.lb.alb` tries: exact match -> `compute.lb` -> `compute` + +```yaml +- id: custom + provider: custom + kind: my.custom.resource + label: "Custom Resource" + layout: { x: 0, y: 0 } +``` + +--- + +## Custom Icons + +Define custom icons when using FigJam Free Plan or needing icons not in the default set. + +### Inline Definition + +```yaml +version: 1 +docId: "my-diagram" +icons: + aws: + "compute.ec2": "./icons/server.png" + "database.rds": "./icons/database.png" + gcp: + "compute.gce": "./icons/vm.png" +nodes: + # ... +``` + +### External Icons File (figram-icons.yaml) + +Create `figram-icons.yaml` in the same directory as your diagram: + +```yaml +version: 1 +icons: + aws: + "compute.ec2": "./icons/server.png" + "database": "./icons/db-generic.png" +``` + +The CLI automatically discovers this file. + +### Hierarchical Fallback + +Define parent kinds as fallbacks: + +```yaml +icons: + aws: + "compute": "./icons/compute-generic.png" # Fallback for all compute.* + "compute.ec2": "./icons/ec2-specific.png" # Specific override +``` + +### Supported Formats + +- PNG, JPG, JPEG, GIF, WebP +- **SVG is NOT supported** by FigJam + +--- + +## Edge Styling + +### Color Format + +- Full HEX: `#RRGGBB` (e.g., `#FF5733`) +- Shorthand: `#RGB` (e.g., `#F53` expands to `#FF5533`) +- Default: `#666666` (gray) + +### Color Conventions + +| Color | HEX | Use For | +|-------|-----|---------| +| Blue | `#3498DB` | HTTP/HTTPS traffic | +| Green | `#27AE60` | Database connections | +| Orange | `#E67E22` | Cache/Redis | +| Red | `#E74C3C` | Critical/Replication | +| Purple | `#9B59B6` | Container/Image pulls | +| Gray | `#666666` | Default/General | + +```yaml +edges: + - id: http + from: alb + to: ecs + label: "HTTP:80" + color: "#3498DB" + + - id: db + from: ecs + to: rds + label: "PostgreSQL:5432" + color: "#27AE60" +``` + +--- + +## Examples + +### AWS: Serverless API + +```yaml +version: 1 +docId: serverless-api +title: "Serverless REST API" + +nodes: + - id: apigw + provider: aws + kind: network.apigateway + label: "REST API" + layout: { x: 100, y: 150 } + + - id: lambda + provider: aws + kind: compute.lambda + label: "Handler" + layout: { x: 300, y: 150 } + + - id: dynamodb + provider: aws + kind: database.dynamodb + label: "Users Table" + layout: { x: 500, y: 150 } + +edges: + - id: api-to-lambda + from: apigw + to: lambda + label: "invoke" + color: "#3498DB" + + - id: lambda-to-db + from: lambda + to: dynamodb + label: "read/write" + color: "#27AE60" +``` + +### GCP: Cloud Run + Pub/Sub + +```yaml +version: 1 +docId: gcp-cloudrun +title: "Event-Driven Cloud Run" + +nodes: + - id: pubsub + provider: gcp + kind: integration.pubsub + label: "Events Topic" + layout: { x: 100, y: 150 } + + - id: cloudrun + provider: gcp + kind: compute.cloudrun + label: "Event Handler" + layout: { x: 300, y: 150 } + + - id: firestore + provider: gcp + kind: database.firestore + label: "Events Store" + layout: { x: 500, y: 150 } + +edges: + - id: pubsub-to-run + from: pubsub + to: cloudrun + label: "push" + color: "#9B59B6" + + - id: run-to-db + from: cloudrun + to: firestore + label: "store" + color: "#27AE60" +``` + +### Azure: App Service Architecture + +```yaml +version: 1 +docId: azure-appservice +title: "Azure Web App" + +nodes: + - id: frontdoor + provider: azure + kind: network.frontdoor + label: "Front Door" + layout: { x: 100, y: 150 } + + - id: appservice + provider: azure + kind: compute.appservice + label: "Web App" + layout: { x: 300, y: 150 } + + - id: cosmosdb + provider: azure + kind: database.cosmosdb + label: "Cosmos DB" + layout: { x: 500, y: 150 } + +edges: + - id: fd-to-app + from: frontdoor + to: appservice + label: "HTTPS" + color: "#3498DB" + + - id: app-to-cosmos + from: appservice + to: cosmosdb + label: "API" + color: "#27AE60" +``` + +### VPC with Nested Resources + +```yaml +version: 1 +docId: vpc-nested +title: "VPC Architecture" + +nodes: + - id: vpc + provider: aws + kind: network.vpc + label: "Production VPC" + layout: { x: 0, y: 0, w: 700, h: 400 } + + - id: subnet-public + provider: aws + kind: network.subnet + label: "Public Subnet" + parent: vpc + layout: { x: 40, y: 60, w: 280, h: 280 } + + - id: subnet-private + provider: aws + kind: network.subnet + label: "Private Subnet" + parent: vpc + layout: { x: 380, y: 60, w: 280, h: 280 } + + - id: alb + provider: aws + kind: compute.lb.alb + label: "ALB" + parent: subnet-public + # Auto-layout: (60, 60) + + - id: ecs + provider: aws + kind: compute.container.ecs_service + label: "ECS Service" + parent: subnet-private + # Auto-layout: (60, 60) + + - id: rds + provider: aws + kind: database.rds + label: "RDS" + parent: subnet-private + # Auto-layout: (220, 60) + +edges: + - id: alb-to-ecs + from: alb + to: ecs + label: "HTTP:80" + + - id: ecs-to-rds + from: ecs + to: rds + label: "PostgreSQL" +``` + +--- + +## Common Patterns + +### 3-Tier Architecture + +```yaml +nodes: + - id: vpc + provider: aws + kind: network.vpc + layout: { x: 0, y: 0, w: 600, h: 400 } + + - id: alb + provider: aws + kind: compute.lb.alb + label: "Web Tier" + parent: vpc + + - id: ecs + provider: aws + kind: compute.container.ecs_service + label: "App Tier" + parent: vpc + + - id: rds + provider: aws + kind: database.rds + label: "Data Tier" + parent: vpc + +edges: + - id: web-to-app + from: alb + to: ecs + - id: app-to-data + from: ecs + to: rds +``` + +### Microservices Pattern + +```yaml +nodes: + - id: gateway + provider: aws + kind: network.apigateway + layout: { x: 0, y: 200 } + + - id: svc-users + provider: aws + kind: compute.lambda + label: "Users Service" + layout: { x: 200, y: 100 } + + - id: svc-orders + provider: aws + kind: compute.lambda + label: "Orders Service" + layout: { x: 200, y: 300 } + + - id: queue + provider: aws + kind: integration.sqs + label: "Event Queue" + layout: { x: 400, y: 200 } + +edges: + - id: gw-to-users + from: gateway + to: svc-users + - id: gw-to-orders + from: gateway + to: svc-orders + - id: users-to-queue + from: svc-users + to: queue + - id: orders-to-queue + from: svc-orders + to: queue +``` + +--- + +## Validation & Commands + +### Build (Validate) + +```bash +# Validate and output JSON +npx figram build diagram.yaml + +# Specify output file +npx figram build diagram.yaml -o output.json +``` + +### Serve (Live Sync) + +```bash +# Start WebSocket server (default: localhost:3456) +npx figram serve diagram.yaml + +# Custom port +npx figram serve diagram.yaml -p 8080 + +# With custom icons +npx figram serve diagram.yaml --icons figram-icons.yaml +``` + +--- + +## Troubleshooting + +### Common Errors + +**Missing required field:** +``` +Error: Missing required field "version" +Error: Missing required field "docId" +``` +Ensure `version` and `docId` are at the document root. + +**Duplicate ID:** +``` +Error: Duplicate node id: "my-node" +``` +Each node and edge must have a unique `id`. + +**Missing layout for top-level node:** +``` +Error: layout is required for top-level nodes +Error: layout.x is required for top-level nodes +``` +Top-level nodes (without `parent`) must have `layout` with `x` and `y`. + +**Partial coordinates:** +``` +Error: layout.x and layout.y must be both specified or both omitted +``` +Provide both `x` and `y`, or omit both for auto-layout. + +**Invalid parent reference:** +``` +Error: Node "child" references unknown parent: "missing-vpc" +``` +Ensure `parent` references an existing container node. + +**Missing edge target:** +``` +Error: Edge references unknown node: "missing-id" +``` +Ensure `from` and `to` reference existing node IDs. + +**Cycle detected:** +``` +Error: Cycle detected in parent hierarchy +``` +Parent relationships cannot form cycles. + +**YAML syntax error:** +``` +Error: YAML parse error at line 5 +``` +Check indentation (2 spaces) and proper quoting. + +--- + +## Best Practices + +1. **Use descriptive IDs:** `user-api` not `n1` +2. **Labels for clarity:** Include context like ports or regions +3. **Nest appropriately:** Use `parent` for VPC/Subnet hierarchy +4. **Group edges:** Comment or order edges by connection type +5. **Consistent layout:** Align related resources +6. **Use auto-layout:** For child nodes when possible +7. **Color-code edges:** Follow conventions for readability