# Breadboard — Replace Luciq: writes stay node-local, admin aggregates cross-node. # Corrected model (Lucian, 7/20): a report saves to the node it ORIGINATES from. # No central store, no nodeName FK. The app POSTs to its OWN node (JWT native — # no cross-node auth on write). The ONLY multi-tenancy bend is the admin READ, # via a service key per node. Axis A vs B = where the thin aggregator UI lives; # NEITHER owns a database. # Render: ../../../.claude/skills/breadboarding/render.sh luciq-architecture.d2 vars: { d2-config: { layout-engine: dagre } } classes: { place: { style: { fill: "#ffedd5"; stroke: "#f97316"; font-color: "#9a3412"; bold: true } } affordance: { style: { fill: "#ffffff"; stroke: "#94a3b8"; font-color: "#334155"; font-size: 13 } } data: { shape: cylinder; style: { fill: "#eef2f6"; stroke: "#64748b"; font-color: "#334155"; font-size: 13 } } conditional: { shape: diamond; style: { fill: "#f3e8ff"; stroke: "#9333ea"; font-color: "#6b21a8"; font-size: 13 } } note: { style: { fill: "#fef9c3"; stroke: "#eab308"; font-color: "#713f12"; font-size: 12; border-radius: 10; stroke-dash: 2 } } } grid-columns: 3 grid-gap: 90 # ───────────────────────────────────────────────────────────── current: "① CURRENT — Luciq SDK (599 USD/mo)" { style: { stroke: "#cbd5e1"; fill: "#ffffff" } app: "Mobile app (~6 flavors)" { class: place; grid-columns: 1 menu: "'Report a Bug' menu item" { class: affordance } shake: "Shake gesture" { class: affordance } } cloud: "Luciq cloud (dashboard.luciq.ai)" { class: place } app.menu -> cloud: "submit + crashes" { style.stroke: "#ef4444" } app.shake -> cloud store: "Reports + crash data in Luciq's cloud" { class: data } cloud -> store pain: "Bundles TWO jobs: crash capture\n(already duplicated by in-app Sentry)\n+ user report loop. Paying 599 USD/mo\nmostly for the redundant half." { class: note } } # ───────────────────────────────────────────────────────────── verA: "② VERSION A — aggregator page inside the Tribe CMS" { style: { stroke: "#cbd5e1"; fill: "#ffffff" } app: "Mobile app (e.g. 828 flavor)" { class: place; grid-columns: 1 form: "In-app report modal" { class: affordance; style.stroke-dash: 4 } } node: "Origin node (828)\nPOST /api/bug-report" { class: place; style.stroke-dash: 4 } app.form -> node: "POST to its OWN node — JWT native, mirrors /api/chat" db: "BugReports (NEW, one table per node)\nUserId · PlatformId · body · screenshotUrl\nappVersion · device · os\nstatus(open/closed) · adminReply · repliedAt" { class: data; style.stroke-dash: 4 } node -> db: "create (auth.isAuthenticated → req.user)" others: "…tribe · gbb nodes —\nsame table + endpoint" { class: place; style.stroke-dash: 4 } cms: "Tribe CMS ▸ 'Bug Reports' page" { class: place; grid-columns: 1; style.stroke-dash: 4 gate: "Gated: @inovo email + platform 103" { class: affordance } reply: "Reply → node /reply → email + status=closed" { class: affordance } } db -> cms.gate: "service-key READ (fan-out)" others -> cms.gate: "service-key READ" note: "One new table, single reply field — no\nthread/tags/assignment (stays out of\nticketing-system land). Follow-up = new row.\nReuses CMS shell + login." { class: note } } # ───────────────────────────────────────────────────────────── verB: "③ VERSION B — standalone thin aggregator site" { style: { stroke: "#cbd5e1"; fill: "#ffffff" } app: "Mobile app (e.g. 828 flavor)" { class: place; grid-columns: 1 form: "In-app report modal" { class: affordance; style.stroke-dash: 4 } } node: "Origin node (828)\nPOST /api/bug-report" { class: place; style.stroke-dash: 4 } app.form -> node: "POST to its OWN node" db: "BugReports (NEW, per node)\n— same schema as A" { class: data; style.stroke-dash: 4 } node -> db: "create" site: "bugs.tribesocial.io (standalone)" { class: place; grid-columns: 1; style.stroke-dash: 4 login: "Own admin login (NEW)" { class: affordance } reply: "Reply → node /reply → email" { class: affordance } } db -> site.login: "service-key READ (fan-out)" note: "IDENTICAL writes + same node endpoints.\nAggregator has NO DB — pure API fan-out.\nCost vs A: new hosting + a second admin\nlogin, for zero data benefit right now." { class: note } }