feat: introduce archify skill for generating architecture diagrams
- Added a new Archify skill, enabling users to create polished architecture, workflow, sequence, data-flow, and lifecycle diagrams. - Implemented comprehensive functionality including rendering, validation, and delivery of diagrams in various formats. - Integrated a user-friendly command-line interface for generating and previewing diagrams. - Developed supporting files including package.json, LICENSE, and SKILL.md for documentation and licensing. - Added unit tests to ensure reliability and functionality of the new skill. These changes enhance the application by providing a structured approach to visualizing system architecture and workflows, improving user experience and data representation.
This commit is contained in:
+40
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"diagram_type": "workflow",
|
||||
"meta": {
|
||||
"title": "自动连线节点边框避让回归",
|
||||
"quality_profile": "showcase",
|
||||
"viewBox": [720, 360]
|
||||
},
|
||||
"lanes": [
|
||||
{ "id": "orchestrator", "label": "Orchestrator PTY" },
|
||||
{ "id": "runtime", "label": "Hive Runtime" }
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"id": "team_send",
|
||||
"lane": "orchestrator",
|
||||
"col": 2,
|
||||
"type": "backend",
|
||||
"label": "team send 派单",
|
||||
"sublabel": "选择目标 Worker"
|
||||
},
|
||||
{
|
||||
"id": "inject",
|
||||
"lane": "runtime",
|
||||
"col": 1,
|
||||
"type": "security",
|
||||
"label": "校验并注入输入",
|
||||
"sublabel": "UI token → PTY stdin"
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "stdin",
|
||||
"from": "inject",
|
||||
"to": "team_send",
|
||||
"label": "PTY stdin",
|
||||
"variant": "emphasis"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
const originalRmSync = fs.rmSync.bind(fs);
|
||||
let injectedFailure = false;
|
||||
|
||||
fs.rmSync = function failMigrationCleanupOnce(target, options) {
|
||||
const isMigrationStagingDirectory = path.basename(String(target)).startsWith('.archify-migration-');
|
||||
if (!injectedFailure && isMigrationStagingDirectory) {
|
||||
injectedFailure = true;
|
||||
originalRmSync(target, options);
|
||||
const error = new Error('simulated migration cleanup failure');
|
||||
error.code = 'EPERM';
|
||||
throw error;
|
||||
}
|
||||
return originalRmSync(target, options);
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"schema_version": 2,
|
||||
"diagram_type": "workflow",
|
||||
"meta": {
|
||||
"title": "Sanitized custom widths",
|
||||
"legend": { "mode": "hidden" }
|
||||
},
|
||||
"lanes": [
|
||||
{ "id": "main", "label": "Main flow" }
|
||||
],
|
||||
"nodes": [
|
||||
{ "id": "compact", "lane": "main", "col": 1, "type": "frontend", "label": "In", "width": 32 },
|
||||
{ "id": "wide", "lane": "main", "col": 2, "type": "database", "label": "Sanitized downstream service", "width": 240 }
|
||||
],
|
||||
"edges": [
|
||||
{ "id": "compact-wide", "from": "compact", "to": "wide" }
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"schema_version": 2,
|
||||
"diagram_type": "workflow",
|
||||
"meta": {
|
||||
"title": "Sanitized explicit route",
|
||||
"viewBox": [900, 420],
|
||||
"legend": { "mode": "hidden" }
|
||||
},
|
||||
"lanes": [
|
||||
{ "id": "source", "label": "Source" },
|
||||
{ "id": "target", "label": "Target" }
|
||||
],
|
||||
"nodes": [
|
||||
{ "id": "producer", "lane": "source", "col": 1, "type": "backend", "label": "Producer" },
|
||||
{ "id": "consumer", "lane": "target", "col": 1, "type": "backend", "label": "Consumer" }
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "producer-consumer",
|
||||
"from": "producer",
|
||||
"to": "consumer",
|
||||
"fromSide": "right",
|
||||
"toSide": "right",
|
||||
"route": "outside-right",
|
||||
"channelX": 720
|
||||
}
|
||||
]
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"schema_version": 2,
|
||||
"diagram_type": "workflow",
|
||||
"meta": {
|
||||
"title": "Sanitized explicit viewBox",
|
||||
"viewBox": [1600, 520],
|
||||
"legend": { "mode": "hidden" }
|
||||
},
|
||||
"lanes": [
|
||||
{ "id": "main", "label": "Main flow" }
|
||||
],
|
||||
"nodes": [
|
||||
{ "id": "start", "lane": "main", "col": 0, "type": "frontend", "label": "Start" },
|
||||
{ "id": "finish", "lane": "main", "col": 5, "type": "backend", "label": "Finish" }
|
||||
],
|
||||
"edges": [
|
||||
{ "id": "start-finish", "from": "start", "to": "finish", "label": "complete" }
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"schema_version": 2,
|
||||
"diagram_type": "workflow",
|
||||
"meta": {
|
||||
"title": "Sanitized semantic labels",
|
||||
"legend": { "mode": "hidden" }
|
||||
},
|
||||
"lanes": [
|
||||
{ "id": "main", "label": "Main flow" }
|
||||
],
|
||||
"nodes": [
|
||||
{ "id": "request", "lane": "main", "col": 3, "type": "frontend", "label": "Request" },
|
||||
{ "id": "result", "lane": "main", "col": 4, "type": "backend", "label": "Result" }
|
||||
],
|
||||
"edges": [
|
||||
{ "id": "request-result", "from": "request", "to": "result", "label": "同步 ✅ ready" }
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"diagram_type": "lifecycle",
|
||||
"meta": {
|
||||
"title": "Agent Run Lifecycle",
|
||||
"subtitle": "State machine for planning, tool execution, human approval, retries, and terminal outcomes",
|
||||
"output": "examples/lifecycle-agent-run.html",
|
||||
"viewBox": [980, 660]
|
||||
},
|
||||
"lanes": [
|
||||
{ "id": "main", "label": "Lifecycle phases" },
|
||||
{ "id": "waiting", "label": "Interruptions" },
|
||||
{ "id": "exceptions", "label": "Recovery loop" },
|
||||
{ "id": "terminal", "label": "Terminal exits" }
|
||||
],
|
||||
"states": [
|
||||
{ "id": "queued", "type": "start", "label": "Queued", "sublabel": "request accepted", "lane": "main", "col": 0, "step": "01", "tag": "entry" },
|
||||
{ "id": "planning", "type": "active", "label": "Planning", "sublabel": "build task graph", "lane": "main", "col": 1, "step": "02", "tag": "model" },
|
||||
{ "id": "executing", "type": "active", "label": "Executing", "sublabel": "tool calls", "lane": "main", "col": 2, "step": "03", "tag": "work" },
|
||||
{ "id": "reviewing", "type": "decision", "label": "Reviewing", "sublabel": "quality gate", "lane": "main", "col": 3, "step": "04", "tag": "check" },
|
||||
{ "id": "completed", "type": "success", "label": "Completed", "sublabel": "final response", "lane": "main", "col": 4, "step": "05", "tag": "done" },
|
||||
{ "id": "approval", "type": "waiting", "label": "Needs Approval", "sublabel": "human gate", "lane": "waiting", "col": 0, "tag": "pause" },
|
||||
{ "id": "blocked", "type": "waiting", "label": "Blocked", "sublabel": "missing input", "lane": "waiting", "col": 1, "tag": "wait" },
|
||||
{ "id": "failed", "type": "failure", "label": "Failed", "sublabel": "recoverable error", "lane": "exceptions", "col": 0, "yOffset": 78, "tag": "retryable" },
|
||||
{ "id": "cancelled", "type": "failure", "label": "Cancelled", "sublabel": "user stopped", "lane": "terminal", "col": 0, "tag": "terminal" },
|
||||
{ "id": "expired", "type": "failure", "label": "Expired", "sublabel": "timeout", "lane": "terminal", "col": 1, "tag": "terminal" }
|
||||
],
|
||||
"transitions": [
|
||||
{ "from": "executing", "to": "approval", "variant": "security", "fromSide": "bottom", "toSide": "top", "route": "straight" },
|
||||
{ "from": "reviewing", "to": "blocked", "variant": "default", "route": "drop" },
|
||||
{ "from": "executing", "to": "failed", "variant": "security", "fromSide": "left", "toSide": "top", "via": [[320, 157], [320, 342], [402, 342]] },
|
||||
{ "from": "blocked", "to": "expired", "variant": "security", "fromSide": "bottom", "toSide": "top", "route": "straight" },
|
||||
{ "from": "approval", "to": "cancelled", "variant": "security", "fromSide": "bottom", "toSide": "top", "via": [[320, 336], [320, 430], [402, 430]] }
|
||||
],
|
||||
"cards": [
|
||||
{
|
||||
"dot": "emerald",
|
||||
"title": "Main Path",
|
||||
"items": [
|
||||
"The run has five ordered phases from queue to completion",
|
||||
"The primary lifecycle is carried by one horizontal rail",
|
||||
"Completion is a phase, not a detached side box"
|
||||
]
|
||||
},
|
||||
{
|
||||
"dot": "amber",
|
||||
"title": "Human + Input Gates",
|
||||
"items": [
|
||||
"Approval pauses execution without ending the run",
|
||||
"Blocked waits for missing user input",
|
||||
"Wait states can resume back into planning or execution"
|
||||
]
|
||||
},
|
||||
{
|
||||
"dot": "rose",
|
||||
"title": "Terminal + Recovery",
|
||||
"items": [
|
||||
"Failed loops back while retry budget remains",
|
||||
"Cancelled and Expired are exits from the lifecycle",
|
||||
"Terminal exits do not point back into active execution"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"diagram_type": "workflow",
|
||||
"meta": {
|
||||
"title": "Agent Tool Call Workflow",
|
||||
"subtitle": "Renderer-driven workflow prototype with lanes, anchored nodes, and orthogonal edges",
|
||||
"output": "examples/workflow-agent-tool-call-rendered.html",
|
||||
"viewBox": [720, 900]
|
||||
},
|
||||
"lanes": [
|
||||
{ "id": "ui", "label": "User Interface" },
|
||||
{ "id": "agent", "label": "Agent Runtime" },
|
||||
{ "id": "policy", "label": "Policy Boundary" },
|
||||
{ "id": "exceptions", "label": "Exception Handling", "variant": "exception" },
|
||||
{ "id": "tools", "label": "Tool Execution" },
|
||||
{ "id": "trace", "label": "Observability" }
|
||||
],
|
||||
"phases": [
|
||||
{ "id": "intake", "label": "Intake", "fromCol": 0, "toCol": 1 },
|
||||
{ "id": "reasoning", "label": "Plan + route", "fromCol": 2, "toCol": 3, "variant": "emphasis" },
|
||||
{ "id": "execution", "label": "Execute + report", "fromCol": 4, "toCol": 5, "variant": "dashed" }
|
||||
],
|
||||
"groups": [
|
||||
{ "id": "agent_loop", "label": "Planning loop", "lane": "agent", "fromCol": 2, "toCol": 3, "variant": "emphasis" },
|
||||
{ "id": "tool_work", "label": "Tool work", "lane": "tools", "fromCol": 4, "toCol": 5, "variant": "dashed" },
|
||||
{ "id": "exception_path", "label": "Human or policy stop", "lane": "exceptions", "fromCol": 3, "toCol": 5, "variant": "security" }
|
||||
],
|
||||
"mainPath": ["user", "chat", "planner", "router", "approval", "tool", "external", "final"],
|
||||
"nodes": [
|
||||
{ "id": "user", "lane": "ui", "col": 0, "type": "external", "label": "User", "sublabel": "asks for work" },
|
||||
{ "id": "chat", "lane": "ui", "col": 1, "type": "frontend", "label": "Chat Surface", "sublabel": "thread + files" },
|
||||
{ "id": "final", "lane": "ui", "col": 5, "type": "backend", "label": "Final Reply", "sublabel": "answer + changes" },
|
||||
{ "id": "planner", "lane": "agent", "col": 2, "type": "backend", "label": "Agent Planner", "sublabel": "plan next step", "tag": "context aware" },
|
||||
{ "id": "router", "lane": "agent", "col": 3, "type": "backend", "label": "Tool Router", "sublabel": "choose capability" },
|
||||
{ "id": "approval", "lane": "policy", "col": 3, "type": "security", "label": "Approval Gate", "sublabel": "scope + consent", "tag": "block risky ops" },
|
||||
{ "id": "blocked", "lane": "exceptions", "col": 4, "type": "security", "label": "Blocked", "sublabel": "wait or reject" },
|
||||
{ "id": "retry", "lane": "exceptions", "col": 5, "type": "messagebus", "label": "Retry Path", "sublabel": "revise request" },
|
||||
{ "id": "tool", "lane": "tools", "col": 4, "type": "messagebus", "label": "Tool Call", "sublabel": "shell / browser / MCP", "tag": "structured result" },
|
||||
{ "id": "external", "lane": "tools", "col": 5, "type": "cloud", "label": "External API", "sublabel": "network service" },
|
||||
{ "id": "store", "lane": "trace", "col": 1, "type": "database", "label": "Context Store", "sublabel": "repo + memory" },
|
||||
{ "id": "trace", "lane": "trace", "col": 4, "type": "database", "label": "Trace Log", "sublabel": "events + output" }
|
||||
],
|
||||
"edges": [
|
||||
{ "from": "user", "to": "chat", "variant": "default" },
|
||||
{ "from": "chat", "to": "planner", "label": "plan", "variant": "emphasis", "fromSide": "bottom", "toSide": "top", "route": "drop", "labelSegment": 1 },
|
||||
{ "from": "planner", "to": "router", "variant": "default" },
|
||||
{ "from": "router", "to": "approval", "label": "needs approval?", "variant": "security", "fromSide": "bottom", "toSide": "top", "route": "drop", "labelSegment": 0, "labelDx": 34, "labelDy": 18 },
|
||||
{ "from": "approval", "to": "tool", "variant": "emphasis", "fromSide": "left", "toSide": "left", "route": "return-left" },
|
||||
{ "from": "approval", "to": "blocked", "label": "denied", "variant": "security", "role": "error", "fromSide": "bottom", "toSide": "top", "route": "drop", "labelSegment": 1, "labelDy": 12 },
|
||||
{ "from": "blocked", "to": "retry", "variant": "dashed", "role": "branch" },
|
||||
{ "from": "tool", "to": "external", "variant": "default" },
|
||||
{ "from": "external", "to": "final", "variant": "emphasis", "role": "return", "fromSide": "right", "toSide": "right", "route": "outside-right", "width": 1.2 },
|
||||
{ "from": "external", "to": "trace", "label": "record result", "variant": "dashed", "fromSide": "bottom", "toSide": "bottom", "route": "bottom-channel", "labelSegment": 1 },
|
||||
{ "from": "store", "to": "trace", "label": "trace + memory", "variant": "dashed", "labelAt": [365, 735] }
|
||||
],
|
||||
"cards": [
|
||||
{
|
||||
"dot": "cyan",
|
||||
"title": "Renderer Rules",
|
||||
"items": [
|
||||
"Lanes and columns determine node placement",
|
||||
"Edges attach to explicit node anchors",
|
||||
"Cross-lane paths use orthogonal routing",
|
||||
"Short adjacent links stay unlabeled"
|
||||
]
|
||||
},
|
||||
{
|
||||
"dot": "rose",
|
||||
"title": "Workflow Semantics",
|
||||
"items": [
|
||||
"Approval is a first-class policy step",
|
||||
"Consent gates are visible in the main path",
|
||||
"External calls stay inside the tool lane",
|
||||
"Trace writes are separate from the hot path"
|
||||
]
|
||||
},
|
||||
{
|
||||
"dot": "emerald",
|
||||
"title": "Why It Matters",
|
||||
"items": [
|
||||
"This is closer to a diagram_type renderer",
|
||||
"The graph can be edited without SVG surgery",
|
||||
"Layout rules can be tested and improved",
|
||||
"A future IR can reuse this shape directly"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"diagram_type": "sequence",
|
||||
"meta": {
|
||||
"title": "Cache Miss Request Sequence",
|
||||
"subtitle": "Frontend request path with auth, cache fallback, persistence, and async trace",
|
||||
"output": "examples/sequence-cache-miss-request.html",
|
||||
"viewBox": [820, 760]
|
||||
},
|
||||
"participants": [
|
||||
{ "id": "user", "type": "external", "label": "User", "sublabel": "browser session" },
|
||||
{ "id": "web", "type": "frontend", "label": "Web App", "sublabel": "React UI" },
|
||||
{ "id": "api", "type": "backend", "label": "API", "sublabel": "request handler" },
|
||||
{ "id": "auth", "type": "security", "label": "Auth", "sublabel": "JWT verify" },
|
||||
{ "id": "redis", "type": "database", "label": "Redis", "sublabel": "cache" },
|
||||
{ "id": "db", "type": "database", "label": "Postgres", "sublabel": "source of truth" },
|
||||
{ "id": "trace", "type": "messagebus", "label": "Trace", "sublabel": "async event" }
|
||||
],
|
||||
"segments": [
|
||||
{ "from": 150, "to": 295, "label": "Request" },
|
||||
{ "from": 315, "to": 505, "label": "Fallback" },
|
||||
{ "from": 525, "to": 665, "label": "Response + trace" }
|
||||
],
|
||||
"messages": [
|
||||
{ "from": "user", "to": "web", "y": 185, "label": "open page", "variant": "default" },
|
||||
{ "from": "web", "to": "api", "y": 228, "label": "GET /dashboard", "variant": "emphasis" },
|
||||
{ "from": "api", "to": "auth", "y": 270, "label": "verify JWT", "variant": "security" },
|
||||
{ "from": "auth", "to": "api", "y": 305, "label": "claims ok", "variant": "return" },
|
||||
{ "from": "api", "to": "redis", "y": 354, "label": "read cache", "variant": "default" },
|
||||
{ "from": "redis", "to": "api", "y": 391, "label": "miss", "variant": "return" },
|
||||
{ "from": "api", "to": "db", "y": 443, "label": "query profile + metrics", "variant": "emphasis" },
|
||||
{ "from": "db", "to": "api", "y": 489, "label": "rows", "variant": "return" },
|
||||
{ "from": "api", "to": "redis", "y": 536, "label": "set cache", "variant": "dashed" },
|
||||
{ "from": "api", "to": "trace", "y": 580, "label": "emit trace", "variant": "dashed" },
|
||||
{ "from": "api", "to": "web", "y": 625, "label": "200 JSON", "variant": "return" },
|
||||
{ "from": "web", "to": "user", "y": 662, "label": "render", "variant": "return" }
|
||||
],
|
||||
"activations": [
|
||||
{ "participant": "web", "from": 220, "to": 668, "type": "frontend" },
|
||||
{ "participant": "api", "from": 228, "to": 632, "type": "backend" },
|
||||
{ "participant": "auth", "from": 265, "to": 310, "type": "security" },
|
||||
{ "participant": "redis", "from": 349, "to": 398, "type": "database" },
|
||||
{ "participant": "db", "from": 438, "to": 496, "type": "database" },
|
||||
{ "participant": "trace", "from": 575, "to": 630, "type": "messagebus" }
|
||||
],
|
||||
"cards": [
|
||||
{
|
||||
"dot": "emerald",
|
||||
"title": "Happy Path",
|
||||
"items": [
|
||||
"The main request is Web App -> API -> data source -> response",
|
||||
"Return messages are quieter than forward calls",
|
||||
"Activation bars make ownership duration visible"
|
||||
]
|
||||
},
|
||||
{
|
||||
"dot": "rose",
|
||||
"title": "Policy + Fallback",
|
||||
"items": [
|
||||
"JWT verification is colored as a security interaction",
|
||||
"Cache miss is visible without overpowering the main path",
|
||||
"Database access only appears after cache fallback"
|
||||
]
|
||||
},
|
||||
{
|
||||
"dot": "orange",
|
||||
"title": "Async Trace",
|
||||
"items": [
|
||||
"Trace emission is dashed and secondary",
|
||||
"It does not block the response path",
|
||||
"The diagram separates user-facing latency from observability"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"diagram_type": "dataflow",
|
||||
"meta": {
|
||||
"title": "Order Event-stream Topology",
|
||||
"output": "examples/event-stream.html",
|
||||
"viewBox": [1080, 780],
|
||||
"animation": "trace",
|
||||
"visual_preset": "signal-flow",
|
||||
"quality_profile": "showcase",
|
||||
"views": [
|
||||
{ "id": "order-transit", "label": "Order event transit", "focus": ["checkout", "orders", "validate", "state", "fulfillment"], "note": "Follow an order from producer through ordered processing to fulfillment." },
|
||||
{ "id": "payment-transit", "label": "Payment event transit", "focus": ["billing", "payments", "enrich", "state", "analytics"], "note": "Track payment facts into the shared materialized state and analytics." },
|
||||
{ "id": "failure-and-replay", "label": "Failure and replay", "focus": ["validate", "enrich", "dlq", "replay", "ops"], "note": "Isolate dead letters, operator review, and controlled replay ownership." }
|
||||
]
|
||||
},
|
||||
"stages": [
|
||||
{ "label": "Producers" },
|
||||
{ "label": "Transit" },
|
||||
{ "label": "Processors" },
|
||||
{ "label": "State + recovery" },
|
||||
{ "label": "Consumers" }
|
||||
],
|
||||
"nodes": [
|
||||
{ "id": "checkout", "type": "frontend", "label": "Checkout API", "sublabel": "order producer", "stage": 0, "row": 0, "tag": "team commerce" },
|
||||
{ "id": "billing", "type": "backend", "label": "Billing API", "sublabel": "payment producer", "stage": 0, "row": 2, "tag": "team money" },
|
||||
{ "id": "orders", "type": "messagebus", "label": "orders.v1", "sublabel": "12 partitions", "stage": 1, "row": 0, "tag": "key: order_id" },
|
||||
{ "id": "payments", "type": "messagebus", "label": "payments.v2", "sublabel": "8 partitions", "stage": 1, "row": 2, "tag": "key: order_id" },
|
||||
{ "id": "validate", "type": "backend", "label": "Order Validate", "sublabel": "group fulfillment", "stage": 2, "row": 0, "tag": "ordered" },
|
||||
{ "id": "enrich", "type": "backend", "label": "Payment Enrich", "sublabel": "group analytics", "stage": 2, "row": 2, "tag": "at-least-once" },
|
||||
{ "id": "state", "type": "database", "label": "Order State", "sublabel": "materialized view", "stage": 3, "row": 1, "tag": "idempotent" },
|
||||
{ "id": "dlq", "type": "messagebus", "label": "events.dlq", "sublabel": "poison events", "stage": 3, "row": 4, "tag": "7-day retention" },
|
||||
{ "id": "fulfillment", "type": "backend", "label": "Fulfillment", "sublabel": "shipping workflow", "stage": 4, "row": 0, "tag": "consumer" },
|
||||
{ "id": "analytics", "type": "database", "label": "Analytics", "sublabel": "streaming facts", "stage": 4, "row": 2, "tag": "consumer" },
|
||||
{ "id": "replay", "type": "security", "label": "Replay Tool", "sublabel": "approved batch", "stage": 4, "row": 4, "tag": "operator gate" },
|
||||
{ "id": "ops", "type": "external", "label": "On-call", "sublabel": "DLQ owner", "stage": 4, "row": 3, "yOffset": -18, "tag": "SRE" }
|
||||
],
|
||||
"flows": [
|
||||
{ "from": "checkout", "to": "orders", "label": "OrderPlaced", "classification": "schema v1", "variant": "emphasis", "route": "straight" },
|
||||
{ "from": "billing", "to": "payments", "label": "PaymentCaptured", "classification": "schema v2", "variant": "emphasis", "route": "straight" },
|
||||
{ "from": "orders", "to": "validate", "label": "ordered orders", "classification": "consumer group", "variant": "emphasis", "route": "straight" },
|
||||
{ "from": "payments", "to": "enrich", "label": "payment facts", "classification": "at-least-once", "variant": "emphasis", "route": "straight" },
|
||||
{ "from": "validate", "to": "state", "label": "valid order", "classification": "idempotent", "variant": "emphasis", "route": "vertical-channel" },
|
||||
{ "from": "enrich", "to": "state", "label": "enriched payment", "classification": "idempotent", "variant": "default", "route": "vertical-channel" },
|
||||
{ "from": "state", "to": "fulfillment", "label": "ready orders", "classification": "read model", "variant": "emphasis", "route": "vertical-channel" },
|
||||
{ "from": "state", "to": "analytics", "label": "order facts", "classification": "non-PII", "variant": "default", "route": "vertical-channel" },
|
||||
{ "from": "validate", "to": "dlq", "label": "invalid event", "classification": "dead letter", "variant": "security", "fromSide": "top", "toSide": "top", "via": [[530, 80], [20, 80], [20, 550], [745, 550]], "labelAt": [300, 550] },
|
||||
{ "from": "enrich", "to": "dlq", "label": "poison event", "classification": "dead letter", "variant": "security", "route": "bottom-channel", "labelDy": 30 },
|
||||
{ "from": "dlq", "to": "ops", "label": "failure sample", "classification": "restricted", "variant": "security", "route": "vertical-channel" },
|
||||
{ "from": "dlq", "to": "replay", "label": "approved replay", "classification": "audited batch", "variant": "dashed", "route": "straight", "labelDy": 30 }
|
||||
],
|
||||
"cards": [
|
||||
{ "dot": "amber", "title": "Transit Contract", "items": ["Every event and topic is named", "Partition keys preserve per-order ordering", "Consumer groups expose processing ownership"] },
|
||||
{ "dot": "emerald", "title": "State + Delivery", "items": ["Processors write an idempotent materialized view", "Fulfillment and analytics consume distinct assets", "At-least-once delivery never implies duplicate business effects"] },
|
||||
{ "dot": "rose", "title": "Failure Ownership", "items": ["Poison events land in a retained dead-letter topic", "On-call inspects samples before replay", "Replay is gated, batched, and auditable"] }
|
||||
]
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"diagram_type": "dataflow",
|
||||
"meta": {
|
||||
"title": "Product Analytics Data Flow",
|
||||
"subtitle": "Events, consent, PII isolation, warehouse sync, and downstream analytics",
|
||||
"output": "examples/dataflow-product-analytics.html",
|
||||
"viewBox": [1080, 760]
|
||||
},
|
||||
"stages": [
|
||||
{ "label": "Sources" },
|
||||
{ "label": "Ingest" },
|
||||
{ "label": "Process" },
|
||||
{ "label": "Store" },
|
||||
{ "label": "Consume" }
|
||||
],
|
||||
"nodes": [
|
||||
{ "id": "web", "type": "frontend", "label": "Web App", "sublabel": "browser SDK", "stage": 0, "row": 0, "tag": "events" },
|
||||
{ "id": "mobile", "type": "frontend", "label": "Mobile", "sublabel": "iOS / Android", "stage": 0, "row": 2, "tag": "events" },
|
||||
{ "id": "edge", "type": "cloud", "label": "Edge API", "sublabel": "collector", "stage": 1, "row": 1, "tag": "TLS" },
|
||||
{ "id": "consent", "type": "security", "label": "Consent Gate", "sublabel": "policy filter", "stage": 2, "row": 0, "tag": "PII guard" },
|
||||
{ "id": "stream", "type": "messagebus", "label": "Event Stream", "sublabel": "Kafka topic", "stage": 2, "row": 2, "tag": "ordered" },
|
||||
{ "id": "pii", "type": "security", "label": "PII Vault", "sublabel": "encrypted", "stage": 3, "row": 0, "tag": "restricted" },
|
||||
{ "id": "warehouse", "type": "database", "label": "Warehouse", "sublabel": "analytics tables", "stage": 3, "row": 2, "tag": "curated" },
|
||||
{ "id": "features", "type": "database", "label": "Feature Store", "sublabel": "daily batch", "stage": 3, "row": 4, "tag": "derived" },
|
||||
{ "id": "dashboard", "type": "backend", "label": "Dashboards", "sublabel": "product metrics", "stage": 4, "row": 1, "tag": "SQL" },
|
||||
{ "id": "model", "type": "backend", "label": "ML Model", "sublabel": "ranking job", "stage": 4, "row": 4, "tag": "features" }
|
||||
],
|
||||
"flows": [
|
||||
{ "from": "web", "to": "edge", "label": "clickstream", "classification": "user events", "variant": "emphasis", "fromSide": "right", "toSide": "left", "via": [[184, 157], [184, 271]], "labelAt": [204, 190] },
|
||||
{ "from": "mobile", "to": "edge", "label": "app events", "classification": "device events", "variant": "default", "fromSide": "right", "toSide": "left", "via": [[222, 385], [222, 271]], "labelAt": [220, 342] },
|
||||
{ "from": "edge", "to": "consent", "label": "identity + consent", "classification": "PII touch", "variant": "security", "fromSide": "top", "toSide": "left", "via": [[315, 112], [450, 112], [450, 157]], "labelAt": [382, 100] },
|
||||
{ "from": "edge", "to": "stream", "label": "accepted events", "classification": "append-only", "variant": "emphasis", "fromSide": "right", "toSide": "left", "via": [[420, 271], [420, 385]], "labelAt": [438, 324] },
|
||||
{ "from": "consent", "to": "pii", "label": "identity map", "classification": "encrypted PII", "variant": "security", "route": "straight", "labelAt": [638, 144] },
|
||||
{ "from": "stream", "to": "warehouse", "label": "normalized facts", "classification": "non-PII", "variant": "emphasis", "route": "straight", "labelAt": [638, 372] },
|
||||
{ "from": "warehouse", "to": "features", "label": "daily aggregates", "classification": "batch", "variant": "dashed", "fromSide": "bottom", "toSide": "top", "route": "straight", "labelAt": [745, 496] },
|
||||
{ "from": "warehouse", "to": "dashboard", "label": "metrics SQL", "classification": "read-only", "variant": "default", "fromSide": "right", "toSide": "left", "via": [[852, 385], [852, 271]], "labelAt": [830, 326] },
|
||||
{ "from": "features", "to": "model", "label": "feature vectors", "classification": "derived", "variant": "dashed", "route": "straight", "labelAt": [852, 598] },
|
||||
{ "from": "pii", "to": "dashboard", "label": "restricted join", "classification": "approved only", "variant": "security", "fromSide": "right", "toSide": "top", "via": [[878, 157], [878, 212], [960, 212]], "labelAt": [880, 198] }
|
||||
],
|
||||
"cards": [
|
||||
{
|
||||
"dot": "emerald",
|
||||
"title": "Primary Data Path",
|
||||
"items": [
|
||||
"Events move left to right through source, ingest, process, store, and consume stages",
|
||||
"The hot path stays visually clear even with secondary batch flows",
|
||||
"Labels name data assets instead of generic API verbs"
|
||||
]
|
||||
},
|
||||
{
|
||||
"dot": "rose",
|
||||
"title": "Sensitive Boundary",
|
||||
"items": [
|
||||
"Consent and PII paths are styled as security flows",
|
||||
"PII lands in a restricted vault, separate from the analytics warehouse",
|
||||
"Restricted joins are visible without implying default access"
|
||||
]
|
||||
},
|
||||
{
|
||||
"dot": "orange",
|
||||
"title": "Derived Consumers",
|
||||
"items": [
|
||||
"Dashboards read curated facts from the warehouse",
|
||||
"Feature vectors are derived by batch from analytics tables",
|
||||
"Consumption paths stay distinct from collection and consent handling"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"diagram_type": "architecture",
|
||||
"meta": {
|
||||
"title": "Production Deployment Ownership",
|
||||
"output": "examples/production-deployment.html",
|
||||
"visual_preset": "blueprint",
|
||||
"animation": "trace",
|
||||
"quality_profile": "showcase",
|
||||
"engineering_profile": "deployment-ownership",
|
||||
"views": [
|
||||
{
|
||||
"id": "request-boundary",
|
||||
"label": "Request crosses the edge",
|
||||
"focus": ["clients", "edge", "gateway", "api_a", "api_b"],
|
||||
"note": "Follow public traffic into the private application network."
|
||||
},
|
||||
{
|
||||
"id": "state-ownership",
|
||||
"label": "State and ownership",
|
||||
"focus": ["api_a", "api_b", "redis", "postgres", "replica"],
|
||||
"note": "Separate stateless platform workloads from data-team-owned state."
|
||||
},
|
||||
{
|
||||
"id": "async-operations",
|
||||
"label": "Async and operations",
|
||||
"focus": ["api_b", "events", "worker", "audit", "observability"],
|
||||
"note": "See the asynchronous work and the evidence it emits."
|
||||
}
|
||||
]
|
||||
},
|
||||
"components": [
|
||||
{ "id": "clients", "type": "external", "label": "Customers", "sublabel": "web + mobile", "pos": [38, 300], "size": [122, 60] },
|
||||
{ "id": "edge", "type": "cloud", "label": "Global Edge", "sublabel": "CDN + WAF", "pos": [230, 300], "size": [126, 60], "tag": "edge team" },
|
||||
{ "id": "gateway", "type": "security", "label": "API Gateway", "sublabel": "public :443", "pos": [430, 300], "size": [128, 60], "tag": "platform" },
|
||||
{ "id": "api_a", "type": "backend", "label": "API Pods / AZ-a", "sublabel": "private subnet", "pos": [630, 195], "size": [136, 62], "tag": "app team" },
|
||||
{ "id": "api_b", "type": "backend", "label": "API Pods / AZ-b", "sublabel": "private subnet", "pos": [630, 405], "size": [136, 62], "tag": "app team" },
|
||||
{ "id": "redis", "type": "database", "label": "Redis", "sublabel": "multi-AZ cache", "pos": [840, 195], "size": [126, 62], "tag": "platform" },
|
||||
{ "id": "postgres", "type": "database", "label": "PostgreSQL", "sublabel": "primary / encrypted", "pos": [840, 405], "size": [126, 62], "tag": "data team" },
|
||||
{ "id": "events", "type": "messagebus", "label": "Event Bus", "sublabel": "orders.v1", "pos": [1040, 300], "size": [126, 60], "tag": "platform" },
|
||||
{ "id": "worker", "type": "backend", "label": "Workers", "sublabel": "private workload", "pos": [1240, 300], "size": [126, 60], "tag": "app team" },
|
||||
{ "id": "replica", "type": "database", "label": "DR Replica", "sublabel": "eu-west-1", "pos": [1040, 610], "size": [126, 62], "tag": "data team" },
|
||||
{ "id": "audit", "type": "cloud", "label": "Audit Archive", "sublabel": "immutable objects", "pos": [1240, 465], "size": [126, 62], "tag": "security" },
|
||||
{ "id": "observability", "type": "external", "label": "Observability", "sublabel": "metrics + traces", "pos": [1240, 85], "size": [126, 62], "tag": "SRE" }
|
||||
],
|
||||
"boundaries": [
|
||||
{ "kind": "region", "label": "AWS us-east-1 / production", "wraps": ["edge", "gateway", "api_a", "api_b", "redis", "postgres", "events", "worker", "audit"] },
|
||||
{ "kind": "security-group", "label": "private application network", "wraps": ["api_a", "api_b", "redis", "postgres", "events", "worker"] },
|
||||
{ "kind": "region", "label": "AWS eu-west-1 / disaster recovery", "wraps": ["replica"] },
|
||||
{ "kind": "security-group", "label": "DR private subnet", "wraps": ["replica"], "pad": 14 }
|
||||
],
|
||||
"connections": [
|
||||
{ "from": "clients", "to": "edge", "label": "HTTPS", "variant": "emphasis" },
|
||||
{ "from": "edge", "to": "gateway", "label": "mTLS", "variant": "security" },
|
||||
{ "from": "gateway", "to": "api_a", "label": "VPC route", "variant": "emphasis", "route": "orthogonal-h", "labelAt": [594, 275] },
|
||||
{ "from": "gateway", "to": "api_b", "label": "VPC route", "variant": "emphasis", "route": "orthogonal-h", "labelAt": [594, 385] },
|
||||
{ "from": "api_a", "to": "redis", "label": "cache", "route": "straight" },
|
||||
{ "from": "api_b", "to": "postgres", "label": "SQL", "route": "straight" },
|
||||
{ "from": "api_a", "to": "events", "label": "publish", "variant": "dashed", "fromSide": "top", "toSide": "top", "via": [[698, 170], [1103, 170]] },
|
||||
{ "from": "api_b", "to": "events", "variant": "dashed", "fromSide": "top", "toSide": "bottom", "via": [[698, 380], [1103, 380]] },
|
||||
{ "from": "events", "to": "worker", "variant": "emphasis" },
|
||||
{ "from": "postgres", "to": "replica", "label": "cross-region WAL", "variant": "security", "route": "orthogonal-v", "labelAt": [1003, 529] },
|
||||
{ "from": "worker", "to": "audit", "label": "evidence", "variant": "dashed", "fromSide": "bottom", "toSide": "top", "labelDy": 58 },
|
||||
{ "from": "worker", "to": "observability", "label": "OTLP", "variant": "dashed", "route": "orthogonal-v" }
|
||||
],
|
||||
"cards": [
|
||||
{ "dot": "cyan", "title": "Runtime Ownership", "items": ["Platform owns the edge, gateway, cache, and event bus", "Application teams own API pods and workers", "Data owns primary and disaster-recovery state"] },
|
||||
{ "dot": "rose", "title": "Named Crossings", "items": ["Public HTTPS terminates at the managed edge", "mTLS crosses into the application network", "Cross-region WAL is explicit and encrypted"] },
|
||||
{ "dot": "emerald", "title": "Operational Evidence", "items": ["Workers emit traces to SRE-owned observability", "Audit evidence lands in immutable storage", "Unknown placement should remain marked, never invented"] }
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"diagram_type": "architecture",
|
||||
"meta": {
|
||||
"title": "Sample Web App",
|
||||
"subtitle": "Classic 3-tier SaaS on AWS — rendered by Archify",
|
||||
"output": "web-app-rendered.html"
|
||||
},
|
||||
"components": [
|
||||
{ "id": "users", "type": "external", "label": "Users", "sublabel": "Browser / Mobile", "pos": [40, 300], "size": [120, 60] },
|
||||
{ "id": "auth", "type": "security", "label": "Auth Provider", "sublabel": "OAuth 2.0", "pos": [40, 110], "size": [120, 64], "tag": "JWT + PKCE" },
|
||||
{ "id": "cdn", "type": "cloud", "label": "CloudFront", "sublabel": "CDN", "pos": [250, 300], "size": [130, 60] },
|
||||
{ "id": "lb", "type": "cloud", "label": "Load Balancer", "sublabel": "HTTPS :443", "pos": [460, 300], "size": [130, 60] },
|
||||
{ "id": "api", "type": "backend", "label": "API Server", "sublabel": "FastAPI :8000", "pos": [670, 300], "size": [130, 60] },
|
||||
{ "id": "cache", "type": "database", "label": "Redis", "sublabel": "cache :6379", "pos": [670, 150], "size": [130, 60] },
|
||||
{ "id": "db", "type": "database", "label": "PostgreSQL", "sublabel": "primary :5432", "pos": [880, 300], "size": [130, 60] },
|
||||
{ "id": "s3", "type": "cloud", "label": "S3", "sublabel": "static assets", "pos": [250, 440], "size": [130, 60], "tag": "OAI protected" },
|
||||
{ "id": "queue", "type": "messagebus", "label": "SQS", "sublabel": "job queue", "pos": [670, 440], "size": [130, 60] },
|
||||
{ "id": "worker", "type": "backend", "label": "Worker", "sublabel": "async jobs", "pos": [880, 440], "size": [130, 60] }
|
||||
],
|
||||
"boundaries": [
|
||||
{ "kind": "region", "label": "AWS Region: us-west-2", "wraps": ["cdn", "lb", "api", "cache", "db", "s3", "queue", "worker"] },
|
||||
{ "kind": "security-group", "label": "sg-api :443/:8000", "wraps": ["lb", "api"] }
|
||||
],
|
||||
"connections": [
|
||||
{ "from": "users", "to": "cdn", "label": "HTTPS", "variant": "emphasis" },
|
||||
{ "from": "auth", "to": "api", "label": "verify JWT", "variant": "security", "fromSide": "right", "toSide": "left", "via": [[620, 142], [620, 330]] },
|
||||
{ "from": "cdn", "to": "lb" },
|
||||
{ "from": "cdn", "to": "s3", "label": "static", "variant": "dashed", "fromSide": "bottom", "toSide": "top", "labelDy": 58 },
|
||||
{ "from": "lb", "to": "api" },
|
||||
{ "from": "api", "to": "cache", "label": "read-through", "fromSide": "top", "toSide": "bottom", "labelDy": -68 },
|
||||
{ "from": "api", "to": "db", "label": "SQL" },
|
||||
{ "from": "api", "to": "queue", "label": "enqueue", "variant": "dashed", "fromSide": "bottom", "toSide": "top", "labelDy": 58 },
|
||||
{ "from": "queue", "to": "worker" }
|
||||
],
|
||||
"cards": [
|
||||
{ "dot": "cyan", "title": "Edge", "items": ["CloudFront CDN fronts all traffic", "S3 serves static assets via OAI"] },
|
||||
{ "dot": "emerald", "title": "Application", "items": ["FastAPI behind an HTTPS load balancer", "Redis read-through cache", "Async work drained from SQS by a worker"] },
|
||||
{ "dot": "rose", "title": "Security", "items": ["OAuth 2.0 with JWT + PKCE", "API + LB isolated in a security group"] }
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"diagram_type": "workflow",
|
||||
"meta": {
|
||||
"title": "Legacy narrow workflow",
|
||||
"viewBox": [700, 400]
|
||||
},
|
||||
"lanes": [
|
||||
{ "id": "first", "label": "First" },
|
||||
{ "id": "second", "label": "Second" }
|
||||
],
|
||||
"nodes": [
|
||||
{ "id": "node_0", "lane": "first", "col": 0, "type": "frontend", "label": "frontend" },
|
||||
{ "id": "node_1", "lane": "first", "col": 2, "type": "backend", "label": "backend" },
|
||||
{ "id": "node_2", "lane": "first", "col": 4, "type": "database", "label": "database" },
|
||||
{ "id": "node_3", "lane": "second", "col": 0, "type": "cloud", "label": "cloud" },
|
||||
{ "id": "node_4", "lane": "second", "col": 2, "type": "security", "label": "security" },
|
||||
{ "id": "node_5", "lane": "second", "col": 4, "type": "messagebus", "label": "messagebus" },
|
||||
{ "id": "node_6", "lane": "second", "col": 5, "type": "external", "label": "external" }
|
||||
],
|
||||
"edges": []
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"diagram_type": "workflow",
|
||||
"meta": {
|
||||
"title": "Pinned coordinate migration",
|
||||
"viewBox": [720, 700],
|
||||
"legend": { "mode": "hidden" }
|
||||
},
|
||||
"lanes": [
|
||||
{ "id": "route", "label": "Explicit route" },
|
||||
{ "id": "label", "label": "Explicit label" },
|
||||
{ "id": "channel-source", "label": "Channel source" },
|
||||
{ "id": "channel-target", "label": "Channel target" }
|
||||
],
|
||||
"nodes": [
|
||||
{ "id": "route-a", "lane": "route", "col": 0, "type": "backend", "label": "A" },
|
||||
{ "id": "route-b", "lane": "route", "col": 2, "type": "backend", "label": "B" },
|
||||
{ "id": "label-a", "lane": "label", "col": 2, "type": "backend", "label": "C" },
|
||||
{ "id": "label-b", "lane": "label", "col": 3, "type": "backend", "label": "D" },
|
||||
{ "id": "channel-a", "lane": "channel-source", "col": 1, "type": "backend", "label": "E" },
|
||||
{ "id": "channel-b", "lane": "channel-target", "col": 1, "type": "backend", "label": "F" }
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "pinned-via",
|
||||
"from": "route-a",
|
||||
"to": "route-b",
|
||||
"via": [[220, 119]]
|
||||
},
|
||||
{
|
||||
"id": "pinned-label",
|
||||
"from": "label-a",
|
||||
"to": "label-b",
|
||||
"label": "ok",
|
||||
"labelAt": [365, 203]
|
||||
},
|
||||
{
|
||||
"id": "pinned-channel",
|
||||
"from": "channel-a",
|
||||
"to": "channel-b",
|
||||
"fromSide": "right",
|
||||
"toSide": "right",
|
||||
"route": "outside-right",
|
||||
"channelX": 500
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user