Replace baked-in UOM/MysticMoon/UOMysticmoon branding with a BRAND_* env scheme so one prebuilt image runs as any shard; UOMysticmoon becomes the first tenant that sets these vars rather than a special case in the code. Architecture (chosen because the app ships as a prebuilt image): - server/src/config/brand.js + bot/src/brand.js read BRAND_* once at boot, with Runic Gateway defaults. - Text/colors reach the SPA at RUNTIME through the existing public settings API (settings.model.getPublic -> SiteContext), so no client rebuild. The admin-editable site title + contact email still override BRAND_NAME/email. - SiteContext applies BRAND_ACCENT_COLOR to the --accent CSS var at runtime. - Express templates the built index.html <title>/description/OG/favicon at serve time from BRAND_* (renderIndexHtml in app.js). - Server-side consumers read brand directly: emails, TOTP issuer, API docs, boot logs, HTML error page. Bot uses it for embed color + logs. Assets: logo/hero/favicon delivered from a ./brand:/app/brand bind-mount (BRAND_LOGO/HERO/FAVICON), with neutral defaults baked in; hero falls back to a built-in image when unset. Scope: also genericized package.json names (uomysticmoon-* -> runic-gateway-*) and the DB_NAME/DB_USER/COOKIE_NAME code defaults (runic_gateway/runic/ rg_token). Production keeps its real values by pinning them in .env — see .env.uomysticmoon.example, which reproduces the exact UOMysticmoon identity (proof the substitution works). Changing a deployed COOKIE_NAME invalidates existing sessions, so UOMysticmoon pins uomm_token. Verified: 193 server tests pass, client builds, app.js loads + templates the built index.html, brand transform injects title/description/OG/favicon.
42 lines
1.5 KiB
JavaScript
42 lines
1.5 KiB
JavaScript
// DB pool for the bot's OWN tables (guild_config, mod_actions, warnings) —
|
|
// mirrors server/src/utils/db.js. The bot never reads/writes any table it
|
|
// doesn't own; site-owned tables (users, bot_config, etc.) are reached only
|
|
// through the internal API, never directly. Schema for these tables lives in
|
|
// server/db/schema.sql (same physical database, ensured by the main server on
|
|
// boot) — there's no separate migration tool to justify a second database for
|
|
// a single-guild v1 bot.
|
|
const mariadb = require('mariadb')
|
|
|
|
const pool = mariadb.createPool({
|
|
host: process.env.DB_HOST || '127.0.0.1',
|
|
port: Number(process.env.DB_PORT) || 3306,
|
|
user: process.env.DB_USER || 'root',
|
|
password: process.env.DB_PASSWORD || '',
|
|
database: process.env.DB_NAME || 'runic_gateway',
|
|
connectionLimit: 5,
|
|
insertIdAsNumber: true,
|
|
bigIntAsNumber: true,
|
|
decimalAsNumber: true,
|
|
// The driver defaults to 'local' — silently serializing bound JS Date
|
|
// params using the HOST MACHINE's local offset instead of the DB session's
|
|
// timezone (discovered via temp_roles.expires_at coming back hours off in
|
|
// dev, CDT vs the container's UTC). 'auto' negotiates the actual session
|
|
// timezone so Date round-trips correctly regardless of host TZ.
|
|
timezone: 'auto',
|
|
})
|
|
|
|
async function query(sql, params) {
|
|
const conn = await pool.getConnection()
|
|
try {
|
|
return await conn.query(sql, params)
|
|
} finally {
|
|
conn.release()
|
|
}
|
|
}
|
|
|
|
async function close() {
|
|
await pool.end()
|
|
}
|
|
|
|
module.exports = { query, close }
|