Files
libnovel/docs/d2/api-routing.svg
Admin 040072c3f5
All checks were successful
CI / Backend (pull_request) Successful in 33s
CI / UI (pull_request) Successful in 40s
docs(d2): update architecture and api-routing diagrams to current state
architecture.d2:
- Split app into prod VPS (165.22.70.138) and homelab runner (192.168.0.109)
- Add CrowdSec, Dozzle agent, pocket-tts (voice samples)
- Valkey now shown as Asynq job queue in addition to presign cache
- Add caddy-l4 Redis TCP proxy (:6380) to Caddy label
- Add CI/CD node (Gitea Actions) with full job list incl. releases.json bake
- Remove runner from prod app group (it runs on homelab only)
- Watchtower: note runner is label-disabled on prod

api-routing.d2:
- Add /api/presign/* routes to backend (presign_be group)
- Add /api/audio POST + status GET to both sk and be
- Add /api/scrape/book and /api/scrape/book/range to scrape_sk
- Catalogue: annotate Meilisearch vs legacy browse
- Add Meilisearch filter/sort fields to storage node
- Add Asynq queue note to Valkey storage node
- Fix presign proxy: sk routes through be.presign_be, not directly to storage
2026-03-28 22:44:31 +05:00

129 lines
60 KiB
XML

<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" data-d2-version="0.7.1" preserveAspectRatio="xMinYMin meet" viewBox="0 0 4686 2293"><svg class="d2-4043408742 d2-svg" width="4686" height="2293" viewBox="49 -29 4686 2293"><rect x="49.000000" y="-29.000000" width="4686.000000" height="2293.000000" rx="0.000000" fill="#FFFFFF" class=" fill-N7" stroke-width="0" /><style type="text/css"><![CDATA[
.d2-4043408742 .text {
font-family: "d2-4043408742-font-regular";
}
@font-face {
font-family: d2-4043408742-font-regular;
src: url("data:application/font-woff;base64,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");
}
.d2-4043408742 .text-bold {
font-family: "d2-4043408742-font-bold";
}
@font-face {
font-family: d2-4043408742-font-bold;
src: url("data:application/font-woff;base64,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");
}
.d2-4043408742 .text-italic {
font-family: "d2-4043408742-font-italic";
}
@font-face {
font-family: d2-4043408742-font-italic;
src: url("data:application/font-woff;base64,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");
}]]></style><style type="text/css"><![CDATA[.shape {
shape-rendering: geometricPrecision;
stroke-linejoin: round;
}
.connection {
stroke-linecap: round;
stroke-linejoin: round;
}
.blend {
mix-blend-mode: multiply;
opacity: 0.5;
}
.d2-4043408742 .fill-N1{fill:#0A0F25;}
.d2-4043408742 .fill-N2{fill:#676C7E;}
.d2-4043408742 .fill-N3{fill:#9499AB;}
.d2-4043408742 .fill-N4{fill:#CFD2DD;}
.d2-4043408742 .fill-N5{fill:#DEE1EB;}
.d2-4043408742 .fill-N6{fill:#EEF1F8;}
.d2-4043408742 .fill-N7{fill:#FFFFFF;}
.d2-4043408742 .fill-B1{fill:#0D32B2;}
.d2-4043408742 .fill-B2{fill:#0D32B2;}
.d2-4043408742 .fill-B3{fill:#E3E9FD;}
.d2-4043408742 .fill-B4{fill:#E3E9FD;}
.d2-4043408742 .fill-B5{fill:#EDF0FD;}
.d2-4043408742 .fill-B6{fill:#F7F8FE;}
.d2-4043408742 .fill-AA2{fill:#4A6FF3;}
.d2-4043408742 .fill-AA4{fill:#EDF0FD;}
.d2-4043408742 .fill-AA5{fill:#F7F8FE;}
.d2-4043408742 .fill-AB4{fill:#EDF0FD;}
.d2-4043408742 .fill-AB5{fill:#F7F8FE;}
.d2-4043408742 .stroke-N1{stroke:#0A0F25;}
.d2-4043408742 .stroke-N2{stroke:#676C7E;}
.d2-4043408742 .stroke-N3{stroke:#9499AB;}
.d2-4043408742 .stroke-N4{stroke:#CFD2DD;}
.d2-4043408742 .stroke-N5{stroke:#DEE1EB;}
.d2-4043408742 .stroke-N6{stroke:#EEF1F8;}
.d2-4043408742 .stroke-N7{stroke:#FFFFFF;}
.d2-4043408742 .stroke-B1{stroke:#0D32B2;}
.d2-4043408742 .stroke-B2{stroke:#0D32B2;}
.d2-4043408742 .stroke-B3{stroke:#E3E9FD;}
.d2-4043408742 .stroke-B4{stroke:#E3E9FD;}
.d2-4043408742 .stroke-B5{stroke:#EDF0FD;}
.d2-4043408742 .stroke-B6{stroke:#F7F8FE;}
.d2-4043408742 .stroke-AA2{stroke:#4A6FF3;}
.d2-4043408742 .stroke-AA4{stroke:#EDF0FD;}
.d2-4043408742 .stroke-AA5{stroke:#F7F8FE;}
.d2-4043408742 .stroke-AB4{stroke:#EDF0FD;}
.d2-4043408742 .stroke-AB5{stroke:#F7F8FE;}
.d2-4043408742 .background-color-N1{background-color:#0A0F25;}
.d2-4043408742 .background-color-N2{background-color:#676C7E;}
.d2-4043408742 .background-color-N3{background-color:#9499AB;}
.d2-4043408742 .background-color-N4{background-color:#CFD2DD;}
.d2-4043408742 .background-color-N5{background-color:#DEE1EB;}
.d2-4043408742 .background-color-N6{background-color:#EEF1F8;}
.d2-4043408742 .background-color-N7{background-color:#FFFFFF;}
.d2-4043408742 .background-color-B1{background-color:#0D32B2;}
.d2-4043408742 .background-color-B2{background-color:#0D32B2;}
.d2-4043408742 .background-color-B3{background-color:#E3E9FD;}
.d2-4043408742 .background-color-B4{background-color:#E3E9FD;}
.d2-4043408742 .background-color-B5{background-color:#EDF0FD;}
.d2-4043408742 .background-color-B6{background-color:#F7F8FE;}
.d2-4043408742 .background-color-AA2{background-color:#4A6FF3;}
.d2-4043408742 .background-color-AA4{background-color:#EDF0FD;}
.d2-4043408742 .background-color-AA5{background-color:#F7F8FE;}
.d2-4043408742 .background-color-AB4{background-color:#EDF0FD;}
.d2-4043408742 .background-color-AB5{background-color:#F7F8FE;}
.d2-4043408742 .color-N1{color:#0A0F25;}
.d2-4043408742 .color-N2{color:#676C7E;}
.d2-4043408742 .color-N3{color:#9499AB;}
.d2-4043408742 .color-N4{color:#CFD2DD;}
.d2-4043408742 .color-N5{color:#DEE1EB;}
.d2-4043408742 .color-N6{color:#EEF1F8;}
.d2-4043408742 .color-N7{color:#FFFFFF;}
.d2-4043408742 .color-B1{color:#0D32B2;}
.d2-4043408742 .color-B2{color:#0D32B2;}
.d2-4043408742 .color-B3{color:#E3E9FD;}
.d2-4043408742 .color-B4{color:#E3E9FD;}
.d2-4043408742 .color-B5{color:#EDF0FD;}
.d2-4043408742 .color-B6{color:#F7F8FE;}
.d2-4043408742 .color-AA2{color:#4A6FF3;}
.d2-4043408742 .color-AA4{color:#EDF0FD;}
.d2-4043408742 .color-AA5{color:#F7F8FE;}
.d2-4043408742 .color-AB4{color:#EDF0FD;}
.d2-4043408742 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker-d2-4043408742);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker-d2-4043408742);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright-d2-4043408742);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright-d2-4043408742);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright-d2-4043408742);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright-d2-4043408742);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark-d2-4043408742);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright-d2-4043408742);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright-d2-4043408742);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright-d2-4043408742);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright-d2-4043408742);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker-d2-4043408742);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark-d2-4043408742);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal-d2-4043408742);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal-d2-4043408742);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright-d2-4043408742);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright-d2-4043408742);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright-d2-4043408742);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]></style><g class="bGVnZW5k"><g class="shape" ><rect x="150.000000" y="241.000000" width="185.000000" height="378.000000" stroke="#d4d4d8" fill="#fafafa" style="stroke-width:2;" /></g><text x="242.500000" y="228.000000" fill="#0A0F25" class="text fill-N1" style="text-anchor:middle;font-size:28px">Legend</text></g><g class="Y2xpZW50"><g class="shape" ><path d="M 312 1415 H 172 V 1414 C 172 1398 187 1384 212 1377 C 198 1371 190 1362 190 1352 C 190 1336 213 1322 242 1322 C 270 1322 294 1336 294 1352 C 294 1362 286 1371 273 1377 C 297 1384 313 1398 313 1414 V 1415 H 312 Z" stroke="#0D32B2" fill="#fff9e6" class=" stroke-B1" style="stroke-width:2;" /></g><text x="242.000000" y="1436.000000" fill="#0A0F25" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px">Browser / iOS App</text></g><g class="Y2FkZHk="><g class="shape" ><rect x="902.000000" y="1303.000000" width="331.000000" height="130.000000" stroke="#0D32B2" fill="#f1f5f9" class=" stroke-B1" style="stroke-width:2;" /></g><text x="1067.500000" y="1341.500000" fill="#0A0F25" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px"><tspan x="1067.500000" dy="0.000000">Caddy :443</tspan><tspan x="1067.500000" dy="17.000000">custom build · caddy-l4 · caddy-ratelimit</tspan><tspan x="1067.500000" dy="17.000000">CrowdSec bouncer · security headers</tspan><tspan x="1067.500000" dy="17.000000">rate limiting · static error pages</tspan><tspan x="1067.500000" dy="17.000000">Redis TCP proxy :6380</tspan></text></g><g class="c2s="><g class="shape" ><rect x="1885.000000" y="371.000000" width="393.000000" height="1662.000000" stroke="#0D32B2" fill="#fef3c7" class=" stroke-B1" style="stroke-width:2;" /></g><text x="2081.500000" y="358.000000" fill="#0A0F25" class="text fill-N1" style="text-anchor:middle;font-size:28px">SvelteKit UI :3000</text></g><g class="YmU="><g class="shape" ><rect x="3119.000000" y="886.000000" width="390.000000" height="1160.000000" stroke="#0D32B2" fill="#eef3ff" class=" stroke-B1" style="stroke-width:2;" /></g><text x="3314.000000" y="873.000000" fill="#0A0F25" class="text fill-N1" style="text-anchor:middle;font-size:28px">Backend API :8080</text></g><g class="c3RvcmFnZQ=="><g class="shape" ><rect x="4300.000000" y="565.000000" width="334.000000" height="1557.000000" stroke="#0D32B2" fill="#eaf7ea" class=" stroke-B1" style="stroke-width:2;" /></g><text x="4467.000000" y="552.000000" fill="#0A0F25" class="text fill-N1" style="text-anchor:middle;font-size:28px">Storage</text></g><g class="bGVnZW5kLnB1Yg=="><g class="shape" ><rect x="198.000000" y="271.000000" width="89.000000" height="66.000000" stroke="#86efac" fill="#f0fdf4" style="stroke-width:2;" /></g><text x="242.500000" y="309.500000" fill="#15803d" class="text-bold" style="text-anchor:middle;font-size:16px">public</text></g><g class="bGVnZW5kLnVzZXI="><g class="shape" ><rect x="186.000000" y="397.000000" width="112.000000" height="66.000000" stroke="#93c5fd" fill="#eff6ff" style="stroke-width:2;" /></g><text x="242.000000" y="435.500000" fill="#1d4ed8" class="text-bold" style="text-anchor:middle;font-size:16px">user auth</text></g><g class="bGVnZW5kLmFkbQ=="><g class="shape" ><rect x="180.000000" y="523.000000" width="125.000000" height="66.000000" stroke="#fdba74" fill="#fff7ed" style="stroke-width:2;" /></g><text x="242.500000" y="561.500000" fill="#c2410c" class="text-bold" style="text-anchor:middle;font-size:16px">admin only</text></g><g class="c2suYXV0aA=="><g class="shape" ><rect x="1940.000000" y="401.000000" width="283.000000" height="114.000000" stroke="#f59e0b" fill="#fde68a" style="stroke-width:2;" /></g><text x="2081.500000" y="439.500000" fill="#0A0F25" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px"><tspan x="2081.500000" dy="0.000000">POST /api/auth/login</tspan><tspan x="2081.500000" dy="17.250000">POST /api/auth/register</tspan><tspan x="2081.500000" dy="17.250000">POST /api/auth/change-password</tspan><tspan x="2081.500000" dy="17.250000">GET /api/auth/session</tspan></text></g><g class="c2suY2F0YWxvZ3VlX3Nr"><g class="shape" ><rect x="1917.000000" y="1427.000000" width="330.000000" height="82.000000" stroke="#86efac" fill="#f0fdf4" style="stroke-width:2;" /></g><text x="2082.000000" y="1465.500000" fill="#0A0F25" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px"><tspan x="2082.000000" dy="0.000000">GET /api/catalogue-page (infinite scroll)</tspan><tspan x="2082.000000" dy="18.500000">GET /api/search</tspan></text></g><g class="c2suYm9va19zaw=="><g class="shape" ><rect x="1915.000000" y="1239.000000" width="333.000000" height="98.000000" stroke="#86efac" fill="#f0fdf4" style="stroke-width:2;" /></g><text x="2081.500000" y="1277.500000" fill="#0A0F25" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px"><tspan x="2081.500000" dy="0.000000">GET /api/book/{slug}</tspan><tspan x="2081.500000" dy="17.666667">GET /api/chapter/{slug}/{n}</tspan><tspan x="2081.500000" dy="17.666667">GET /api/chapter-text-preview/{slug}/{n}</tspan></text></g><g class="c2suc2NyYXBlX3Nr"><g class="shape" ><rect x="1955.000000" y="575.000000" width="254.000000" height="146.000000" stroke="#fdba74" fill="#fff7ed" style="stroke-width:2;" /></g><text x="2082.000000" y="613.500000" fill="#0A0F25" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px"><tspan x="2082.000000" dy="0.000000">GET /api/scrape/status</tspan><tspan x="2082.000000" dy="16.833333">GET /api/scrape/tasks</tspan><tspan x="2082.000000" dy="16.833333">POST /api/scrape</tspan><tspan x="2082.000000" dy="16.833333">POST /api/scrape/book</tspan><tspan x="2082.000000" dy="16.833333">POST /api/scrape/book/range</tspan><tspan x="2082.000000" dy="16.833333">POST /api/scrape/cancel/{id}</tspan></text></g><g class="c2suYXVkaW9fc2s="><g class="shape" ><rect x="1945.000000" y="1593.000000" width="274.000000" height="98.000000" stroke="#86efac" fill="#f0fdf4" style="stroke-width:2;" /></g><text x="2082.000000" y="1631.500000" fill="#0A0F25" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px"><tspan x="2082.000000" dy="0.000000">POST /api/audio/{slug}/{n}</tspan><tspan x="2082.000000" dy="17.666667">GET /api/audio/status/{slug}/{n}</tspan><tspan x="2082.000000" dy="17.666667">GET /api/voices</tspan></text></g><g class="c2sucHJlc2lnbl9zaw=="><g class="shape" ><rect x="1924.000000" y="1763.000000" width="316.000000" height="98.000000" stroke="#86efac" fill="#f0fdf4" style="stroke-width:2;" /></g><text x="2082.000000" y="1801.500000" fill="#0A0F25" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px"><tspan x="2082.000000" dy="0.000000">GET /api/presign/chapter/{slug}/{n}</tspan><tspan x="2082.000000" dy="17.666667">GET /api/presign/audio/{slug}/{n}</tspan><tspan x="2082.000000" dy="17.666667">GET /api/presign/voice-sample/{voice}</tspan></text></g><g class="c2sucHJlc2lnbl91c2Vy"><g class="shape" ><rect x="1917.000000" y="1921.000000" width="330.000000" height="82.000000" stroke="#93c5fd" fill="#eff6ff" style="stroke-width:2;" /></g><text x="2082.000000" y="1959.500000" fill="#0A0F25" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px"><tspan x="2082.000000" dy="0.000000">GET /api/presign/avatar-upload/{userId}</tspan><tspan x="2082.000000" dy="18.500000">GET /api/presign/avatar/{userId}</tspan></text></g><g class="c2sucHJvZ3Jlc3Nfc2s="><g class="shape" ><rect x="1960.000000" y="781.000000" width="243.000000" height="98.000000" stroke="#86efac" fill="#f0fdf4" style="stroke-width:2;" /></g><text x="2081.500000" y="819.500000" fill="#0A0F25" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px"><tspan x="2081.500000" dy="0.000000">GET /api/progress</tspan><tspan x="2081.500000" dy="17.666667">POST /api/progress/{slug}</tspan><tspan x="2081.500000" dy="17.666667">DELETE /api/progress/{slug}</tspan></text></g><g class="c2subGlicmFyeV9zaw=="><g class="shape" ><rect x="1967.000000" y="939.000000" width="229.000000" height="98.000000" stroke="#86efac" fill="#f0fdf4" style="stroke-width:2;" /></g><text x="2081.500000" y="977.500000" fill="#0A0F25" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px"><tspan x="2081.500000" dy="0.000000">GET /api/library</tspan><tspan x="2081.500000" dy="17.666667">POST /api/library/{slug}</tspan><tspan x="2081.500000" dy="17.666667">DELETE /api/library/{slug}</tspan></text></g><g class="c2suY29tbWVudHNfc2s="><g class="shape" ><rect x="1962.000000" y="1097.000000" width="240.000000" height="82.000000" stroke="#86efac" fill="#f0fdf4" style="stroke-width:2;" /></g><text x="2082.000000" y="1135.500000" fill="#0A0F25" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px"><tspan x="2082.000000" dy="0.000000">GET /api/comments/{slug}</tspan><tspan x="2082.000000" dy="18.500000">POST /api/comments/{slug}</tspan></text></g><g class="YmUuaGVhbHRoX2Jl"><g class="shape" ><rect x="3233.000000" y="916.000000" width="162.000000" height="82.000000" stroke="#86efac" fill="#f0fdf4" style="stroke-width:2;" /></g><text x="3314.000000" y="954.500000" fill="#0A0F25" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px"><tspan x="3314.000000" dy="0.000000">GET /health</tspan><tspan x="3314.000000" dy="18.500000">GET /api/version</tspan></text></g><g class="YmUuc2NyYXBlX2Jl"><g class="shape" ><rect x="3202.000000" y="1058.000000" width="225.000000" height="98.000000" stroke="#fdba74" fill="#fff7ed" style="stroke-width:2;" /></g><text x="3314.500000" y="1096.500000" fill="#0A0F25" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px"><tspan x="3314.500000" dy="0.000000">POST /scrape</tspan><tspan x="3314.500000" dy="17.666667">POST /scrape/book</tspan><tspan x="3314.500000" dy="17.666667">POST /scrape/book/range</tspan></text></g><g class="YmUuY2F0YWxvZ3VlX2Jl"><g class="shape" ><rect x="3158.000000" y="1411.000000" width="313.000000" height="114.000000" stroke="#86efac" fill="#f0fdf4" style="stroke-width:2;" /></g><text x="3314.500000" y="1449.500000" fill="#0A0F25" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px"><tspan x="3314.500000" dy="0.000000">GET /api/catalogue (Meilisearch)</tspan><tspan x="3314.500000" dy="17.250000">GET /api/browse (legacy MinIO cache)</tspan><tspan x="3314.500000" dy="17.250000">GET /api/ranking</tspan><tspan x="3314.500000" dy="17.250000">GET /api/cover/{domain}/{slug}</tspan></text></g><g class="YmUuYm9va19iZQ=="><g class="shape" ><rect x="3153.000000" y="1216.000000" width="322.000000" height="114.000000" stroke="#86efac" fill="#f0fdf4" style="stroke-width:2;" /></g><text x="3314.000000" y="1254.500000" fill="#0A0F25" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px"><tspan x="3314.000000" dy="0.000000">GET /api/book-preview/{slug}</tspan><tspan x="3314.000000" dy="17.250000">GET /api/chapter-text/{slug}/{n}</tspan><tspan x="3314.000000" dy="17.250000">GET /api/chapter-markdown/{slug}/{n}</tspan><tspan x="3314.000000" dy="17.250000">POST /api/reindex/{slug} ⚠ admin</tspan></text></g><g class="YmUuYXVkaW9fYmU="><g class="shape" ><rect x="3177.000000" y="1660.000000" width="274.000000" height="114.000000" stroke="#86efac" fill="#f0fdf4" style="stroke-width:2;" /></g><text x="3314.000000" y="1698.500000" fill="#0A0F25" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px"><tspan x="3314.000000" dy="0.000000">POST /api/audio/{slug}/{n}</tspan><tspan x="3314.000000" dy="17.250000">GET /api/audio/status/{slug}/{n}</tspan><tspan x="3314.000000" dy="17.250000">GET /api/audio-proxy/{slug}/{n}</tspan><tspan x="3314.000000" dy="17.250000">GET /api/voices</tspan></text></g><g class="YmUucHJlc2lnbl9iZQ=="><g class="shape" ><rect x="3149.000000" y="1886.000000" width="330.000000" height="130.000000" stroke="#86efac" fill="#f0fdf4" style="stroke-width:2;" /></g><text x="3314.000000" y="1924.500000" fill="#0A0F25" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px"><tspan x="3314.000000" dy="0.000000">GET /api/presign/chapter/{slug}/{n}</tspan><tspan x="3314.000000" dy="17.000000">GET /api/presign/audio/{slug}/{n}</tspan><tspan x="3314.000000" dy="17.000000">GET /api/presign/voice-sample/{voice}</tspan><tspan x="3314.000000" dy="17.000000">GET /api/presign/avatar-upload/{userId}</tspan><tspan x="3314.000000" dy="17.000000">GET /api/presign/avatar/{userId}</tspan></text></g><g class="c3RvcmFnZS5wYg=="><g class="shape" ><path d="M 4352 619 C 4352 595 4456 595 4467 595 C 4479 595 4582 595 4582 619 V 737 C 4582 761 4479 761 4467 761 C 4456 761 4352 761 4352 737 V 619 Z" stroke="#0D32B2" fill="#F7F8FE" class=" stroke-B1 fill-AA5" style="stroke-width:2;" /><path d="M 4352 619 C 4352 643 4456 643 4467 643 C 4479 643 4582 643 4582 619" stroke="#0D32B2" fill="#F7F8FE" class=" stroke-B1 fill-AA5" style="stroke-width:2;" /></g><text x="4467.000000" y="671.500000" fill="#0A0F25" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px"><tspan x="4467.000000" dy="0.000000">auth · books · progress</tspan><tspan x="4467.000000" dy="17.250000">comments · library</tspan><tspan x="4467.000000" dy="17.250000">scrape_jobs · audio_cache</tspan><tspan x="4467.000000" dy="17.250000">ranking</tspan></text></g><g class="c3RvcmFnZS5tbg=="><g class="shape" ><path d="M 4344 1345 C 4344 1321 4455 1321 4467 1321 C 4479 1321 4590 1321 4590 1345 V 1431 C 4590 1455 4479 1455 4467 1455 C 4455 1455 4344 1455 4344 1431 V 1345 Z" stroke="#0D32B2" fill="#F7F8FE" class=" stroke-B1 fill-AA5" style="stroke-width:2;" /><path d="M 4344 1345 C 4344 1369 4455 1369 4467 1369 C 4479 1369 4590 1369 4590 1345" stroke="#0D32B2" fill="#F7F8FE" class=" stroke-B1 fill-AA5" style="stroke-width:2;" /></g><text x="4467.000000" y="1397.500000" fill="#0A0F25" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px"><tspan x="4467.000000" dy="0.000000">chapters · audio</tspan><tspan x="4467.000000" dy="18.500000">avatars · catalogue (browse)</tspan></text></g><g class="c3RvcmFnZS5tcw=="><g class="shape" ><path d="M 4332 1749 C 4332 1725 4454 1725 4468 1725 C 4481 1725 4603 1725 4603 1749 V 1867 C 4603 1891 4481 1891 4468 1891 C 4454 1891 4332 1891 4332 1867 V 1749 Z" stroke="#0D32B2" fill="#F7F8FE" class=" stroke-B1 fill-AA5" style="stroke-width:2;" /><path d="M 4332 1749 C 4332 1773 4454 1773 4468 1773 C 4481 1773 4603 1773 4603 1749" stroke="#0D32B2" fill="#F7F8FE" class=" stroke-B1 fill-AA5" style="stroke-width:2;" /></g><text x="4467.500000" y="1801.500000" fill="#0A0F25" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px"><tspan x="4467.500000" dy="0.000000">index: books</tspan><tspan x="4467.500000" dy="17.250000">filterable: status · genres</tspan><tspan x="4467.500000" dy="17.250000">sortable: rank · rating</tspan><tspan x="4467.500000" dy="17.250000"> total_chapters · meta_updated</tspan></text></g><g class="c3RvcmFnZS52aw=="><g class="shape" ><path d="M 4330 1982 C 4330 1958 4453 1958 4467 1958 C 4481 1958 4604 1958 4604 1982 V 2068 C 4604 2092 4481 2092 4467 2092 C 4453 2092 4330 2092 4330 2068 V 1982 Z" stroke="#0D32B2" fill="#F7F8FE" class=" stroke-B1 fill-AA5" style="stroke-width:2;" /><path d="M 4330 1982 C 4330 2006 4453 2006 4467 2006 C 4481 2006 4604 2006 4604 1982" stroke="#0D32B2" fill="#F7F8FE" class=" stroke-B1 fill-AA5" style="stroke-width:2;" /></g><text x="4467.000000" y="2034.500000" fill="#0A0F25" class="text-bold fill-N1" style="text-anchor:middle;font-size:16px"><tspan x="4467.000000" dy="0.000000">presign URL cache (TTL ~55 min)</tspan><tspan x="4467.000000" dy="18.500000">Asynq job queue (runner)</tspan></text></g><g class="KGNsaWVudCAtJmd0OyBjYWRkeSlbMF0="><marker id="mk-d2-4043408742-3488378134" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" fill="#0D32B2" class="connection fill-B1" stroke-width="2" /> </marker><path d="M 287.999998 1368.002525 C 444.399994 1368.199951 734.799988 1368.250000 898.000000 1368.250000" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-4043408742-3488378134)" mask="url(#d2-4043408742)" /><text x="594.000000" y="1374.000000" fill="#676C7E" class="text-italic fill-N2" style="text-anchor:middle;font-size:16px">HTTPS :443</text></g><g class="KGNhZGR5IC0mZ3Q7IHNrKVswXQ=="><path d="M 1130.469664 1434.701735 C 1416.218018 1736.250000 1567.400024 1812.000000 1881.000000 1812.000000" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-4043408742-3488378134)" mask="url(#d2-4043408742)" /><text x="1447.000000" y="1749.000000" fill="#676C7E" class="text-italic fill-N2" style="text-anchor:middle;font-size:16px"><tspan x="1447.000000" dy="0.000000">/* (catch-all)</tspan><tspan x="1447.000000" dy="18.500000">→ SvelteKit enforces auth</tspan></text></g><g class="KGNhZGR5IC0mZ3Q7IGJlKVswXQ=="><path d="M 1105.157874 1434.991854 C 1411.234985 1977.449951 1539.000000 2113.500000 1615.500000 2113.500000 C 1692.000000 2113.500000 1810.699951 2113.500000 1912.250000 2113.500000 C 2013.800049 2113.500000 2149.199951 2113.500000 2250.750000 2113.500000 C 2352.300049 2113.500000 2782.699951 1250.750000 3115.500000 1250.750000" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-4043408742-3488378134)" mask="url(#d2-4043408742)" /><text x="2190.000000" y="2079.000000" fill="#676C7E" class="text-italic fill-N2" style="text-anchor:middle;font-size:16px"><tspan x="2190.000000" dy="0.000000">/health /scrape*</tspan><tspan x="2190.000000" dy="16.833333">/api/browse /api/catalogue /api/ranking</tspan><tspan x="2190.000000" dy="16.833333">/api/version /api/book-preview/*</tspan><tspan x="2190.000000" dy="16.833333">/api/chapter-text/* /api/chapter-markdown/*</tspan><tspan x="2190.000000" dy="16.833333">/api/reindex/* /api/cover/*</tspan><tspan x="2190.000000" dy="16.833333">/api/audio* /api/voices /api/presign/*</tspan></text></g><g class="KGNhZGR5IC0mZ3Q7IHN0b3JhZ2UubW4pWzBd"><path d="M 1094.728101 1301.137242 C 1409.199951 496.598999 1539.000000 295.000000 1615.500000 295.000000 C 1692.000000 295.000000 1810.699951 295.000000 1912.250000 295.000000 C 2013.800049 295.000000 2149.199951 295.000000 2250.750000 295.000000 C 2352.300049 295.000000 2475.699951 298.200012 2559.250000 303.000000 C 2642.800049 307.799988 2754.199951 311.000000 2837.750000 311.000000 C 2921.300049 311.000000 3044.399902 311.000000 3145.500000 311.000000 C 3246.600098 311.000000 3381.399902 311.000000 3482.500000 311.000000 C 3583.600098 311.000000 3701.699951 413.399994 3777.750000 567.000000 C 3853.800049 720.599976 4212.399902 922.799988 4428.085577 1318.487880" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-4043408742-3488378134)" mask="url(#d2-4043408742)" /><text x="2691.500000" y="307.000000" fill="#676C7E" class="text-italic fill-N2" style="text-anchor:middle;font-size:16px"><tspan x="2691.500000" dy="0.000000">/avatars/* /audio/* /chapters/*</tspan><tspan x="2691.500000" dy="18.500000">(presigned MinIO GETs)</tspan></text></g><g class="KHNrLmNhdGFsb2d1ZV9zayAtJmd0OyBiZS5jYXRhbG9ndWVfYmUpWzBd"><path d="M 2249.000000 1468.000000 C 2385.399902 1468.000000 2475.699951 1468.000000 2559.250000 1468.000000 C 2642.800049 1468.000000 3013.100098 1468.000000 3153.500000 1468.000000" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-4043408742-3488378134)" mask="url(#d2-4043408742)" /><text x="2702.000000" y="1474.000000" fill="#676C7E" class="text-italic fill-N2" style="text-anchor:middle;font-size:16px">internal proxy</text></g><g class="KHNrLmJvb2tfc2sgLSZndDsgYmUuYm9va19iZSlbMF0="><path d="M 2250.000000 1288.000000 C 2385.600098 1288.000000 2475.699951 1288.000000 2559.250000 1288.000000 C 2642.800049 1288.000000 3012.199951 1286.400024 3149.004126 1280.181631" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-4043408742-3488378134)" mask="url(#d2-4043408742)" /><text x="2701.000000" y="1293.000000" fill="#676C7E" class="text-italic fill-N2" style="text-anchor:middle;font-size:16px">internal proxy</text></g><g class="KHNrLmF1ZGlvX3NrIC0mZ3Q7IGJlLmF1ZGlvX2JlKVswXQ=="><path d="M 2221.500000 1642.000000 C 2379.899902 1642.000000 2475.699951 1657.050049 2559.250000 1679.625000 C 2642.800049 1702.199951 3017.000000 1717.250000 3173.000000 1717.250000" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-4043408742-3488378134)" mask="url(#d2-4043408742)" /><text x="2695.000000" y="1710.000000" fill="#676C7E" class="text-italic fill-N2" style="text-anchor:middle;font-size:16px">internal proxy</text></g><g class="KHNrLnByZXNpZ25fc2sgLSZndDsgYmUucHJlc2lnbl9iZSlbMF0="><path d="M 2242.500000 1812.000000 C 2384.100098 1812.000000 2475.699951 1815.349976 2559.250000 1820.375000 C 2642.800049 1825.400024 3011.399902 1841.150024 3145.237008 1889.393574" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-4043408742-3488378134)" mask="url(#d2-4043408742)" /><text x="2699.000000" y="1833.000000" fill="#676C7E" class="text-italic fill-N2" style="text-anchor:middle;font-size:16px">internal proxy</text></g><g class="KHNrLnByZXNpZ25fdXNlciAtJmd0OyBiZS5wcmVzaWduX2JlKVswXQ=="><path d="M 2249.000000 1962.000000 C 2385.399902 1962.000000 2475.699951 1964.449951 2559.250000 1968.125000 C 2642.800049 1971.800049 3011.399902 1971.849976 3145.009700 1962.528392" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-4043408742-3488378134)" mask="url(#d2-4043408742)" /><text x="2698.000000" y="1977.000000" fill="#676C7E" class="text-italic fill-N2" style="text-anchor:middle;font-size:16px">internal proxy</text></g><g class="KHNrLmF1dGggLSZndDsgc3RvcmFnZS5wYilbMF0="><path d="M 2225.000000 458.000000 C 2380.600098 458.000000 2475.699951 382.700012 2559.250000 269.750000 C 2642.800049 156.800003 2754.199951 81.500000 2837.750000 81.500000 C 2921.300049 81.500000 3044.399902 81.500000 3145.500000 81.500000 C 3246.600098 81.500000 3381.399902 81.500000 3482.500000 81.500000 C 3583.600098 81.500000 3701.699951 81.500000 3777.750000 81.500000 C 3853.800049 81.500000 4210.600098 184.600006 4419.182175 593.436924" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-4043408742-3488378134)" mask="url(#d2-4043408742)" /><text x="3374.000000" y="87.000000" fill="#676C7E" class="text-italic fill-N2" style="text-anchor:middle;font-size:16px">sessions / users</text></g><g class="KHNrLnNjcmFwZV9zayAtJmd0OyBzdG9yYWdlLnBiKVswXQ=="><path d="M 2211.500000 648.000000 C 2377.899902 648.000000 2475.699951 542.900024 2559.250000 385.250000 C 2642.800049 227.598999 2754.199951 122.500000 2837.750000 122.500000 C 2921.300049 122.500000 3044.399902 122.500000 3145.500000 122.500000 C 3246.600098 122.500000 3381.399902 122.500000 3482.500000 122.500000 C 3583.600098 122.500000 3701.699951 122.500000 3777.750000 122.500000 C 3853.800049 122.500000 4210.000000 217.399994 4416.077861 593.492097" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-4043408742-3488378134)" mask="url(#d2-4043408742)" /><text x="3294.000000" y="128.000000" fill="#676C7E" class="text-italic fill-N2" style="text-anchor:middle;font-size:16px">scrape job records</text></g><g class="KHNrLnByb2dyZXNzX3NrIC0mZ3Q7IHN0b3JhZ2UucGIpWzBd"><path d="M 2205.000000 830.000000 C 2376.600098 830.000000 2475.699951 694.599976 2559.250000 491.500000 C 2642.800049 288.399994 2754.199951 153.000000 2837.750000 153.000000 C 2921.300049 153.000000 3044.399902 153.000000 3145.500000 153.000000 C 3246.600098 153.000000 3381.399902 153.000000 3482.500000 153.000000 C 3583.600098 153.000000 3701.699951 153.000000 3777.750000 153.000000 C 3853.800049 153.000000 4209.399902 241.800003 4412.996162 593.538117" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-4043408742-3488378134)" mask="url(#d2-4043408742)" /></g><g class="KHNrLmxpYnJhcnlfc2sgLSZndDsgc3RvcmFnZS5wYilbMF0="><path d="M 2198.000000 988.000000 C 2375.199951 988.000000 2475.699951 825.000000 2559.250000 580.500000 C 2642.800049 336.000000 2754.199951 173.000000 2837.750000 173.000000 C 2921.300049 173.000000 3044.399902 173.000000 3145.500000 173.000000 C 3246.600098 173.000000 3381.399902 173.000000 3482.500000 173.000000 C 3583.600098 173.000000 3701.699951 173.000000 3777.750000 173.000000 C 3853.800049 173.000000 4209.000000 257.799988 4410.938451 593.572170" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-4043408742-3488378134)" mask="url(#d2-4043408742)" /></g><g class="KHNrLmNvbW1lbnRzX3NrIC0mZ3Q7IHN0b3JhZ2UucGIpWzBd"><path d="M 2204.500000 1138.000000 C 2376.500000 1138.000000 2475.699951 958.549988 2559.250000 689.375000 C 2642.800049 420.199005 2754.199951 240.750000 2837.750000 240.750000 C 2921.300049 240.750000 3044.399902 240.750000 3145.500000 240.750000 C 3246.600098 240.750000 3381.399902 240.750000 3482.500000 240.750000 C 3583.600098 240.750000 3701.699951 240.750000 3777.750000 240.750000 C 3853.800049 240.750000 4207.200195 312.200012 4401.731441 594.705514" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-4043408742-3488378134)" mask="url(#d2-4043408742)" /></g><g class="KGJlLmNhdGFsb2d1ZV9iZSAtJmd0OyBzdG9yYWdlLm1zKVswXQ=="><path d="M 3371.409190 1526.669220 C 3594.800049 1751.650024 3701.699951 1808.250000 3777.750000 1808.250000 C 3853.800049 1808.250000 4192.799805 1808.199951 4328.000004 1808.005746" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-4043408742-3488378134)" mask="url(#d2-4043408742)" /><text x="3797.000000" y="1814.000000" fill="#676C7E" class="text-italic fill-N2" style="text-anchor:middle;font-size:16px">full-text search + facets</text></g><g class="KGJlLmNhdGFsb2d1ZV9iZSAtJmd0OyBzdG9yYWdlLnBiKVswXQ=="><path d="M 3365.319286 1409.746842 C 3593.600098 1149.650024 3701.699951 986.099976 3777.750000 838.875000 C 3853.800049 691.650024 4196.799805 604.000000 4348.138885 644.955112" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-4043408742-3488378134)" mask="url(#d2-4043408742)" /><text x="3771.000000" y="857.000000" fill="#676C7E" class="text-italic fill-N2" style="text-anchor:middle;font-size:16px">ranking records</text></g><g class="KGJlLmNhdGFsb2d1ZV9iZSAtJmd0OyBzdG9yYWdlLm1uKVswXQ=="><path d="M 3473.494568 1456.358681 C 3615.100098 1445.901001 3701.699951 1443.250000 3777.750000 1443.250000 C 3853.800049 1443.250000 4195.200195 1436.599976 4340.062421 1410.703896" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-4043408742-3488378134)" mask="url(#d2-4043408742)" /><text x="3909.000000" y="1448.000000" fill="#676C7E" class="text-italic fill-N2" style="text-anchor:middle;font-size:16px">cover presign</text></g><g class="KGJlLmJvb2tfYmUgLSZndDsgc3RvcmFnZS5tbilbMF0="><path d="M 3390.589749 1331.463548 C 3598.600098 1490.250000 3701.699951 1530.250000 3777.750000 1530.250000 C 3853.800049 1530.250000 4197.000000 1512.400024 4349.362858 1442.664692" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-4043408742-3488378134)" mask="url(#d2-4043408742)" /><text x="3848.000000" y="1536.000000" fill="#676C7E" class="text-italic fill-N2" style="text-anchor:middle;font-size:16px">chapter objects</text></g><g class="KGJlLmJvb2tfYmUgLSZndDsgc3RvcmFnZS5wYilbMF0="><path d="M 3476.999484 1269.954558 C 3615.800049 1266.800049 3701.699951 1171.300049 3777.750000 1029.250000 C 3853.800049 887.200012 4196.799805 778.200012 4348.246792 722.383268" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-4043408742-3488378134)" mask="url(#d2-4043408742)" /><text x="3838.000000" y="922.000000" fill="#676C7E" class="text-italic fill-N2" style="text-anchor:middle;font-size:16px">book metadata</text></g><g class="KGJlLmF1ZGlvX2JlIC0mZ3Q7IHN0b3JhZ2UubW4pWzBd"><path d="M 3448.833139 1659.450249 C 3610.199951 1589.050049 3701.699951 1571.250000 3777.750000 1571.250000 C 3853.800049 1571.250000 4200.000000 1546.400024 4364.557437 1449.036850" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-4043408742-3488378134)" mask="url(#d2-4043408742)" /><text x="3913.000000" y="1572.000000" fill="#676C7E" class="text-italic fill-N2" style="text-anchor:middle;font-size:16px">audio presign</text></g><g class="KGJlLmF1ZGlvX2JlIC0mZ3Q7IHN0b3JhZ2UudmspWzBd"><path d="M 3404.407779 1775.331010 C 3601.344971 1901.849976 3701.699951 1933.750000 3777.750000 1933.750000 C 3853.800049 1933.750000 4192.398926 1944.000000 4326.166552 1983.857775" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-4043408742-3488378134)" mask="url(#d2-4043408742)" /><text x="3848.000000" y="1939.000000" fill="#676C7E" class="text-italic fill-N2" style="text-anchor:middle;font-size:16px">presign cache</text></g><g class="KGJlLnByZXNpZ25fYmUgLSZndDsgc3RvcmFnZS52aylbMF0="><path d="M 3480.926393 1997.787598 C 3616.600098 2035.650024 3701.699951 2045.250000 3777.750000 2045.250000 C 3853.800049 2045.250000 4192.398926 2043.000000 4326.008529 2034.261068" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-4043408742-3488378134)" mask="url(#d2-4043408742)" /><text x="3901.500000" y="2050.000000" fill="#676C7E" class="text-italic fill-N2" style="text-anchor:middle;font-size:16px">check / set presign cache</text></g><g class="KGJlLnByZXNpZ25fYmUgLSZndDsgc3RvcmFnZS5tbilbMF0="><path d="M 3397.300464 1884.505147 C 3599.947021 1723.349976 3701.699951 1682.750000 3777.750000 1682.750000 C 3853.800049 1682.750000 4206.399902 1636.599976 4397.105084 1454.760337" stroke="#0D32B2" fill="none" class="connection stroke-B1" style="stroke-width:2;" marker-end="url(#mk-d2-4043408742-3488378134)" mask="url(#d2-4043408742)" /><text x="3903.500000" y="1682.000000" fill="#676C7E" class="text-italic fill-N2" style="text-anchor:middle;font-size:16px">generate presigned URL</text></g><mask id="d2-4043408742" maskUnits="userSpaceOnUse" x="49" y="-29" width="4686" height="2293">
<rect x="49" y="-29" width="4686" height="2293" fill="white"></rect>
<rect x="555.000000" y="1358.000000" width="78" height="21" fill="black"></rect>
<rect x="1362.000000" y="1733.000000" width="170" height="37" fill="black"></rect>
<rect x="2036.000000" y="2063.000000" width="308" height="101" fill="black"></rect>
<rect x="2583.000000" y="291.000000" width="217" height="37" fill="black"></rect>
<rect x="2654.000000" y="1458.000000" width="96" height="21" fill="black"></rect>
<rect x="2653.000000" y="1277.000000" width="96" height="21" fill="black"></rect>
<rect x="2647.000000" y="1694.000000" width="96" height="21" fill="black"></rect>
<rect x="2651.000000" y="1817.000000" width="96" height="21" fill="black"></rect>
<rect x="2650.000000" y="1961.000000" width="96" height="21" fill="black"></rect>
<rect x="3321.000000" y="71.000000" width="106" height="21" fill="black"></rect>
<rect x="3231.000000" y="112.000000" width="126" height="21" fill="black"></rect>
<rect x="3719.000000" y="1798.000000" width="156" height="21" fill="black"></rect>
<rect x="3717.000000" y="841.000000" width="108" height="21" fill="black"></rect>
<rect x="3863.000000" y="1432.000000" width="92" height="21" fill="black"></rect>
<rect x="3795.000000" y="1520.000000" width="106" height="21" fill="black"></rect>
<rect x="3785.000000" y="906.000000" width="106" height="21" fill="black"></rect>
<rect x="3866.000000" y="1556.000000" width="94" height="21" fill="black"></rect>
<rect x="3800.000000" y="1923.000000" width="96" height="21" fill="black"></rect>
<rect x="3818.000000" y="2034.000000" width="167" height="21" fill="black"></rect>
<rect x="3823.000000" y="1666.000000" width="161" height="21" fill="black"></rect>
</mask></svg></svg>