437 lines
18 KiB
Plaintext
437 lines
18 KiB
Plaintext
#import "@preview/fletcher:0.5.8" as fletcher: diagram, node, edge
|
|
|
|
#set page(width: auto, height: auto, margin: 1.5em)
|
|
#set text(font: "Fira Sans", size: 9pt, fill: rgb("#1a1a2e"))
|
|
|
|
// === Color Palette ===
|
|
#let c-edge = rgb("#e8f4f8")
|
|
#let c-gateway = rgb("#fce4ec")
|
|
#let c-api = rgb("#e8eaf6")
|
|
#let c-session = rgb("#e0f2f1")
|
|
#let c-client = rgb("#fff3e0")
|
|
#let c-infra = rgb("#f3e5f5")
|
|
#let c-bus = rgb("#fff9c4")
|
|
#let c-future = rgb("#f5f5f5")
|
|
|
|
#let s-main = rgb("#37474f") + 0.8pt
|
|
#let s-data = rgb("#7b1fa2") + 0.8pt
|
|
#let s-bus = rgb("#e65100") + 0.8pt
|
|
#let s-dim = rgb("#bbb") + 0.6pt
|
|
|
|
#let label-sm(body) = text(size: 7pt, body)
|
|
#let label-xs(body) = text(size: 6.5pt, fill: rgb("#666"), body)
|
|
#let section(title) = {
|
|
v(2em)
|
|
align(center, text(size: 13pt, weight: "bold", fill: rgb("#37474f"), title))
|
|
v(0.6em)
|
|
}
|
|
|
|
// ============================================================
|
|
// TITLE
|
|
// ============================================================
|
|
#align(center)[
|
|
#text(size: 18pt, weight: "bold")[ajet-chat]
|
|
#v(0.2em)
|
|
#text(size: 9pt, fill: rgb("#666"))[System Architecture — Clojure · http-kit · PostgreSQL · Datastar · MinIO]
|
|
]
|
|
|
|
// ============================================================
|
|
// 1. SYSTEM OVERVIEW
|
|
// ============================================================
|
|
#section[1 · System Overview]
|
|
|
|
#align(center)[
|
|
#diagram(
|
|
spacing: (3.5em, 2.4em),
|
|
node-stroke: s-main,
|
|
node-corner-radius: 4pt,
|
|
|
|
// External
|
|
node((2.5, 0.0), [*Internet*], stroke: none, fill: none),
|
|
node((-0.5, 0.0), [*Webhooks*\ #label-xs[git · CI · monitoring]], fill: c-client),
|
|
|
|
// nginx
|
|
node((2.5, 1.0), [*nginx*\ #label-xs[TLS termination · prod only]], fill: c-edge, width: 16em),
|
|
|
|
// Auth Gateway
|
|
node((2.5, 2.2), [*Auth Gateway*\ #label-xs[http-kit · session/token validation · rate limit · CORS · routing]], fill: c-gateway, width: 26em),
|
|
|
|
// Services row
|
|
node((-0.5, 4.0), [*API*\ #label-xs[stateless REST]\ #label-xs[reads / writes → PG]\ #label-xs[publishes → NATS]], fill: c-api),
|
|
node((1.8, 4.0), [*Web SM*\ #label-xs[Hiccup + Datastar SSE]\ #label-xs[browser connections]], fill: c-session),
|
|
node((3.8, 4.0), [*TUI SM*\ #label-xs[SSE + HTTP POST]\ #label-xs[terminal connections]], fill: c-session),
|
|
node((5.2, 4.0), [*Mobile SM*\ #label-xs[(future)]], fill: c-future, stroke: s-dim),
|
|
|
|
// Event bus
|
|
node((2.5, 5.8), [*NATS*\ #label-xs[pub/sub event bus]\ #label-xs[community-scoped subjects]], fill: c-bus),
|
|
|
|
// Data stores
|
|
node((-0.5, 7.5), [*PostgreSQL*\ #label-xs[data store · FTS]\ #label-xs[Auth GW + API only]], fill: c-infra),
|
|
node((-2.2, 4.0), [*MinIO*\ #label-xs[S3 files · avatars]], fill: c-infra),
|
|
|
|
// Clients
|
|
node((1.8, 8.0), [*Browsers*], stroke: none, fill: none),
|
|
node((3.8, 8.0), [*Terminals*\ #label-xs[CLI + TUI]], stroke: none, fill: none),
|
|
node((5.2, 8.0), [#text(fill: rgb("#aaa"))[*Phones*]], stroke: none, fill: none),
|
|
|
|
// --- Edges ---
|
|
// Internet → nginx → Auth Gateway
|
|
edge((2.5, 0.0), (2.5, 1.0), "-|>"),
|
|
edge((-0.5, 0.0), (2.5, 2.2), "-|>"),
|
|
edge((2.5, 1.0), (2.5, 2.2), "-|>"),
|
|
|
|
// Auth Gateway → services
|
|
edge((2.5, 2.2), (-0.5, 4.0), "-|>", label: label-sm[`/api/*`], label-side: left),
|
|
edge((2.5, 2.2), (1.8, 4.0), "-|>", label: label-sm[`/web`], label-side: left),
|
|
edge((2.5, 2.2), (3.8, 4.0), "-|>", label: label-sm[`/ws/tui`], label-side: right),
|
|
edge((2.5, 2.2), (5.2, 4.0), "-|>", stroke: s-dim),
|
|
|
|
// API → PG (data reads/writes — only API + Auth GW touch PG)
|
|
edge((-0.5, 4.0), (-0.5, 7.5), "<-|>", stroke: s-data,
|
|
label: text(size: 7pt, fill: rgb("#7b1fa2"))[data], label-side: left),
|
|
|
|
// API → NATS (publish events after writes)
|
|
edge((-0.5, 4.0), (2.5, 5.8), "-|>", stroke: s-bus,
|
|
label: text(size: 7pt, fill: rgb("#e65100"))[pub], label-side: left),
|
|
|
|
// NATS → SMs (subscribe for events)
|
|
edge((2.5, 5.8), (1.8, 4.0), "-|>", stroke: s-bus,
|
|
label: text(size: 7pt, fill: rgb("#e65100"))[sub], label-side: right),
|
|
edge((2.5, 5.8), (3.8, 4.0), "-|>", stroke: s-bus),
|
|
edge((2.5, 5.8), (5.2, 4.0), "-|>", stroke: s-dim),
|
|
|
|
// SMs → API (fetch full data after event notification)
|
|
edge((1.8, 4.0), (-0.5, 4.0), "-|>", stroke: s-data, bend: 20deg,
|
|
label: text(size: 7pt, fill: rgb("#7b1fa2"))[fetch], label-side: right),
|
|
edge((3.8, 4.0), (-0.5, 4.0), "-|>", stroke: s-data, bend: 12deg),
|
|
|
|
// API → MinIO (files)
|
|
edge((-0.5, 4.0), (-2.2, 4.0), "-|>", stroke: s-data,
|
|
label: text(size: 7pt, fill: rgb("#7b1fa2"))[files], label-side: left),
|
|
|
|
// SMs → clients
|
|
edge((1.8, 4.0), (1.8, 8.0), "-|>", label: label-sm[SSE], label-side: left),
|
|
edge((3.8, 4.0), (3.8, 8.0), "-|>", label: label-sm[SSE], label-side: left),
|
|
edge((5.2, 4.0), (5.2, 8.0), "-|>", stroke: s-dim),
|
|
)
|
|
]
|
|
|
|
// Legend
|
|
#v(0.5em)
|
|
#align(center)[
|
|
#rect(stroke: 0.5pt + rgb("#ccc"), radius: 4pt, inset: 0.6em)[
|
|
#text(size: 7pt)[
|
|
#box(rect(fill: c-gateway, width: 0.7em, height: 0.7em, radius: 2pt)) Auth
|
|
#h(0.8em)
|
|
#box(rect(fill: c-api, width: 0.7em, height: 0.7em, radius: 2pt)) API
|
|
#h(0.8em)
|
|
#box(rect(fill: c-session, width: 0.7em, height: 0.7em, radius: 2pt)) Session Mgr
|
|
#h(0.8em)
|
|
#box(rect(fill: c-infra, width: 0.7em, height: 0.7em, radius: 2pt)) Infrastructure
|
|
#h(0.8em)
|
|
#box(rect(fill: c-bus, width: 0.7em, height: 0.7em, radius: 2pt)) NATS
|
|
#h(0.8em)
|
|
#line(length: 1em, stroke: s-bus) pub/sub
|
|
#h(0.6em)
|
|
#line(length: 1em, stroke: s-data) data
|
|
]
|
|
]
|
|
]
|
|
|
|
// ============================================================
|
|
// 2. AUTH GATEWAY DETAIL
|
|
// ============================================================
|
|
#section[2 · Auth Gateway Flow]
|
|
|
|
#align(center)[
|
|
#diagram(
|
|
spacing: (3.5em, 2em),
|
|
node-stroke: s-main,
|
|
node-corner-radius: 4pt,
|
|
|
|
// Incoming
|
|
node((0, 0), [*Client Request*\ #label-xs[HTTPS / SSE]], fill: c-client),
|
|
|
|
// Steps
|
|
node((0, 1), [*TLS Termination*\ #label-xs[nginx (prod only)]], fill: c-edge),
|
|
node((0, 2), [*Extract Token*\ #label-xs[cookie or Authorization header]], fill: c-gateway),
|
|
node((0, 3), [*DB Lookup*\ #label-xs[sessions / api\_tokens table]], fill: c-gateway),
|
|
|
|
// Branch
|
|
node((-1.5, 4), [*401 Unauthorized*], fill: rgb("#ffcdd2"), stroke: rgb("#c62828") + 0.8pt),
|
|
node((1.5, 4), [*Attach User Context*\ #label-xs[user\_id, role, community\_id]], fill: c-gateway),
|
|
|
|
// Rate limit
|
|
node((1.5, 5), [*Rate Limit Check*\ #label-xs[per-user / per-IP]], fill: c-gateway),
|
|
|
|
// Route
|
|
node((1.5, 6), [*Route to Service*], fill: c-gateway),
|
|
|
|
// Targets
|
|
node((0, 7), [*API*], fill: c-api),
|
|
node((1.5, 7), [*Web SM*], fill: c-session),
|
|
node((3, 7), [*TUI SM*], fill: c-session),
|
|
|
|
// Edges
|
|
edge((0, 0), (0, 1), "-|>"),
|
|
edge((0, 1), (0, 2), "-|>"),
|
|
edge((0, 2), (0, 3), "-|>"),
|
|
edge((0, 3), (-1.5, 4), "-|>", label: label-sm[invalid], label-side: left),
|
|
edge((0, 3), (1.5, 4), "-|>", label: label-sm[valid], label-side: right),
|
|
edge((1.5, 4), (1.5, 5), "-|>"),
|
|
edge((1.5, 5), (1.5, 6), "-|>"),
|
|
edge((1.5, 6), (0, 7), "-|>", label: label-sm[`/api/*`], label-side: left),
|
|
edge((1.5, 6), (1.5, 7), "-|>", label: label-sm[`/web`], label-side: left),
|
|
edge((1.5, 6), (3, 7), "-|>", label: label-sm[`/ws/tui`], label-side: right),
|
|
)
|
|
]
|
|
|
|
// ============================================================
|
|
// 3. REAL-TIME EVENT FLOW
|
|
// ============================================================
|
|
#section[3 · Real-Time Event Flow]
|
|
|
|
#align(center)[
|
|
#diagram(
|
|
spacing: (3.5em, 2.2em),
|
|
node-stroke: s-main,
|
|
node-corner-radius: 4pt,
|
|
|
|
// Trigger
|
|
node((0, 0), [*User sends message*\ #label-xs[POST /api/messages]], fill: c-client),
|
|
|
|
// API
|
|
node((0, 1), [*API*\ #label-xs[validate · write to DB]], fill: c-api),
|
|
|
|
// Two steps: DB write then NATS publish
|
|
node((-1, 2.2), [*PostgreSQL*\ #label-xs[INSERT message row]], fill: c-infra),
|
|
node((1, 2.2), [*NATS*\ #label-xs[publish `chat.events.\{community\}`]], fill: c-bus),
|
|
|
|
// Fan out — SMs subscribe to NATS
|
|
node((-1.5, 3.8), [*Web SM*\ #label-xs[receives via NATS sub]], fill: c-session),
|
|
node((0, 3.8), [*TUI SM*\ #label-xs[receives via NATS sub]], fill: c-session),
|
|
node((1.5, 3.8), [*Mobile SM*\ #label-xs[NATS sub]], fill: c-future, stroke: s-dim),
|
|
|
|
// Client delivery — SMs fetch full data from API
|
|
node((-1.5, 5), [*Fetch full message*\ #label-xs[GET /api/messages/:id]], fill: c-api),
|
|
|
|
node((-1.5, 6.2), [*Datastar SSE*\ #label-xs[push HTML fragment]], fill: c-session),
|
|
node((0, 6.2), [*SSE*\ #label-xs[push JSON payload]], fill: c-session),
|
|
|
|
// Clients
|
|
node((-1.5, 7.4), [*Browser*\ #label-xs[DOM patched live]], fill: none, stroke: none),
|
|
node((0, 7.4), [*Terminal*\ #label-xs[message rendered]], fill: none, stroke: none),
|
|
|
|
// Edges
|
|
edge((0, 0), (0, 1), "-|>"),
|
|
edge((0, 1), (-1, 2.2), "-|>", stroke: s-data,
|
|
label: text(size: 7pt, fill: rgb("#7b1fa2"))[INSERT], label-side: left),
|
|
edge((0, 1), (1, 2.2), "-|>", stroke: s-bus,
|
|
label: text(size: 7pt, fill: rgb("#e65100"))[publish], label-side: right),
|
|
edge((1, 2.2), (-1.5, 3.8), "-|>", stroke: s-bus),
|
|
edge((1, 2.2), (0, 3.8), "-|>", stroke: s-bus),
|
|
edge((1, 2.2), (1.5, 3.8), "-|>", stroke: s-dim),
|
|
edge((-1.5, 3.8), (-1.5, 5), "-|>"),
|
|
edge((0, 3.8), (0, 6.2), "-|>"),
|
|
edge((-1.5, 5), (-1.5, 6.2), "-|>"),
|
|
edge((-1.5, 6.2), (-1.5, 7.4), "-|>"),
|
|
edge((0, 6.2), (0, 7.4), "-|>"),
|
|
)
|
|
]
|
|
|
|
// ============================================================
|
|
// 4. DATA MODEL
|
|
// ============================================================
|
|
#section[4 · Data Model]
|
|
|
|
#align(center)[
|
|
#diagram(
|
|
spacing: (4em, 2.5em),
|
|
node-stroke: s-main,
|
|
node-corner-radius: 3pt,
|
|
|
|
// Core entities
|
|
node((2.5, 1.0), [*communities*\ #label-xs[id · name · slug]], fill: rgb("#e1bee7")),
|
|
node((0.3, 1.9), [*users*\ #label-xs[id · username · email\ display\_name · avatar]], fill: rgb("#bbdefb")),
|
|
node((5.0, 0.7), [*channels*\ #label-xs[id · name · type\ public / private / voice]], fill: rgb("#c8e6c9")),
|
|
|
|
// Junction
|
|
node((2.6, 2.0), [*community\_members*\ #label-xs[role: owner / admin / member\ nickname · avatar override]], fill: rgb("#f0f4c3")),
|
|
node((2.4, 0.1), [*channel\_members*\ #label-xs[joined\_at]], fill: rgb("#f0f4c3")),
|
|
|
|
// Messages
|
|
node((2.6, 4.1), [*messages*\ #label-xs[id · body\_md · parent\_id\ created\_at · edited\_at]], fill: rgb("#ffe0b2")),
|
|
|
|
// Related
|
|
node((0.4, 0.0), [*notifications*\ #label-xs[id · type · source\_id\ read: bool]], fill: rgb("#ffccbc")),
|
|
node((5.2, 5.0), [*attachments*\ #label-xs[id · filename · storage\_key\ content\_type · size]], fill: rgb("#d1c4e9")),
|
|
node((2.0, 6.3), [*reactions*\ #label-xs[emoji · user\_id\ PK: msg + user + emoji]], fill: rgb("#fff9c4")),
|
|
node((4.1, 6.3), [*mentions*\ #label-xs[target\_type · target\_id]], fill: rgb("#ffccbc")),
|
|
node((5.0, 2.7), [*webhooks*\ #label-xs[id · name · token\_hash\ channel\_id · avatar]], fill: rgb("#b2dfdb")),
|
|
|
|
// Auth
|
|
node((0.2, 3.9), [*sessions*\ #label-xs[token\_hash · expires\_at]], fill: rgb("#cfd8dc")),
|
|
node((0.0, 8.0), [*api\_users*\ #label-xs[name · scopes]], fill: rgb("#cfd8dc")),
|
|
node((2.6, 8.0), [*api\_tokens*\ #label-xs[token\_hash · scopes · expires]], fill: rgb("#cfd8dc")),
|
|
|
|
// Relationships
|
|
edge((2.5, 1.0), (5.0, 0.7), "-|>", label: label-sm[has], label-side: right),
|
|
edge((2.5, 1.0), (2.6, 2.0), "-|>", label: label-sm[membership], label-side: left),
|
|
edge((0.3, 1.9), (2.6, 2.0), "-|>"),
|
|
edge((5.0, 0.7), (2.4, 0.1), "-|>"),
|
|
edge((0.3, 1.9), (2.4, 0.1), "-|>"),
|
|
edge((5.0, 0.7), (2.6, 4.1), "-|>"),
|
|
edge((0.3, 1.9), (2.6, 4.1), "-|>", label: label-sm[author], label-side: left),
|
|
edge((2.6, 4.1), (2.6, 4.1), "-|>", bend: 130deg, label: label-sm[thread], label-side: right),
|
|
edge((2.6, 4.1), (5.2, 5.0), "-|>"),
|
|
edge((2.6, 4.1), (2.0, 6.3), "-|>"),
|
|
edge((2.6, 4.1), (4.1, 6.3), "-|>"),
|
|
edge((0.3, 1.9), (0.4, 0.0), "-|>"),
|
|
edge((0.3, 1.9), (2.0, 6.3), "-|>", bend: -10deg),
|
|
edge((0.3, 1.9), (0.2, 3.9), "-|>", label: label-sm[owns], label-side: left),
|
|
edge((0.0, 8.0), (2.6, 8.0), "-|>"),
|
|
edge((5.0, 0.7), (5.0, 2.7), "-|>"),
|
|
)
|
|
]
|
|
|
|
// ============================================================
|
|
// 5. PRESENCE & TYPING
|
|
// ============================================================
|
|
#section[5 · Presence & Typing Indicators]
|
|
|
|
#align(center)[
|
|
#diagram(
|
|
spacing: (3.5em, 2em),
|
|
node-stroke: s-main,
|
|
node-corner-radius: 4pt,
|
|
|
|
// Heartbeat flow
|
|
node((-1, 0), [*Heartbeat (60s)*], stroke: none, fill: none),
|
|
node((2.5, 0), [*Typing*], stroke: none, fill: none),
|
|
|
|
// Heartbeat
|
|
node((-1, 1), [*Client*\ #label-xs[POST /api/heartbeat]], fill: c-client),
|
|
node((-1, 2), [*API*\ #label-xs[instant 200 response]], fill: c-api),
|
|
node((-1, 3.2), [*PostgreSQL*\ #label-xs[UPDATE last\_seen\_at]], fill: c-infra),
|
|
node((-1, 4.0), [*NATS*\ #label-xs[API publishes presence event]], fill: c-bus),
|
|
node((-1, 5.2), [*Session Managers*\ #label-xs[receive via NATS sub]\ #label-xs[buffer → flush 1x/min per client]\ #label-xs[filter: relevant users only]\ #label-xs[diff: status changes only]], fill: c-session),
|
|
node((-1, 6.8), [*Clients*\ #label-xs[batched presence snapshot]], fill: none, stroke: none),
|
|
|
|
// Typing — SM publishes directly to NATS, not via API
|
|
node((2.5, 1), [*Keypress in input*], fill: c-client),
|
|
node((2.5, 2), [*Session Manager*\ #label-xs[receives via HTTP POST]], fill: c-session),
|
|
node((2.5, 3.2), [*NATS*\ #label-xs[SM publishes typing event]\ #label-xs[no API round-trip]], fill: c-bus),
|
|
node((2.5, 4.5), [*Other SMs*\ #label-xs[receive via NATS sub]\ #label-xs[filter: same channel/DM]\ #label-xs[deliver immediately]], fill: c-session),
|
|
node((2.5, 5.8), [*Clients*\ #label-xs[show "user is typing..."]], fill: none, stroke: none),
|
|
node((2.5, 6.8), [*Auto-expire*\ #label-xs[15s no keypress → hide]\ #label-xs[typing:stop on send or clear input]], fill: rgb("#fff3e0")),
|
|
|
|
// Heartbeat edges
|
|
edge((-1, 1), (-1, 2), "-|>"),
|
|
edge((-1, 2), (-1, 3.2), "-|>", stroke: s-data),
|
|
edge((-1, 3.2), (-1, 4.0), "-|>", stroke: s-bus),
|
|
edge((-1, 4.0), (-1, 5.2), "-|>", stroke: s-bus),
|
|
edge((-1, 5.2), (-1, 6.8), "-|>"),
|
|
|
|
// Typing edges
|
|
edge((2.5, 1), (2.5, 2), "-|>"),
|
|
edge((2.5, 2), (2.5, 3.2), "-|>", stroke: s-bus),
|
|
edge((2.5, 3.2), (2.5, 4.5), "-|>", stroke: s-bus),
|
|
edge((2.5, 4.5), (2.5, 5.8), "-|>"),
|
|
)
|
|
]
|
|
|
|
// ============================================================
|
|
// 6. CLI / TUI CLIENT
|
|
// ============================================================
|
|
#section[6 · CLI / TUI Client]
|
|
|
|
#align(center)[
|
|
#diagram(
|
|
spacing: (3.5em, 2em),
|
|
node-stroke: s-main,
|
|
node-corner-radius: 4pt,
|
|
|
|
// Entry
|
|
node((1, 0), [*`ajet-chat`*\ #label-xs[single binary · babashka/bbin]], fill: c-client),
|
|
|
|
// Branch
|
|
node((0, 1.5), [*CLI Mode*\ #label-xs[`ajet-chat <cmd> [args]`]\ #label-xs[one-shot · stateless]], fill: rgb("#e3f2fd")),
|
|
node((2, 1.5), [*TUI Mode*\ #label-xs[`ajet-chat` (no args)]\ #label-xs[interactive · clojure-tui]], fill: rgb("#e8f5e9")),
|
|
|
|
// CLI details
|
|
node((-0.5, 3), [*Commands*\ #label-xs[send · read · channels\ notifications · status\ /help · /ban · /kick]], fill: rgb("#e3f2fd")),
|
|
node((0, 4.5), [*API Client*\ #label-xs[HTTP → Auth GW → API]], fill: c-api),
|
|
|
|
// TUI details
|
|
node((2, 3), [*UI Layout*\ #label-xs[channel sidebar\ message list · input\ presence · typing]], fill: rgb("#e8f5e9")),
|
|
node((3, 3), [*timg*\ #label-xs[inline images\ optional dep]], fill: rgb("#fff3e0")),
|
|
node((2, 4.5), [*TUI SM Connection*\ #label-xs[SSE for live updates]], fill: c-session),
|
|
|
|
// Shared
|
|
node((1, 6), [*Shared Components*\ #label-xs[API client · auth/config (~/.config/ajet-chat/)\ message formatting · notification model]], fill: rgb("#f5f5f5"), width: 20em),
|
|
|
|
// Edges
|
|
edge((1, 0), (0, 1.5), "-|>", label: label-sm[args], label-side: left),
|
|
edge((1, 0), (2, 1.5), "-|>", label: label-sm[no args], label-side: right),
|
|
edge((0, 1.5), (-0.5, 3), "-|>"),
|
|
edge((-0.5, 3), (0, 4.5), "-|>"),
|
|
edge((2, 1.5), (2, 3), "-|>"),
|
|
edge((2, 3), (2, 4.5), "-|>"),
|
|
edge((0, 4.5), (1, 6), "-|>"),
|
|
edge((2, 4.5), (1, 6), "-|>"),
|
|
)
|
|
]
|
|
|
|
// ============================================================
|
|
// 7. DEPLOYMENT
|
|
// ============================================================
|
|
#section[7 · Deployment]
|
|
|
|
#align(center)[
|
|
#diagram(
|
|
spacing: (3em, 2em),
|
|
node-stroke: s-main,
|
|
node-corner-radius: 4pt,
|
|
|
|
// Dev
|
|
node((-1, 0), [*Development*], stroke: none, fill: none),
|
|
node((3, 0), [*Production*], stroke: none, fill: none),
|
|
|
|
// Dev stack
|
|
node((-1, 1), [*docker-compose.dev.yml*\ #label-xs[infrastructure only]], fill: c-edge),
|
|
node((-2.5, 2.5), [*PostgreSQL*\ #label-xs[container]], fill: c-infra),
|
|
node((-1, 2.5), [*NATS*\ #label-xs[container]], fill: c-bus),
|
|
node((0.5, 2.5), [*MinIO*\ #label-xs[container]], fill: c-infra),
|
|
node((-1, 4), [*Clojure REPLs*\ #label-xs[local JVM processes]\ #label-xs[nrepl + cider-nrepl]\ #label-xs[start! / stop! / reset!]], fill: c-api, width: 14em),
|
|
|
|
// Prod stack
|
|
node((3.5, 1), [*docker-compose.yml*\ #label-xs[full stack]], fill: c-edge),
|
|
node((2.5, 2.5), [*nginx*], fill: c-edge),
|
|
node((2.5, 3.5), [*Auth GW*\ #label-xs[uberjar]], fill: c-gateway),
|
|
node((2, 4.5), [*API*\ #label-xs[uberjar]], fill: c-api),
|
|
node((3, 4.5), [*Web SM*\ #label-xs[uberjar]], fill: c-session),
|
|
node((4, 4.5), [*TUI SM*\ #label-xs[uberjar]], fill: c-session),
|
|
node((2, 5.8), [*PostgreSQL*], fill: c-infra),
|
|
node((3, 5.8), [*NATS*], fill: c-bus),
|
|
node((4, 5.8), [*MinIO*], fill: c-infra),
|
|
|
|
// Dev edges
|
|
edge((-1, 1), (-2.5, 2.5), "-|>"),
|
|
edge((-1, 1), (-1, 2.5), "-|>"),
|
|
edge((-1, 1), (0.5, 2.5), "-|>"),
|
|
edge((-1, 4), (-2.5, 2.5), "<-|>", stroke: s-data, label: label-sm[JDBC], label-side: left),
|
|
edge((-1, 4), (-1, 2.5), "<-|>", stroke: s-bus, label: label-sm[pub/sub], label-side: left),
|
|
edge((-1, 4), (0.5, 2.5), "<-|>", stroke: s-data, label: label-sm[S3], label-side: right),
|
|
|
|
// Prod edges
|
|
edge((3.5, 1), (2.5, 2.5), "-|>"),
|
|
edge((2.5, 2.5), (2.5, 3.5), "-|>"),
|
|
edge((2.5, 3.5), (2, 4.5), "-|>"),
|
|
edge((2.5, 3.5), (3, 4.5), "-|>"),
|
|
edge((2.5, 3.5), (4, 4.5), "-|>"),
|
|
edge((2, 4.5), (2, 5.8), "-|>", stroke: s-data),
|
|
edge((2, 4.5), (3, 5.8), "-|>", stroke: s-bus),
|
|
edge((2, 4.5), (4, 5.8), "-|>", stroke: s-data),
|
|
)
|
|
]
|