Project Specification · Draft 0.7 · P2 complete · Overlay v1 · Scan v1

StarBuddy / Org Forge Ledger

A cross-platform companion tool that gives a Star Citizen org one shared answer to three questions: what resources do we hold, who can craft what, and what should we craft next.

DATE 2026-08-25 AUTHOR ulrich.dahl@gmail.com + Claude GAME Alpha 4.9 LIVE (4.10 PTU) TARGETS Windows 10/11 · Linux

01 · Vision

One ledger for the whole org

Crafting went live in Alpha 4.7 (March 2026). Blueprints are account-bound and wipe-proof; resources carry quality that directly drives crafted item stats. That makes an org's real capability the combination of every member's blueprint library and every member's material stash — a combination no player can see in-game, and no existing community tool tracks across an org.

StarBuddy tracks three asset classes per member and per storage location — resources (with quality), blueprints, and refining orders — filling in automatically from each player's Game.log where possible, and via fast manual entry or screenshot OCR where the log is silent. On top of that ledger it answers:

Delivery surfaces, in priority order: a desktop client (log watcher + entry UI), a website sharing the same backend, Discord integration (login, slash commands, notifications), and a hotkey-activated in-game overlay.

Why now

Regolith.rocks — the org-collaboration tool of the mining era — shut down 1 June 2026. Every surviving crafting tool (SC-Craft.Tools, SC Crafting Lab, SC DataHub, SCForge…) is a single-player calculator or database. Nothing today offers an org-wide ledger, a blueprint coverage matrix, a Discord-native workflow, or Linux support. That entire niche is vacant.

02 · Ground Truth

What the Game.log actually gives us

Verified against 192 real session logs on this machine (builds 11010425 → 12344265, Jan–Aug 2026, Alpha 4.6 → 4.9), cross-checked against community parsers. The log is an append-only text file, rotated into logbackups/ on every game start — identical relative path on Windows and inside the Wine prefix on Linux.

SignalIn the log?Detail available
Blueprint acquired Yes Localized item name only, via HUD notification — and players with custom localization packs log different names for the same blueprint. The client resolves names to the canonical item class by reverse-mapping the player's own data/Localization/*/global.ini (item_Name<Class>=Display Name); unresolved names fall back to the server's stock-name table and an alias review queue. [BP] tokens in contract names also mark blueprint-reward missions.
Refinery order completed Partial Timestamp + station name only. No materials, yields, method, or cost. Fires only while logged in.
Refinery order created No Kiosk events fire but the payload is empty (request[]). This is why Regolith used OCR.
Crafting job start/finish Not found No fabricator queue events in any 4.7–4.9 log examined; no community parser has them either. Treat as UI-only; re-verify each patch.
Shop buy / sell Yes Item class, GUID, quantity, price since 3.23 — includes refined-ore sales at refinery kiosks. Useful for auto-decrementing sold stock.
Inventory quantities / quality No Browsing logs item class names as pages load, but never counts, SCU, or quality. Resources require manual entry or OCR.
Session context Yes Player handle, patch version, locations, missions accepted/ended — enough to attribute events to member + patch automatically.

Representative lines from this machine's own logs:

<2026-05-14T14:53:29.219Z> [Notice] <SHUDEvent_OnNotification> Added notification "Received Blueprint: Monde Helmet Hiro: " [116] to queue. … <2026-07-28T13:45:54.143Z> [Notice] <SHUDEvent_OnNotification> Added notification "A Refinery Work Order has been Completed at Levski: " [4] to queue. … <2026-07-28T13:50:28.135Z> [Notice] <CEntityComponentShopUIProvider::SendShopBuyRequest> … itemName[Mining_Laser_THCN_Helix_S2] quantity[3] …
Format volatility

CIG treats the log as debug output and has broken parsers repeatedly (kill events restricted in 4.0.2, tags renamed between 4.1.0 → 4.1.1). Notification texts are localized — English-only regexes break on other g_language settings. The parser must read build/version from the log header and gate its regexes per version, the way all-slain does.

Game mechanics the data model must mirror

Iron874
Aslarite854
Gold644

Real crate labels — exact numbers, resource-specific bands.

Recipe data — we don't build this ourselves

The Star Citizen Wiki API exposes dedicated /blueprints endpoints (ingredients, quantities, craft time, unlocking missions, per-game-version scoping), generated from game-file dumps via ScDataDumper. We sync recipes from there per patch (with attribution), optionally self-hosting the dump pipeline later. UEX Corp API supplies commodity prices and refinery yield data for "craft vs. buy" comparisons.

03 · Compliance Posture

Staying on the right side of CIG

Star Citizen runs Easy Anti-Cheat, and CIG's July 2025 crackdown removed tolerance for anything in-process. But log tailing, non-injecting overlays, and passive screen capture sit in a well-established tolerated zone: CIG's own support pages treat overlays as a compatibility topic, log-reading tools have operated openly for years with zero known bans, and CIG features such tools on its Community Hub.

Never

Process injection or hooking · reading game memory · sending inputs to the game (automation) · scraping RSI profile pages · modifying game files.

Always

Separate OS windows only · read-only Game.log tailing · OCR strictly opt-in and user-triggered · publish the non-injecting design prominently · post to RSI Community Hub for implicit blessing.

04 · Features

Feature set

Shipped as of v0.1.2 (2026-08-25) — production at one community, self-hostable by others

Web app: Discord login gated to the home server; dashboard with org join/leave and pooled stats; materials ledger with exact per-resource quality bands, spawn-derived rarity, keyboard-first sticky entry, filters, sorting, pagination; items ledger; blueprints with canonical item-class identity across localization packs; refinery orders; CSV bulk import and audited bulk clear; craft list with holders count and human-readable item types; craft modal with product stats (base vs. quality-modified), per-material Low/Mid/High stack selection, batch crafting, personal/org blueprint-use tracking, and undo (modal and Items page). Desktop client (Windows/Linux): logbackups import, live Game.log watcher with auto-sync, pairing codes, dev and tagged releases. Bot: /starbuddy ping|whoami|stash|org …, org administration by server admins, self-branding avatar. Platform: Docker Compose production behind an external proxy, cron auto-updater, nightly wiki syncs (recipes, item classification and stats, resource types, quality bands, rarity, locations), English/Danish localization across web, client and bot, CIG fan-kit compliant footers.

F1 Log watcher shipped

Tails Game.log live and ingests logbackups history. Captures blueprint acquisitions, refinery completions, shop transactions, session/patch context. Version-gated regexes; Wine-prefix path autodetection on Linux.

F2 Quick resource entry shipped

Keyboard-first flow: autocomplete resource → type the exact quality number off the crate label (known values for that resource offered as one-key chips) → amount in crates (0.001 SCU steps) or pieces for raw/gems → storage location. The form is sticky: location, visibility, and last quality carry over to the next line, so bulk-entering a hangar full of containers means changing only what differs. Target: under 5 seconds per line. Refinery-completion events pop a pre-filled "what was in this order?" prompt.

F3 Org ledger shipped

Per-member, per-location stashes of resources (exact quality), general items (no quality — crafted items and their buffs come later), blueprints, and pending refinery orders. Everything is private by default; members opt stashes into org visibility. Transfer + consumption bookkeeping.

F4 Blueprint coverage matrix shipped

Shipped as the craft list (holders count, "you have it"), the modal's holder list with per-copy personal/org use counts, and the member × blueprint matrix view on the Blueprints page. Answers "who can craft X" instantly; highlights coverage gaps worth grinding for. Log import only reaches as far back as logbackups on disk, so members can also mark blueprints owned manually — starter-set blueprints and pre-install acquisitions come in this way.

F5 Craftability engine shipped

Joins ledger × recipes: everything craftable right now (with best achievable output quality), then nearest-misses ranked by least missing material. Filters on blueprint tags: type, resource, grade, size, tier.

F6 Need-driven search shipped

Search for an item → blueprint holders + best-quality ingredient sources across the org, with locations and the quality math for expected output stats. Entry points: the "Find an item" search in the top bar (lands on the craft list with unowned recipes included), the craft modal, and /starbuddy need in Discord.

F7 Discord integration shipped

Discord OAuth is the only login; org membership via guild roles. Bot slash commands, all under one /starbuddy root (/starbuddy craftable, /starbuddy need, /starbuddy whoami, /starbuddy org …; /starbuddy stash is still a placeholder) and channel notifications for refinery completions (transfers later). Replies follow the member's language.

F8 OCR capture P3

Opt-in screenshot capture of refinery and inventory screens. Local PaddleOCR (ONNX) + fuzzy matching against the known resource vocabulary — the proven, open-source Regolith recipe. User confirms parsed values before sync. Strictly local: screenshots never leave the player's machine.

F9 Overlay P4

Hotkey-toggled transparent always-on-top window over the game. Tiered by platform (see §06); the web UI on a second screen/phone is the universal fallback and ships first.

F10 Website shipped

Same backend, browser UI for members without the desktop client: ledger browsing, craftability lists, entry forms, org admin.

05 · Architecture

System shape

One central backend, three thin faces on it. The desktop client is the only component that touches the player's machine (log file, screenshots, overlay); everything shared lives server-side.

Tenancy model: the community instance

StarBuddy ships as a self-hostable community platform, not a public SaaS. One deployment serves one community: it is bound to a single Discord server, and only members of that server can join. Inside an instance there can be multiple orgs — org membership and roles map from the community server's Discord roles (with in-app admin override). Another community that wants StarBuddy deploys its own instance and configures its own Discord application and bot; nothing is shared between instances.

ComponentChoiceRationale
Desktop client Tauri v2 (Rust core, web UI) ~10 MB installer; Rust notify for log tailing; official updater covers NSIS + AppImage/deb/rpm; overlay windows on Windows/X11; runner-up: Electron if overlay polish (hover forwarding) proves critical.
Backend Decided Laravel 12 + PostgreSQL Team's home turf. Socialite (Discord OAuth), Sanctum (desktop-client API tokens), Reverb (websockets for live ledger updates), queues + scheduler for recipe sync and notification fan-out.
Web frontend Decided React (+ MUI) SPA SPA against the Sanctum API — the same API the Tauri client consumes, so web and desktop share a React + MUI component library.
Deployment Decided Docker Compose Published docker-compose.yml + .env.example is the distribution: app (PHP-FPM), web (Caddy, auto-TLS), db (Postgres), redis, queue, scheduler, reverb (one app image) + bot (Node image). Nightly pg_dump sidecar.
Recipe data SC Wiki API /blueprints sync per patch Ingredients, quantities, craft times, tags, version-scoped. UEX API for prices/refinery methods. Attribution to both.
OCR PaddleOCR PP-OCRv4 ONNX, local, in client Field-proven on SC refinery screens by Regolith (open source). Closed vocabulary + Levenshtein correction; numbers validated and user-confirmed.
Auth Discord OAuth only, home-guild gated No passwords stored; joining requires membership of the instance's Discord server; org + role mapping from guild roles. Optional RSI handle verification later (token-in-bio pattern) — never RSI scraping from our servers without review.
Discord bot Decided Node + discord.js sidecar Richest Discord ecosystem. Own container; talks to Laravel over an internal service API (token-authenticated, not exposed by Caddy) and receives notification jobs from the backend queue via webhook/redis. Slash commands + embeds registered against the instance's own Discord application.

Data model (first cut)

EntityKey fields
memberdiscord_id, handle, org roles, visibility defaults
locationmember_id?, kind (hangar / freight elevator / ship / base), station, name
resource_typename, category (ore / refined / salvage / gem / …), unit (mSCU / pieces), known_qualities[] — quality values seen for this resource, learned from entries/OCR and patch-data sync, offered as entry chips
resource_stacklocation_id, resource_type_id, quality (exact number off the crate, 0–1000), quantity_mscu | quantity_pieces, visibility (private default / org), source (manual / ocr / log), updated_by, updated_at
item_stacklocation_id, item_class (any game item — weapons, components, commodities…), quantity, visibility — no quality; crafted-item buff tracking is a later extension
blueprint_ownedmember_id, blueprint_id (resolved from recipe DB), raw localized name, item_class (canonical identity, resolved client-side via the player's localization file), acquired_at, source_event
recipeblueprint_id, item, tier, tags[], craft_time, ingredient slots (resource_type, qty_mscu, min_quality), game_version
refinery_ordermember_id, station, materials[] (entered/OCR), method, placed_at, eta, completed_at (from log event)
craft_jobrecipe_id, crafter member_id, reserved stacks[], status — manual tracking until the log proves otherwise

06 · Platform Matrix

Overlay & hotkey feasibility

Star Citizen has no exclusive-fullscreen mode (borderless only), which makes external overlay windows viable everywhere the window system cooperates. No existing SC overlay supports Linux at all — this is a differentiator.

PlatformOverlayHotkeyApproach
Windows 10/11 Proven Proven Layered transparent click-through topmost window (SC Overlay / Arkanis pattern). RegisterHotKey + Raw Input fallback. EAC-safe by construction.
Linux · X11 / XWayland Feasible XGrabKey Override-redirect ARGB window + XShape empty input region + self-re-raise. Needs a running compositor.
Linux · Wayland (KDE, Hyprland, Sway, …) Clean Portal / IPC wlr-layer-shell overlay layer stacks above the XWayland game by design. GlobalShortcuts portal on KDE/Hyprland; Sway via user keybind → IPC.
Linux · Wayland (GNOME) No clean path Portal Mutter refuses layer-shell. Ship the web-UI fallback; document it.
Steam Deck Game Mode Closed Gamescope's external overlay slot is taken by mangoapp; LUG doesn't support Proton installs anyway. Deck works as a companion browser device instead.

Consequence: the overlay is built as one core with two window backends (layered-window / layer-shell + X11), and the localhost/LAN web UI is the tier-0 fallback that always works — second monitor, phone, tablet, Deck.

07 · Roadmap

Phased delivery

P1MVP

Ledger + log watcher + web done · v0.1.0

  • Backend, Discord OAuth, org/member/location/stash schema.
  • Desktop client: log watcher (blueprints, refinery completions, shop sales) + quick resource entry; historical logbackups import on first run.
  • Web UI: ledger browsing, entry forms, blueprint coverage matrix.
  • Discord webhook: refinery-completion pings to a channel.
P1.1Bulk

Bulk import & clear done · v0.1.0

  • CSV import of existing org resources: template download; columns for member handle, location, resource, quality, quantity, unit; per-row validation with a preview step before anything is committed; row-level error report.
  • Bulk clear of org inventory by resource type or category, scopable to member or location, with confirmation and an audit-log entry recording what was cleared and by whom.
P2Brain

Craftability engine + bot done · v0.1.4

  • Recipe and item-classification sync from the Wiki API; craft-now and nearest-miss lists with filters; craft modal with product stats, stack selection, batch crafts, blueprint uses and undo; org administration via /starbuddy org; localized bot replies.
  • /starbuddy craftable and /starbuddy need on a shared craftability service; refinery-completion pings to a configurable channel (live events only); "Find an item" search in the top bar; member × blueprint matrix view.
P2+Alarm

RSI maintenance alarm Done

Pulled forward because it is testable today and the payoff is immediate: RSI posts a maintenance notice on status.robertsspaceindustries.com roughly 30 minutes before servers go down, and that window is all players get to stow ships and gear.

  • Backend polls the status page's cstate JSON every minute (starbuddy:poll-rsi-status), mirrors incidents in rsi_incidents, and classifies each change as new / updated / resolved. The announced shutdown time ("Servers will go offline at 1445 UTC") is parsed out of the notice.
  • Discord: a new notice posts to STARBUDDY_STATUS_CHANNEL_ID with a configurable ping (@here, a role, or none) and a Discord-native relative time for the shutdown; updates and the all-clear post without pinging. /starbuddy status answers on demand.
  • Website: a severity-coloured banner under the top bar on every page with a live countdown, affected systems, the full notice on demand, opt-in browser notifications, and a ⚠ tab-title prefix; collapses to a one-line strip and re-expands whenever RSI edits the notice.
  • Desktop client: same banner plus a native OS notification on first sight of a new notice — the surface that reaches a player who is in-game.
  • Status overlay window (first P4 surface, pulled forward): a frameless, transparent, always-on-top Tauri window toggled by a configurable global hotkey (default Ctrl+Alt+S; on Wayland desktops a --toggle-status CLI flag bound to a desktop-environment key does the same through the single-instance plugin). Shows green "All systems operational" with the per-system list, or the severity-coloured notice with a shutdown countdown. Every overlay window shares the Launcher-Glass chrome and a size · placement · opacity · close cluster: Full/Minimal, floating or docked left/right (drag along the edge) / top/bottom (centred strip), per-window opacity 25–100 %, all persisted per window in overlay.json.

Feature versions

Each feature carries a single-digit version so the roadmap can name a target state per feature instead of per release. v0 = pipeline proven, output is raw; v1 = first useful behaviour; higher = refinement.

FeatureNowNext
Maintenance alarmv1 — Discord ping, web banner, client notification, status overlay windowv2: per-member opt-in roles, quiet hours
Overlay windowsv1 — Launcher Glass chrome, floating/docked modes with along-edge drag, Full/Minimal, per-window opacity and position, hotkeys, KDE layer rulev2: click-through outside controls, layer-shell backend on Linux
Vision (screen understanding)v0 planned — a small on-device object detector (YOLO-nano class, ONNX, ~6 MB, CPU ≈ 20–40 ms per frame) that finds regions of interest in the game frame and names them: fabricator kiosk header / "Owned" chip / hover tooltip, crafting resource rows, refinery order card, shop price tag, inventory slot name, scan badge. Each detection is cropped, upscaled and read with the existing OCR, and emitted with a context string ("fabricator blueprint", "fabricator crafting", "refinery order", …) so domain parsers know what the text is. The scene is inferred from which regions are present — no LLM needed. Trained offline (Ultralytics) on the screenshot corpus; labels bootstrapped from today's colour/OCR heuristics and checked by hand; ~50–200 frames per class suffice for a deterministic UI; exported model downloaded once like the OCR models.v0: kiosk tooltip (auto-add owned blueprints while browsing the kiosk) + scan badge (replaces the pin template); v1: crafting consumption and refinery orders; v2: inventory and shop prices
Scan (signature)v2 — hotkey captures the game (game window on Windows; on Linux the game's X window, or the focused game window via the desktop's screenshot tool for Wine's Wayland driver), finds the signature badge's pin icon among saturated HUD pixels of any hue (the badge takes the ship's HUD colour), confirms it against a map-pin shape template (real pins score ≥ 0.78, other marks ≤ 0.65, threshold 0.70) and reads the number from a 3× upscaled crop with on-device OCR (ocrs). F7 runs this live on the signature region only (~1 reading/s). The value is matched against the reference table (backend/database/data/scan-signatures.json: since Alpha 4.7 every ship mineral has a fixed base signature, a cluster shows the sum; ground deposits 3,000/4,000 encode size only) — the window names the mineral or cluster, its share range, companions, resistance, instability, rarity and quality band. Table bundled in the client, refreshed from the server.v3: auto-trigger when the scan UI is on screen, PipeWire/portal capture for Wayland-native games, more ships/resolutions in the corpus
Refinery OCRv0: read a work order off the terminal into the refinery ledger
P3aEyes

Vision — regions of interest → OCR with context (planned, agreed 2026-08-28)

  • Why a detector, not a vision LLM: CPU-only VLMs run at 0.5–8 s per frame, weigh 0.4–2 GB and transcribe less exactly than dedicated OCR; the values we need are always one of a known set (1,591 blueprint names, mineral signatures, station names). A tiny detector answers the two hard questions cheaply — where is the text and what kind is it — and ocrs reads it exactly.
  • Classes are regions, scenes are derived: kiosk_header, kiosk_owned_chip, kiosk_tooltip, craft_resource_row, refinery_order, shop_price, inventory_name, scan_badge. A frame with header + owned chip + tooltip is the scene "fabricator blueprint" (auto-add the hovered blueprint); header + resource rows is "fabricator crafting" (record what was consumed).
  • Pipeline in the client: capture (≈1 fps today) → detector (ONNX Runtime via ort; +10–20 MB runtime) → per region: crop with padding, 3× upscale, ocrs → {scene, region, text, bbox, confidence} → domain parser (fuzzy match to blueprint names, refinery fields, price + item) → action, with the same two-consecutive-frames rule the scan uses. Findings from the kiosk sweep: the tooltip reads exactly at 3× on a padded crop; whole-panel OCR misses 14 px text; the box border is too low-contrast for colour detection — precisely the gap a detector closes.
  • Training: Python/Ultralytics offline on screenshots/; weak labels from the current heuristics (badge pin finder, kiosk tooltip sweep) reviewed by hand; augment resolution (1080p–1440p–ultrawide), HUD colour, JPEG/scaling. Model versioned per game patch; retrain when CIG changes the UI. Members' screenshots (any ship, any HUD colour) are the dataset — the corpus README already asks for them.
  • Feature versions: v0 kiosk tooltip + scan badge · v1 crafting consumption + refinery orders · v2 inventory + shop prices.

Basic OCR — scan signature detection

  • Local capture pipeline (PaddleOCR/ONNX, on-device only) with a fast signature detector: recognise which game screen is on display (refinery terminal, inventory, mining scan result) from its stable UI landmarks before spending a full OCR pass.
  • Scan v2 shipped: hotkey (F7) → capture → colour-based badge finder → 3× crop → on-device OCR (pure-Rust ocrs, ≈15 MB of models fetched once) → signature → reference lookup (mineral / cluster, composition, resistance, quality band) in the scan overlay window. Verified against real captures in screenshots/ and in-game (3,400 = Lindinium).
  • Everything opt-in, hotkey- or toggle-driven; screenshots never leave the machine.
P3bRefinery

Refinery OCR — Regolith functionality

  • Read a refinery work order off the terminal: station, method, materials in, expected yields, processing time.
  • Popup offers save to refinery orders and start timer; the order lands in the member's ledger with its ETA, the timer surfaces in client, web and (optionally) a Discord ping on completion — matched against the Game.log completion event we already capture.
P4Glass

Overlay

  • Windows layered window first, then Linux layer-shell/X11 backends; hotkey chain per platform; craft-now list and quick entry in-overlay. Grows out of the status overlay window (shipped with the maintenance alarm) and the P3a scan popup.
  • Current Linux stance: under Wayland the client forces GDK_BACKEND=x11 so it runs through XWayland like the Wine game — that restores window positioning, always-on-top and X11 global hotkeys in one move; a native layer-shell backend remains the long-term fix.
P5Research

Later versions — needs research first

  • Materials OCR. Watch the inventory screen while the mouse hovers over a material and grab type, quality, crate size and quantity, auto-syncing to the ledger. Treat those four values as a crate's unique identifier — this cannot work for gems, which carry no quality. Open questions: hover detection cost, false positives on similar crates, and whether continuous scanning is acceptable at all — the likely answer is a hotkey that scans only while pressed, then a popup confirming "saved" or warning of a possible duplicate and asking what to do.
  • Rock OCR. Read a scanned rock's difficulty and composition; the popup suggests the minimum mining-laser setup (laser, modules, gadgets) able to crack it, and when the member's own setup can't, offers to look for other online org members to call in. Needs a curated laser/module capability table and a definition of "online" (Discord presence or client heartbeat).

08 · Decision Record

Settled decisions

Decided 2026-08-24

Stack: Laravel + PostgreSQL, React SPA, Docker Compose deployment. Tenancy: self-hostable community instance — one deployment per community, join-gated to members of that community's Discord server, multiple orgs per instance; other communities run their own instance with their own Discord app/bot. License: AGPL-3.0-or-later, public repository at github.com/ulrichdahl/StarBuddy.

Decided 2026-08-25

Renamed StarMaker → StarBuddy (repo, UI, client, bot; internal identifiers followed on 2026-08-27 — compose project, env keys, config, Tauri identifier — with a one-time migration in update.sh and the installer; upgrade compatibility). Blueprints are never consumed by crafting — each craft counts a personal or org use on the owner's copy. Every craft is undoable, from the modal or the Items ledger. Item types come from the wiki item classification ("Armor · Undersuit", "Radar · Industrial"), synced in bulk nightly. Localization: English default, Danish first; one JSON file per language per app; browser/OS/Discord language on first use, then remembered per member; game data is never translated. Bot commands live under one /starbuddy root. CIG fan-kit compliance: the Made-by-the-Community badge and required notice in every footer.

  1. Name: StarBuddy (renamed from StarMaker on 2026-08-25) — repo, Discord application, and any domain register under this name.
  2. Item scope: everything is enterable, only resources carry quality. The ledger accepts any game item (weapons, components, commodities) as quantity-only stacks; resources additionally carry the exact quality number. Crafted items and their quality-derived buffs are a later extension.
  3. Privacy: private by default, opt-in to org visibility per stash. The entry form is sticky — location, visibility, and last quality carry over between lines, so bulk entry never repeats settings container by container.
  4. OCR: local only, no cloud. PaddleOCR on-device; screenshots never leave the player's machine. No LLM-vision fallback.
  5. Bot: Node + discord.js in its own container, talking to the Laravel backend over an internal token-authenticated API — chosen for the Node Discord ecosystem's library depth.
  6. Frontend: React SPA against the Sanctum API, sharing a React + MUI component library with the Tauri desktop client.