<div class="chartlet-wrapper"><style>.chartlet-stage{position:relative;display:inline-block;max-width:100%;vertical-align:top}.chartlet-stage>svg{display:block}.chartlet-hotspot{position:absolute;border-radius:8px;cursor:pointer}.chartlet-focus{margin:0 0 12px 0;font-size:13px}.chartlet-focus summary{cursor:pointer;min-height:24px}.chartlet-focus fieldset{border:none;padding:0;margin:4px 0 0 0}.chartlet-focus label{display:inline-flex;align-items:center;min-height:44px;margin-right:14px;cursor:pointer;white-space:nowrap}.chartlet-focus input{margin-right:4px}.chartlet-focus input:focus-visible{outline:2px solid #2563eb;outline-offset:2px}.chartlet-wrapper:has(.chartlet-focus-node:checked) #chartlet-0cad13a20646171f .chartlet-f{opacity:.18}#chartlet-0cad13a20646171f-hs-0{left:45.481%;top:1.277%;width:13%;height:5.745%}#chartlet-0cad13a20646171f-hs-1{left:45.229%;top:19.313%;width:13.505%;height:6.596%}#chartlet-0cad13a20646171f-hs-2{left:45.435%;top:34.827%;width:13.093%;height:5.319%}#chartlet-0cad13a20646171f-hs-3{left:27.22%;top:55.5%;width:13.148%;height:5.319%}#chartlet-0cad13a20646171f-hs-4{left:26.863%;top:68.461%;width:13.863%;height:5.319%}#chartlet-0cad13a20646171f-hs-5{left:43.868%;top:54.968%;width:16.228%;height:6.383%}#chartlet-0cad13a20646171f-hs-6{left:16.676%;top:83.903%;width:15.254%;height:5.745%}#chartlet-0cad13a20646171f-hs-7{left:67.345%;top:56.245%;width:17.479%;height:3.83%}#chartlet-0cad13a20646171f-hs-8{left:30.023%;top:94.468%;width:14.814%;height:3.83%}.chartlet-wrapper:has(#chartlet-0cad13a20646171f-focus-0:checked) #chartlet-0cad13a20646171f .chartlet-f-0{opacity:1}.chartlet-wrapper:has(#chartlet-0cad13a20646171f-focus-0:checked) #chartlet-0cad13a20646171f .chartlet-n-0 .chartlet-flow-node,.chartlet-wrapper:has(#chartlet-0cad13a20646171f-focus-0:checked) #chartlet-0cad13a20646171f .chartlet-n-0 .chartlet-seq-box{stroke-width:3}.chartlet-wrapper:has(#chartlet-0cad13a20646171f-focus-1:checked) #chartlet-0cad13a20646171f .chartlet-f-1{opacity:1}.chartlet-wrapper:has(#chartlet-0cad13a20646171f-focus-1:checked) #chartlet-0cad13a20646171f .chartlet-n-1 .chartlet-flow-node,.chartlet-wrapper:has(#chartlet-0cad13a20646171f-focus-1:checked) #chartlet-0cad13a20646171f .chartlet-n-1 .chartlet-seq-box{stroke-width:3}.chartlet-wrapper:has(#chartlet-0cad13a20646171f-focus-2:checked) #chartlet-0cad13a20646171f .chartlet-f-2{opacity:1}.chartlet-wrapper:has(#chartlet-0cad13a20646171f-focus-2:checked) #chartlet-0cad13a20646171f .chartlet-n-2 .chartlet-flow-node,.chartlet-wrapper:has(#chartlet-0cad13a20646171f-focus-2:checked) #chartlet-0cad13a20646171f .chartlet-n-2 .chartlet-seq-box{stroke-width:3}.chartlet-wrapper:has(#chartlet-0cad13a20646171f-focus-3:checked) #chartlet-0cad13a20646171f .chartlet-f-3{opacity:1}.chartlet-wrapper:has(#chartlet-0cad13a20646171f-focus-3:checked) #chartlet-0cad13a20646171f .chartlet-n-3 .chartlet-flow-node,.chartlet-wrapper:has(#chartlet-0cad13a20646171f-focus-3:checked) #chartlet-0cad13a20646171f .chartlet-n-3 .chartlet-seq-box{stroke-width:3}.chartlet-wrapper:has(#chartlet-0cad13a20646171f-focus-4:checked) #chartlet-0cad13a20646171f .chartlet-f-4{opacity:1}.chartlet-wrapper:has(#chartlet-0cad13a20646171f-focus-4:checked) #chartlet-0cad13a20646171f .chartlet-n-4 .chartlet-flow-node,.chartlet-wrapper:has(#chartlet-0cad13a20646171f-focus-4:checked) #chartlet-0cad13a20646171f .chartlet-n-4 .chartlet-seq-box{stroke-width:3}.chartlet-wrapper:has(#chartlet-0cad13a20646171f-focus-5:checked) #chartlet-0cad13a20646171f .chartlet-f-5{opacity:1}.chartlet-wrapper:has(#chartlet-0cad13a20646171f-focus-5:checked) #chartlet-0cad13a20646171f .chartlet-n-5 .chartlet-flow-node,.chartlet-wrapper:has(#chartlet-0cad13a20646171f-focus-5:checked) #chartlet-0cad13a20646171f .chartlet-n-5 .chartlet-seq-box{stroke-width:3}.chartlet-wrapper:has(#chartlet-0cad13a20646171f-focus-6:checked) #chartlet-0cad13a20646171f .chartlet-f-6{opacity:1}.chartlet-wrapper:has(#chartlet-0cad13a20646171f-focus-6:checked) #chartlet-0cad13a20646171f .chartlet-n-6 .chartlet-flow-node,.chartlet-wrapper:has(#chartlet-0cad13a20646171f-focus-6:checked) #chartlet-0cad13a20646171f .chartlet-n-6 .chartlet-seq-box{stroke-width:3}.chartlet-wrapper:has(#chartlet-0cad13a20646171f-focus-7:checked) #chartlet-0cad13a20646171f .chartlet-f-7{opacity:1}.chartlet-wrapper:has(#chartlet-0cad13a20646171f-focus-7:checked) #chartlet-0cad13a20646171f .chartlet-n-7 .chartlet-flow-node,.chartlet-wrapper:has(#chartlet-0cad13a20646171f-focus-7:checked) #chartlet-0cad13a20646171f .chartlet-n-7 .chartlet-seq-box{stroke-width:3}.chartlet-wrapper:has(#chartlet-0cad13a20646171f-focus-8:checked) #chartlet-0cad13a20646171f .chartlet-f-8{opacity:1}.chartlet-wrapper:has(#chartlet-0cad13a20646171f-focus-8:checked) #chartlet-0cad13a20646171f .chartlet-n-8 .chartlet-flow-node,.chartlet-wrapper:has(#chartlet-0cad13a20646171f-focus-8:checked) #chartlet-0cad13a20646171f .chartlet-n-8 .chartlet-seq-box{stroke-width:3}</style><details class="chartlet-focus"><summary>Focus</summary><fieldset><label><input type="radio" name="chartlet-0cad13a20646171f-focus" checked> Show all</label><label><input type="radio" name="chartlet-0cad13a20646171f-focus" class="chartlet-focus-node" id="chartlet-0cad13a20646171f-focus-0"> Learner</label><label><input type="radio" name="chartlet-0cad13a20646171f-focus" class="chartlet-focus-node" id="chartlet-0cad13a20646171f-focus-1"> Web app</label><label><input type="radio" name="chartlet-0cad13a20646171f-focus" class="chartlet-focus-node" id="chartlet-0cad13a20646171f-focus-2"> Booking API</label><label><input type="radio" name="chartlet-0cad13a20646171f-focus" class="chartlet-focus-node" id="chartlet-0cad13a20646171f-focus-3"> Job queue</label><label><input type="radio" name="chartlet-0cad13a20646171f-focus" class="chartlet-focus-node" id="chartlet-0cad13a20646171f-focus-4"> Worker</label><label><input type="radio" name="chartlet-0cad13a20646171f-focus" class="chartlet-focus-node" id="chartlet-0cad13a20646171f-focus-5"> Bookings</label><label><input type="radio" name="chartlet-0cad13a20646171f-focus" class="chartlet-focus-node" id="chartlet-0cad13a20646171f-focus-6"> Certificates</label><label><input type="radio" name="chartlet-0cad13a20646171f-focus" class="chartlet-focus-node" id="chartlet-0cad13a20646171f-focus-7"> Payment provider</label><label><input type="radio" name="chartlet-0cad13a20646171f-focus" class="chartlet-focus-node" id="chartlet-0cad13a20646171f-focus-8"> E-mail service</label></fieldset></details><figure class="chartlet-figure" data-viz="chart"><figcaption>Course booking: containers</figcaption><div class="chartlet-stage"><svg xmlns="http://www.w3.org/2000/svg" width="800" height="940" viewBox="0 0 800 940" id="chartlet-0cad13a20646171f" role="img" aria-labelledby="chartlet-0cad13a20646171f-title chartlet-0cad13a20646171f-description" class="chartlet-root"><title id="chartlet-0cad13a20646171f-title">Course booking: containers</title><desc id="chartlet-0cad13a20646171f-description">Architecture diagram with 9 components and 8 connections in 1 boundary. Course booking (software system): Web app, Booking API, Job queue, Worker, Bookings, Certificates. Main path: Learner → Web app → Booking API → Bookings. Most connected: Booking API (4 connections). Nothing leads into Learner. Bottlenecks: Booking API and Job queue; without either the diagram falls apart. Learner (person): connects to Web app (books a course, via HTTPS). Web app (frontend): connects to Booking API (calls, via JSON/HTTPS). Booking API (service): connects to Bookings (reads, writes, via SQL), Payment provider (takes payment, via HTTPS) and Job queue (queues jobs). Job queue (queue): connects to Worker (delivers). Bookings (database): no outgoing connection. Payment provider (external system): no outgoing connection. Worker (service): connects to Certificates (stores certificates) and E-mail service (sends confirmations, via SMTP). Certificates (storage): no outgoing connection. E-mail service (external system): no outgoing connection.</desc><style>.chartlet-root{--chartlet-text:#172033;--chartlet-muted:#344054;--chartlet-grid:#d9dee8;--chartlet-zero:#667085;--chartlet-accent:#2563eb;--chartlet-background:#fff;--chartlet-color-1:#2563eb;--chartlet-color-2:#c2410c;--chartlet-color-3:#475569;--chartlet-color-4:#111827;max-width:100%;height:auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif;color:var(--chartlet-text)}#chartlet-0cad13a20646171f .chartlet-title{font-size:22px;font-weight:650;fill:var(--chartlet-text)}#chartlet-0cad13a20646171f .chartlet-label,#chartlet-0cad13a20646171f .chartlet-tick,#chartlet-0cad13a20646171f .chartlet-value,#chartlet-0cad13a20646171f .chartlet-value-inverse,#chartlet-0cad13a20646171f .chartlet-axis-title{font-size:12px;fill:var(--chartlet-muted)}#chartlet-0cad13a20646171f .chartlet-value,#chartlet-0cad13a20646171f .chartlet-value-inverse{font-weight:600}#chartlet-0cad13a20646171f .chartlet-value{fill:var(--chartlet-text)}#chartlet-0cad13a20646171f .chartlet-value-inverse{fill:var(--chartlet-background)}#chartlet-0cad13a20646171f .chartlet-axis-title{font-weight:600}#chartlet-0cad13a20646171f .chartlet-grid{stroke:var(--chartlet-grid);stroke-width:1}#chartlet-0cad13a20646171f .chartlet-zero{stroke:var(--chartlet-zero);stroke-width:1.5}#chartlet-0cad13a20646171f .chartlet-bar,#chartlet-0cad13a20646171f .chartlet-point{fill:var(--chartlet-accent)}#chartlet-0cad13a20646171f .chartlet-line{fill:none;stroke:var(--chartlet-accent);stroke-width:3;stroke-linecap:round;stroke-linejoin:round}#chartlet-0cad13a20646171f .chartlet-background{fill:var(--chartlet-background)}.chartlet-root{--chartlet-node:#eef3fd;--chartlet-lane:#f7f9fc;--chartlet-lane-head:#eef1f6;--chartlet-shadow:rgba(16,24,40,.09);--chartlet-role-blue:#2563eb;--chartlet-role-blue-fill:#eef3fd;--chartlet-role-green:#15803d;--chartlet-role-green-fill:#ecfdf3;--chartlet-role-amber:#b45309;--chartlet-role-amber-fill:#fff7e8;--chartlet-role-teal:#0f766e;--chartlet-role-teal-fill:#e9faf7;--chartlet-role-violet:#6d28d9;--chartlet-role-violet-fill:#f3efff;--chartlet-role-gray:#667085;--chartlet-role-gray-fill:#f7f8fa;--chartlet-role-red:#b42318;--chartlet-role-red-fill:#fef3f2}.chartlet-root.chartlet-theme-dark{--chartlet-node:#1a2436;--chartlet-lane:#121925;--chartlet-lane-head:#18212f;--chartlet-shadow:rgba(0,0,0,.45);--chartlet-role-blue:#7ea6ff;--chartlet-role-blue-fill:#1a2436;--chartlet-role-green:#4ade80;--chartlet-role-green-fill:#132a1d;--chartlet-role-amber:#fbbf24;--chartlet-role-amber-fill:#2b2210;--chartlet-role-teal:#2dd4bf;--chartlet-role-teal-fill:#0f2a27;--chartlet-role-violet:#b69cff;--chartlet-role-violet-fill:#231c38;--chartlet-role-gray:#9aa7bd;--chartlet-role-gray-fill:#161d29;--chartlet-role-red:#f97066;--chartlet-role-red-fill:#2d1616}#chartlet-0cad13a20646171f .chartlet-role-blue{fill:var(--chartlet-role-blue-fill);stroke:var(--chartlet-role-blue)}#chartlet-0cad13a20646171f .chartlet-role-green{fill:var(--chartlet-role-green-fill);stroke:var(--chartlet-role-green)}#chartlet-0cad13a20646171f .chartlet-role-amber{fill:var(--chartlet-role-amber-fill);stroke:var(--chartlet-role-amber)}#chartlet-0cad13a20646171f .chartlet-role-teal{fill:var(--chartlet-role-teal-fill);stroke:var(--chartlet-role-teal)}#chartlet-0cad13a20646171f .chartlet-role-violet{fill:var(--chartlet-role-violet-fill);stroke:var(--chartlet-role-violet)}#chartlet-0cad13a20646171f .chartlet-role-gray{fill:var(--chartlet-role-gray-fill);stroke:var(--chartlet-role-gray)}#chartlet-0cad13a20646171f .chartlet-role-red{fill:var(--chartlet-role-red-fill);stroke:var(--chartlet-role-red)}#chartlet-0cad13a20646171f .chartlet-diagram-rim{fill:none;stroke:var(--chartlet-role-teal);stroke-width:1.5}#chartlet-0cad13a20646171f .chartlet-diagram-shadow{fill:var(--chartlet-shadow);stroke:none;rx:7px}#chartlet-0cad13a20646171f .chartlet-diagram-chip{fill:var(--chartlet-background);stroke:var(--chartlet-grid);stroke-width:1;rx:4px}#chartlet-0cad13a20646171f .chartlet-diagram-chip-text{font-size:12px;fill:var(--chartlet-text)}#chartlet-0cad13a20646171f .chartlet-diagram-badge{fill:var(--chartlet-accent);stroke:var(--chartlet-background);stroke-width:2}#chartlet-0cad13a20646171f .chartlet-diagram-badge-text{font-size:10px;font-weight:700;fill:var(--chartlet-background)}#chartlet-0cad13a20646171f .chartlet-flow-node{stroke-width:1.5;stroke-linejoin:round;rx:7px}#chartlet-0cad13a20646171f .chartlet-flow-start{stroke-width:2}#chartlet-0cad13a20646171f .chartlet-flow-end{stroke-width:3}#chartlet-0cad13a20646171f .chartlet-flow-external{stroke-dasharray:5 3}#chartlet-0cad13a20646171f .chartlet-flow-inner{stroke:var(--chartlet-role-blue);stroke-width:1}#chartlet-0cad13a20646171f .chartlet-flow-label{font-size:13px;font-weight:600;fill:var(--chartlet-text)}#chartlet-0cad13a20646171f .chartlet-flow-sublabel{font-size:11px;fill:var(--chartlet-muted)}#chartlet-0cad13a20646171f .chartlet-flow-edge{fill:none;stroke:var(--chartlet-zero);stroke-width:1.4;stroke-linejoin:round}#chartlet-0cad13a20646171f .chartlet-flow-dashed{stroke-dasharray:5 4}#chartlet-0cad13a20646171f .chartlet-flow-dotted{stroke-dasharray:1 4;stroke-linecap:round}#chartlet-0cad13a20646171f .chartlet-flow-main{stroke:var(--chartlet-accent);stroke-width:2.2}#chartlet-0cad13a20646171f .chartlet-flow-head{fill:var(--chartlet-zero);stroke:var(--chartlet-zero);stroke-width:1;stroke-linejoin:round}#chartlet-0cad13a20646171f .chartlet-flow-main-head{fill:var(--chartlet-accent);stroke:var(--chartlet-accent)}#chartlet-0cad13a20646171f .chartlet-flow-lane{fill:var(--chartlet-lane);stroke:var(--chartlet-grid);stroke-width:1}#chartlet-0cad13a20646171f .chartlet-flow-lane-alt{fill:var(--chartlet-background)}#chartlet-0cad13a20646171f .chartlet-flow-lane-head{fill:var(--chartlet-lane-head);stroke:none}#chartlet-0cad13a20646171f .chartlet-flow-lane-label{font-size:11px;font-weight:650;fill:var(--chartlet-muted);letter-spacing:.04em}#chartlet-0cad13a20646171f .chartlet-flow-group{fill:var(--chartlet-accent);fill-opacity:.04;stroke:var(--chartlet-zero);stroke-width:1;stroke-dasharray:4 3;rx:10px}#chartlet-0cad13a20646171f .chartlet-flow-group-label{font-size:11px;font-weight:600;fill:var(--chartlet-muted)}#chartlet-0cad13a20646171f .chartlet-arch-head{fill:var(--chartlet-role-violet-fill);stroke:var(--chartlet-role-violet);stroke-width:1.5}#chartlet-0cad13a20646171f .chartlet-arch-dot{fill:var(--chartlet-role-blue);stroke:none}</style><rect x="121.41" y="153.544" width="371.351" height="701.145" class="chartlet-flow-group"/><text x="129.41" y="166.544" text-anchor="start" class="chartlet-flow-group-label">Course booking (software system)</text><g class="chartlet-f chartlet-f-0 chartlet-f-1"><polyline points="415.85,66 415.85,173.544" class="chartlet-flow-edge chartlet-flow-main"><title>Learner → Web app: books a course [HTTPS]</title></polyline><polyline points="412.35,173.544 415.85,181.544 419.35,173.544 412.35,173.544" class="chartlet-flow-head chartlet-flow-main-head"/></g><g class="chartlet-f chartlet-f-1 chartlet-f-2"><polyline points="415.85,243.544 415.85,319.369" class="chartlet-flow-edge chartlet-flow-main"><title>Web app → Booking API: calls [JSON/HTTPS]</title></polyline><polyline points="412.35,319.369 415.85,327.369 419.35,319.369 412.35,319.369" class="chartlet-flow-head chartlet-flow-main-head"/></g><g class="chartlet-f chartlet-f-2 chartlet-f-5"><polyline points="415.85,377.369 415.85,508.701" class="chartlet-flow-edge chartlet-flow-main"><title>Booking API → Bookings: reads, writes [SQL]</title></polyline><polyline points="412.35,508.701 415.85,516.701 419.35,508.701 412.35,508.701" class="chartlet-flow-head chartlet-flow-main-head"/></g><g class="chartlet-f chartlet-f-2 chartlet-f-7"><polyline points="439.85,377.369 439.85,489.515 608.675,489.515 608.675,520.701" class="chartlet-flow-edge"><title>Booking API → Payment provider: takes payment [HTTPS]</title></polyline><polyline points="605.175,520.701 608.675,528.701 612.175,520.701 605.175,520.701" class="chartlet-flow-head"/></g><g class="chartlet-f chartlet-f-2 chartlet-f-3"><polyline points="391.85,377.369 391.85,489.515 270.35,489.515 270.35,513.701" class="chartlet-flow-edge"><title>Booking API → Job queue: queues jobs</title></polyline><polyline points="266.85,513.701 270.35,521.701 273.85,513.701 266.85,513.701" class="chartlet-flow-head"/></g><g class="chartlet-f chartlet-f-3 chartlet-f-4"><polyline points="270.35,571.701 270.35,635.535" class="chartlet-flow-edge"><title>Job queue → Worker: delivers</title></polyline><polyline points="266.85,635.535 270.35,643.535 273.85,635.535 266.85,635.535" class="chartlet-flow-head"/></g><g class="chartlet-f chartlet-f-4 chartlet-f-6"><polyline points="258.35,693.535 258.35,761.502 194.425,761.502 194.425,780.689" class="chartlet-flow-edge"><title>Worker → Certificates: stores certificates</title></polyline><polyline points="190.925,780.689 194.425,788.689 197.925,780.689 190.925,780.689" class="chartlet-flow-head"/></g><g class="chartlet-f chartlet-f-4 chartlet-f-8"><polyline points="282.35,693.535 282.35,761.502 299.44,761.502 299.44,880" class="chartlet-flow-edge"><title>Worker → E-mail service: sends confirmations [SMTP]</title></polyline><polyline points="295.94,880 299.44,888 302.94,880 295.94,880" class="chartlet-flow-head"/></g><g class="chartlet-f chartlet-n-0 chartlet-f-0 chartlet-f-1"></g><g class="chartlet-f chartlet-n-1 chartlet-f-0 chartlet-f-1 chartlet-f-2"></g><g class="chartlet-f chartlet-n-2 chartlet-f-1 chartlet-f-2 chartlet-f-3 chartlet-f-5 chartlet-f-7"></g><g class="chartlet-f chartlet-n-3 chartlet-f-2 chartlet-f-3 chartlet-f-4"></g><g class="chartlet-f chartlet-n-4 chartlet-f-3 chartlet-f-4 chartlet-f-6 chartlet-f-8"></g><g class="chartlet-f chartlet-n-5 chartlet-f-2 chartlet-f-5"></g><g class="chartlet-f chartlet-n-6 chartlet-f-4 chartlet-f-6"></g><g class="chartlet-f chartlet-n-7 chartlet-f-2 chartlet-f-7"></g><g class="chartlet-f chartlet-n-8 chartlet-f-4 chartlet-f-8"></g><g class="chartlet-f chartlet-f-0 chartlet-f-1"><rect x="419.85" y="71" width="98.32" height="36" class="chartlet-diagram-chip"/><text x="424.85" y="85" text-anchor="start" class="chartlet-diagram-chip-text">books a course</text><text x="424.85" y="100" text-anchor="start" class="chartlet-diagram-chip-text">[HTTPS]</text></g><g class="chartlet-f chartlet-f-1 chartlet-f-2"><rect x="419.85" y="248.544" width="102.52" height="36" class="chartlet-diagram-chip"/><text x="424.85" y="262.544" text-anchor="start" class="chartlet-diagram-chip-text">calls</text><text x="424.85" y="277.544" text-anchor="start" class="chartlet-diagram-chip-text">[JSON/HTTPS]</text></g><g class="chartlet-f chartlet-f-2 chartlet-f-5"><rect x="443.85" y="382.369" width="92.32" height="36" class="chartlet-diagram-chip"/><text x="448.85" y="396.369" text-anchor="start" class="chartlet-diagram-chip-text">reads, writes</text><text x="448.85" y="411.369" text-anchor="start" class="chartlet-diagram-chip-text">[SQL]</text></g><g class="chartlet-f chartlet-f-2 chartlet-f-7"><rect x="443.85" y="421.369" width="98.56" height="36" class="chartlet-diagram-chip"/><text x="448.85" y="435.369" text-anchor="start" class="chartlet-diagram-chip-text">takes payment</text><text x="448.85" y="450.369" text-anchor="start" class="chartlet-diagram-chip-text">[HTTPS]</text></g><g class="chartlet-f chartlet-f-2 chartlet-f-3"><rect x="309.93" y="382.369" width="77.92" height="21" class="chartlet-diagram-chip"/><text x="382.85" y="396.369" text-anchor="end" class="chartlet-diagram-chip-text">queues jobs</text></g><g class="chartlet-f chartlet-f-3 chartlet-f-4"><rect x="274.35" y="576.701" width="57.52" height="21" class="chartlet-diagram-chip"/><text x="279.35" y="590.701" text-anchor="start" class="chartlet-diagram-chip-text">delivers</text></g><g class="chartlet-f chartlet-f-4 chartlet-f-6"><rect x="125.79" y="698.535" width="128.56" height="21" class="chartlet-diagram-chip"/><text x="249.35" y="712.535" text-anchor="end" class="chartlet-diagram-chip-text">stores certificates</text></g><g class="chartlet-f chartlet-f-4 chartlet-f-8"><rect x="286.35" y="698.535" width="132.64" height="36" class="chartlet-diagram-chip"/><text x="291.35" y="712.535" text-anchor="start" class="chartlet-diagram-chip-text">sends confirmations</text><text x="291.35" y="727.535" text-anchor="start" class="chartlet-diagram-chip-text">[SMTP]</text></g><g class="chartlet-f chartlet-n-0 chartlet-f-0 chartlet-f-1"><rect x="363.85" y="14.5" width="104" height="54" class="chartlet-diagram-shadow"/><rect x="363.85" y="12" width="104" height="54" class="chartlet-flow-node chartlet-role-violet"><title>Learner</title></rect><circle cx="415.85" cy="23" r="6" class="chartlet-arch-head"/><text x="415.85" y="51.5" text-anchor="middle" class="chartlet-flow-label">Learner</text></g><g class="chartlet-f chartlet-n-1 chartlet-f-0 chartlet-f-1 chartlet-f-2"><rect x="361.83" y="184.044" width="108.04" height="62" class="chartlet-diagram-shadow"/><rect x="361.83" y="181.544" width="108.04" height="62" class="chartlet-flow-node chartlet-role-blue"><title>Web app – single-page app</title></rect><line x1="361.83" y1="193.544" x2="469.87" y2="193.544" class="chartlet-flow-inner"/><circle cx="369.83" cy="187.544" r="1.8" class="chartlet-arch-dot"/><circle cx="375.83" cy="187.544" r="1.8" class="chartlet-arch-dot"/><circle cx="381.83" cy="187.544" r="1.8" class="chartlet-arch-dot"/><text x="415.85" y="216.044" text-anchor="middle" class="chartlet-flow-label">Web app</text><text x="415.85" y="230.044" text-anchor="middle" class="chartlet-flow-sublabel">single-page app</text></g><g class="chartlet-f chartlet-n-2 chartlet-f-1 chartlet-f-2 chartlet-f-3 chartlet-f-5 chartlet-f-7"><rect x="363.48" y="329.869" width="104.74" height="50" class="chartlet-diagram-shadow"/><rect x="363.48" y="327.369" width="104.74" height="50" class="chartlet-flow-node chartlet-role-blue"><title>Booking API – API application</title></rect><text x="415.85" y="349.869" text-anchor="middle" class="chartlet-flow-label">Booking API</text><text x="415.85" y="363.869" text-anchor="middle" class="chartlet-flow-sublabel">API application</text></g><g class="chartlet-f chartlet-n-3 chartlet-f-2 chartlet-f-3 chartlet-f-4"><rect x="221.76" y="520.201" width="105.18" height="50" class="chartlet-diagram-shadow"/><rect x="221.76" y="517.701" width="105.18" height="50" class="chartlet-flow-node chartlet-role-violet"/><rect x="217.76" y="524.201" width="105.18" height="50" class="chartlet-diagram-shadow"/><rect x="217.76" y="521.701" width="105.18" height="50" class="chartlet-flow-node chartlet-role-violet"><title>Job queue – message queue</title></rect><text x="270.35" y="544.201" text-anchor="middle" class="chartlet-flow-label">Job queue</text><text x="270.35" y="558.201" text-anchor="middle" class="chartlet-flow-sublabel">message queue</text></g><g class="chartlet-f chartlet-n-4 chartlet-f-3 chartlet-f-4 chartlet-f-6 chartlet-f-8"><rect x="214.9" y="646.035" width="110.9" height="50" class="chartlet-diagram-shadow"/><rect x="214.9" y="643.535" width="110.9" height="50" class="chartlet-flow-node chartlet-role-blue"><title>Worker – background jobs</title></rect><text x="270.35" y="666.035" text-anchor="middle" class="chartlet-flow-label">Worker</text><text x="270.35" y="680.035" text-anchor="middle" class="chartlet-flow-sublabel">background jobs</text></g><g class="chartlet-f chartlet-n-5 chartlet-f-2 chartlet-f-5"><polyline points="350.94,524.201 350.94,574.201 353.152,575.495 359.637,576.701 369.952,577.737 383.395,578.531 399.05,579.031 415.85,579.201 432.65,579.031 448.305,578.531 461.749,577.737 472.064,576.701 478.549,575.495 480.76,574.201 480.76,524.201 478.549,522.907 472.064,521.701 461.749,520.666 448.305,519.871 432.65,519.372 415.85,519.201 399.05,519.372 383.395,519.871 369.952,520.666 359.637,521.701 353.152,522.907 350.94,524.201 350.94,524.201" class="chartlet-diagram-shadow"/><polyline points="350.94,521.701 350.94,571.701 353.152,572.995 359.637,574.201 369.952,575.237 383.395,576.031 399.05,576.531 415.85,576.701 432.65,576.531 448.305,576.031 461.749,575.237 472.064,574.201 478.549,572.995 480.76,571.701 480.76,521.701 478.549,520.407 472.064,519.201 461.749,518.166 448.305,517.371 432.65,516.872 415.85,516.701 399.05,516.872 383.395,517.371 369.952,518.166 359.637,519.201 353.152,520.407 350.94,521.701 350.94,521.701" class="chartlet-flow-node chartlet-role-teal"><title>Bookings – relational database</title></polyline><polyline points="350.94,521.701 353.152,522.995 359.637,524.201 369.952,525.237 383.395,526.031 399.05,526.531 415.85,526.701 432.65,526.531 448.305,526.031 461.749,525.237 472.064,524.201 478.549,522.995 480.76,521.701" class="chartlet-diagram-rim"/><text x="415.85" y="547.201" text-anchor="middle" class="chartlet-flow-label">Bookings</text><text x="415.85" y="561.201" text-anchor="middle" class="chartlet-flow-sublabel">relational database</text></g><g class="chartlet-f chartlet-n-6 chartlet-f-4 chartlet-f-6"><polyline points="133.41,791.189 255.44,791.189 247.44,845.189 141.41,845.189 133.41,791.189" class="chartlet-diagram-shadow"/><polyline points="133.41,788.689 255.44,788.689 247.44,842.689 141.41,842.689 133.41,788.689" class="chartlet-flow-node chartlet-role-teal"><title>Certificates – file store</title></polyline><text x="194.425" y="813.189" text-anchor="middle" class="chartlet-flow-label">Certificates</text><text x="194.425" y="827.189" text-anchor="middle" class="chartlet-flow-sublabel">file store</text></g><g class="chartlet-f chartlet-n-7 chartlet-f-2 chartlet-f-7"><rect x="538.76" y="531.201" width="139.83" height="36" class="chartlet-diagram-shadow"/><rect x="538.76" y="528.701" width="139.83" height="36" class="chartlet-flow-node chartlet-flow-external chartlet-role-gray"><title>Payment provider</title></rect><text x="608.675" y="551.201" text-anchor="middle" class="chartlet-flow-label">Payment provider</text></g><g class="chartlet-f chartlet-n-8 chartlet-f-4 chartlet-f-8"><rect x="240.185" y="890.5" width="118.51" height="36" class="chartlet-diagram-shadow"/><rect x="240.185" y="888" width="118.51" height="36" class="chartlet-flow-node chartlet-flow-external chartlet-role-gray"><title>E-mail service</title></rect><text x="299.44" y="910.5" text-anchor="middle" class="chartlet-flow-label">E-mail service</text></g></svg><label class="chartlet-hotspot" id="chartlet-0cad13a20646171f-hs-0" for="chartlet-0cad13a20646171f-focus-0"></label><label class="chartlet-hotspot" id="chartlet-0cad13a20646171f-hs-1" for="chartlet-0cad13a20646171f-focus-1"></label><label class="chartlet-hotspot" id="chartlet-0cad13a20646171f-hs-2" for="chartlet-0cad13a20646171f-focus-2"></label><label class="chartlet-hotspot" id="chartlet-0cad13a20646171f-hs-3" for="chartlet-0cad13a20646171f-focus-3"></label><label class="chartlet-hotspot" id="chartlet-0cad13a20646171f-hs-4" for="chartlet-0cad13a20646171f-focus-4"></label><label class="chartlet-hotspot" id="chartlet-0cad13a20646171f-hs-5" for="chartlet-0cad13a20646171f-focus-5"></label><label class="chartlet-hotspot" id="chartlet-0cad13a20646171f-hs-6" for="chartlet-0cad13a20646171f-focus-6"></label><label class="chartlet-hotspot" id="chartlet-0cad13a20646171f-hs-7" for="chartlet-0cad13a20646171f-focus-7"></label><label class="chartlet-hotspot" id="chartlet-0cad13a20646171f-hs-8" for="chartlet-0cad13a20646171f-focus-8"></label></div><details class="chartlet-data" data-viz-text><summary>Show chart data</summary><table><caption>Data for Course booking: containers</caption><thead><tr><th scope="col">Component</th><th scope="col">Kind</th><th scope="col">Boundary</th><th scope="col">Connects to</th></tr></thead><tbody><tr><th scope="row">Learner</th><td>person</td><td></td><td>Web app (books a course, via HTTPS)</td></tr><tr><th scope="row">Web app</th><td>frontend</td><td>Course booking (software system)</td><td>Booking API (calls, via JSON/HTTPS)</td></tr><tr><th scope="row">Booking API</th><td>service</td><td>Course booking (software system)</td><td>Bookings (reads, writes, via SQL), Payment provider (takes payment, via HTTPS), Job queue (queues jobs)</td></tr><tr><th scope="row">Job queue</th><td>queue</td><td>Course booking (software system)</td><td>Worker (delivers)</td></tr><tr><th scope="row">Bookings</th><td>database</td><td>Course booking (software system)</td><td></td></tr><tr><th scope="row">Payment provider</th><td>external system</td><td></td><td></td></tr><tr><th scope="row">Worker</th><td>service</td><td>Course booking (software system)</td><td>Certificates (stores certificates), E-mail service (sends confirmations, via SMTP)</td></tr><tr><th scope="row">Certificates</th><td>storage</td><td>Course booking (software system)</td><td></td></tr><tr><th scope="row">E-mail service</th><td>external system</td><td></td><td></td></tr></tbody></table></details></figure></div>