@meltemi/diagrams-cli 1.9.0 → 1.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent-setup/prompt.md +83 -0
- package/dist/assets-command.d.ts.map +1 -1
- package/dist/assets-command.js +15 -0
- package/dist/assets-command.js.map +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +11 -1
- package/dist/cli.js.map +1 -1
- package/dist/export-command.d.ts.map +1 -1
- package/dist/export-command.js +16 -3
- package/dist/export-command.js.map +1 -1
- package/dist/init-command.d.ts.map +1 -1
- package/dist/init-command.js +6 -3
- package/dist/init-command.js.map +1 -1
- package/dist/messages/en.d.ts +45 -7
- package/dist/messages/en.d.ts.map +1 -1
- package/dist/messages/en.js +82 -9
- package/dist/messages/en.js.map +1 -1
- package/dist/messages/es.d.ts.map +1 -1
- package/dist/messages/es.js +79 -8
- package/dist/messages/es.js.map +1 -1
- package/dist/messages/index.d.ts +41 -6
- package/dist/messages/index.d.ts.map +1 -1
- package/dist/skill-command.d.ts +48 -0
- package/dist/skill-command.d.ts.map +1 -0
- package/dist/skill-command.js +148 -0
- package/dist/skill-command.js.map +1 -0
- package/package.json +25 -18
- package/skills/.skills-sync.json +5 -0
- package/skills/meltemi-diagrams/SKILL.md +232 -0
- package/skills/meltemi-diagrams/examples/architecture.meltemi +73 -0
- package/skills/meltemi-diagrams/examples/platform.meltemi +139 -0
- package/skills/meltemi-diagrams/examples/sequence.meltemi +52 -0
- package/skills/meltemi-diagrams/examples/slide.meltemi +60 -0
- package/skills/meltemi-diagrams/examples/story.meltemi +53 -0
- package/skills/meltemi-diagrams/reference/c4.md +92 -0
- package/skills/meltemi-diagrams/reference/cloud.md +19 -0
- package/skills/meltemi-diagrams/reference/converting.md +101 -0
- package/skills/meltemi-diagrams/reference/free.md +327 -0
- package/skills/meltemi-diagrams/reference/language.md +245 -0
- package/skills/meltemi-diagrams/reference/layout.md +165 -0
- package/skills/meltemi-diagrams/reference/sequence.md +143 -0
- package/skills/meltemi-diagrams/reference/stories.md +94 -0
- package/skills/meltemi-diagrams/reference/themes.md +148 -0
- package/templates/kanban/diagrams/board.meltemi +57 -0
- package/templates/whiteboard/diagrams/whiteboard.meltemi +59 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
language "0.2"
|
|
2
|
+
|
|
3
|
+
// Shared model and views from the product proposal ("Modelos y vistas"), with a context view and
|
|
4
|
+
// a component view that lift and combine the model's relations.
|
|
5
|
+
model commerce {
|
|
6
|
+
person customer "Cliente" { description "Compra en línea" }
|
|
7
|
+
|
|
8
|
+
system shop "Commerce" {
|
|
9
|
+
description "Tienda en línea"
|
|
10
|
+
container web "Web" { technology "React" }
|
|
11
|
+
container api "API" {
|
|
12
|
+
technology "HTTP"
|
|
13
|
+
component orders "Pedidos" { technology "Kotlin" }
|
|
14
|
+
component payments "Pagos" { technology "Kotlin" }
|
|
15
|
+
}
|
|
16
|
+
datastore db "Pedidos" { technology "PostgreSQL" }
|
|
17
|
+
api.orders -> db: "Guarda" as store
|
|
18
|
+
}
|
|
19
|
+
system bank "Banco" {
|
|
20
|
+
description "Autoriza tarjetas"
|
|
21
|
+
external
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
customer -> shop.web: "Compra" as visit
|
|
25
|
+
shop.web -> shop.api: "HTTPS" as request { technology "JSON/HTTPS" }
|
|
26
|
+
shop.api -> shop.db: "SQL" as persist
|
|
27
|
+
shop.api.payments -> bank: "Autoriza" as authorize
|
|
28
|
+
shop.web -> shop.api.orders: "Pedidos" as orders
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
diagram context: c4 using commerce {
|
|
32
|
+
level context
|
|
33
|
+
layout assisted
|
|
34
|
+
title "Commerce en contexto"
|
|
35
|
+
|
|
36
|
+
placement {
|
|
37
|
+
place customer at (92, 64)
|
|
38
|
+
place shop at (456, 64)
|
|
39
|
+
place bank at (833, 64)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
diagram containers: c4 using commerce {
|
|
44
|
+
level container
|
|
45
|
+
scope shop
|
|
46
|
+
include customer, shop.web, shop.api, shop.db
|
|
47
|
+
layout assisted
|
|
48
|
+
direction LR
|
|
49
|
+
theme "editorial.light"
|
|
50
|
+
label shop.api "API de pedidos"
|
|
51
|
+
|
|
52
|
+
placement {
|
|
53
|
+
place customer at (92, 93)
|
|
54
|
+
place shop.web at (473, 93)
|
|
55
|
+
place shop.api at (855, 93)
|
|
56
|
+
place shop.db at (1214, 94)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
diagram components: c4 using commerce {
|
|
61
|
+
level component
|
|
62
|
+
scope shop.api
|
|
63
|
+
layout assisted
|
|
64
|
+
shop.web -> shop.api.orders: "Usa" as uses
|
|
65
|
+
|
|
66
|
+
placement {
|
|
67
|
+
place shop.web at (97, 88)
|
|
68
|
+
place shop.api.orders at (459, 88)
|
|
69
|
+
place shop.api.payments at (459, 200)
|
|
70
|
+
place shop.db at (845, 88)
|
|
71
|
+
place bank at (850, 210)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
language "0.2"
|
|
2
|
+
|
|
3
|
+
// A complete sheet using every construct of the flow profile: bands, nodes with descriptions,
|
|
4
|
+
// data stores, a decision, notes, tags, named relations with numbered steps, waypoints, shared
|
|
5
|
+
// styles for a palette and for "proposed" pieces, a legend and a file theme with the brand frame.
|
|
6
|
+
|
|
7
|
+
theme acme {
|
|
8
|
+
extends "technical.light"
|
|
9
|
+
accent "#1D4ED8"
|
|
10
|
+
accentEnd "#0891B2"
|
|
11
|
+
brand "Acme · Meltemi Diagrams"
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
diagram paymentsPlatform: flow {
|
|
15
|
+
title "Payments platform"
|
|
16
|
+
description "Target architecture of the payments platform: edge, services, approval and data."
|
|
17
|
+
layout manual
|
|
18
|
+
theme "acme"
|
|
19
|
+
|
|
20
|
+
// ---- Bands --------------------------------------------------------------------------------
|
|
21
|
+
group identity "Identity" {
|
|
22
|
+
node login "Login + PKCE" { description "customers" }
|
|
23
|
+
node obo "Token exchange" { description "on behalf of" }
|
|
24
|
+
note identityLimits "To validate\nrate limits\ntoken lifetimes"
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
group services "Services" {
|
|
28
|
+
node orders "Orders" { description "Go · gRPC" }
|
|
29
|
+
node payments "Payments" { description "Go · gRPC" }
|
|
30
|
+
decision risky "Manual approval?"
|
|
31
|
+
node approvals "Approvals" { description "Temporal workflow" }
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
group data "Data" {
|
|
35
|
+
data documents "Documents" { description "S3" }
|
|
36
|
+
data ledger "Ledger" { description "PostgreSQL" }
|
|
37
|
+
data cache "Cache" { description "Redis · TTL" }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ---- Edge and partners --------------------------------------------------------------------
|
|
41
|
+
node app "Mobile app" { description "signed-in user" }
|
|
42
|
+
node gateway "API Gateway" { description "validates JWT · routes" }
|
|
43
|
+
node partner "Partner API" { description "banks and PSPs" }
|
|
44
|
+
|
|
45
|
+
// ---- Tags: capability that acts at that point ---------------------------------------------
|
|
46
|
+
tag tPkce "PKCE"
|
|
47
|
+
tag tJwt "JWT"
|
|
48
|
+
tag tObo "OBO"
|
|
49
|
+
|
|
50
|
+
// ---- Main path (the numbers are the steps) ------------------------------------------------
|
|
51
|
+
// 1. The user signs in and the app calls the gateway with the user's JWT.
|
|
52
|
+
app -> gateway: "1" as r1
|
|
53
|
+
// 2. The gateway validates the token and routes to Orders.
|
|
54
|
+
gateway -> orders: "2" as r2
|
|
55
|
+
// 3. Orders asks Payments to charge.
|
|
56
|
+
orders -> payments: "3" as r3
|
|
57
|
+
// 4. Payments decides whether a human must approve.
|
|
58
|
+
payments -> risky: "4" as r4
|
|
59
|
+
// 5. Risky payments wait for approval in a durable workflow; the rest settle at once.
|
|
60
|
+
risky -> approvals: "yes" as r5
|
|
61
|
+
risky -> ledger: "no" as r6
|
|
62
|
+
approvals -> ledger as r7
|
|
63
|
+
approvals -> documents as r10
|
|
64
|
+
// Partners are called with a token exchanged on behalf of the user.
|
|
65
|
+
payments -> partner as r8
|
|
66
|
+
payments -> cache as r9
|
|
67
|
+
|
|
68
|
+
// ---- Legend --------------------------------------------------------------------------------
|
|
69
|
+
tag lgIdentity "Identity"
|
|
70
|
+
tag lgServices "Services"
|
|
71
|
+
tag lgData "Data"
|
|
72
|
+
tag lgDashed "Dashed: proposed"
|
|
73
|
+
|
|
74
|
+
placement {
|
|
75
|
+
// Bands
|
|
76
|
+
place identity at (120, 250); size identity (200, 460)
|
|
77
|
+
place services at (560, 340); size services (520, 280)
|
|
78
|
+
place data at (640, 620); size data (600, 160)
|
|
79
|
+
|
|
80
|
+
// Identity
|
|
81
|
+
place login at (120, 98); size login (160, 56)
|
|
82
|
+
place obo at (120, 178); size obo (160, 56)
|
|
83
|
+
place identityLimits at (118, 290); size identityLimits (150, 54)
|
|
84
|
+
|
|
85
|
+
// Edge and partners
|
|
86
|
+
place app at (380, 60); size app (180, 56)
|
|
87
|
+
place gateway at (560, 160); size gateway (420, 50)
|
|
88
|
+
place partner at (980, 160); size partner (160, 56)
|
|
89
|
+
|
|
90
|
+
// Services
|
|
91
|
+
place orders at (440, 300); size orders (160, 56)
|
|
92
|
+
place payments at (660, 300); size payments (160, 56)
|
|
93
|
+
place risky at (660, 410); size risky (180, 80)
|
|
94
|
+
place approvals at (440, 410); size approvals (160, 56)
|
|
95
|
+
|
|
96
|
+
// Data
|
|
97
|
+
place documents at (440, 640)
|
|
98
|
+
place ledger at (620, 640)
|
|
99
|
+
place cache at (840, 640)
|
|
100
|
+
|
|
101
|
+
// Tags on box corners
|
|
102
|
+
place tPkce at (470, 32)
|
|
103
|
+
place tJwt at (770, 135)
|
|
104
|
+
place tObo at (740, 272)
|
|
105
|
+
|
|
106
|
+
// Steps beside the arrows
|
|
107
|
+
label r1 at 50% offset (16, 0)
|
|
108
|
+
label r2 at 50% offset (16, 0)
|
|
109
|
+
label r3 at 50% offset (0, -16)
|
|
110
|
+
label r4 at 50% offset (16, 0)
|
|
111
|
+
label r5 at 50% offset (0, -16)
|
|
112
|
+
label r6 at 50% offset (16, 0)
|
|
113
|
+
|
|
114
|
+
// Bends: one waypoint per corner
|
|
115
|
+
route r7 from approvals.south to ledger.north via [(480, 520), (600, 520)]
|
|
116
|
+
route r8 from payments.east to partner.south via [(980, 300)]
|
|
117
|
+
route r9 from payments.south to cache.north via [(720, 345), (840, 345)]
|
|
118
|
+
|
|
119
|
+
// Legend
|
|
120
|
+
place lgIdentity at (80, 760)
|
|
121
|
+
place lgServices at (180, 760)
|
|
122
|
+
place lgData at (266, 760)
|
|
123
|
+
place lgDashed at (402, 760)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// ---- Palette -------------------------------------------------------------------------------
|
|
127
|
+
style identity, lgIdentity { fill "#f6f3fe"; stroke "#6a4fd0"; color "#33247a" }
|
|
128
|
+
style login, obo { fill "#ebe5fd"; stroke "#6a4fd0"; color "#33247a" }
|
|
129
|
+
style identityLimits { color "#33247a" }
|
|
130
|
+
style services, lgServices { fill "#eef6f9"; stroke "#2f7f9c"; color "#144a5e" }
|
|
131
|
+
style data, lgData { fill "#fdf5e6"; stroke "#b9800f"; color "#6b4500" }
|
|
132
|
+
style gateway { fill "#e2f3e5"; stroke "#3d8c50"; color "#1d5a2d" }
|
|
133
|
+
style tPkce, tJwt, tObo { fill "#6a4fd0"; color "#ffffff" }
|
|
134
|
+
style lgDashed { fill "#ffffff"; stroke "#526579"; color "#526579" }
|
|
135
|
+
style r1, r2, r3, r4 { fill "#0B1830"; color "#FFFFFF" }
|
|
136
|
+
|
|
137
|
+
// ---- Proposed or to validate ---------------------------------------------------------------
|
|
138
|
+
style obo, approvals, documents, partner, lgDashed { line dashed }
|
|
139
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
language "0.2"
|
|
2
|
+
|
|
3
|
+
// A payment with an approval branch, a call that returns, a retry loop and two scenarios.
|
|
4
|
+
diagram payment: sequence {
|
|
5
|
+
title "Card payment"
|
|
6
|
+
autonumber
|
|
7
|
+
|
|
8
|
+
actor customer "Customer"
|
|
9
|
+
boundary web "Checkout page"
|
|
10
|
+
group backend "Backend" {
|
|
11
|
+
participant api "Payments API"
|
|
12
|
+
database ledger "Ledger"
|
|
13
|
+
}
|
|
14
|
+
participant bank "Card network"
|
|
15
|
+
|
|
16
|
+
customer -> web: "Pay" as pay
|
|
17
|
+
web -> api: "Create payment" as create
|
|
18
|
+
activate api
|
|
19
|
+
api -> bank: "Authorize" as authorize
|
|
20
|
+
|
|
21
|
+
alt result "Approved" {
|
|
22
|
+
bank --> api: "Approved" as approved
|
|
23
|
+
// The ledger is active for the call, until it returns.
|
|
24
|
+
api -> ledger: "Record" as record {
|
|
25
|
+
return "Recorded" as recorded
|
|
26
|
+
}
|
|
27
|
+
api --> web: "Receipt" as receipt
|
|
28
|
+
} else "Declined" {
|
|
29
|
+
bank --> api: "Declined" as declined
|
|
30
|
+
loop retries "Until the card works" {
|
|
31
|
+
api --> web: "Ask for another card" as again
|
|
32
|
+
web -> api: "New card" as card
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
note over web, api "The page never sees the card number"
|
|
37
|
+
deactivate api
|
|
38
|
+
api -> web: "Payment settled" as settled { kind async }
|
|
39
|
+
|
|
40
|
+
placement {
|
|
41
|
+
space authorize 14
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
scenario approved "Payment approved" {
|
|
45
|
+
choose result "Approved"
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
scenario declined "Declined twice" {
|
|
49
|
+
choose result "Declined"
|
|
50
|
+
repeat retries 2
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
language "0.2"
|
|
2
|
+
|
|
3
|
+
// The source flow: the slide below links each of its boxes to these elements.
|
|
4
|
+
diagram checkout: flow {
|
|
5
|
+
layout manual
|
|
6
|
+
|
|
7
|
+
client["Client app"]
|
|
8
|
+
api["Order API"]
|
|
9
|
+
data orders "Orders DB"
|
|
10
|
+
|
|
11
|
+
client -> api: "HTTPS" as request
|
|
12
|
+
api -> orders as persist
|
|
13
|
+
|
|
14
|
+
placement {
|
|
15
|
+
place client at (120, 60)
|
|
16
|
+
place api at (380, 60)
|
|
17
|
+
place orders at (640, 60)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// A free composition: text, shapes, an icon, a group placed by its interior, and two layers.
|
|
22
|
+
diagram slide: free {
|
|
23
|
+
title "Checkout at a glance"
|
|
24
|
+
preset slide
|
|
25
|
+
routing orthogonal
|
|
26
|
+
layers main, front
|
|
27
|
+
|
|
28
|
+
text heading "Checkout at a glance"
|
|
29
|
+
text lead "Every order passes through one API" { class muted }
|
|
30
|
+
|
|
31
|
+
box client "Client app" { link checkout.client }
|
|
32
|
+
group backend "Backend" {
|
|
33
|
+
box api "Order API" { description "REST · validates input"; link checkout.api }
|
|
34
|
+
box orders "Orders DB" { link checkout.orders }
|
|
35
|
+
api -> orders as persist
|
|
36
|
+
}
|
|
37
|
+
icon secure "tabler:lock" { layer front }
|
|
38
|
+
text secureNote "TLS everywhere" { layer front }
|
|
39
|
+
|
|
40
|
+
client -> api: "HTTPS" as request
|
|
41
|
+
|
|
42
|
+
placement {
|
|
43
|
+
place heading at (960, 140)
|
|
44
|
+
place lead at (960, 210)
|
|
45
|
+
place client at (420, 560)
|
|
46
|
+
place backend at (1180, 560)
|
|
47
|
+
size backend (640, 240)
|
|
48
|
+
place api at (140, 92)
|
|
49
|
+
place orders at (460, 92)
|
|
50
|
+
place secure at (420, 420)
|
|
51
|
+
place secureNote at (420, 470)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
class muted { color muted; fontSize 28; fontWeight 400 }
|
|
55
|
+
style heading { fontSize 56; fontWeight 700; textAlign center }
|
|
56
|
+
style lead { textAlign center }
|
|
57
|
+
style client { shape pill }
|
|
58
|
+
style orders { shape cylinder }
|
|
59
|
+
style secureNote { textAlign center }
|
|
60
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
language "0.2"
|
|
2
|
+
|
|
3
|
+
// A checkout flow and the story that walks through a purchase. Export any instant with
|
|
4
|
+
// pnpm mdg export story.meltemi --story purchase --at 2.4s
|
|
5
|
+
diagram checkout: flow {
|
|
6
|
+
title "Checkout"
|
|
7
|
+
layout manual
|
|
8
|
+
|
|
9
|
+
client["Client app"]
|
|
10
|
+
api["Order API"]
|
|
11
|
+
orders["Orders service"]
|
|
12
|
+
data db "Orders DB"
|
|
13
|
+
|
|
14
|
+
client -> api: "HTTPS" as request
|
|
15
|
+
api -> orders: "Create order" as create
|
|
16
|
+
orders -> db: "Persist" as save
|
|
17
|
+
|
|
18
|
+
placement {
|
|
19
|
+
place client at (120, 80)
|
|
20
|
+
place api at (380, 80)
|
|
21
|
+
place orders at (640, 80)
|
|
22
|
+
place db at (640, 220)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
animate request { effect flow }
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
story purchase for checkout {
|
|
29
|
+
title "A purchase"
|
|
30
|
+
description "From the client's request to the stored order."
|
|
31
|
+
|
|
32
|
+
scene overview "The pieces" {
|
|
33
|
+
reveal client, api, orders, db over 800ms
|
|
34
|
+
hold 1s
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
scene request "The request" {
|
|
38
|
+
focus client, api
|
|
39
|
+
trace request over 1200ms
|
|
40
|
+
camera api, orders
|
|
41
|
+
trace create over 1200ms
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
scene stored "Stored" {
|
|
45
|
+
focus all
|
|
46
|
+
camera all
|
|
47
|
+
parallel {
|
|
48
|
+
trace save over 1200ms
|
|
49
|
+
highlight db over 1200ms
|
|
50
|
+
}
|
|
51
|
+
hold 2s
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Models and C4 views
|
|
2
|
+
|
|
3
|
+
Use a `model` block for the architecture (who uses what, which containers a system has) and C4
|
|
4
|
+
views to draw it at one level each. Declare entities once in the model; views only list them.
|
|
5
|
+
|
|
6
|
+
## Model
|
|
7
|
+
|
|
8
|
+
```text
|
|
9
|
+
model commerce {
|
|
10
|
+
person customer "Cliente" { description "Compra en línea" }
|
|
11
|
+
system shop "Commerce" {
|
|
12
|
+
container web "Web" { technology "React" }
|
|
13
|
+
container api "API" {
|
|
14
|
+
technology "Kotlin"
|
|
15
|
+
component orders "Pedidos"
|
|
16
|
+
}
|
|
17
|
+
datastore db "Pedidos" { technology "PostgreSQL" }
|
|
18
|
+
api -> db: "SQL" as persist // inside shop: api is shop.api
|
|
19
|
+
}
|
|
20
|
+
system bank "Banco" { external }
|
|
21
|
+
|
|
22
|
+
customer -> shop.web: "Compra" as visit
|
|
23
|
+
shop.web -> shop.api: "HTTPS" as request { technology "JSON/HTTPS" }
|
|
24
|
+
shop.api.orders -> bank: "Autoriza" as authorize
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
- Persons and systems at the root; containers and datastores in systems; components in containers
|
|
29
|
+
(`model.invalid-nesting` otherwise).
|
|
30
|
+
- Entities are named by path: `shop.api.orders`. Relations use `->` only and name paths.
|
|
31
|
+
- `external` marks persons and systems outside the organisation (drawn grey and dashed).
|
|
32
|
+
|
|
33
|
+
## Views
|
|
34
|
+
|
|
35
|
+
```text
|
|
36
|
+
diagram containers: c4 using commerce {
|
|
37
|
+
level container // context | container | component
|
|
38
|
+
scope shop // a system; a container for component views
|
|
39
|
+
include customer, shop.web, shop.api, shop.db
|
|
40
|
+
label shop.api "API de pedidos" // local text, the model keeps "API"
|
|
41
|
+
direction LR
|
|
42
|
+
layout assisted
|
|
43
|
+
placement { place shop.api at (420, 120) }
|
|
44
|
+
style shop.db { fill accent }
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
- Without `include`, a view draws its default set: everything at the context level, otherwise
|
|
49
|
+
the scope's children and the entities related to them. `exclude` removes entities.
|
|
50
|
+
- A container view draws the scope's containers and datastores (inside a dashed boundary),
|
|
51
|
+
persons and other systems; a component view the scope's components, the other containers of the
|
|
52
|
+
system, persons and other systems. Anything else is `c4.out-of-level`.
|
|
53
|
+
- Relations come from the model; ends inside hidden entities are lifted to the drawn ancestor
|
|
54
|
+
(at the context level `customer -> shop.web` becomes `customer -> shop`). Two relations to the
|
|
55
|
+
same pair stay two arrows; to draw one, write a combination in the view:
|
|
56
|
+
`customer -> shop: "Usa" as uses`. A combination with no model relation behind it is
|
|
57
|
+
`c4.unsupported-relation`.
|
|
58
|
+
- Placement, styles and routes take paths: `route request from shop.web.east to shop.api.west`.
|
|
59
|
+
|
|
60
|
+
## Notes in views
|
|
61
|
+
|
|
62
|
+
A view accepts `note <id> "Text" [on <entity path>]` beside its lists: an annotation of the view,
|
|
63
|
+
never of the model and never an entity (`include`, `exclude`, `label` and relations cannot name it).
|
|
64
|
+
`note cache "Cached 5 min" on shop.api` draws a note with a dotted leader to `shop.api`, which the
|
|
65
|
+
view must draw (else `ref.unknown-element`). It takes `class` and `url`, the view's `style`, `class`,
|
|
66
|
+
`rule` and `animate`, and a `place` in the view's `placement`.
|
|
67
|
+
|
|
68
|
+
## Files
|
|
69
|
+
|
|
70
|
+
Keep the model in `models/` and the views in `diagrams/` of a project, and import the model:
|
|
71
|
+
|
|
72
|
+
```text
|
|
73
|
+
import commerce from "../models/commerce.meltemi"
|
|
74
|
+
diagram context: c4 using commerce { level context }
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Sequence and free objects link to entities with `link commerce.shop.api`; a participant without its
|
|
78
|
+
own label shows the entity's.
|
|
79
|
+
|
|
80
|
+
## Diagnostics
|
|
81
|
+
|
|
82
|
+
| Code | Fix |
|
|
83
|
+
| ------------------------- | ------------------------------------------------------------------------ |
|
|
84
|
+
| `c4.invalid-level` | add `level context`, `level container` or `level component` |
|
|
85
|
+
| `c4.scope-required` | add `scope <system>` (container view) or `scope <container>` (component) |
|
|
86
|
+
| `c4.invalid-scope` | scope a system or a container; datastores have no components |
|
|
87
|
+
| `c4.out-of-level` | remove the entity from `include`, or change the level |
|
|
88
|
+
| `c4.unsupported-relation` | add the relation to the model, or remove the combination |
|
|
89
|
+
| `ref.unknown-entity` | use the full path from the model's root (`shop.api`, not `api`) |
|
|
90
|
+
| `ref.unknown-model` | declare or import the model named after `using` |
|
|
91
|
+
| `model.invalid-nesting` | move the entity into the right parent |
|
|
92
|
+
| `model.invalid-relation` | relate separate entities, not an entity and its parent |
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Sharing in the cloud (only when the person asks)
|
|
2
|
+
|
|
3
|
+
A project can mirror itself in the optional Meltemi cloud service, to open it in the browser, share
|
|
4
|
+
it or publish its catalog as a web page. These commands need a signed-in person and change things
|
|
5
|
+
outside the repository, so run them only when asked, and never add `--force` unasked.
|
|
6
|
+
|
|
7
|
+
- `pnpm mdg login` opens the person's browser to approve the request (`--no-browser` prints the
|
|
8
|
+
address); `logout` revokes the token and `whoami` says who it is for. In CI the token is
|
|
9
|
+
`MELTEMI_TOKEN`. Exit code 3 means "run `login`".
|
|
10
|
+
- `pnpm mdg push <folder> --create` makes the cloud project and records it in `project.json`
|
|
11
|
+
(`cloud`). Later `push <folder>` lists what differs by path and by id and asks. `push --check`
|
|
12
|
+
writes nothing and exits 1 when the cloud differs, so it is safe to run.
|
|
13
|
+
- `pnpm mdg pull [<id>] [folder]` brings the cloud's files into the folder (files that differ are
|
|
14
|
+
kept unless `--force`); `pnpm mdg review <folder> --base cloud` lists what differs by id.
|
|
15
|
+
- `pnpm mdg publish <folder> --slug name` makes the catalog a public web page, so only on request;
|
|
16
|
+
`--unpublish` takes it down. `pnpm mdg projects --json` lists the person's cloud projects.
|
|
17
|
+
|
|
18
|
+
Never print, read or copy a token (`mdg_…`): it lives in `MELTEMI_TOKEN` or in the credentials file
|
|
19
|
+
that `login` keeps, and belongs in no command line, file or commit. `docs/cli.md` has the details.
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Converting an existing diagram into a `.meltemi` sheet
|
|
2
|
+
|
|
3
|
+
The goal is a sheet whose export can be put beside the original with only intended differences.
|
|
4
|
+
Work from the source's own geometry whenever it has one.
|
|
5
|
+
|
|
6
|
+
## Mermaid and PlantUML: import
|
|
7
|
+
|
|
8
|
+
Never retype a Mermaid or PlantUML diagram; import it:
|
|
9
|
+
|
|
10
|
+
````bash
|
|
11
|
+
pnpm mdg import docs/checkout.mmd # writes docs/checkout.meltemi
|
|
12
|
+
pnpm mdg import design.puml --out sheets/design.meltemi
|
|
13
|
+
pnpm mdg import README.md # every ```mermaid and ```plantuml block
|
|
14
|
+
````
|
|
15
|
+
|
|
16
|
+
- Mermaid `flowchart`/`graph`, `sequenceDiagram`, `C4Context`/`C4Container`/`C4Component`/
|
|
17
|
+
`C4Dynamic`, `architecture-beta` and `block-beta`; PlantUML component, deployment, use case,
|
|
18
|
+
sequence and C4-PlantUML diagrams, with `!define`, `!procedure`, `!function`, variables,
|
|
19
|
+
conditionals, loops and local `!include` files. Other types are refused.
|
|
20
|
+
- Read every finding: `import.approximated` (kept with another drawing), `import.unsupported-construct`
|
|
21
|
+
(dropped) and `import.syntax` (a line it could not read, kept as a `// Not imported:` comment).
|
|
22
|
+
Exit 1 means something essential is missing: add it by hand from the comment and the source.
|
|
23
|
+
- Flow imports use `layout auto`; adjust them on the canvas or with `layout assisted` and `place`.
|
|
24
|
+
When the source changes, run `pnpm mdg import <source> --merge`: placement, styles, classes,
|
|
25
|
+
animations, scenarios and local labels are kept for everything still in the source.
|
|
26
|
+
- C4 macros become a `model` and a view; check the level, the scope and the `include` list.
|
|
27
|
+
- Shapes are kept: Mermaid hexagons, parallelograms, trapezoids, circles, stadiums, subroutines
|
|
28
|
+
and flags, and PlantUML clouds, hexagons, actors, use cases, interfaces and files become nodes
|
|
29
|
+
(or boxes) with `style <id> { shape … }`; mirrored Mermaid forms are drawn as the nearest shape
|
|
30
|
+
and reported. Mermaid `block:` groups become untitled groups.
|
|
31
|
+
- `docs/import/mermaid.md` and `docs/import/plantuml.md` in the repository list what each construct
|
|
32
|
+
becomes.
|
|
33
|
+
|
|
34
|
+
The rest of this page is for sources that cannot be imported: HTML, SVG, draw.io, screenshots.
|
|
35
|
+
|
|
36
|
+
## 1. Get the geometry
|
|
37
|
+
|
|
38
|
+
| Source | Where the numbers are |
|
|
39
|
+
| ----------------------- | ------------------------------------------------------------------------------------------- |
|
|
40
|
+
| HTML or SVG sheet | `rect x y width height` and `text x y`; arrows as `line`/`path`; classes tell the category |
|
|
41
|
+
| draw.io / Excalidraw | the XML or JSON holds `x`, `y`, `width`, `height` per shape |
|
|
42
|
+
| D2 and other text tools | no coordinates: list nodes and edges, then design a grid (columns 200 px apart, rows 80 px) |
|
|
43
|
+
| Screenshot or photo | estimate on a 20 px grid; keep relative alignment, not pixel fidelity |
|
|
44
|
+
|
|
45
|
+
Record each box as centre and size: `place id at (x + w/2, y + h/2)` and `size id (w, h)`.
|
|
46
|
+
|
|
47
|
+
In draw.io a shape inside a container has `parent` set to the container and `x`, `y` relative to
|
|
48
|
+
the container's top-left corner. In a free diagram write the container as a group and the child's
|
|
49
|
+
`place` relative to the group's interior: `(x + w/2 - 16, y + h/2 - 16)` for an untitled group,
|
|
50
|
+
`(x + w/2 - 16, y + h/2 - 40)` for a titled one (technical themes). In a flow diagram keep diagram
|
|
51
|
+
coordinates.
|
|
52
|
+
|
|
53
|
+
## 2. Map the pieces
|
|
54
|
+
|
|
55
|
+
| In the original | In the sheet |
|
|
56
|
+
| ---------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
|
|
57
|
+
| Coloured band or swimlane with a title | `group id "Title" { ... }` with `place` and `size` of the band; colours in `style` |
|
|
58
|
+
| Nested plain rectangles, untitled containers (draw.io) | untitled groups `group id "" { ... }`, `style id { fill "…"; stroke "…"; radius 0 }` |
|
|
59
|
+
| Backdrop behind a row of boxes | an untitled group with `place`, `size` and `layer back` (`layers back, main`) |
|
|
60
|
+
| Rectangles drawn one inside another | boxes declared outer first, outer labels `""`; the stack is not an overlap |
|
|
61
|
+
| Hexagon, ellipse, circle, cloud, document, actor, star, triangle | `style id { shape hexagon }` on a `node` (flow) or `box` (free); see the note below |
|
|
62
|
+
| Square or more rounded corners (`rounded=0`) | `style id { radius 0 }`, or `radius 16`; `rule group { radius 0 }` for all groups |
|
|
63
|
+
| Box with title and subtitle | `node id "Title" { description "subtitle" }` (or `id["Title"]` without subtitle) |
|
|
64
|
+
| Database, cache, bucket, queue of records | `data id "Name" { description "..." }` |
|
|
65
|
+
| Diamond / question | `decision id "Question?"` |
|
|
66
|
+
| Free text, footnotes, limits | `note id "line\nline"` |
|
|
67
|
+
| Small badges or pills on boxes | `tag id "TEXT"` placed on the corner |
|
|
68
|
+
| Dashed outline, "proposed", "to validate" | `style a, b, c { line dashed }` |
|
|
69
|
+
| Numbered step circles on arrows | relation labels `"1"`, `"2"` with `label r1 at 50% offset (16, 0)` and a dark style |
|
|
70
|
+
| Arrow | `a -> b` (named `as id` when it has a label, a route or a style) |
|
|
71
|
+
| Bent arrow | `route id from a.side to b.side via [(x, y)]`, one waypoint per bend |
|
|
72
|
+
| Legend | a row of `tag`s under the sheet with the category colours |
|
|
73
|
+
| Explanatory paragraphs, step list | comments next to the relations; the ones not drawn stay as comments |
|
|
74
|
+
|
|
75
|
+
Some shapes are the nearest picture, not the same one. `shape triangle` points up, while draw.io's
|
|
76
|
+
`triangle` points right unless rotated: draw a right-pointing marker as `shape arrow`, or accept
|
|
77
|
+
the turned triangle. `shape person` is a head over a body, not draw.io's stick-figure actor.
|
|
78
|
+
|
|
79
|
+
Keep the original ids where they exist; otherwise derive camelCase ids from the labels.
|
|
80
|
+
|
|
81
|
+
## 3. Write the file
|
|
82
|
+
|
|
83
|
+
Order inside the diagram: properties, bands with their children, free-standing elements, tags,
|
|
84
|
+
relations with comments, legend, `placement`, then `style`. Group the placement block by area and
|
|
85
|
+
the style block by palette, with one shared statement for "dashed".
|
|
86
|
+
|
|
87
|
+
## 4. Prove it
|
|
88
|
+
|
|
89
|
+
1. `pnpm mdg validate file.meltemi` until no diagnostics remain.
|
|
90
|
+
2. `pnpm mdg export file.meltemi`, open the SVG beside the original (`pnpm preview`).
|
|
91
|
+
3. Compare arrow by arrow: in the original the arrows usually join boxes where they overlap, which
|
|
92
|
+
is what the exporter does without routes; only arrows that bend need waypoints.
|
|
93
|
+
4. Write down the intended differences (cylinders for stores, left-aligned band titles, legend inside
|
|
94
|
+
the sheet, fonts) in a README next to the file.
|
|
95
|
+
|
|
96
|
+
## Worked example
|
|
97
|
+
|
|
98
|
+
A real architecture sheet (30 boxes, 4 bands, 13 arrows, 8 steps, 7 tags) converts into one
|
|
99
|
+
file where only one arrow carries a waypoint; every other arrow is reproduced by the anchor rules.
|
|
100
|
+
See [examples/platform.meltemi](../examples/platform.meltemi) in this skill for a complete sheet
|
|
101
|
+
of the same shape.
|