Skip to content

Commit 9e6faec

Browse files
ankur-archclaude
andauthored
fix(blog): replace unreadable mermaid diagram in custom domains post (#7947)
* fix(blog): replace unreadable mermaid diagram with a table in custom domains post Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(blog): replace mermaid with custom SVG sequence diagram component Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 8d45ce8 commit 9e6faec

3 files changed

Lines changed: 225 additions & 17 deletions

File tree

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
const W = 750
2+
const BOX_W = 124
3+
const BOX_H = 34
4+
const BOX_R = 7
5+
const BOX_Y = 12
6+
const LIFE_Y0 = BOX_Y + BOX_H + 2
7+
const STEP_Y0 = LIFE_Y0 + 38
8+
const STEP_DY = 52
9+
const LOOP_W = 44
10+
11+
const PARTICIPANTS = ["User", "DNS provider", "Prisma Compute", "Certificate authority"]
12+
const PX = [76, 249, 430, 618]
13+
14+
type Step = { from: number; to: number; label: string; dashed?: boolean }
15+
16+
const STEPS: Step[] = [
17+
{ from: 0, to: 2, label: "Add custom domain" },
18+
{ from: 2, to: 0, label: "Return CNAME target", dashed: true },
19+
{ from: 0, to: 1, label: "Create CNAME record" },
20+
{ from: 2, to: 3, label: "Request certificate" },
21+
{ from: 3, to: 2, label: "Return http-01 challenge", dashed: true },
22+
{ from: 3, to: 2, label: "Check HTTP challenge path" },
23+
{ from: 2, to: 3, label: "Serve challenge response", dashed: true },
24+
{ from: 3, to: 2, label: "Issue TLS certificate", dashed: true },
25+
{ from: 2, to: 2, label: "Encrypt and store certificate material" },
26+
]
27+
28+
const H = STEP_Y0 + STEPS.length * STEP_DY + 24
29+
30+
export function SequenceDiagram() {
31+
return (
32+
<figure className="seq-diagram not-prose">
33+
<svg
34+
viewBox={`0 0 ${W} ${H}`}
35+
width="100%"
36+
aria-label="TLS certificate provisioning sequence diagram"
37+
role="img"
38+
>
39+
<defs>
40+
<marker
41+
id="seq-arr"
42+
viewBox="0 0 8 8"
43+
refX="7"
44+
refY="4"
45+
markerWidth="5"
46+
markerHeight="5"
47+
orient="auto"
48+
>
49+
<path d="M0,0 L8,4 L0,8 Z" className="seq-arr-fill" />
50+
</marker>
51+
<marker
52+
id="seq-arr-d"
53+
viewBox="0 0 8 8"
54+
refX="7"
55+
refY="4"
56+
markerWidth="5"
57+
markerHeight="5"
58+
orient="auto"
59+
>
60+
<path d="M0,0 L8,4 L0,8 Z" className="seq-arr-d-fill" />
61+
</marker>
62+
</defs>
63+
64+
{/* participant boxes */}
65+
{PARTICIPANTS.map((name, i) => (
66+
<g key={name}>
67+
<rect
68+
x={PX[i] - BOX_W / 2}
69+
y={BOX_Y}
70+
width={BOX_W}
71+
height={BOX_H}
72+
rx={BOX_R}
73+
className="seq-box"
74+
/>
75+
<text
76+
x={PX[i]}
77+
y={BOX_Y + BOX_H / 2}
78+
textAnchor="middle"
79+
dominantBaseline="central"
80+
className="seq-box-text"
81+
>
82+
{name}
83+
</text>
84+
</g>
85+
))}
86+
87+
{/* lifelines */}
88+
{PARTICIPANTS.map((_, i) => (
89+
<line
90+
key={i}
91+
x1={PX[i]}
92+
y1={LIFE_Y0}
93+
x2={PX[i]}
94+
y2={H - 8}
95+
strokeDasharray="3 5"
96+
className="seq-lifeline"
97+
/>
98+
))}
99+
100+
{/* steps */}
101+
{STEPS.map((step, idx) => {
102+
const y = STEP_Y0 + idx * STEP_DY
103+
const isSelf = step.from === step.to
104+
const mid = isSelf
105+
? PX[step.from] + LOOP_W + 8
106+
: (PX[step.from] + PX[step.to]) / 2
107+
const markerId = `url(#seq-arr${step.dashed ? "-d" : ""})`
108+
const arrowClass = `seq-arrow${step.dashed ? " seq-arrow-dashed" : ""}`
109+
110+
return (
111+
<g key={idx}>
112+
<circle cx={16} cy={y} r={9} className="seq-num-bg" />
113+
<text
114+
x={16}
115+
y={y}
116+
textAnchor="middle"
117+
dominantBaseline="central"
118+
className="seq-num-text"
119+
>
120+
{idx + 1}
121+
</text>
122+
123+
{isSelf ? (
124+
<path
125+
d={`M${PX[step.from]},${y - 8} H${PX[step.from] + LOOP_W} V${y + 8} H${PX[step.from]}`}
126+
fill="none"
127+
markerEnd={markerId}
128+
className={arrowClass}
129+
/>
130+
) : (
131+
<line
132+
x1={PX[step.from]}
133+
y1={y}
134+
x2={PX[step.to]}
135+
y2={y}
136+
markerEnd={markerId}
137+
className={arrowClass}
138+
/>
139+
)}
140+
141+
<text
142+
x={mid}
143+
y={y - 11}
144+
textAnchor={isSelf ? "start" : "middle"}
145+
className="seq-label"
146+
>
147+
{step.label}
148+
</text>
149+
</g>
150+
)
151+
})}
152+
</svg>
153+
</figure>
154+
)
155+
}

apps/blog/content/blog/prisma-compute-custom-domains/index.mdx

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ series: prisma-compute
1414
seriesIndex: 3
1515
---
1616

17+
import { SequenceDiagram } from "./SequenceDiagram"
18+
1719
We launched Prisma Compute with custom domain support. You can add a domain to a Compute service, point one DNS record at Prisma, and let Prisma Compute handle certificate provisioning and routing behind the scenes.
1820

1921
This is a small but incredibly important feature. Custom domains give you a stable, public URL that you own for sharing and integrating. In this post, we'll get into the behind-the-scenes work that handles DNS, certificate provisioning, certificate storage, and request routing correctly. Let's get into how we approached it.
@@ -53,23 +55,7 @@ The proof step is where things get interesting. ACME supports several challenge
5355

5456
That maps well to Compute's custom domain flow. Once the user creates the CNAME and DNS starts resolving to Compute, HTTP traffic for the domain reaches Prisma's routing layer. Even though we do not have the final certificate yet, we can serve the ACME challenge response for the certificate authority. The challenge is used only for certificate issuance; the user does not need to see it, configure it, or respond to it.
5557

56-
```mermaid
57-
sequenceDiagram
58-
participant User as User
59-
participant DNS as DNS provider
60-
participant Compute as Prisma Compute
61-
participant ACME as Certificate authority
62-
63-
User->>Compute: Add custom domain
64-
Compute-->>User: Return CNAME target
65-
User->>DNS: Create CNAME record
66-
Compute->>ACME: Request certificate
67-
ACME-->>Compute: Return http-01 challenge
68-
ACME->>Compute: Check HTTP challenge path
69-
Compute-->>ACME: Serve challenge response
70-
ACME-->>Compute: Issue TLS certificate
71-
Compute->>Compute: Encrypt and store certificate material
72-
```
58+
<SequenceDiagram />
7359

7460
In this flow, the user handles the domain assignment and DNS record. Compute handles the certificate request, challenge response, certificate retrieval, encryption, and storage. The user experience stays focused on the single DNS step, and automatic provisioning can complete quickly once DNS resolves.
7561

apps/blog/src/app/global.css

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1640,3 +1640,70 @@
16401640
font-size: 0.875rem;
16411641
line-height: 1.1;
16421642
}
1643+
1644+
/* ── Sequence diagram ───────────────────────────────────────────────── */
1645+
.seq-diagram {
1646+
--seq-accent: #5fb878;
1647+
--seq-accent-bg: color-mix(in srgb, #5fb878 15%, transparent);
1648+
margin: 1.75rem 0;
1649+
border: 1px solid var(--color-stroke-neutral);
1650+
border-radius: 10px;
1651+
background: var(--color-background-default);
1652+
padding: 12px 16px 16px;
1653+
overflow-x: auto;
1654+
}
1655+
1656+
.seq-box {
1657+
fill: color-mix(in srgb, var(--color-foreground-ppg) 6%, var(--color-background-default));
1658+
stroke: var(--color-stroke-neutral);
1659+
stroke-width: 1.5;
1660+
}
1661+
1662+
.seq-box-text {
1663+
fill: var(--color-foreground-neutral);
1664+
font-family: var(--font-sans, ui-sans-serif, system-ui, sans-serif);
1665+
font-size: 11.5px;
1666+
font-weight: 600;
1667+
}
1668+
1669+
.seq-lifeline {
1670+
stroke: var(--color-stroke-neutral);
1671+
stroke-width: 1;
1672+
}
1673+
1674+
.seq-arrow {
1675+
stroke: var(--color-foreground-neutral);
1676+
stroke-width: 1.5;
1677+
}
1678+
1679+
.seq-arrow-dashed {
1680+
stroke: color-mix(in srgb, var(--color-foreground-neutral) 55%, transparent);
1681+
stroke-dasharray: 5 3;
1682+
}
1683+
1684+
.seq-arr-fill {
1685+
fill: var(--color-foreground-neutral);
1686+
}
1687+
1688+
.seq-arr-d-fill {
1689+
fill: color-mix(in srgb, var(--color-foreground-neutral) 55%, transparent);
1690+
}
1691+
1692+
.seq-label {
1693+
fill: var(--color-foreground-neutral);
1694+
font-family: var(--font-sans, ui-sans-serif, system-ui, sans-serif);
1695+
font-size: 11px;
1696+
}
1697+
1698+
.seq-num-bg {
1699+
fill: var(--seq-accent-bg);
1700+
stroke: var(--seq-accent);
1701+
stroke-width: 1;
1702+
}
1703+
1704+
.seq-num-text {
1705+
fill: var(--seq-accent);
1706+
font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
1707+
font-size: 9px;
1708+
font-weight: 700;
1709+
}

0 commit comments

Comments
 (0)