chiltepin 0.47.0
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/LICENSE +21 -0
- package/README.md +249 -0
- package/dist/bin.js +3582 -0
- package/dist/bin.js.map +1 -0
- package/package.json +93 -0
- package/templates/chiltepin.config.json +5 -0
- package/templates/demo.md +2161 -0
- package/templates/docs/getting-started.md +155 -0
- package/templates/docs/tutorial.md +559 -0
- package/templates/skill/SKILL.md +172 -0
- package/templates/skill/reference/blocks/INDEX.md +141 -0
- package/templates/skill/reference/blocks/agentic.md +63 -0
- package/templates/skill/reference/blocks/algorithms.md +49 -0
- package/templates/skill/reference/blocks/api.md +40 -0
- package/templates/skill/reference/blocks/architecture.md +94 -0
- package/templates/skill/reference/blocks/business.md +70 -0
- package/templates/skill/reference/blocks/charts-overviews.md +74 -0
- package/templates/skill/reference/blocks/data-model.md +34 -0
- package/templates/skill/reference/blocks/design-system.md +50 -0
- package/templates/skill/reference/blocks/flows.md +74 -0
- package/templates/skill/reference/blocks/narrative.md +65 -0
- package/templates/skill/reference/blocks/planning.md +74 -0
- package/templates/skill/reference/blocks/quality.md +43 -0
- package/templates/skill/reference/blocks/tables-data.md +55 -0
- package/templates/skill/reference/check.md +62 -0
- package/templates/skill/reference/decks.md +198 -0
- package/templates/skill/reference/exemplars/adr.md +87 -0
- package/templates/skill/reference/exemplars/agent-system.md +113 -0
- package/templates/skill/reference/exemplars/api-reference.md +110 -0
- package/templates/skill/reference/exemplars/backend-arch.md +117 -0
- package/templates/skill/reference/exemplars/data-pipeline.md +107 -0
- package/templates/skill/reference/exemplars/frontend-arch.md +93 -0
- package/templates/skill/reference/exemplars/incident-postmortem.md +93 -0
- package/templates/skill/reference/exemplars/migration-plan.md +95 -0
- package/templates/skill/reference/exemplars/onboarding.md +78 -0
- package/templates/skill/reference/exemplars/product-spec.md +81 -0
- package/templates/skill/reference/intake.md +140 -0
- package/templates/skill/reference/mermaid.md +216 -0
- package/templates/skill/reference/organizing.md +118 -0
- package/templates/skill/reference/patterns-design.md +59 -0
- package/templates/skill/reference/patterns.md +167 -0
- package/templates/skill/reference/recipes.md +153 -0
- package/templates/skill/reference/style-ste.md +119 -0
- package/templates/skill/reference/system-design.md +161 -0
- package/templates/skill/reference/writing.md +132 -0
|
@@ -0,0 +1,2161 @@
|
|
|
1
|
+
```meta
|
|
2
|
+
title: Chiltepin — all blocks
|
|
3
|
+
subtitle: One rendered example of every block type the renderer supports.
|
|
4
|
+
tag: DEMO · v1
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
## Welcome
|
|
8
|
+
|
|
9
|
+
Each section renders one block type from a typed YAML fence in this file.
|
|
10
|
+
Copy a fence into your own doc as a starting point.
|
|
11
|
+
|
|
12
|
+
```callout
|
|
13
|
+
tone: tip
|
|
14
|
+
title: Source of truth
|
|
15
|
+
body: Every diagram on this page comes from a YAML block. There is no
|
|
16
|
+
hand-written HTML or SVG — change the YAML to change the picture.
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
```prose
|
|
20
|
+
title: Structured prose
|
|
21
|
+
lede: "Use the prose block when prose must travel inside a structured layout: headings, paragraphs, lists, and quotes become typed data."
|
|
22
|
+
blocks:
|
|
23
|
+
- { type: h, text: Why structured prose }
|
|
24
|
+
- { type: p, text: It plays nicely with the section-head wrapper and keeps content uniform across docs. }
|
|
25
|
+
- { type: ul, items: [Predictable spacing, Consistent fonts, Easier diffs] }
|
|
26
|
+
- { type: quote, text: A document degrades gracefully — opens in any editor with no tooling. }
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
```glossary
|
|
30
|
+
title: A few terms
|
|
31
|
+
terms:
|
|
32
|
+
- { term: Idempotent, def: A call that produces the same outcome on a replay. }
|
|
33
|
+
- { term: SLO, def: A service-level objective the team commits to., avoid: [uptime target, service promise] }
|
|
34
|
+
- { term: Saga, def: A long-running transaction split across services. }
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```proscons
|
|
38
|
+
title: Sync vs async writes
|
|
39
|
+
prosLabel: Synchronous
|
|
40
|
+
consLabel: Asynchronous
|
|
41
|
+
pros:
|
|
42
|
+
- One transaction, easy to reason about
|
|
43
|
+
- Errors surface at call time
|
|
44
|
+
- Latency budget is predictable
|
|
45
|
+
cons:
|
|
46
|
+
- Caller waits for downstream
|
|
47
|
+
- Failure mode is "everything stops"
|
|
48
|
+
- Hard to scale horizontally
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
```cvt
|
|
52
|
+
title: Migration plan
|
|
53
|
+
current:
|
|
54
|
+
label: Today (monolith)
|
|
55
|
+
items: [Single deployable, Shared Postgres, Manual releases]
|
|
56
|
+
target:
|
|
57
|
+
label: Target (services)
|
|
58
|
+
items: [Per-service deploys, Per-service stores, Continuous releases]
|
|
59
|
+
note: Migrate one service per quarter; freeze new monolith features.
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```stats
|
|
63
|
+
title: This quarter
|
|
64
|
+
stats:
|
|
65
|
+
- { value: 12.4k, label: Active users, delta: "+18%", trend: up }
|
|
66
|
+
- { value: 99.95%, label: Uptime, delta: "0", trend: flat }
|
|
67
|
+
- { value: 142ms, label: p95 latency, delta: "-22ms", trend: up }
|
|
68
|
+
- { value: $84k, label: MRR, delta: "+$6.1k", trend: up }
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
```code
|
|
72
|
+
title: Reference snippets
|
|
73
|
+
blocks:
|
|
74
|
+
- title: order-handler.ts
|
|
75
|
+
lang: TypeScript
|
|
76
|
+
code: |
|
|
77
|
+
export async function placeOrder(req: OrderRequest): Promise<Order> {
|
|
78
|
+
const order = await db.tx(async (t) => {
|
|
79
|
+
const inserted = await t.orders.insert({ ...req, status: 'PENDING' });
|
|
80
|
+
await payments.authorize(inserted.id, req.token);
|
|
81
|
+
return t.orders.update(inserted.id, { status: 'CONFIRMED' });
|
|
82
|
+
});
|
|
83
|
+
return order;
|
|
84
|
+
}
|
|
85
|
+
- title: schema.sql
|
|
86
|
+
lang: PostgreSQL
|
|
87
|
+
code: |
|
|
88
|
+
CREATE TABLE orders (
|
|
89
|
+
id uuid PRIMARY KEY,
|
|
90
|
+
user_id uuid NOT NULL REFERENCES users(id),
|
|
91
|
+
amount_cents integer NOT NULL,
|
|
92
|
+
status text NOT NULL DEFAULT 'PENDING'
|
|
93
|
+
);
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
```agenda
|
|
97
|
+
title: Tuesday standup
|
|
98
|
+
items:
|
|
99
|
+
- { time: "09:00", duration: 5m, title: Round-robin, owner: Host }
|
|
100
|
+
- { time: "09:05", duration: 20m, title: Status updates, desc: Each team for 5 minutes }
|
|
101
|
+
- { time: "09:25", duration: 30m, title: Tech deep-dive, owner: API team, desc: Walk-through of the new orders service }
|
|
102
|
+
- { time: "09:55", duration: 5m, title: Action items + wrap }
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
```tree
|
|
106
|
+
title: Repo layout
|
|
107
|
+
nodes:
|
|
108
|
+
- { id: root, label: chiltepin }
|
|
109
|
+
- { id: packages, parent: root, label: packages }
|
|
110
|
+
- { id: core, parent: packages, label: 'chiltepin-core', note: pure model }
|
|
111
|
+
- { id: render, parent: packages, label: 'chiltepin-render', note: HTML out }
|
|
112
|
+
- { id: studio, parent: packages, label: 'chiltepin-studio', note: visual editor }
|
|
113
|
+
- { id: cli, parent: packages, label: 'chiltepin', note: chiltepin binary }
|
|
114
|
+
- { id: resources, parent: root, label: resources, note: fixtures + reference renderer }
|
|
115
|
+
- { id: docs, parent: root, label: docs, note: the documents }
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
```pyramid
|
|
119
|
+
title: Engineering priorities
|
|
120
|
+
levels:
|
|
121
|
+
- { label: Vision, desc: Documentation as a navigable typed model }
|
|
122
|
+
- { label: Strategy, desc: Files on disk are the source of truth }
|
|
123
|
+
- { label: This quarter, desc: "107 blocks, one look, agent skill" }
|
|
124
|
+
- { label: This week, desc: Phase 2 blocks shipped }
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
```flow
|
|
128
|
+
title: Decision flow
|
|
129
|
+
description: The flow decides whether to accept a payment; the error path ends in a rejection. An invalid token never reaches the charge step.
|
|
130
|
+
nodes:
|
|
131
|
+
- { id: start, col: 1, row: 1, kind: start, label: Start }
|
|
132
|
+
- { id: check, col: 2, row: 1, kind: decision, label: Token valid? }
|
|
133
|
+
- { id: charge, col: 3, row: 1, kind: process, label: Charge card }
|
|
134
|
+
- { id: reject, col: 2, row: 2, kind: end, label: Reject }
|
|
135
|
+
- { id: done, col: 3, row: 2, kind: end, label: Done }
|
|
136
|
+
edges:
|
|
137
|
+
- start -> check
|
|
138
|
+
- check -> charge: "yes"
|
|
139
|
+
- check -x-> reject: "no"
|
|
140
|
+
- charge -> done
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
```state
|
|
144
|
+
title: Order lifecycle
|
|
145
|
+
description: PENDING is the only state visible inside the txn; CONFIRMED is the only post-commit state.
|
|
146
|
+
states:
|
|
147
|
+
- { id: s0, col: 1, row: 1, kind: start }
|
|
148
|
+
- { id: pending, col: 2, row: 1, kind: wait, name: PENDING }
|
|
149
|
+
- { id: confirmed, col: 3, row: 1, kind: active, name: CONFIRMED }
|
|
150
|
+
- { id: cancelled, col: 3, row: 2, kind: wait, name: CANCELLED }
|
|
151
|
+
- { id: end, col: 4, row: 1, kind: terminal }
|
|
152
|
+
transitions:
|
|
153
|
+
- { from: s0, to: pending, event: create }
|
|
154
|
+
- { from: pending, to: confirmed, event: authorize_ok }
|
|
155
|
+
- { from: pending, to: cancelled, event: authorize_fail }
|
|
156
|
+
- { from: confirmed, to: end, event: ship }
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
```dfd
|
|
160
|
+
title: Order placement data flow
|
|
161
|
+
nodes:
|
|
162
|
+
- { id: client, col: 1, row: 1, kind: external, name: Client }
|
|
163
|
+
- { id: orders, col: 2, row: 1, kind: process, name: Place order, num: 1 }
|
|
164
|
+
- { id: pay, col: 3, row: 1, kind: external, name: Payment GW }
|
|
165
|
+
- { id: db, col: 2, row: 2, kind: store, name: orders }
|
|
166
|
+
edges:
|
|
167
|
+
- { from: client, to: orders, label: POST /orders }
|
|
168
|
+
- { from: orders, to: pay, label: authorize }
|
|
169
|
+
- { from: orders, to: db, label: INSERT }
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
```journey
|
|
173
|
+
title: Onboarding journey
|
|
174
|
+
stages:
|
|
175
|
+
- { label: Discover }
|
|
176
|
+
- { label: Sign up }
|
|
177
|
+
- { label: Activate }
|
|
178
|
+
- { label: Pay }
|
|
179
|
+
rows:
|
|
180
|
+
- { label: Touchpoint, cells: [Landing, Form, Email, Checkout] }
|
|
181
|
+
- { label: Time, cells: [30s, 90s, 24h, 60s] }
|
|
182
|
+
- { label: Friction, cells: [Low, Medium, Low, Medium] }
|
|
183
|
+
emotion: [0.75, 0.40, 0.60, 0.85]
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
```gantt
|
|
187
|
+
title: Quarterly plan
|
|
188
|
+
periods: [Q1, Q2, Q3, Q4]
|
|
189
|
+
tasks:
|
|
190
|
+
- { label: Discovery, start: 0, span: 1, kind: done }
|
|
191
|
+
- { label: Core build, start: 1, span: 2, kind: active }
|
|
192
|
+
- { label: Beta, start: 2, span: 1 }
|
|
193
|
+
- { label: GA, start: 3, span: 1, kind: milestone }
|
|
194
|
+
- { label: Support hand-off, start: 3, span: 1 }
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
```graph
|
|
198
|
+
title: Service dependency graph
|
|
199
|
+
nodes:
|
|
200
|
+
- { id: web, col: 1, row: 1, label: web, group: 0 }
|
|
201
|
+
- { id: api, col: 2, row: 1, label: api, group: 1 }
|
|
202
|
+
- { id: pay, col: 3, row: 1, label: payment, group: 2 }
|
|
203
|
+
- { id: db, col: 2, row: 2, label: postgres, group: 3 }
|
|
204
|
+
- { id: cache, col: 1, row: 2, label: redis, group: 4 }
|
|
205
|
+
edges:
|
|
206
|
+
- web -> api
|
|
207
|
+
- api -> pay
|
|
208
|
+
- api -> db
|
|
209
|
+
- { from: api, to: cache, dir: undirected }
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
```quadrant
|
|
213
|
+
title: Effort vs impact
|
|
214
|
+
description: The skill ships first — the most impact for the least effort. Quick wins sit top-left, big bets top-right.
|
|
215
|
+
xAxis: { label: Effort, low: Low, high: High }
|
|
216
|
+
yAxis: { label: Impact, low: Low, high: High }
|
|
217
|
+
items:
|
|
218
|
+
- { x: 0.18, y: 0.82, label: Ship the skill }
|
|
219
|
+
- { x: 0.80, y: 0.90, label: MCP server }
|
|
220
|
+
- { x: 0.22, y: 0.30, label: README polish }
|
|
221
|
+
- { x: 0.75, y: 0.22, label: VS Code ext }
|
|
222
|
+
- { x: 0.55, y: 0.65, label: Hosted preview }
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
```swimlane
|
|
226
|
+
title: Cross-functional handoff
|
|
227
|
+
lanes: [Customer, Sales, Engineering, Ops]
|
|
228
|
+
phases:
|
|
229
|
+
- { label: Intake, from: 1, to: 2 }
|
|
230
|
+
- { label: Build, from: 3, to: 4 }
|
|
231
|
+
- { label: Ship, from: 5 }
|
|
232
|
+
steps:
|
|
233
|
+
- req: Submit request · Customer · start
|
|
234
|
+
- triage: Qualify? · Sales · decision
|
|
235
|
+
- scope: Scope work · Engineering
|
|
236
|
+
- build: Build · Engineering
|
|
237
|
+
- { id: deploy, lane: Ops, label: Deploy, note: blue/green, accent: true }
|
|
238
|
+
- done: Receive · Customer · end
|
|
239
|
+
links:
|
|
240
|
+
- req -> triage
|
|
241
|
+
- triage -> scope: approved
|
|
242
|
+
- scope -> build
|
|
243
|
+
- build -> deploy
|
|
244
|
+
- deploy --> done: notified
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
```gitgraph
|
|
248
|
+
title: Release model
|
|
249
|
+
description: "Release branches are short-lived: cut, ship, merge back."
|
|
250
|
+
branches:
|
|
251
|
+
- { name: main, accent: navy }
|
|
252
|
+
- { name: release, accent: teal }
|
|
253
|
+
commits:
|
|
254
|
+
- { label: baseline }
|
|
255
|
+
- { label: feature A }
|
|
256
|
+
- { branch: release, label: cut 1.2 }
|
|
257
|
+
- { merge: release, label: ship, tag: v1.2.0, kind: release }
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
```c4
|
|
262
|
+
title: System context
|
|
263
|
+
description: Who uses ShopCo and which external systems it depends on.
|
|
264
|
+
level: container
|
|
265
|
+
boundary: { label: ShopCo platform }
|
|
266
|
+
nodes:
|
|
267
|
+
- { id: shopper, col: 1, row: 1, kind: person, name: Shopper, desc: A customer placing an order from web or mobile. }
|
|
268
|
+
- { id: web, col: 2, row: 1, kind: container, family: client, name: Web app, tech: Next.js, desc: Server-rendered React. }
|
|
269
|
+
- { id: api, col: 3, row: 1, kind: container, family: service, name: Orders API, tech: Go, desc: "Authorises, persists, emits events." }
|
|
270
|
+
- { id: pg, col: 3, row: 2, kind: store, name: Orders DB, tech: Postgres 16, desc: Single source of truth for orders. }
|
|
271
|
+
- { id: pay, col: 4, row: 1, kind: external, name: Payment GW, desc: Stripe authorisation. }
|
|
272
|
+
edges:
|
|
273
|
+
- { from: shopper, to: web, label: places order }
|
|
274
|
+
- { from: web, to: api, label: POST /orders }
|
|
275
|
+
- { from: api, to: pg, label: writes }
|
|
276
|
+
- { from: api, to: pay, label: authorises }
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
```uml
|
|
280
|
+
title: Domain classes
|
|
281
|
+
description: Order owns its items by composition — an OrderItem cannot outlive its Order.
|
|
282
|
+
classes:
|
|
283
|
+
- id: order
|
|
284
|
+
col: 1
|
|
285
|
+
row: 1
|
|
286
|
+
name: Order
|
|
287
|
+
attrs: ["id: UUID", "status: Status", "total: Money", "items: OrderItem[]"]
|
|
288
|
+
methods: ["place()", "confirm()", "cancel()"]
|
|
289
|
+
- id: item
|
|
290
|
+
col: 2
|
|
291
|
+
row: 1
|
|
292
|
+
name: OrderItem
|
|
293
|
+
attrs: ["id: UUID", "sku: String", "qty: int", "price: Money"]
|
|
294
|
+
- id: status
|
|
295
|
+
col: 1
|
|
296
|
+
row: 2
|
|
297
|
+
name: Status
|
|
298
|
+
stereotype: enumeration
|
|
299
|
+
attrs: ["PENDING", "CONFIRMED", "CANCELLED"]
|
|
300
|
+
- id: shopper
|
|
301
|
+
col: 2
|
|
302
|
+
row: 2
|
|
303
|
+
name: Shopper
|
|
304
|
+
attrs: ["id: UUID", "email: String"]
|
|
305
|
+
rels:
|
|
306
|
+
- { from: order, to: item, kind: composition, label: contains }
|
|
307
|
+
- { from: order, to: status, kind: association, label: has }
|
|
308
|
+
- { from: shopper, to: order, kind: association, label: places }
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
```tree
|
|
312
|
+
variant: issue
|
|
313
|
+
title: Why are conversions down?
|
|
314
|
+
description: A MECE breakdown of plausible causes. Each leaf is a claim we can test before spending on a fix.
|
|
315
|
+
nodes:
|
|
316
|
+
- { id: root, label: Lower conversion this quarter }
|
|
317
|
+
- { id: traffic, parent: root, label: Traffic quality }
|
|
318
|
+
- { id: friction, parent: root, label: Funnel friction }
|
|
319
|
+
- { id: pricing, parent: root, label: Pricing / offer }
|
|
320
|
+
- { id: t1, parent: traffic, label: Wrong audience }
|
|
321
|
+
- { id: t2, parent: traffic, label: Ad fatigue, note: paid creative is stale }
|
|
322
|
+
- { id: f1, parent: friction, label: Slow checkout, note: p95 over 4s on mobile }
|
|
323
|
+
- { id: f2, parent: friction, label: Mobile bugs }
|
|
324
|
+
- { id: f3, parent: friction, label: Required signup }
|
|
325
|
+
- { id: p1, parent: pricing, label: Competitor undercut }
|
|
326
|
+
- { id: p2, parent: pricing, label: Shipping fee surprise }
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
```tree
|
|
330
|
+
variant: org
|
|
331
|
+
title: Platform group
|
|
332
|
+
description: "The same tree block as an org chart: parents center over their children, role under the name."
|
|
333
|
+
nodes:
|
|
334
|
+
- { id: dana, label: Dana Reyes, role: VP Engineering }
|
|
335
|
+
- { id: sam, parent: dana, label: Sam Ortiz, role: "Manager, Core" }
|
|
336
|
+
- { id: kim, parent: dana, label: Kim Lau, role: "Manager, Infra" }
|
|
337
|
+
- { id: ada, parent: sam, label: Ada Boone, role: Frontend lead }
|
|
338
|
+
- { id: raj, parent: sam, label: Raj Patel, role: Backend lead }
|
|
339
|
+
- { id: mei, parent: kim, label: Mei Tanaka, role: SRE lead }
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
```frontend
|
|
343
|
+
title: React component tree
|
|
344
|
+
description: "In the orders app, state lives in two places only: the cart store and the useOrders hook."
|
|
345
|
+
nodes:
|
|
346
|
+
- { id: app, kind: root, name: App }
|
|
347
|
+
- { id: auth, parent: app, kind: provider, name: AuthProvider }
|
|
348
|
+
- { id: theme, parent: app, kind: provider, name: ThemeProvider }
|
|
349
|
+
- { id: layout, parent: auth, kind: layout, name: AppLayout }
|
|
350
|
+
- { id: home, parent: layout, kind: page, name: Home }
|
|
351
|
+
- { id: orders, parent: layout, kind: page, name: OrdersPage }
|
|
352
|
+
- { id: list, parent: orders, kind: component, name: OrderList }
|
|
353
|
+
- { id: card, parent: list, kind: component, name: OrderCard }
|
|
354
|
+
- { id: badge, parent: card, kind: leaf, name: StatusBadge }
|
|
355
|
+
- { id: hook, parent: orders, kind: hook, name: useOrders }
|
|
356
|
+
- { id: cart, parent: app, kind: store, name: cartStore, note: Zustand }
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
```cluster
|
|
360
|
+
title: Production cluster
|
|
361
|
+
description: Two namespaces (api and data) with replicas; cross-namespace edges run from the API services to their backing stores. Only the orders service touches all three stores — it is the blast radius to watch.
|
|
362
|
+
clusters:
|
|
363
|
+
- { id: api, label: api namespace, kind: namespace }
|
|
364
|
+
- { id: data, label: data namespace, kind: namespace }
|
|
365
|
+
services:
|
|
366
|
+
- { id: web, cluster: api, label: web, kind: service, tech: Next.js, replicas: 3 }
|
|
367
|
+
- { id: orders, cluster: api, label: orders, kind: service, tech: Go 1.22, replicas: 4 }
|
|
368
|
+
- { id: payments, cluster: api, label: payments, kind: service, tech: Node 20, replicas: 2 }
|
|
369
|
+
- { id: pg, cluster: data, label: postgres, kind: store, tech: Postgres 16, replicas: 1 }
|
|
370
|
+
- { id: redis, cluster: data, label: redis, kind: cache, tech: Redis 7, replicas: 2 }
|
|
371
|
+
- { id: bus, cluster: data, label: events, kind: queue, tech: NATS, replicas: 3 }
|
|
372
|
+
edges:
|
|
373
|
+
- { from: web, to: orders }
|
|
374
|
+
- { from: orders, to: pg }
|
|
375
|
+
- { from: orders, to: redis }
|
|
376
|
+
- { from: orders, to: bus, kind: dashed }
|
|
377
|
+
- { from: payments, to: pg }
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
```block
|
|
381
|
+
title: Layered architecture
|
|
382
|
+
description: "Clients call the gateway, which fans out to the microservices, each backed by the data layer. The gateway is the single entry point: cross-cutting concerns live there, not in each service."
|
|
383
|
+
systemLabel: E-COMMERCE PLATFORM
|
|
384
|
+
layers:
|
|
385
|
+
- { label: Client layer }
|
|
386
|
+
- { label: API gateway }
|
|
387
|
+
- { label: Microservices }
|
|
388
|
+
- { label: Data layer }
|
|
389
|
+
nodes:
|
|
390
|
+
- { id: web, layer: 0, kind: client, name: Web app, tech: React }
|
|
391
|
+
- { id: mob, layer: 0, kind: client, name: Mobile, tech: iOS / Android }
|
|
392
|
+
- { id: gw, layer: 1, kind: gateway, name: API Gateway, tech: Kong }
|
|
393
|
+
- { id: orders, layer: 2, kind: microservice, name: Orders, tech: Go }
|
|
394
|
+
- { id: catalog, layer: 2, kind: microservice, name: Catalog, tech: Node }
|
|
395
|
+
- { id: payments, layer: 2, kind: microservice, name: Payments, tech: Java }
|
|
396
|
+
- { id: ordersdb, layer: 3, kind: db, name: Orders DB, tech: Postgres }
|
|
397
|
+
- { id: catalogdb, layer: 3, kind: db, name: Catalog DB, tech: MongoDB }
|
|
398
|
+
- { id: cache, layer: 3, kind: cache, name: Cache, tech: Redis }
|
|
399
|
+
edges:
|
|
400
|
+
- web -> gw
|
|
401
|
+
- mob -> gw
|
|
402
|
+
- gw -> orders
|
|
403
|
+
- gw -> catalog
|
|
404
|
+
- gw -> payments
|
|
405
|
+
- orders -> ordersdb
|
|
406
|
+
- catalog -> catalogdb
|
|
407
|
+
- catalog --> cache
|
|
408
|
+
- payments -> ordersdb
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
```block
|
|
412
|
+
preset: infra
|
|
413
|
+
title: Cloud deployment
|
|
414
|
+
description: "Edge → gateway → containers, backed by a database, object storage, a cache, and a queue worker. Two nested groups mark the cloud account and the private network inside it. The queue decouples the API from the worker: a slow job never blocks a request."
|
|
415
|
+
groups:
|
|
416
|
+
- { id: cloud, label: Cloud account, col: 1, row: 1, cols: 4, rows: 2, color: "#374151" }
|
|
417
|
+
- { id: net, label: Private network, col: 2, row: 1, cols: 3, rows: 2, color: "#0e54a1" }
|
|
418
|
+
nodes:
|
|
419
|
+
- { id: cdn, col: 1, row: 1, kind: cdn, name: CDN, tech: edge cache }
|
|
420
|
+
- { id: gw, col: 2, row: 1, kind: gateway, name: API Gateway, tech: load balancer }
|
|
421
|
+
- { id: svc, col: 3, row: 1, kind: compute, name: API, tech: containers }
|
|
422
|
+
- { id: db, col: 4, row: 1, kind: db, name: Database, tech: managed SQL }
|
|
423
|
+
- { id: bucket, col: 4, row: 2, kind: bucket, name: Object storage, tech: blobs / files }
|
|
424
|
+
- { id: cache, col: 3, row: 2, kind: cache, name: Cache, tech: in-memory }
|
|
425
|
+
- { id: q, col: 2, row: 2, kind: queue, name: Queue, tech: messages }
|
|
426
|
+
- { id: wk, col: 1, row: 2, kind: function, name: Worker, tech: async jobs }
|
|
427
|
+
edges:
|
|
428
|
+
- cdn -> gw: HTTPS
|
|
429
|
+
- gw -> svc: routes
|
|
430
|
+
- svc -> db: SQL
|
|
431
|
+
- svc --> bucket: reads
|
|
432
|
+
- svc --> cache: cache
|
|
433
|
+
- svc --> q: publish
|
|
434
|
+
- q --> wk: consume
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
```block
|
|
438
|
+
preset: event
|
|
439
|
+
title: Order events
|
|
440
|
+
description: Producers publish to topics and consumers subscribe. Producers never know their consumers — Analytics subscribed without a change to the Orders API.
|
|
441
|
+
nodes:
|
|
442
|
+
- { id: api, col: 1, row: 1, kind: producer, name: Orders API, tech: publishes }
|
|
443
|
+
- { id: pays, col: 1, row: 2, kind: producer, name: Payments, tech: publishes }
|
|
444
|
+
- { id: t1, col: 2, row: 1, kind: topic, name: order.created, tech: topic }
|
|
445
|
+
- { id: t2, col: 2, row: 2, kind: topic, name: payment.captured, tech: topic }
|
|
446
|
+
- { id: email, col: 3, row: 1, kind: consumer, name: Email worker, tech: subscribes }
|
|
447
|
+
- { id: ship, col: 3, row: 2, kind: consumer, name: Fulfilment, tech: subscribes }
|
|
448
|
+
- { id: an, col: 3, row: 3, kind: consumer, name: Analytics, tech: subscribes }
|
|
449
|
+
edges:
|
|
450
|
+
- api -> t1: publish
|
|
451
|
+
- pays -> t2: publish
|
|
452
|
+
- t1 --> email
|
|
453
|
+
- t1 --> ship
|
|
454
|
+
- t1 --> an
|
|
455
|
+
- t2 --> ship
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
```block
|
|
459
|
+
preset: ddd
|
|
460
|
+
title: Context map
|
|
461
|
+
description: "Sales is upstream of Billing and Shipping: its model changes ripple downstream, never the reverse."
|
|
462
|
+
nodes:
|
|
463
|
+
- { id: sales, col: 1, row: 1, kind: context, name: Sales, tech: core }
|
|
464
|
+
- { id: billing, col: 2, row: 1, kind: context, name: Billing, tech: supporting }
|
|
465
|
+
- { id: ship, col: 2, row: 2, kind: context, name: Shipping, tech: supporting }
|
|
466
|
+
- { id: catalog, col: 1, row: 2, kind: context, name: Catalog, tech: generic }
|
|
467
|
+
edges:
|
|
468
|
+
- sales -> billing: U → D
|
|
469
|
+
- sales -> ship: U → D · ACL
|
|
470
|
+
- catalog --> sales: shared kernel
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
```block
|
|
474
|
+
preset: network
|
|
475
|
+
title: Network zones
|
|
476
|
+
description: Trust boundaries run from edge to data. The load balancer must never reach the database directly — the red "no direct" edge marks the forbidden connection and makes the rule reviewable.
|
|
477
|
+
groups:
|
|
478
|
+
- { id: z1, label: DMZ, col: 1, row: 1, cols: 1, rows: 2, color: "#f7952c" }
|
|
479
|
+
- { id: z2, label: Private subnet, col: 2, row: 1, cols: 1, rows: 2, color: "#0e54a1" }
|
|
480
|
+
- { id: z3, label: Data subnet, col: 3, row: 1, cols: 1, rows: 2, color: "#991b1b" }
|
|
481
|
+
nodes:
|
|
482
|
+
- { id: lb, col: 1, row: 1, kind: gateway, name: Load balancer, tech: public }
|
|
483
|
+
- { id: waf, col: 1, row: 2, kind: firewall, name: Firewall, tech: WAF }
|
|
484
|
+
- { id: web, col: 2, row: 1, kind: compute, name: App servers, tech: private }
|
|
485
|
+
- { id: cache, col: 2, row: 2, kind: cache, name: Cache, tech: private }
|
|
486
|
+
- { id: db, col: 3, row: 1, kind: db, name: Database, tech: restricted }
|
|
487
|
+
edges:
|
|
488
|
+
- lb -> waf: filter
|
|
489
|
+
- waf -> web: "443"
|
|
490
|
+
- web -> cache: "6379"
|
|
491
|
+
- web -> db: "5432"
|
|
492
|
+
- { from: lb, to: db, label: no direct, kind: forbidden }
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
```felogic
|
|
496
|
+
title: Frontend logic — strategy + engine
|
|
497
|
+
description: The checkout UI drives a pricing engine that selects a DiscountStrategy implementation; the API client egresses over HTTPS to the backend. Discount rules hide behind one interface — a new promotion is a new strategy class, not an engine change.
|
|
498
|
+
groups:
|
|
499
|
+
- { id: app, label: App (browser), col: 1, row: 1, cols: 3, rows: 3, color: "#0e54a1" }
|
|
500
|
+
- { id: net, label: Egress · network, col: 4, row: 1, cols: 1, rows: 1, color: "#6b7280" }
|
|
501
|
+
nodes:
|
|
502
|
+
- { id: ui, col: 1, row: 1, kind: component, name: Checkout UI, note: renders form }
|
|
503
|
+
- { id: engine, col: 2, row: 1, kind: engine, name: PricingEngine, note: computes total }
|
|
504
|
+
- { id: api, col: 3, row: 1, kind: service, name: ApiClient, note: fetch wrapper }
|
|
505
|
+
- { id: backend, col: 4, row: 1, kind: external, name: Orders API, note: REST /orders }
|
|
506
|
+
- { id: cart, col: 1, row: 2, kind: hook, name: useCart(), note: state }
|
|
507
|
+
- { id: iface, col: 2, row: 2, kind: interface, name: DiscountStrategy, note: calculate() }
|
|
508
|
+
- { id: s1, col: 1, row: 3, kind: strategy, name: PercentOff, note: "% off" }
|
|
509
|
+
- { id: s2, col: 2, row: 3, kind: strategy, name: BuyXGetY, note: bundle }
|
|
510
|
+
- { id: s3, col: 3, row: 3, kind: strategy, name: NoDiscount, note: default }
|
|
511
|
+
edges:
|
|
512
|
+
- { from: ui, to: engine, label: uses, kind: uses }
|
|
513
|
+
- { from: ui, to: cart, label: reads, kind: reads }
|
|
514
|
+
- { from: engine, to: iface, label: selects, kind: uses }
|
|
515
|
+
- { from: s1, to: iface, kind: implements }
|
|
516
|
+
- { from: s2, to: iface, kind: implements }
|
|
517
|
+
- { from: s3, to: iface, kind: implements }
|
|
518
|
+
- { from: engine, to: api, label: calls, kind: uses }
|
|
519
|
+
- { from: api, to: backend, label: HTTPS, kind: egress }
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
```felogic
|
|
523
|
+
variant: be
|
|
524
|
+
title: Backend logic — gateway + repository
|
|
525
|
+
description: The controller calls OrderService, which loads through OrderRepository and charges through the PaymentGateway interface (Stripe and Adyen adapters). Writes go to Postgres, the event bus, and the external gateways. One interface per provider, so a Stripe outage is a config change.
|
|
526
|
+
groups:
|
|
527
|
+
- { id: svc, label: Service boundary, col: 1, row: 1, cols: 3, rows: 3, color: "#0e54a1" }
|
|
528
|
+
- { id: infra, label: Infrastructure · egress, col: 4, row: 1, cols: 1, rows: 3, color: "#6b7280" }
|
|
529
|
+
nodes:
|
|
530
|
+
- { id: ctrl, col: 1, row: 1, kind: controller, name: OrdersController, note: HTTP /orders }
|
|
531
|
+
- { id: service, col: 2, row: 1, kind: service, name: OrderService, note: use case }
|
|
532
|
+
- { id: stripe, col: 3, row: 1, kind: adapter, name: StripeAdapter, note: implements }
|
|
533
|
+
- { id: queue, col: 4, row: 1, kind: queue, name: EventBus, note: order.created }
|
|
534
|
+
- { id: repo, col: 1, row: 2, kind: repository, name: OrderRepository, note: data access }
|
|
535
|
+
- { id: iface, col: 2, row: 2, kind: interface, name: PaymentGateway, note: charge() }
|
|
536
|
+
- { id: adyen, col: 3, row: 2, kind: adapter, name: AdyenAdapter, note: implements }
|
|
537
|
+
- { id: db, col: 4, row: 2, kind: db, name: postgres, note: orders table }
|
|
538
|
+
- { id: model, col: 1, row: 3, kind: model, name: Order, note: entity }
|
|
539
|
+
- { id: ext1, col: 4, row: 3, kind: external, name: Stripe API, note: HTTPS }
|
|
540
|
+
edges:
|
|
541
|
+
- { from: ctrl, to: service, label: handles, kind: uses }
|
|
542
|
+
- { from: service, to: repo, label: loads, kind: uses }
|
|
543
|
+
- { from: repo, to: model, label: reads, kind: reads }
|
|
544
|
+
- { from: repo, to: db, label: SQL, kind: egress }
|
|
545
|
+
- { from: service, to: iface, label: charges, kind: uses }
|
|
546
|
+
- { from: stripe, to: iface, kind: implements }
|
|
547
|
+
- { from: adyen, to: iface, kind: implements }
|
|
548
|
+
- { from: stripe, to: ext1, label: HTTPS, kind: egress }
|
|
549
|
+
- { from: service, to: queue, label: publishes, kind: uses }
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
```flow
|
|
553
|
+
variant: dag
|
|
554
|
+
title: Build pipeline
|
|
555
|
+
description: "Lint and unit tests run in parallel; both gate the build. The w: 2 span lets Deploy cover two columns."
|
|
556
|
+
nodes:
|
|
557
|
+
- { id: src, col: 1, row: 1, kind: start, label: Checkout }
|
|
558
|
+
- { id: lint, col: 2, row: 1, kind: process, label: Lint }
|
|
559
|
+
- { id: test, col: 2, row: 2, kind: process, label: Unit tests }
|
|
560
|
+
- { id: build, col: 3, row: 1, kind: process, label: Build }
|
|
561
|
+
- { id: deploy, col: 4, row: 1, w: 2, kind: end, label: Deploy }
|
|
562
|
+
edges:
|
|
563
|
+
- src -> lint
|
|
564
|
+
- src -> test
|
|
565
|
+
- lint -> build
|
|
566
|
+
- test -> build
|
|
567
|
+
- build -> deploy
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
## Saga
|
|
571
|
+
|
|
572
|
+
Each service owns its own database, so no single transaction covers an order.
|
|
573
|
+
The order service issues every compensation itself, and a customer can see the
|
|
574
|
+
stock reservation before the refund lands.
|
|
575
|
+
|
|
576
|
+
```saga
|
|
577
|
+
title: Place order
|
|
578
|
+
mode: orchestration
|
|
579
|
+
coordinator: Order service
|
|
580
|
+
steps:
|
|
581
|
+
- reserve: Reserve stock · inventory · release stock
|
|
582
|
+
- coupon: Redeem coupon · promotions · restore coupon
|
|
583
|
+
- charge: Charge card · payments · refund card
|
|
584
|
+
- ship: Book shipment · shipping · cancel shipment
|
|
585
|
+
- notify: Send confirmation · notifications
|
|
586
|
+
failAt: ship
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
## Incident loop
|
|
590
|
+
|
|
591
|
+
Every incident feeds the next one: the review only closes when a guardrail
|
|
592
|
+
lands in code. A loop that ends at the write-up is the one that repeats.
|
|
593
|
+
|
|
594
|
+
```cycle
|
|
595
|
+
title: How an incident closes
|
|
596
|
+
steps:
|
|
597
|
+
- { label: Detect, desc: An SLO burn alert pages the on-call engineer }
|
|
598
|
+
- { label: Mitigate, desc: "Stop the bleeding first — roll back or shed load" }
|
|
599
|
+
- { label: Review, desc: Write the timeline while the details are fresh }
|
|
600
|
+
- { label: Guardrail, desc: "Ship the alert, test, or limit that catches it next time" }
|
|
601
|
+
center: every page
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
## Architecture map
|
|
605
|
+
|
|
606
|
+
```archmap
|
|
607
|
+
title: Retail platform — target architecture
|
|
608
|
+
description: The legacy ESB retires once the event bus carries its traffic.
|
|
609
|
+
cols: 3
|
|
610
|
+
areas:
|
|
611
|
+
- label: Customer channels
|
|
612
|
+
accent: blue
|
|
613
|
+
items:
|
|
614
|
+
- Web storefront
|
|
615
|
+
- { name: Mobile app, status: target }
|
|
616
|
+
- Contact centre
|
|
617
|
+
- label: Commerce
|
|
618
|
+
accent: teal
|
|
619
|
+
items:
|
|
620
|
+
- Catalog
|
|
621
|
+
- Checkout
|
|
622
|
+
- { name: Promotions, status: gap }
|
|
623
|
+
- { name: Subscriptions, status: new }
|
|
624
|
+
- label: Fulfilment
|
|
625
|
+
accent: green
|
|
626
|
+
items:
|
|
627
|
+
- Warehouse mgmt
|
|
628
|
+
- { name: Carrier gateway, status: target }
|
|
629
|
+
- label: Data & analytics
|
|
630
|
+
accent: amber
|
|
631
|
+
items:
|
|
632
|
+
- Reporting
|
|
633
|
+
- { name: Customer 360, status: target }
|
|
634
|
+
- { name: ML forecasting, status: gap }
|
|
635
|
+
- label: Platform services
|
|
636
|
+
accent: purple
|
|
637
|
+
desc: Shared capabilities every domain builds on.
|
|
638
|
+
items:
|
|
639
|
+
- Identity
|
|
640
|
+
- { name: Event bus, status: new }
|
|
641
|
+
- { name: Legacy ESB, status: deprecated }
|
|
642
|
+
- label: Integration
|
|
643
|
+
accent: navy
|
|
644
|
+
items:
|
|
645
|
+
- API gateway
|
|
646
|
+
- { name: Partner APIs, status: target }
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
## Table
|
|
650
|
+
|
|
651
|
+
```table
|
|
652
|
+
title: Plan comparison
|
|
653
|
+
columns:
|
|
654
|
+
- { label: Plan }
|
|
655
|
+
- { label: Price, align: r }
|
|
656
|
+
- { label: Seats, align: r, highlight: true }
|
|
657
|
+
rows:
|
|
658
|
+
- [ Free, "$0", "1" ]
|
|
659
|
+
- [ Pro, "$20", "10" ]
|
|
660
|
+
- [ Team, { v: "$80", tone: pos }, "50" ]
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
## Benchmark
|
|
664
|
+
|
|
665
|
+
```benchmark
|
|
666
|
+
title: Retrieval engines, measured
|
|
667
|
+
description: "The best number in each row is derived, not authored — `better: low` flips it for latency and cost."
|
|
668
|
+
metricLabel: Benchmark
|
|
669
|
+
subjects:
|
|
670
|
+
- { label: Ours, sub: v2.1, featured: true }
|
|
671
|
+
- { label: Vendor A }
|
|
672
|
+
- { label: Vendor B, tone: muted }
|
|
673
|
+
rows:
|
|
674
|
+
- { label: Answer accuracy, sub: internal QA set, cells: ["82.4%", "79.1%", "74.8%"] }
|
|
675
|
+
- { label: Citations correct, sub: 500 sampled answers, cells: ["91.0%", "88.2%", "83.4%"] }
|
|
676
|
+
- { label: p95 latency, sub: 500 rps soak, better: low, cells: ["310 ms", "420 ms", "290 ms"] }
|
|
677
|
+
- label: Cost per 1k queries
|
|
678
|
+
variants: [cached, cold]
|
|
679
|
+
better: low
|
|
680
|
+
cells:
|
|
681
|
+
- ["$0.14", "$0.90"]
|
|
682
|
+
- ["$0.21", "$1.10"]
|
|
683
|
+
- ["$0.18", "—"]
|
|
684
|
+
- { label: Index size, sub: 40M docs, better: none, cells: ["112 GB", "98 GB", "150 GB"] }
|
|
685
|
+
note: Single region, same corpus, October run. Vendor B declined the cold-cache test.
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
## Sequence
|
|
689
|
+
|
|
690
|
+
```sequence
|
|
691
|
+
id: sw-seq-checkout
|
|
692
|
+
title: Place order
|
|
693
|
+
endpoint: { method: POST, path: /orders }
|
|
694
|
+
actors:
|
|
695
|
+
- { id: client, name: Client }
|
|
696
|
+
- { id: api, name: Orders API }
|
|
697
|
+
- { id: db, name: Postgres, external: true }
|
|
698
|
+
messages:
|
|
699
|
+
- client -> api: POST /orders
|
|
700
|
+
- { from: api, to: db, label: INSERT order, kind: async }
|
|
701
|
+
- api --> client: 201 Created
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
## Trace waterfall
|
|
705
|
+
|
|
706
|
+
A trace holds one sampled request, not an average. A dependency that retries
|
|
707
|
+
only sometimes costs a real user the full time here, which a percentile chart
|
|
708
|
+
hides.
|
|
709
|
+
|
|
710
|
+
```spans
|
|
711
|
+
title: GET /orders/{id}
|
|
712
|
+
description: One sampled request, 2026-08-28. The payments call was retried once.
|
|
713
|
+
unit: ms
|
|
714
|
+
spans:
|
|
715
|
+
- { id: get, service: api, name: "GET /orders/{id}", start: 0, duration: 138, kind: server }
|
|
716
|
+
- api/auth: verify token · 3 · 9 · get
|
|
717
|
+
- db/orders: SELECT orders · 14 · 38 · get
|
|
718
|
+
- { id: cat, service: catalogue, name: "GET /skus", start: 55, duration: 62, parent: get, kind: client }
|
|
719
|
+
- { id: sku, service: cache, name: "GET sku:A1", start: 58, duration: 4, parent: cat, kind: cache }
|
|
720
|
+
- { id: pay, service: payments, name: "GET /payments/ord_123", start: 120, duration: 16, parent: get, kind: client, error: true, attrs: { http.status: 502 }, note: The first call returned 502 and the retry succeeded. }
|
|
721
|
+
```
|
|
722
|
+
|
|
723
|
+
## ERD
|
|
724
|
+
|
|
725
|
+
```erd
|
|
726
|
+
title: Shop schema
|
|
727
|
+
entities:
|
|
728
|
+
- name: users
|
|
729
|
+
columns:
|
|
730
|
+
- { name: id, type: uuid, pk: true }
|
|
731
|
+
- { name: email, type: text }
|
|
732
|
+
- name: orders
|
|
733
|
+
columns:
|
|
734
|
+
- { name: id, type: uuid, pk: true }
|
|
735
|
+
- { name: user_id, type: uuid, fk: true }
|
|
736
|
+
- { name: total, type: numeric }
|
|
737
|
+
relations:
|
|
738
|
+
- orders }o--|| users: placed by
|
|
739
|
+
```
|
|
740
|
+
|
|
741
|
+
## User story
|
|
742
|
+
|
|
743
|
+
```userstory
|
|
744
|
+
id: sw-us-1
|
|
745
|
+
role: shopper
|
|
746
|
+
want: pay in one step
|
|
747
|
+
soThat: I can check out quickly
|
|
748
|
+
priority: High
|
|
749
|
+
points: 3
|
|
750
|
+
criteria:
|
|
751
|
+
- { given: a saved card, when: I confirm, then: the order is placed }
|
|
752
|
+
links:
|
|
753
|
+
- { ref: '#sw-seq-checkout', label: Checkout flow }
|
|
754
|
+
```
|
|
755
|
+
|
|
756
|
+
## Timeline
|
|
757
|
+
|
|
758
|
+
```timeline
|
|
759
|
+
title: Roadmap
|
|
760
|
+
items:
|
|
761
|
+
- "[done] Q1 · MVP"
|
|
762
|
+
- "[current] Q2 · Beta"
|
|
763
|
+
- "[next] Q3 · GA"
|
|
764
|
+
```
|
|
765
|
+
|
|
766
|
+
## Kanban
|
|
767
|
+
|
|
768
|
+
```kanban
|
|
769
|
+
title: Sprint board
|
|
770
|
+
columns:
|
|
771
|
+
- { label: To do, cards: [ { title: Auth, tag: backend }, { title: Login UI } ] }
|
|
772
|
+
- { label: Doing, cards: [ { title: Checkout, tag: api } ] }
|
|
773
|
+
- { label: Done, cards: [ { title: DB schema } ] }
|
|
774
|
+
```
|
|
775
|
+
|
|
776
|
+
## Rollout
|
|
777
|
+
|
|
778
|
+
A gate compares the new version against the old one on the same traffic, not
|
|
779
|
+
against last week. A stage that fails its gate holds; nothing reverts until a
|
|
780
|
+
person or the rollback line says so.
|
|
781
|
+
|
|
782
|
+
```rollout
|
|
783
|
+
title: Orders API v2
|
|
784
|
+
strategy: canary
|
|
785
|
+
stages:
|
|
786
|
+
- "[done] 1% · Smoke · 15m — no 5xx"
|
|
787
|
+
- "[current] 10% · Canary · 30m — error rate < 0.5%"
|
|
788
|
+
- "[next] 50% · Half · 2h — p95 < 300 ms"
|
|
789
|
+
- { name: Full, traffic: 100, status: next, note: Delete the v1 deployment after 24 h. }
|
|
790
|
+
rollback: Flip the orders-v2 flag off; v1 keeps serving without a deploy.
|
|
791
|
+
```
|
|
792
|
+
|
|
793
|
+
## Story map
|
|
794
|
+
|
|
795
|
+
```storymap
|
|
796
|
+
title: Checkout story map
|
|
797
|
+
description: "The backbone of activities across the top; each release slice holds the cards that ship under each step."
|
|
798
|
+
backbone:
|
|
799
|
+
- { label: Browse, note: Find the product }
|
|
800
|
+
- { label: Decide, note: Trust the price }
|
|
801
|
+
- { label: Pay }
|
|
802
|
+
- { label: Confirm }
|
|
803
|
+
slices:
|
|
804
|
+
- label: MVP
|
|
805
|
+
cells:
|
|
806
|
+
- [Search box]
|
|
807
|
+
- ["Product page", "Price incl. tax"]
|
|
808
|
+
- [{ title: Card payment, tag: risky }]
|
|
809
|
+
- [Order email]
|
|
810
|
+
- label: Later
|
|
811
|
+
cells:
|
|
812
|
+
- ["Filters", "Saved carts"]
|
|
813
|
+
- [Reviews]
|
|
814
|
+
- [{ title: Wallet pay, tag: spike }]
|
|
815
|
+
- []
|
|
816
|
+
```
|
|
817
|
+
|
|
818
|
+
## Task tracker
|
|
819
|
+
|
|
820
|
+
```statustable
|
|
821
|
+
variant: tracker
|
|
822
|
+
title: Tasks
|
|
823
|
+
items:
|
|
824
|
+
- { task: Set up CI, status: done, priority: high, owner: Ana }
|
|
825
|
+
- { task: Payment flow, status: doing, priority: high, owner: Lee, due: Fri }
|
|
826
|
+
- { task: Write docs, status: todo, priority: med }
|
|
827
|
+
- { task: Rate limiting, status: blocked, priority: low }
|
|
828
|
+
```
|
|
829
|
+
|
|
830
|
+
## Status table
|
|
831
|
+
|
|
832
|
+
```statustable
|
|
833
|
+
title: Launch workstreams
|
|
834
|
+
description: Weekly status roll-up; statuses use our own vocabulary.
|
|
835
|
+
columns: [Workstream, Latest update]
|
|
836
|
+
statuses:
|
|
837
|
+
- { label: on track, color: green }
|
|
838
|
+
- { label: at risk, color: amber }
|
|
839
|
+
- { label: blocked, color: error }
|
|
840
|
+
- { label: in review, color: purple }
|
|
841
|
+
rows:
|
|
842
|
+
- { cells: [Checkout revamp, A/B test at 50%; conversion up 0.3pp], status: on track }
|
|
843
|
+
- cells: [Vendor SSO, Contract countersigned; sandbox creds due this week]
|
|
844
|
+
status: at risk
|
|
845
|
+
subtasks:
|
|
846
|
+
- { cells: [SAML metadata exchange, Our metadata sent Tuesday], status: on track }
|
|
847
|
+
- { cells: [Provisioning sync, Waiting on sandbox credentials], status: blocked }
|
|
848
|
+
- { cells: [Rate-limit rework, PR up for second review], status: in review }
|
|
849
|
+
- { cells: [Docs refresh, Draft complete], status: done }
|
|
850
|
+
```
|
|
851
|
+
|
|
852
|
+
## Risk register
|
|
853
|
+
|
|
854
|
+
```risk
|
|
855
|
+
title: Launch risks
|
|
856
|
+
description: Reviewed weekly until GA.
|
|
857
|
+
items:
|
|
858
|
+
- { risk: Key dependency ships late, likelihood: high, impact: high, mitigation: Feature-flag the integration and keep the old path., owner: PM, status: open }
|
|
859
|
+
- { risk: Traffic spike overwhelms the API, likelihood: med, impact: high, mitigation: Autoscaling + load-shedding at the gateway., owner: Platform, status: mitigating }
|
|
860
|
+
- { risk: Docs lag the release, likelihood: med, impact: low, status: accepted }
|
|
861
|
+
- { risk: Beta feedback arrives after freeze, likelihood: low, impact: low, mitigation: Weekly beta digest to the team., owner: DevRel, status: closed }
|
|
862
|
+
```
|
|
863
|
+
|
|
864
|
+
## Wireframe
|
|
865
|
+
|
|
866
|
+
```wireframe
|
|
867
|
+
title: Checkout screen
|
|
868
|
+
screens:
|
|
869
|
+
- device: phone
|
|
870
|
+
title: Checkout
|
|
871
|
+
elements:
|
|
872
|
+
- { type: header, label: Checkout }
|
|
873
|
+
- { type: input, label: Card number }
|
|
874
|
+
- { type: input, label: Expiry }
|
|
875
|
+
- { type: button, label: Pay now, tone: accent }
|
|
876
|
+
- { type: text, label: Secure payment, align: c, tone: muted }
|
|
877
|
+
```
|
|
878
|
+
|
|
879
|
+
## API endpoint
|
|
880
|
+
|
|
881
|
+
```endpoint
|
|
882
|
+
method: POST
|
|
883
|
+
path: /orders/{cartId}
|
|
884
|
+
title: Create an order
|
|
885
|
+
description: Convert a cart into an order and start fulfilment.
|
|
886
|
+
auth: Bearer <token>
|
|
887
|
+
params:
|
|
888
|
+
- { name: cartId, in: path, type: uuid, required: true, desc: Cart to convert }
|
|
889
|
+
- { name: dry-run, in: query, type: boolean, desc: Validate without persisting }
|
|
890
|
+
body:
|
|
891
|
+
- { name: items, type: "Item[]", required: true, desc: Line items }
|
|
892
|
+
- { name: coupon, type: string, desc: Optional discount code }
|
|
893
|
+
responses:
|
|
894
|
+
- { status: 201, desc: Order created }
|
|
895
|
+
- { status: 400, desc: Invalid cart }
|
|
896
|
+
- { status: 401, desc: Missing or invalid token }
|
|
897
|
+
request: |
|
|
898
|
+
{ "items": [{ "sku": "A1", "qty": 2 }], "coupon": "SAVE10" }
|
|
899
|
+
response: |
|
|
900
|
+
{ "id": "ord_123", "status": "pending", "total": 42.00 }
|
|
901
|
+
```
|
|
902
|
+
|
|
903
|
+
```packet
|
|
904
|
+
title: Wire format of the request header
|
|
905
|
+
width: 32
|
|
906
|
+
fields:
|
|
907
|
+
- { label: Version, bits: 4, value: "1" }
|
|
908
|
+
- { label: Flags, bits: 4 }
|
|
909
|
+
- { label: Total length, bits: 24 }
|
|
910
|
+
- { label: Request id, bits: 32, accent: teal }
|
|
911
|
+
```
|
|
912
|
+
|
|
913
|
+
## Event contract
|
|
914
|
+
|
|
915
|
+
Payments emits this event and never waits for a reply, so the endpoint contract
|
|
916
|
+
above does not apply to it. Delivery is at-least-once: a consumer that is not
|
|
917
|
+
idempotent will ship the same order twice.
|
|
918
|
+
|
|
919
|
+
```eventcontract
|
|
920
|
+
name: order.paid
|
|
921
|
+
version: v2
|
|
922
|
+
channel: orders
|
|
923
|
+
summary: Payment for an order was captured, so fulfilment may start.
|
|
924
|
+
producers: [payments]
|
|
925
|
+
consumers: [fulfilment, billing, analytics]
|
|
926
|
+
delivery: at-least-once
|
|
927
|
+
ordering: per-key
|
|
928
|
+
key: order_id
|
|
929
|
+
retention: 7d
|
|
930
|
+
schema:
|
|
931
|
+
- order_id uuid required — The order the payment belongs to
|
|
932
|
+
- payment_id uuid required — The capture in the payment provider
|
|
933
|
+
- amount money required — Captured amount, as a decimal string with currency
|
|
934
|
+
- method string required — One of card, wallet, or invoice
|
|
935
|
+
- captured_at timestamp required — When the provider confirmed the capture
|
|
936
|
+
headers:
|
|
937
|
+
- trace_id string required — W3C trace id of the checkout request
|
|
938
|
+
example: |
|
|
939
|
+
{ "order_id": "ord_123", "payment_id": "pay_77", "amount": "42.00 EUR", "method": "card" }
|
|
940
|
+
errors:
|
|
941
|
+
- DuplicateCapture — the same payment_id arrived twice; drop the event
|
|
942
|
+
note: Fulfilment must be idempotent on order_id.
|
|
943
|
+
```
|
|
944
|
+
|
|
945
|
+
## Pull quote
|
|
946
|
+
|
|
947
|
+
```pullquote
|
|
948
|
+
text: Site group = read at that plant. Role group = extra actions on top.
|
|
949
|
+
attribution: The taxonomy in one line
|
|
950
|
+
```
|
|
951
|
+
|
|
952
|
+
## Access in three layers
|
|
953
|
+
|
|
954
|
+
```layers
|
|
955
|
+
items:
|
|
956
|
+
- { kicker: L1, title: Identity, source: IdP JWT, question: "Are you a signed-in user?", body: Validate the token and resolve groups. }
|
|
957
|
+
- { kicker: L2, title: Site scope, source: JWT + lookup, question: "Which sites may you see?", body: Confirm the site is in the user's set. }
|
|
958
|
+
- { kicker: L3, title: Permission, source: App DB, question: "What may you do here?", body: Resolve persona permissions from the matrix. }
|
|
959
|
+
```
|
|
960
|
+
|
|
961
|
+
## Success callout
|
|
962
|
+
|
|
963
|
+
```callout
|
|
964
|
+
tone: success
|
|
965
|
+
title: Why this scales
|
|
966
|
+
body: Site and role are separate group types, so they grow on independent axes.
|
|
967
|
+
```
|
|
968
|
+
|
|
969
|
+
## Capability matrix
|
|
970
|
+
|
|
971
|
+
```matrix
|
|
972
|
+
title: Who can do what
|
|
973
|
+
corner: Role / App
|
|
974
|
+
cols: [Billing, Reports, Admin]
|
|
975
|
+
rows:
|
|
976
|
+
- { label: Owner, cells: [Full, Full, Full] }
|
|
977
|
+
- { label: Manager, cells: [Full, Read, "—"] }
|
|
978
|
+
- { label: Viewer, cells: [Read, Read, "—"] }
|
|
979
|
+
```
|
|
980
|
+
|
|
981
|
+
## Anatomy of a permission
|
|
982
|
+
|
|
983
|
+
```anatomy
|
|
984
|
+
separator: ":"
|
|
985
|
+
parts:
|
|
986
|
+
- { label: App, value: meridian, note: Which product. }
|
|
987
|
+
- { label: Feature, value: billing, note: The area within the app. }
|
|
988
|
+
- { label: Action, value: invoices.read, note: The specific capability. }
|
|
989
|
+
```
|
|
990
|
+
|
|
991
|
+
## Composition
|
|
992
|
+
|
|
993
|
+
```composition
|
|
994
|
+
title: How access is decided
|
|
995
|
+
result: May read invoices
|
|
996
|
+
gates:
|
|
997
|
+
- { label: Identity, desc: A valid signed-in user. }
|
|
998
|
+
- { label: Scope, desc: The request is in range. }
|
|
999
|
+
- { label: Permission, desc: The action is granted. }
|
|
1000
|
+
```
|
|
1001
|
+
|
|
1002
|
+
## Drivers
|
|
1003
|
+
|
|
1004
|
+
```drivers
|
|
1005
|
+
title: What guided the design
|
|
1006
|
+
items:
|
|
1007
|
+
- { title: Single sign-on, body: One login carries the user everywhere., tag: "HOW: token", icon: lock, accent: purple }
|
|
1008
|
+
- { title: Read per site, body: "Access is scoped to the user's sites.", tag: "WHERE: site group", icon: location, accent: green }
|
|
1009
|
+
- { title: Governed roles, body: "An IGA requests, approves, certifies.", tag: "WHO: role groups", icon: shield, accent: blue }
|
|
1010
|
+
- { title: Per-app permissions, body: The same role differs per app., tag: "WHAT: matrix", icon: grid, accent: amber }
|
|
1011
|
+
```
|
|
1012
|
+
|
|
1013
|
+
## Options
|
|
1014
|
+
|
|
1015
|
+
```options
|
|
1016
|
+
title: Approaches explored
|
|
1017
|
+
items:
|
|
1018
|
+
- { kicker: Option 1, title: App-managed roles, how: Roles in our own DB., pros: [Full control], cons: ["Second source of truth"], verdict: "REJECTED", tone: rejected }
|
|
1019
|
+
- { kicker: Option 2, title: Global role groups, how: One global group per role., pros: [Fewest groups], cons: ["Applies at every site"], verdict: "VIABLE", tone: viable }
|
|
1020
|
+
- { kicker: Option 3, title: Per-site role groups, how: One group per persona per site., pros: [Least privilege], cons: [Most groups], verdict: "CHOSEN", tone: chosen }
|
|
1021
|
+
```
|
|
1022
|
+
|
|
1023
|
+
## Decision scorecard
|
|
1024
|
+
|
|
1025
|
+
```scorecard
|
|
1026
|
+
title: Queue technology choice
|
|
1027
|
+
description: "Weighted 0-5 scoring across the four criteria that mattered. Throughput and operational cost carry double weight; SQS wins on the weighted total."
|
|
1028
|
+
criteria:
|
|
1029
|
+
- { label: Throughput, weight: 2 }
|
|
1030
|
+
- { label: Operational cost, weight: 2 }
|
|
1031
|
+
- { label: Team familiarity }
|
|
1032
|
+
- { label: Ecosystem }
|
|
1033
|
+
options:
|
|
1034
|
+
- { label: Kafka, scores: [5, 2, 3, 5], note: self-hosted }
|
|
1035
|
+
- { label: SQS, scores: [3, 5, 4, 3], note: managed }
|
|
1036
|
+
- { label: RabbitMQ, scores: [3, 3, 4, 4] }
|
|
1037
|
+
```
|
|
1038
|
+
|
|
1039
|
+
## Spec
|
|
1040
|
+
|
|
1041
|
+
```spec
|
|
1042
|
+
title: Per-site role groups
|
|
1043
|
+
accent: green
|
|
1044
|
+
rows:
|
|
1045
|
+
- { label: Groups, value: "SiteN-Users (read) + SiteN-<Persona> per staffed plant." }
|
|
1046
|
+
- { label: Roles, value: "Each group reads as (site, role); the token carries the scope." }
|
|
1047
|
+
- { label: Resolution, steps: [Decode token, "Read (site, role)", Check matrix] }
|
|
1048
|
+
```
|
|
1049
|
+
|
|
1050
|
+
## Fancy list
|
|
1051
|
+
|
|
1052
|
+
```list
|
|
1053
|
+
title: Why documentation-as-code
|
|
1054
|
+
style: accent
|
|
1055
|
+
items:
|
|
1056
|
+
- { lead: Typed blocks, text: "76 strict schemas, validated by chiltepin check.", accent: blue }
|
|
1057
|
+
- { lead: One source of truth, text: Diagrams live in the .md file., accent: green }
|
|
1058
|
+
- { lead: Many outputs, text: "HTML, slides, and PDF from one file.", accent: amber }
|
|
1059
|
+
```
|
|
1060
|
+
|
|
1061
|
+
## Story backlog
|
|
1062
|
+
|
|
1063
|
+
```stories
|
|
1064
|
+
title: Sprint backlog
|
|
1065
|
+
items:
|
|
1066
|
+
- { id: US-1, title: One-step checkout, role: shopper, want: pay in one step, soThat: I finish faster, priority: High, points: 5, tags: [checkout], open: true, criteria: [{ given: items in cart, when: I pay, then: an order is created }] }
|
|
1067
|
+
- { id: US-2, title: Save payment method, role: returning shopper, want: store a card, soThat: I skip re-entry, priority: Med, points: 3 }
|
|
1068
|
+
```
|
|
1069
|
+
|
|
1070
|
+
## Design pattern
|
|
1071
|
+
|
|
1072
|
+
```pattern
|
|
1073
|
+
name: Repository
|
|
1074
|
+
category: Backend
|
|
1075
|
+
intent: Hide persistence behind a collection-like interface so the domain never sees the database.
|
|
1076
|
+
forces: [Swap the data store, Unit-test without a DB, No query leaks into the domain]
|
|
1077
|
+
participants:
|
|
1078
|
+
- { name: OrderRepository, role: interface the service depends on }
|
|
1079
|
+
- { name: PgOrderRepository, role: Postgres implementation }
|
|
1080
|
+
- { name: OrderService, role: caller (domain logic) }
|
|
1081
|
+
consequences:
|
|
1082
|
+
pros: [Swappable storage, Testable with a fake]
|
|
1083
|
+
cons: [Another layer, Risk of anemic pass-through]
|
|
1084
|
+
```
|
|
1085
|
+
|
|
1086
|
+
## Bug gallery
|
|
1087
|
+
|
|
1088
|
+
```gallery
|
|
1089
|
+
cols: 2
|
|
1090
|
+
items:
|
|
1091
|
+
- { title: "N+1 query", lang: JavaScript, accent: red, caption: "1000 users = 1001 queries.", code: "users.forEach(async u =>\n await q('...user_id=?', u.id));" }
|
|
1092
|
+
- { title: "Off-by-one", lang: JavaScript, accent: amber, caption: "arr[len] is undefined.", code: "for (let i=0; i<=arr.length; i++)\n process(arr[i]);" }
|
|
1093
|
+
- { title: "Open redirect", lang: JavaScript, accent: red, caption: "Allowlist destinations.", code: "res.redirect(req.query.url);" }
|
|
1094
|
+
- { title: "Secrets in code", lang: JavaScript, accent: red, caption: "Use env vars + a scanner.", code: "const KEY = 'sk-live-abc123';" }
|
|
1095
|
+
```
|
|
1096
|
+
|
|
1097
|
+
## Gallery — diagram comparison
|
|
1098
|
+
|
|
1099
|
+
```gallery
|
|
1100
|
+
title: Compare architectures
|
|
1101
|
+
cols: 3
|
|
1102
|
+
items:
|
|
1103
|
+
- title: Monolith
|
|
1104
|
+
caption: One deployable unit.
|
|
1105
|
+
block:
|
|
1106
|
+
type: c4
|
|
1107
|
+
level: container
|
|
1108
|
+
nodes:
|
|
1109
|
+
- { id: u, col: 1, row: 1, kind: person, name: User }
|
|
1110
|
+
- { id: app, col: 2, row: 1, kind: container, family: service, name: App }
|
|
1111
|
+
- { id: db, col: 2, row: 2, kind: store, name: DB }
|
|
1112
|
+
edges:
|
|
1113
|
+
- { from: u, to: app }
|
|
1114
|
+
- { from: app, to: db }
|
|
1115
|
+
- title: Microservices
|
|
1116
|
+
caption: Independent services.
|
|
1117
|
+
block:
|
|
1118
|
+
type: c4
|
|
1119
|
+
level: container
|
|
1120
|
+
nodes:
|
|
1121
|
+
- { id: gw, col: 1, row: 1, kind: container, family: service, name: Gateway }
|
|
1122
|
+
- { id: a, col: 2, row: 1, kind: container, family: service, name: Orders }
|
|
1123
|
+
- { id: b, col: 2, row: 2, kind: container, family: service, name: Billing }
|
|
1124
|
+
edges:
|
|
1125
|
+
- { from: gw, to: a }
|
|
1126
|
+
- { from: gw, to: b }
|
|
1127
|
+
- title: Event-driven
|
|
1128
|
+
caption: Async via a broker.
|
|
1129
|
+
block:
|
|
1130
|
+
type: block
|
|
1131
|
+
nodes:
|
|
1132
|
+
- { id: p, col: 1, row: 1, kind: producer, name: Producer }
|
|
1133
|
+
- { id: bus, col: 2, row: 1, kind: topic, name: Bus }
|
|
1134
|
+
- { id: c, col: 3, row: 1, kind: consumer, name: Consumer }
|
|
1135
|
+
edges:
|
|
1136
|
+
- { from: p, to: bus }
|
|
1137
|
+
- { from: bus, to: c }
|
|
1138
|
+
```
|
|
1139
|
+
|
|
1140
|
+
## Data charts
|
|
1141
|
+
|
|
1142
|
+
```chart
|
|
1143
|
+
title: p95 latency by week
|
|
1144
|
+
kind: line
|
|
1145
|
+
unit: ms
|
|
1146
|
+
labels: [W1, W2, W3, W4, W5, W6]
|
|
1147
|
+
series:
|
|
1148
|
+
- { label: /orders, accent: navy, values: [240, 226, 215, 188, 164, 150] }
|
|
1149
|
+
- { label: /search, accent: teal, values: [310, 295, 288, 262, 246, 231] }
|
|
1150
|
+
```
|
|
1151
|
+
|
|
1152
|
+
```chart
|
|
1153
|
+
title: Monthly cost by service
|
|
1154
|
+
kind: bar
|
|
1155
|
+
unit: k
|
|
1156
|
+
labels: [API, Workers, Postgres, Cache]
|
|
1157
|
+
series:
|
|
1158
|
+
- { label: March, accent: navy, values: [8.2, 4.6, 3.1, 1.2] }
|
|
1159
|
+
- { label: April, accent: amber, values: [7.4, 5.1, 3.3, 1.1] }
|
|
1160
|
+
```
|
|
1161
|
+
|
|
1162
|
+
```chart
|
|
1163
|
+
title: Traffic by client
|
|
1164
|
+
kind: donut
|
|
1165
|
+
unit: "%"
|
|
1166
|
+
items:
|
|
1167
|
+
- { label: Web, value: 62, accent: navy }
|
|
1168
|
+
- { label: iOS, value: 23, accent: teal }
|
|
1169
|
+
- { label: Android, value: 15, accent: amber }
|
|
1170
|
+
```
|
|
1171
|
+
|
|
1172
|
+
```chart
|
|
1173
|
+
title: Migration progress
|
|
1174
|
+
description: "A gauge answers how far along one number is; max is the full sweep (default 100)."
|
|
1175
|
+
kind: gauge
|
|
1176
|
+
unit: "%"
|
|
1177
|
+
items:
|
|
1178
|
+
- { label: Services migrated, value: 68, desc: of 42 services }
|
|
1179
|
+
- { label: Traffic cut over, value: 41, accent: teal }
|
|
1180
|
+
```
|
|
1181
|
+
|
|
1182
|
+
```chart
|
|
1183
|
+
title: Incident causes last quarter
|
|
1184
|
+
description: "A pie is the donut with the centre filled — use it when there is no total worth printing."
|
|
1185
|
+
kind: pie
|
|
1186
|
+
unit: "%"
|
|
1187
|
+
items:
|
|
1188
|
+
- { label: Config change, value: 41 }
|
|
1189
|
+
- { label: Deploy, value: 27 }
|
|
1190
|
+
- { label: Capacity, value: 18, accent: teal }
|
|
1191
|
+
- { label: Third party, value: 14 }
|
|
1192
|
+
```
|
|
1193
|
+
|
|
1194
|
+
```chart
|
|
1195
|
+
title: Checkout latency distribution
|
|
1196
|
+
description: "Sampled requests, binned by the renderer (Sturges); the dashed rule is the mean."
|
|
1197
|
+
kind: histogram
|
|
1198
|
+
unit: ms
|
|
1199
|
+
values: [112, 118, 121, 124, 127, 129, 131, 133, 134, 136, 138, 139, 141, 142, 143, 145,
|
|
1200
|
+
146, 148, 149, 151, 152, 154, 155, 157, 158, 160, 162, 164, 166, 168, 171, 174,
|
|
1201
|
+
177, 181, 185, 189, 194, 199, 205, 212, 220, 231, 244, 258, 275, 296, 322, 358]
|
|
1202
|
+
```
|
|
1203
|
+
|
|
1204
|
+
```chart
|
|
1205
|
+
title: Response time against the SLO
|
|
1206
|
+
description: "Where the p95 target sits on the fitted curve — the z-score under each marker says how far out it is."
|
|
1207
|
+
kind: bell
|
|
1208
|
+
unit: ms
|
|
1209
|
+
mean: 180
|
|
1210
|
+
sd: 35
|
|
1211
|
+
markers:
|
|
1212
|
+
- { at: 250, label: SLO p95, accent: amber }
|
|
1213
|
+
- { at: 120, label: Cache hit }
|
|
1214
|
+
```
|
|
1215
|
+
|
|
1216
|
+
```chart
|
|
1217
|
+
title: Build time by pipeline
|
|
1218
|
+
description: "Five-number summaries over the last 200 runs; the accent box is the pipeline under repair."
|
|
1219
|
+
kind: boxplot
|
|
1220
|
+
unit: min
|
|
1221
|
+
boxes:
|
|
1222
|
+
- { label: Web, min: 4.1, q1: 5.2, median: 5.9, q3: 6.8, max: 8.3, outliers: [11.4] }
|
|
1223
|
+
- { label: API, min: 2.8, q1: 3.4, median: 3.9, q3: 4.6, max: 5.7 }
|
|
1224
|
+
- { label: Mobile, min: 9.5, q1: 12.1, median: 14.2, q3: 16.8, max: 21, outliers: [26.5, 28.1], accent: amber }
|
|
1225
|
+
- { label: Data, min: 6, q1: 7.7, median: 8.4, q3: 9.9, max: 12.2 }
|
|
1226
|
+
```
|
|
1227
|
+
|
|
1228
|
+
```chart
|
|
1229
|
+
title: Support tickets by root cause
|
|
1230
|
+
description: "The accent bars are the vital few — fix those and 80% of the volume is gone."
|
|
1231
|
+
kind: pareto
|
|
1232
|
+
items:
|
|
1233
|
+
- { label: Login, value: 142 }
|
|
1234
|
+
- { label: Billing, value: 96 }
|
|
1235
|
+
- { label: Export, value: 41 }
|
|
1236
|
+
- { label: Search, value: 23 }
|
|
1237
|
+
- { label: Mobile, value: 14 }
|
|
1238
|
+
- { label: Other, value: 9 }
|
|
1239
|
+
```
|
|
1240
|
+
|
|
1241
|
+
```chart
|
|
1242
|
+
title: Q3 engineering targets
|
|
1243
|
+
description: "Measure against target inside poor / ok / good ranges, one row per metric."
|
|
1244
|
+
kind: bullet
|
|
1245
|
+
unit: "%"
|
|
1246
|
+
bullets:
|
|
1247
|
+
- { label: Uptime, value: 99.7, target: 99.9, ranges: [99, 99.5, 100] }
|
|
1248
|
+
- { label: Test coverage, value: 72, target: 80, ranges: [50, 70, 100] }
|
|
1249
|
+
- { label: Cache hit rate, value: 91, target: 85, ranges: [60, 80, 100] }
|
|
1250
|
+
- { label: Error budget used, value: 64, target: 50, ranges: [50, 80, 100], accent: red }
|
|
1251
|
+
```
|
|
1252
|
+
|
|
1253
|
+
```sankey
|
|
1254
|
+
title: Where the cloud bill goes
|
|
1255
|
+
description: "Node height and ribbon thickness are the same scale — the widest ribbon is where the money actually goes."
|
|
1256
|
+
unit: k
|
|
1257
|
+
links:
|
|
1258
|
+
- { from: Bill, to: Compute, value: 62 }
|
|
1259
|
+
- { from: Bill, to: Storage, value: 28 }
|
|
1260
|
+
- { from: Bill, to: Network, value: 10 }
|
|
1261
|
+
- { from: Compute, to: Serving, value: 38 }
|
|
1262
|
+
- { from: Compute, to: Batch, value: 24 }
|
|
1263
|
+
- { from: Storage, to: Hot, value: 19 }
|
|
1264
|
+
- { from: Storage, to: Archive, value: 9 }
|
|
1265
|
+
```
|
|
1266
|
+
|
|
1267
|
+
```treemap
|
|
1268
|
+
title: Cloud spend by service
|
|
1269
|
+
description: "Area is the value — a treemap keeps working where a donut gives up at six slices."
|
|
1270
|
+
unit: k
|
|
1271
|
+
items:
|
|
1272
|
+
- { label: Compute, value: 62, desc: EC2 + Lambda }
|
|
1273
|
+
- { label: Storage, value: 28, desc: S3 and snapshots }
|
|
1274
|
+
- { label: Databases, value: 24 }
|
|
1275
|
+
- { label: Network, value: 16 }
|
|
1276
|
+
- { label: Observability, value: 11, accent: amber }
|
|
1277
|
+
- { label: CI runners, value: 9 }
|
|
1278
|
+
```
|
|
1279
|
+
|
|
1280
|
+
```venn
|
|
1281
|
+
title: Who owns the release process
|
|
1282
|
+
sets:
|
|
1283
|
+
- { label: Platform, desc: runtime and CI }
|
|
1284
|
+
- { label: Product, desc: features and UX }
|
|
1285
|
+
shared:
|
|
1286
|
+
- { sets: [Platform, Product], label: Release process }
|
|
1287
|
+
```
|
|
1288
|
+
|
|
1289
|
+
```fishbone
|
|
1290
|
+
title: Why checkout latency rose
|
|
1291
|
+
description: "One effect at the head, cause categories as bones, specific causes along each bone."
|
|
1292
|
+
effect: p95 checkout over 2s
|
|
1293
|
+
causes:
|
|
1294
|
+
- { label: Code, items: [Sync capture call, N+1 cart query] }
|
|
1295
|
+
- { label: Infrastructure, items: [Undersized DB pool, No read replica] }
|
|
1296
|
+
- { label: Traffic, items: [Flash-sale spikes] }
|
|
1297
|
+
- { label: Process, items: [No load test before release] }
|
|
1298
|
+
```
|
|
1299
|
+
|
|
1300
|
+
```chart
|
|
1301
|
+
title: Queue vendors at a glance
|
|
1302
|
+
kind: radar
|
|
1303
|
+
labels: [Throughput, Latency, Cost, Ops burden, Ecosystem]
|
|
1304
|
+
series:
|
|
1305
|
+
- { label: Kafka, accent: navy, values: [5, 4, 2, 2, 5] }
|
|
1306
|
+
- { label: SQS, accent: amber, values: [3, 3, 5, 5, 3] }
|
|
1307
|
+
```
|
|
1308
|
+
|
|
1309
|
+
```chart
|
|
1310
|
+
title: Fix candidates by effort and impact
|
|
1311
|
+
description: "Bubble area is the affected traffic share; the dashed guides cut the plot into four quadrants."
|
|
1312
|
+
kind: scatter
|
|
1313
|
+
xLabel: Effort (weeks)
|
|
1314
|
+
yLabel: Impact
|
|
1315
|
+
points:
|
|
1316
|
+
- { x: 1, y: 8, size: 30, label: Cache headers }
|
|
1317
|
+
- { x: 3, y: 9, size: 80, label: Read replica }
|
|
1318
|
+
- { x: 2.5, y: 4, size: 15, label: Retry budget }
|
|
1319
|
+
- { x: 6, y: 3, size: 20, label: Full rewrite }
|
|
1320
|
+
- { x: 2, y: 2, label: New font }
|
|
1321
|
+
guides:
|
|
1322
|
+
x: 4
|
|
1323
|
+
y: 5
|
|
1324
|
+
quadrants: [Do first, Plan well, Fill in, Avoid]
|
|
1325
|
+
```
|
|
1326
|
+
|
|
1327
|
+
```slopegraph
|
|
1328
|
+
title: Support volume by channel
|
|
1329
|
+
description: "Each line is one channel between two years; the slope is the message, and the accented line carries the story."
|
|
1330
|
+
left: "2023"
|
|
1331
|
+
right: "2025"
|
|
1332
|
+
unit: "%"
|
|
1333
|
+
items:
|
|
1334
|
+
- { label: Email, from: 48, to: 22 }
|
|
1335
|
+
- { label: Chat, from: 20, to: 45, accent: teal }
|
|
1336
|
+
- { label: Phone, from: 32, to: 33 }
|
|
1337
|
+
- { label: Self-serve, from: 0, to: 12 }
|
|
1338
|
+
```
|
|
1339
|
+
|
|
1340
|
+
## Latency budget
|
|
1341
|
+
|
|
1342
|
+
```chart
|
|
1343
|
+
kind: waterfall
|
|
1344
|
+
description: Where the checkout API's 250 ms budget goes, hop by hop.
|
|
1345
|
+
unit: ms
|
|
1346
|
+
budget: 250
|
|
1347
|
+
items:
|
|
1348
|
+
- { label: DNS + TLS, value: 35 }
|
|
1349
|
+
- { label: Gateway, value: 20, desc: auth + routing }
|
|
1350
|
+
- { label: Orders service, value: 90 }
|
|
1351
|
+
- { label: Database, value: 70 }
|
|
1352
|
+
- { label: Serialization, value: 15 }
|
|
1353
|
+
```
|
|
1354
|
+
|
|
1355
|
+
## Heatmap
|
|
1356
|
+
|
|
1357
|
+
```heatmap
|
|
1358
|
+
title: p95 latency by region × hour
|
|
1359
|
+
description: UTC hours, last 7 days.
|
|
1360
|
+
unit: ms
|
|
1361
|
+
xLabels: ["00", "04", "08", "12", "16", "20"]
|
|
1362
|
+
rows:
|
|
1363
|
+
- { label: us-east-1, values: [122, 118, 145, 210, 265, 190] }
|
|
1364
|
+
- { label: eu-west-1, values: [110, 105, 168, 240, 195, 150] }
|
|
1365
|
+
- { label: ap-south-1, values: [180, 210, 310, 285, 240, 205] }
|
|
1366
|
+
```
|
|
1367
|
+
|
|
1368
|
+
## Figure
|
|
1369
|
+
|
|
1370
|
+
```figure
|
|
1371
|
+
src: https://chiltepin.dev/logo.png
|
|
1372
|
+
alt: The Chiltepin logo
|
|
1373
|
+
caption: "The Chiltepin logo, capped at 420 px."
|
|
1374
|
+
width: 420
|
|
1375
|
+
```
|
|
1376
|
+
|
|
1377
|
+
## Unified diff
|
|
1378
|
+
|
|
1379
|
+
```code
|
|
1380
|
+
kind: diff
|
|
1381
|
+
title: "fix: clamp retry backoff"
|
|
1382
|
+
lang: TypeScript
|
|
1383
|
+
code: |
|
|
1384
|
+
@@ -12,7 +12,7 @@
|
|
1385
|
+
function backoff(attempt: number): number {
|
|
1386
|
+
- return 100 * attempt ** 2;
|
|
1387
|
+
+ return Math.min(30_000, 100 * attempt ** 2);
|
|
1388
|
+
}
|
|
1389
|
+
```
|
|
1390
|
+
|
|
1391
|
+
## Before / after
|
|
1392
|
+
|
|
1393
|
+
```code
|
|
1394
|
+
kind: compare
|
|
1395
|
+
lines: true
|
|
1396
|
+
caption: Backoff grows without bound on the left; the right caps it at 30 s.
|
|
1397
|
+
blocks:
|
|
1398
|
+
- lang: TypeScript
|
|
1399
|
+
highlight: "2"
|
|
1400
|
+
code: |
|
|
1401
|
+
function backoff(attempt: number): number {
|
|
1402
|
+
return 100 * attempt ** 2;
|
|
1403
|
+
}
|
|
1404
|
+
- lang: TypeScript
|
|
1405
|
+
highlight: "2"
|
|
1406
|
+
code: |
|
|
1407
|
+
function backoff(attempt: number): number {
|
|
1408
|
+
return Math.min(30_000, 100 * attempt ** 2);
|
|
1409
|
+
}
|
|
1410
|
+
```
|
|
1411
|
+
|
|
1412
|
+
## Runbook steps
|
|
1413
|
+
|
|
1414
|
+
```steps
|
|
1415
|
+
title: Deploy a hotfix
|
|
1416
|
+
description: The fast path for a production fix — branch, ship, tag.
|
|
1417
|
+
items:
|
|
1418
|
+
- title: Branch from main
|
|
1419
|
+
body: Hotfixes always branch from the latest main.
|
|
1420
|
+
code: git checkout -b hotfix/fix-retry main
|
|
1421
|
+
lang: bash
|
|
1422
|
+
- title: Ship the fix
|
|
1423
|
+
body: Commit and push; CI runs the full suite.
|
|
1424
|
+
code: git push -u origin hotfix/fix-retry
|
|
1425
|
+
lang: bash
|
|
1426
|
+
note: CI must be green before the next step.
|
|
1427
|
+
- title: Tag and deploy
|
|
1428
|
+
code: git tag v1.4.1 && git push --tags
|
|
1429
|
+
lang: bash
|
|
1430
|
+
```
|
|
1431
|
+
|
|
1432
|
+
## FAQ
|
|
1433
|
+
|
|
1434
|
+
```faq
|
|
1435
|
+
title: Common questions
|
|
1436
|
+
items:
|
|
1437
|
+
- q: Where does the content live?
|
|
1438
|
+
a: "In the .md files on disk — they are the single source of truth. Every diagram on this page is a typed YAML block."
|
|
1439
|
+
open: true
|
|
1440
|
+
- q: Do diagrams need a drawing tool?
|
|
1441
|
+
a: "No. Change the YAML and rerun chiltepin html — the SVG updates."
|
|
1442
|
+
- q: How do I validate a doc?
|
|
1443
|
+
a: Run chiltepin check and fix every diagnostic it reports.
|
|
1444
|
+
```
|
|
1445
|
+
|
|
1446
|
+
## Capacity math
|
|
1447
|
+
|
|
1448
|
+
```envelope
|
|
1449
|
+
title: Order-write capacity
|
|
1450
|
+
description: The estimate that sizes the write path.
|
|
1451
|
+
assumptions:
|
|
1452
|
+
- { label: Daily active users, value: 2M }
|
|
1453
|
+
- { label: Orders / user / day, value: "0.5" }
|
|
1454
|
+
- { label: Payload per order, value: 2 KB }
|
|
1455
|
+
- { label: Retention, value: 5 years }
|
|
1456
|
+
steps:
|
|
1457
|
+
- { label: Orders per day, calc: "2M × 0.5", result: 1M/day }
|
|
1458
|
+
- { label: Write QPS, calc: "1M / 86,400 s", result: "≈ 12 rps" }
|
|
1459
|
+
- { label: Peak QPS, calc: "12 × 3 (peak factor)", result: "≈ 36 rps" }
|
|
1460
|
+
- { label: Storage per year, calc: "1M × 2 KB × 365", result: "≈ 730 GB/yr" }
|
|
1461
|
+
result: { label: Provision for, value: "~75 rps write peak · ~4 TB over retention" }
|
|
1462
|
+
```
|
|
1463
|
+
|
|
1464
|
+
## Service objectives
|
|
1465
|
+
|
|
1466
|
+
```slo
|
|
1467
|
+
title: Orders API — SLOs
|
|
1468
|
+
items:
|
|
1469
|
+
- { name: Availability, sli: Successful requests / total requests, target: 99.9%, current: 99.98%, window: 30d, budget: 0.15 }
|
|
1470
|
+
- { name: Latency, sli: Requests served under 400 ms (p99), target: 99%, current: 98.8%, window: 30d, budget: 0.6 }
|
|
1471
|
+
- { name: Freshness, sli: Order events indexed within 60 s, target: 99.5%, current: 97.9%, window: 7d, budget: 1.0 }
|
|
1472
|
+
```
|
|
1473
|
+
|
|
1474
|
+
## Terminal session
|
|
1475
|
+
|
|
1476
|
+
```code
|
|
1477
|
+
kind: terminal
|
|
1478
|
+
title: deploy — production
|
|
1479
|
+
session: |
|
|
1480
|
+
$ kubectl rollout status deploy/orders-api
|
|
1481
|
+
# wait for the rollout to settle before tagging
|
|
1482
|
+
Waiting for deployment "orders-api" rollout to finish: 2 of 4 updated replicas are available...
|
|
1483
|
+
deployment "orders-api" successfully rolled out
|
|
1484
|
+
$ kubectl get pods -l app=orders-api
|
|
1485
|
+
NAME READY STATUS RESTARTS AGE
|
|
1486
|
+
orders-api-7d4b9c6f5d-2xkqp 1/1 Running 0 52s
|
|
1487
|
+
orders-api-7d4b9c6f5d-9mwlt 1/1 Running 0 48s
|
|
1488
|
+
$ git tag v2.3.0 && git push --tags
|
|
1489
|
+
```
|
|
1490
|
+
|
|
1491
|
+
## SWOT
|
|
1492
|
+
|
|
1493
|
+
```swot
|
|
1494
|
+
title: Taking Chiltepin to the enterprise
|
|
1495
|
+
description: Where we stand before the enterprise push.
|
|
1496
|
+
strengths:
|
|
1497
|
+
- Docs-as-code fits existing review workflows
|
|
1498
|
+
- 107 typed blocks cover most technical stories
|
|
1499
|
+
- Renders to HTML, slides, and PDF from one file
|
|
1500
|
+
weaknesses:
|
|
1501
|
+
- No SSO / SCIM integration yet
|
|
1502
|
+
- Small team — support hours are limited
|
|
1503
|
+
opportunities:
|
|
1504
|
+
- Compliance push makes auditable docs attractive
|
|
1505
|
+
- AI agents author blocks natively via the skill
|
|
1506
|
+
threats:
|
|
1507
|
+
- Incumbent wikis bundle "good enough" diagrams
|
|
1508
|
+
- Long procurement cycles slow adoption
|
|
1509
|
+
```
|
|
1510
|
+
|
|
1511
|
+
```scqa
|
|
1512
|
+
title: Why this quarter goes to checkout
|
|
1513
|
+
lede: The one decision this review needs.
|
|
1514
|
+
situation: We process 12k orders a day across three regions.
|
|
1515
|
+
complication: p95 checkout crossed 2s in March and conversion fell 3.1pp with it.
|
|
1516
|
+
question: Where does the next quarter of platform work go?
|
|
1517
|
+
answer: Move payment capture off the request path — it returns 1.8s of the 2.4s.
|
|
1518
|
+
because:
|
|
1519
|
+
- Capture is 74% of p95 and is fully async-able
|
|
1520
|
+
- No schema change, so it ships inside one quarter
|
|
1521
|
+
```
|
|
1522
|
+
|
|
1523
|
+
```scenarios
|
|
1524
|
+
title: Three ways next year goes
|
|
1525
|
+
description: The three cases span $13M of FY27 revenue.
|
|
1526
|
+
drivers: [Capture moved async, Conversion recovery, Volume growth]
|
|
1527
|
+
outcomeLabel: FY27 revenue
|
|
1528
|
+
cases:
|
|
1529
|
+
- { label: Downside, values: ["Q4 slip", "+0.8pp", "5%"], outcome: "$18M", tone: neg }
|
|
1530
|
+
- { label: Base, values: ["Q3", "+2.1pp", "8%"], outcome: "$24M", tone: base }
|
|
1531
|
+
- { label: Upside, values: ["Q3", "+3.4pp", "15%"], outcome: "$31M", tone: pos }
|
|
1532
|
+
```
|
|
1533
|
+
|
|
1534
|
+
```harvey
|
|
1535
|
+
title: Queue vendor fit
|
|
1536
|
+
description: "Ratings are judgements, 0-4; the WEIGHTED row is computed, so the recommendation and the arithmetic agree."
|
|
1537
|
+
columns: [Kafka, SQS, RabbitMQ]
|
|
1538
|
+
scale: [poor, excellent]
|
|
1539
|
+
rows:
|
|
1540
|
+
- { label: Throughput, ratings: [4, 2, 3], weight: 2, note: sustained messages per second }
|
|
1541
|
+
- { label: Operational burden, ratings: [1, 4, 3], weight: 2 }
|
|
1542
|
+
- { label: Team familiarity, ratings: [2, 4, 3] }
|
|
1543
|
+
- { label: Ecosystem, ratings: [4, 3, 3] }
|
|
1544
|
+
recommend: SQS
|
|
1545
|
+
```
|
|
1546
|
+
|
|
1547
|
+
```wardley
|
|
1548
|
+
title: Where to build, where to buy
|
|
1549
|
+
description: "Build the scoring model, buy the warehouse — only the model is still evolving."
|
|
1550
|
+
components:
|
|
1551
|
+
- { id: analyst, label: Analyst, x: 0.72, y: 0.96, kind: user }
|
|
1552
|
+
- { id: reports, label: Reporting UI, x: 0.42, y: 0.74 }
|
|
1553
|
+
- { id: model, label: Scoring model, x: 0.22, y: 0.54, kind: build, movement: 0.18 }
|
|
1554
|
+
- { id: warehouse, label: Warehouse, x: 0.78, y: 0.32, kind: commodity }
|
|
1555
|
+
links:
|
|
1556
|
+
- { from: analyst, to: reports }
|
|
1557
|
+
- { from: reports, to: model }
|
|
1558
|
+
- { from: model, to: warehouse }
|
|
1559
|
+
```
|
|
1560
|
+
|
|
1561
|
+
|
|
1562
|
+
## Conversion funnel
|
|
1563
|
+
|
|
1564
|
+
```chart
|
|
1565
|
+
kind: funnel
|
|
1566
|
+
title: Signup → paid conversion
|
|
1567
|
+
description: Last 90 days, all channels.
|
|
1568
|
+
unit: users
|
|
1569
|
+
items:
|
|
1570
|
+
- { label: Visited landing page, value: 48000 }
|
|
1571
|
+
- { label: Started signup, value: 9600, desc: email + password }
|
|
1572
|
+
- { label: Activated, value: 4300, desc: created a first doc }
|
|
1573
|
+
- { label: Upgraded to paid, value: 860 }
|
|
1574
|
+
```
|
|
1575
|
+
|
|
1576
|
+
## OKRs
|
|
1577
|
+
|
|
1578
|
+
```okr
|
|
1579
|
+
title: Q3 objectives
|
|
1580
|
+
description: Two objectives, reviewed monthly.
|
|
1581
|
+
items:
|
|
1582
|
+
- objective: Make onboarding effortless
|
|
1583
|
+
owner: Growth
|
|
1584
|
+
krs:
|
|
1585
|
+
- { kr: Time-to-first-doc under 5 minutes, progress: 0.7, status: on-track }
|
|
1586
|
+
- { kr: Activation rate from 45% to 60%, progress: 0.4, status: at-risk }
|
|
1587
|
+
- { kr: Ship 10 quick-start templates, progress: 1, status: done }
|
|
1588
|
+
- objective: Earn enterprise trust
|
|
1589
|
+
owner: Platform
|
|
1590
|
+
krs:
|
|
1591
|
+
- { kr: Ship SSO + audit log, progress: 0.85, status: on-track }
|
|
1592
|
+
- { kr: SOC 2 Type II report issued, progress: 0.2, status: off-track }
|
|
1593
|
+
```
|
|
1594
|
+
|
|
1595
|
+
## Personas
|
|
1596
|
+
|
|
1597
|
+
```persona
|
|
1598
|
+
title: Who we build for
|
|
1599
|
+
personas:
|
|
1600
|
+
- name: Maya Chen
|
|
1601
|
+
role: Staff engineer
|
|
1602
|
+
quote: I want the diagram in the PR diff, not in a wiki.
|
|
1603
|
+
goals: [Docs that live with the code, Reviewable architecture changes]
|
|
1604
|
+
frustrations: [Stale wiki pages, Screenshots of whiteboards]
|
|
1605
|
+
tools: [VS Code, GitHub, Mermaid]
|
|
1606
|
+
accent: blue
|
|
1607
|
+
- name: Priya Patel
|
|
1608
|
+
role: Engineering manager
|
|
1609
|
+
quote: Every reorg breaks our onboarding docs.
|
|
1610
|
+
goals: [One source of truth per system, New joiners productive in week one]
|
|
1611
|
+
frustrations: ["Docs no one owns", Tribal knowledge in DMs]
|
|
1612
|
+
tools: [Linear, Notion, Slack]
|
|
1613
|
+
accent: teal
|
|
1614
|
+
```
|
|
1615
|
+
|
|
1616
|
+
## Changelog
|
|
1617
|
+
|
|
1618
|
+
```changelog
|
|
1619
|
+
title: Release history
|
|
1620
|
+
releases:
|
|
1621
|
+
- version: 2.0.0
|
|
1622
|
+
date: 2026-06-24
|
|
1623
|
+
tag: breaking
|
|
1624
|
+
items:
|
|
1625
|
+
- { type: changed, text: "Config moved from .chiltepinrc to chiltepin.config.json" }
|
|
1626
|
+
- { type: removed, text: Dropped Node 18 support }
|
|
1627
|
+
- { type: security, text: Bumped yaml to patch CVE-2026-1234 }
|
|
1628
|
+
- version: 1.4.0
|
|
1629
|
+
date: 2026-05-12
|
|
1630
|
+
tag: minor
|
|
1631
|
+
items:
|
|
1632
|
+
- { type: added, text: Dark theme + custom theme files }
|
|
1633
|
+
- { type: fixed, text: Slide overflow on long tables }
|
|
1634
|
+
- version: 1.3.2
|
|
1635
|
+
date: 2026-04-03
|
|
1636
|
+
tag: patch
|
|
1637
|
+
items:
|
|
1638
|
+
- { type: fixed, text: Windows path handling in chiltepin check }
|
|
1639
|
+
```
|
|
1640
|
+
|
|
1641
|
+
## Team
|
|
1642
|
+
|
|
1643
|
+
```team
|
|
1644
|
+
title: Who owns what
|
|
1645
|
+
members:
|
|
1646
|
+
- { name: Ana Ruiz, role: Tech lead, focus: Rendering pipeline, accent: navy }
|
|
1647
|
+
- { name: Sam Okafor, role: Backend, focus: Sync + integrations, accent: teal }
|
|
1648
|
+
- { name: Lena Fischer, role: Design, focus: Themes and house style, accent: purple }
|
|
1649
|
+
- { name: Tom Alvarez, role: CLI, focus: chiltepin commands and DX, accent: green }
|
|
1650
|
+
- { name: DevRel, initials: DR, role: Advocacy, focus: Docs and community, accent: amber }
|
|
1651
|
+
```
|
|
1652
|
+
|
|
1653
|
+
## Design tokens
|
|
1654
|
+
|
|
1655
|
+
```palette
|
|
1656
|
+
title: Brand palette
|
|
1657
|
+
description: Core color tokens — reference by name, never by raw hex.
|
|
1658
|
+
cols: 4
|
|
1659
|
+
colors:
|
|
1660
|
+
- { name: Primary, value: "#0E54A1", usage: "Buttons, links, focus rings" }
|
|
1661
|
+
- { name: Ink, value: "#1F2937", usage: Body text and headings }
|
|
1662
|
+
- { name: Surface, value: "#F6F8FB", usage: Card and panel backgrounds }
|
|
1663
|
+
- { name: Positive, value: "#1F9747", usage: Success states }
|
|
1664
|
+
- { name: Warning, value: "#B45309", usage: Caution banners }
|
|
1665
|
+
- { name: Negative, value: "#B3261E", usage: Errors and destructive actions }
|
|
1666
|
+
- { name: Accent, value: "#5B4A8A", usage: Charts and highlights }
|
|
1667
|
+
- { name: Muted, value: "#8A8475", usage: Secondary text }
|
|
1668
|
+
```
|
|
1669
|
+
|
|
1670
|
+
## Type scale
|
|
1671
|
+
|
|
1672
|
+
```typescale
|
|
1673
|
+
description: The ramp from display headings down to code.
|
|
1674
|
+
items:
|
|
1675
|
+
- { name: Display, size: 40, weight: 700, font: display, lineHeight: 1.1, note: hero headings }
|
|
1676
|
+
- { name: H1, size: 28, weight: 700, font: display, lineHeight: 1.2 }
|
|
1677
|
+
- { name: Body, size: 15, lineHeight: 1.6 }
|
|
1678
|
+
- { name: Caption, size: 12, weight: 500, note: secondary text }
|
|
1679
|
+
- { name: Code, size: 13, font: mono }
|
|
1680
|
+
```
|
|
1681
|
+
|
|
1682
|
+
## Usage guidelines
|
|
1683
|
+
|
|
1684
|
+
```dodont
|
|
1685
|
+
title: Button usage
|
|
1686
|
+
description: How to place and label buttons.
|
|
1687
|
+
dos:
|
|
1688
|
+
- { text: Use one primary button per view }
|
|
1689
|
+
- { text: Write labels as verbs, example: "Save changes" }
|
|
1690
|
+
- { text: Pair a destructive action with a confirm step }
|
|
1691
|
+
donts:
|
|
1692
|
+
- { text: Stack two primary buttons side by side }
|
|
1693
|
+
- { text: Disable a button without explaining why, example: "tooltip: Add a line item first" }
|
|
1694
|
+
```
|
|
1695
|
+
|
|
1696
|
+
## Component inventory
|
|
1697
|
+
|
|
1698
|
+
```inventory
|
|
1699
|
+
title: Component status
|
|
1700
|
+
description: Maturity of the shared component library.
|
|
1701
|
+
items:
|
|
1702
|
+
- { name: Button, status: stable, tag: v2 }
|
|
1703
|
+
- { name: Data table, status: beta, note: Column-resize API may change before GA }
|
|
1704
|
+
- { name: Date picker, status: experimental }
|
|
1705
|
+
- { name: Modal (legacy), status: deprecated, note: Use Dialog instead }
|
|
1706
|
+
- { name: Charts, status: planned, note: Targeted for next quarter }
|
|
1707
|
+
```
|
|
1708
|
+
|
|
1709
|
+
## Array walkthrough
|
|
1710
|
+
|
|
1711
|
+
```array
|
|
1712
|
+
title: Binary search for 27 — step 2
|
|
1713
|
+
description: mid lands on 19, so the search space halves to the right.
|
|
1714
|
+
items:
|
|
1715
|
+
- { value: "3", tone: muted }
|
|
1716
|
+
- { value: "7", tone: muted }
|
|
1717
|
+
- { value: "12", label: lo }
|
|
1718
|
+
- { value: "19", tone: active, label: mid }
|
|
1719
|
+
- { value: "27", tone: target }
|
|
1720
|
+
- { value: "41", label: hi }
|
|
1721
|
+
window: { from: 2, to: 5, label: search space }
|
|
1722
|
+
```
|
|
1723
|
+
|
|
1724
|
+
## Linked list
|
|
1725
|
+
|
|
1726
|
+
```linkedlist
|
|
1727
|
+
title: Reversing a list — step 2
|
|
1728
|
+
description: prev trails curr; each step flips one next pointer.
|
|
1729
|
+
nodes:
|
|
1730
|
+
- { value: "9", tone: visited, label: prev }
|
|
1731
|
+
- { value: "4", tone: active, label: curr }
|
|
1732
|
+
- { value: "7", label: next }
|
|
1733
|
+
- { value: "1" }
|
|
1734
|
+
```
|
|
1735
|
+
|
|
1736
|
+
## Binary tree
|
|
1737
|
+
|
|
1738
|
+
```bintree
|
|
1739
|
+
title: BST search for 27
|
|
1740
|
+
description: The tinted chain is the comparison path down to the target.
|
|
1741
|
+
nodes:
|
|
1742
|
+
- { id: root, value: "19", tone: visited }
|
|
1743
|
+
- { id: l, value: "8", parent: root, side: left }
|
|
1744
|
+
- { id: ll, value: "4", parent: l, side: left }
|
|
1745
|
+
- { id: lr, value: "12", parent: l, side: right }
|
|
1746
|
+
- { id: r, value: "31", parent: root, side: right, tone: active }
|
|
1747
|
+
- { id: rl, value: "27", parent: r, side: left, tone: target }
|
|
1748
|
+
- { id: rr, value: "40", parent: r, side: right }
|
|
1749
|
+
```
|
|
1750
|
+
|
|
1751
|
+
## Hash table
|
|
1752
|
+
|
|
1753
|
+
```hashmap
|
|
1754
|
+
description: "Chained buckets — hash(key) % 8; plum and grape collide in bucket 2."
|
|
1755
|
+
buckets: 8
|
|
1756
|
+
entries:
|
|
1757
|
+
- { key: apple, value: "3", bucket: 0 }
|
|
1758
|
+
- { key: plum, value: "9", bucket: 2, tone: active }
|
|
1759
|
+
- { key: grape, value: "1", bucket: 2 }
|
|
1760
|
+
- { key: fig, value: "7", bucket: 5, tone: muted }
|
|
1761
|
+
```
|
|
1762
|
+
|
|
1763
|
+
## Agent loop
|
|
1764
|
+
|
|
1765
|
+
```agentloop
|
|
1766
|
+
title: Support triage agent
|
|
1767
|
+
description: "One loop turn — the agent reads the ticket, calls tools, and replies or escalates. The loop ends only two ways: a reply is sent or a human gets the ticket."
|
|
1768
|
+
agent:
|
|
1769
|
+
name: Triage agent
|
|
1770
|
+
model: claude-sonnet-4-6
|
|
1771
|
+
note: Routes each ticket to a fix or a human.
|
|
1772
|
+
env: Customer
|
|
1773
|
+
tools:
|
|
1774
|
+
- { name: search_kb, desc: Search help-center articles }
|
|
1775
|
+
- { name: get_account, desc: Look up plan and billing state }
|
|
1776
|
+
- { name: create_ticket, desc: Escalate to a human queue }
|
|
1777
|
+
memory:
|
|
1778
|
+
- conversation history
|
|
1779
|
+
- customer profile
|
|
1780
|
+
stop: reply sent or ticket escalated
|
|
1781
|
+
```
|
|
1782
|
+
|
|
1783
|
+
## Execution trace
|
|
1784
|
+
|
|
1785
|
+
```trace
|
|
1786
|
+
title: Password reset — one episode
|
|
1787
|
+
description: "One real episode: the agent checked delivery logs before blaming spam."
|
|
1788
|
+
turns:
|
|
1789
|
+
- role: user
|
|
1790
|
+
text: I never get the reset email.
|
|
1791
|
+
- role: assistant
|
|
1792
|
+
thinking: Could be a bounce — check delivery logs before blaming spam.
|
|
1793
|
+
text: Let me check our email logs.
|
|
1794
|
+
- role: tool
|
|
1795
|
+
tool: email_logs.search
|
|
1796
|
+
args: '{ "to": "sam@example.com", "type": "password_reset" }'
|
|
1797
|
+
result: "1 result: bounced (mailbox full)"
|
|
1798
|
+
- role: assistant
|
|
1799
|
+
text: Your mailbox rejected the email — free up space and I will resend it.
|
|
1800
|
+
```
|
|
1801
|
+
|
|
1802
|
+
## Prompt anatomy
|
|
1803
|
+
|
|
1804
|
+
```prompt
|
|
1805
|
+
title: Support reply template
|
|
1806
|
+
description: The system + user template behind every triage turn.
|
|
1807
|
+
segments:
|
|
1808
|
+
- kind: system
|
|
1809
|
+
label: role + guardrails
|
|
1810
|
+
text: "You are a support agent for {{product}}. Answer from the docs only."
|
|
1811
|
+
- kind: user
|
|
1812
|
+
text: "Customer ({{plan}} plan) asks: {{question}}"
|
|
1813
|
+
vars:
|
|
1814
|
+
- { name: product, desc: Product name from config }
|
|
1815
|
+
- { name: plan, desc: Plan tier of the signed-in customer }
|
|
1816
|
+
- { name: question, desc: The inbound message }
|
|
1817
|
+
```
|
|
1818
|
+
|
|
1819
|
+
## Context budget
|
|
1820
|
+
|
|
1821
|
+
```context
|
|
1822
|
+
title: Where the 200k window goes
|
|
1823
|
+
description: Steady-state budget for one triage turn.
|
|
1824
|
+
window: 200000
|
|
1825
|
+
segments:
|
|
1826
|
+
- { label: system prompt, tokens: 6000, accent: navy }
|
|
1827
|
+
- { label: tool schemas, tokens: 14000, accent: teal }
|
|
1828
|
+
- { label: retrieval, tokens: 60000, accent: amber, desc: top-8 chunks }
|
|
1829
|
+
- { label: history, tokens: 70000, accent: purple }
|
|
1830
|
+
```
|
|
1831
|
+
|
|
1832
|
+
## Section divider
|
|
1833
|
+
|
|
1834
|
+
```divider
|
|
1835
|
+
kicker: PART 2
|
|
1836
|
+
title: What we change
|
|
1837
|
+
subtitle: The three fixes, in the order we ship them.
|
|
1838
|
+
accent: navy
|
|
1839
|
+
```
|
|
1840
|
+
|
|
1841
|
+
## Big number
|
|
1842
|
+
|
|
1843
|
+
```bignumber
|
|
1844
|
+
value: "-75%"
|
|
1845
|
+
label: Checkout p95 after moving capture off the request path
|
|
1846
|
+
context: "2.4s → 600ms, measured over four weeks of production traffic"
|
|
1847
|
+
delta: "-1.8s"
|
|
1848
|
+
trend: down
|
|
1849
|
+
accent: green
|
|
1850
|
+
```
|
|
1851
|
+
|
|
1852
|
+
## Takeaways
|
|
1853
|
+
|
|
1854
|
+
```takeaways
|
|
1855
|
+
items:
|
|
1856
|
+
- text: The synchronous capture call was the bottleneck
|
|
1857
|
+
detail: It accounted for 71% of the 2.4s checkout p95.
|
|
1858
|
+
- text: Moving it to a queue cut p95 by 75%
|
|
1859
|
+
detail: No other change shipped in the window.
|
|
1860
|
+
- text: Conversion recovered within two weeks
|
|
1861
|
+
detail: "+0.4pp against the pre-regression baseline."
|
|
1862
|
+
- text: The pattern generalises
|
|
1863
|
+
detail: Audit every synchronous third-party call on the hot path.
|
|
1864
|
+
```
|
|
1865
|
+
|
|
1866
|
+
## Quality, UML, ML, and deck shapes
|
|
1867
|
+
|
|
1868
|
+
Thirteen blocks added in the September coverage sweep. Each is the example `chiltepin block <type>` prints.
|
|
1869
|
+
|
|
1870
|
+
### Audit findings
|
|
1871
|
+
|
|
1872
|
+
What a review found, worst first, with the evidence and the fix.
|
|
1873
|
+
|
|
1874
|
+
```audit
|
|
1875
|
+
title: Security review — payments service
|
|
1876
|
+
scope: payments-api, payments-worker
|
|
1877
|
+
date: 2026-09-01
|
|
1878
|
+
auditor: AppSec
|
|
1879
|
+
findings:
|
|
1880
|
+
- { id: F1, title: Refund endpoint has no rate limit, severity: high, area: API, evidence: "POST /refunds accepted 500 req/s in the load test", fix: Add the shared limiter at 20 req/min per key, owner: payments, status: fixing }
|
|
1881
|
+
- { id: F2, title: Card BIN logged at INFO, severity: critical, area: Logging, evidence: "worker.log line 2231", fix: Mask to first 2 digits; add the log-scrub test, owner: payments, status: open }
|
|
1882
|
+
- { id: F3, title: Dependency openssl 3.0.8 has a known CVE, severity: medium, area: Supply chain, fix: Bump to 3.0.14, owner: platform, status: fixed }
|
|
1883
|
+
- { id: F4, title: Health endpoint leaks build SHA, severity: info, area: API, status: accepted }
|
|
1884
|
+
```
|
|
1885
|
+
|
|
1886
|
+
### Readiness checklist
|
|
1887
|
+
|
|
1888
|
+
A standard applied once: each item a verdict with its proof, the pass rate derived.
|
|
1889
|
+
|
|
1890
|
+
```checklist
|
|
1891
|
+
title: Production readiness — search-indexer
|
|
1892
|
+
standard: PRR v4
|
|
1893
|
+
groups:
|
|
1894
|
+
- label: Observability
|
|
1895
|
+
items:
|
|
1896
|
+
- "[pass] Dashboards for the four golden signals — grafana/search-indexer"
|
|
1897
|
+
- "[pass] Alerts route to the on-call — pagerduty svc P4"
|
|
1898
|
+
- "[partial] Traces sampled at 10% — target is 100% on errors"
|
|
1899
|
+
- label: Resilience
|
|
1900
|
+
items:
|
|
1901
|
+
- "[fail] Load test at 2× peak — not run since the Kafka move"
|
|
1902
|
+
- "[na] Multi-region failover — single-region service by design"
|
|
1903
|
+
```
|
|
1904
|
+
|
|
1905
|
+
### Performance budget
|
|
1906
|
+
|
|
1907
|
+
Measured against budget; over, near, and ok are derived, not typed.
|
|
1908
|
+
|
|
1909
|
+
```perfbudget
|
|
1910
|
+
title: Product page — web vitals
|
|
1911
|
+
context: p75, mobile, 4G, 30-day field data
|
|
1912
|
+
metrics:
|
|
1913
|
+
- { metric: LCP, budget: 2500, measured: 2140, unit: ms }
|
|
1914
|
+
- { metric: INP, budget: 200, measured: 260, unit: ms }
|
|
1915
|
+
- { metric: CLS, budget: 0.1, measured: 0.04 }
|
|
1916
|
+
- { metric: JS transferred, budget: 300, measured: 285, unit: KB }
|
|
1917
|
+
- { metric: Lighthouse perf, budget: 90, measured: 84, lowerIsBetter: false }
|
|
1918
|
+
```
|
|
1919
|
+
|
|
1920
|
+
### Latency percentiles
|
|
1921
|
+
|
|
1922
|
+
The tail per endpoint on one axis, with the SLO drawn.
|
|
1923
|
+
|
|
1924
|
+
```percentiles
|
|
1925
|
+
title: Checkout API latency — last 7 days
|
|
1926
|
+
unit: ms
|
|
1927
|
+
slo: 300
|
|
1928
|
+
rows:
|
|
1929
|
+
- { label: POST /checkout, p50: 120, p90: 210, p95: 260, p99: 420, max: 1900 }
|
|
1930
|
+
- { label: GET /cart, p50: 18, p90: 35, p95: 48, p99: 90, max: 410 }
|
|
1931
|
+
- { label: POST /payments, p50: 240, p90: 380, p95: 470, p99: 900, max: 3100, accent: red }
|
|
1932
|
+
```
|
|
1933
|
+
|
|
1934
|
+
### Threat model
|
|
1935
|
+
|
|
1936
|
+
STRIDE over a data flow with trust boundaries and the mitigations in a table.
|
|
1937
|
+
|
|
1938
|
+
```threatmodel
|
|
1939
|
+
title: Login — STRIDE
|
|
1940
|
+
boundaries:
|
|
1941
|
+
- { id: inet, col: 1, row: 1, cols: 1, rows: 1, label: Internet }
|
|
1942
|
+
- { id: dmz, col: 2, row: 1, cols: 2, rows: 1, label: Trusted network }
|
|
1943
|
+
nodes:
|
|
1944
|
+
- { id: browser, col: 1, row: 1, name: Browser, kind: external }
|
|
1945
|
+
- { id: auth, col: 2, row: 1, name: Auth service }
|
|
1946
|
+
- { id: users, col: 3, row: 1, name: Users DB, kind: store }
|
|
1947
|
+
edges:
|
|
1948
|
+
- { from: browser, to: auth, label: "POST /login", channel: tls }
|
|
1949
|
+
- { from: auth, to: users, label: SELECT by email, channel: internal }
|
|
1950
|
+
threats:
|
|
1951
|
+
- { id: T1, target: browser, category: S, threat: Credential stuffing, mitigation: Rate limit + breached-password check, severity: high, status: mitigated }
|
|
1952
|
+
- { id: T2, target: auth, category: I, threat: Verbose error reveals whether the email exists, mitigation: One generic message, severity: medium, status: open }
|
|
1953
|
+
- { id: T3, target: users, category: T, threat: Password hash column altered by an admin, mitigation: Audit log + Argon2id, severity: high, status: accepted }
|
|
1954
|
+
```
|
|
1955
|
+
|
|
1956
|
+
### Use cases
|
|
1957
|
+
|
|
1958
|
+
Who uses the system for what, and which cases include or extend others.
|
|
1959
|
+
|
|
1960
|
+
```usecase
|
|
1961
|
+
system: Ticketing
|
|
1962
|
+
actors:
|
|
1963
|
+
- { id: cust, name: Customer }
|
|
1964
|
+
- { id: agent, name: Support agent }
|
|
1965
|
+
- { id: pay, name: Payment gateway, kind: system, side: right }
|
|
1966
|
+
cases:
|
|
1967
|
+
- { id: buy, name: Buy ticket }
|
|
1968
|
+
- { id: pay1, name: Pay by card }
|
|
1969
|
+
- { id: refund, name: Request refund }
|
|
1970
|
+
- { id: approve, name: Approve refund }
|
|
1971
|
+
links:
|
|
1972
|
+
- cust -> buy
|
|
1973
|
+
- cust -> refund
|
|
1974
|
+
- agent -> approve
|
|
1975
|
+
- pay -> pay1
|
|
1976
|
+
relations:
|
|
1977
|
+
- { from: buy, to: pay1, kind: include }
|
|
1978
|
+
- { from: refund, to: approve, kind: extend }
|
|
1979
|
+
```
|
|
1980
|
+
|
|
1981
|
+
### Package diagram
|
|
1982
|
+
|
|
1983
|
+
Which module may depend on which.
|
|
1984
|
+
|
|
1985
|
+
```pkg
|
|
1986
|
+
title: Backend module layout
|
|
1987
|
+
packages:
|
|
1988
|
+
- { id: api, col: 1, row: 1, name: api, contains: [routes, middleware] }
|
|
1989
|
+
- { id: domain, col: 2, row: 1, name: domain, contains: [orders, payments, inventory] }
|
|
1990
|
+
- { id: infra, col: 3, row: 1, name: infra, contains: [postgres, kafka, stripe] }
|
|
1991
|
+
- { id: shared, col: 2, row: 2, name: shared, contains: [ids, money, clock] }
|
|
1992
|
+
deps:
|
|
1993
|
+
- { from: api, to: domain, kind: use }
|
|
1994
|
+
- { from: domain, to: infra, kind: import, label: ports only }
|
|
1995
|
+
- { from: domain, to: shared }
|
|
1996
|
+
- { from: infra, to: shared }
|
|
1997
|
+
```
|
|
1998
|
+
|
|
1999
|
+
### Timing diagram
|
|
2000
|
+
|
|
2001
|
+
Two lifelines stepping through states over the same sixty seconds.
|
|
2002
|
+
|
|
2003
|
+
```timing
|
|
2004
|
+
title: Circuit breaker under a downstream outage
|
|
2005
|
+
unit: s
|
|
2006
|
+
lanes:
|
|
2007
|
+
- label: Breaker
|
|
2008
|
+
states:
|
|
2009
|
+
- { state: closed, from: 0, to: 12 }
|
|
2010
|
+
- { state: open, from: 12, to: 42, accent: red }
|
|
2011
|
+
- { state: half-open, from: 42, to: 46, accent: amber }
|
|
2012
|
+
- { state: closed, from: 46, to: 60 }
|
|
2013
|
+
- label: Downstream
|
|
2014
|
+
states:
|
|
2015
|
+
- { state: healthy, from: 0, to: 10 }
|
|
2016
|
+
- { state: down, from: 10, to: 44, accent: red }
|
|
2017
|
+
- { state: healthy, from: 44, to: 60 }
|
|
2018
|
+
events:
|
|
2019
|
+
- { at: 12, label: 5 failures in 10 s }
|
|
2020
|
+
- { at: 46, label: probe ok }
|
|
2021
|
+
constraints:
|
|
2022
|
+
- { from: 12, to: 42, label: open 30 s }
|
|
2023
|
+
```
|
|
2024
|
+
|
|
2025
|
+
### Neural network
|
|
2026
|
+
|
|
2027
|
+
The shape of a model, one column per layer.
|
|
2028
|
+
|
|
2029
|
+
```neuralnet
|
|
2030
|
+
title: Digit classifier
|
|
2031
|
+
params: 1.2M
|
|
2032
|
+
layers:
|
|
2033
|
+
- { label: Input, units: 784, kind: input, note: 28×28 pixels }
|
|
2034
|
+
- { label: Conv 3×3, units: 32, kind: conv, activation: ReLU }
|
|
2035
|
+
- { label: Max pool, units: 32, kind: pool }
|
|
2036
|
+
- { label: Dense, units: 128, kind: dense, activation: ReLU }
|
|
2037
|
+
- { label: Dropout 0.3, units: 128, kind: dropout }
|
|
2038
|
+
- { label: Output, units: 10, kind: output, activation: softmax }
|
|
2039
|
+
```
|
|
2040
|
+
|
|
2041
|
+
### Model card
|
|
2042
|
+
|
|
2043
|
+
The handoff card for a deployed model.
|
|
2044
|
+
|
|
2045
|
+
```modelcard
|
|
2046
|
+
name: support-intent-v3
|
|
2047
|
+
version: 3.2.0
|
|
2048
|
+
task: Text classification (support ticket intent)
|
|
2049
|
+
architecture: DistilBERT fine-tune, 6 layers
|
|
2050
|
+
params: 66M
|
|
2051
|
+
owner: ML platform
|
|
2052
|
+
license: Internal
|
|
2053
|
+
intendedUse:
|
|
2054
|
+
- Route inbound tickets to one of 14 queues
|
|
2055
|
+
- Suggest a queue to an agent; never auto-close
|
|
2056
|
+
outOfScope:
|
|
2057
|
+
- Any language other than English and Spanish
|
|
2058
|
+
trainingData:
|
|
2059
|
+
- 410k tickets, 2024-01 to 2025-06, PII scrubbed
|
|
2060
|
+
metrics:
|
|
2061
|
+
- { name: Macro F1, value: 0.91, split: test }
|
|
2062
|
+
- { name: Latency p95, value: 38 ms, split: prod, note: CPU, batch 1 }
|
|
2063
|
+
limitations:
|
|
2064
|
+
- Confuses billing and refund intents on short tickets
|
|
2065
|
+
```
|
|
2066
|
+
|
|
2067
|
+
### Mind map
|
|
2068
|
+
|
|
2069
|
+
Unordered ideas around one centre.
|
|
2070
|
+
|
|
2071
|
+
```mindmap
|
|
2072
|
+
center: Onboarding v2
|
|
2073
|
+
nodes:
|
|
2074
|
+
- { id: acct, label: Account, accent: blue }
|
|
2075
|
+
- { id: sso, parent: acct, label: SSO first }
|
|
2076
|
+
- { id: invite, parent: acct, label: Team invites }
|
|
2077
|
+
- { id: data, label: Data import, accent: teal }
|
|
2078
|
+
- { id: csv, parent: data, label: CSV }
|
|
2079
|
+
- { id: api, parent: data, label: API sync }
|
|
2080
|
+
- { id: learn, label: Learning, accent: amber }
|
|
2081
|
+
- { id: tour, parent: learn, label: Product tour }
|
|
2082
|
+
- { id: tmpl, parent: learn, label: Templates }
|
|
2083
|
+
```
|
|
2084
|
+
|
|
2085
|
+
### Process chevrons
|
|
2086
|
+
|
|
2087
|
+
The phases of a process and where we are.
|
|
2088
|
+
|
|
2089
|
+
```chevrons
|
|
2090
|
+
title: Incident lifecycle
|
|
2091
|
+
current: 3
|
|
2092
|
+
steps:
|
|
2093
|
+
- { label: Detect, desc: alert fires }
|
|
2094
|
+
- { label: Triage, desc: severity + owner }
|
|
2095
|
+
- { label: Mitigate, desc: stop the bleeding }
|
|
2096
|
+
- { label: Resolve, desc: root cause fixed }
|
|
2097
|
+
- { label: Review, desc: postmortem in 5 days }
|
|
2098
|
+
```
|
|
2099
|
+
|
|
2100
|
+
### Roadmap
|
|
2101
|
+
|
|
2102
|
+
Themes by quarter with a now rule.
|
|
2103
|
+
|
|
2104
|
+
```roadmap
|
|
2105
|
+
title: Platform roadmap 2026
|
|
2106
|
+
periods: [Q1, Q2, Q3, Q4]
|
|
2107
|
+
now: Q3
|
|
2108
|
+
themes: [Reliability, Developer experience, Cost]
|
|
2109
|
+
items:
|
|
2110
|
+
- { label: Multi-region Postgres, theme: Reliability, from: Q1, to: Q2, status: done }
|
|
2111
|
+
- { label: Chaos game days, theme: Reliability, from: Q3, status: current }
|
|
2112
|
+
- { label: Preview envs per PR, theme: Developer experience, from: Q2, to: Q3, status: current }
|
|
2113
|
+
- { label: Golden-path templates, theme: Developer experience, from: Q4, status: next }
|
|
2114
|
+
- { label: Spot instances for batch, theme: Cost, from: Q2, status: done }
|
|
2115
|
+
- { label: Egress cut 30%, theme: Cost, from: Q3, to: Q4, status: risk }
|
|
2116
|
+
```
|
|
2117
|
+
|
|
2118
|
+
## Older spellings still work
|
|
2119
|
+
|
|
2120
|
+
Twelve old block types merged into canonical blocks; their fence tags remain
|
|
2121
|
+
permanent aliases. They parse, validate, and render as before — `chiltepin check`
|
|
2122
|
+
notes the mapping with a `W_ALIAS_TYPE` warning. The four fences below use the
|
|
2123
|
+
old spellings on purpose:
|
|
2124
|
+
|
|
2125
|
+
```waterfall
|
|
2126
|
+
title: "The old waterfall tag — now chart (kind: waterfall)"
|
|
2127
|
+
unit: ms
|
|
2128
|
+
items:
|
|
2129
|
+
- { label: Gateway, value: 20 }
|
|
2130
|
+
- { label: Service, value: 90 }
|
|
2131
|
+
- { label: Database, value: 70 }
|
|
2132
|
+
```
|
|
2133
|
+
|
|
2134
|
+
```infra
|
|
2135
|
+
title: "The old infra tag — now block (preset: infra)"
|
|
2136
|
+
nodes:
|
|
2137
|
+
- { id: cdn, col: 1, row: 1, kind: cdn, name: CDN }
|
|
2138
|
+
- { id: api, col: 2, row: 1, kind: compute, name: API }
|
|
2139
|
+
- { id: db, col: 3, row: 1, kind: db, name: Database }
|
|
2140
|
+
edges:
|
|
2141
|
+
- cdn -> api
|
|
2142
|
+
- api -> db
|
|
2143
|
+
```
|
|
2144
|
+
|
|
2145
|
+
```dag
|
|
2146
|
+
title: "The old dag tag — now flow (variant: dag)"
|
|
2147
|
+
nodes:
|
|
2148
|
+
- { id: build, col: 1, row: 1, kind: start, label: Build }
|
|
2149
|
+
- { id: test, col: 2, row: 1, kind: process, label: Test }
|
|
2150
|
+
- { id: ship, col: 3, row: 1, kind: end, label: Ship }
|
|
2151
|
+
edges:
|
|
2152
|
+
- build -> test
|
|
2153
|
+
- test -> ship
|
|
2154
|
+
```
|
|
2155
|
+
|
|
2156
|
+
```tracker
|
|
2157
|
+
title: "The old tracker tag — now statustable (variant: tracker)"
|
|
2158
|
+
items:
|
|
2159
|
+
- { task: Adopt the canonical spellings, status: doing, priority: med }
|
|
2160
|
+
- { task: Rewrite old fences, status: todo, priority: low, owner: nobody — they keep working }
|
|
2161
|
+
```
|