bober-bbq-bot/webapp/scripts/gen-manifest.mjs
byrsapty 922d9c5172 Make brand identity reusable for redeploying to other clients
Groundwork for reusing this codebase per-client (own VPS/DB/bot per
cafe): the operational config (bot token, DB URL, secrets, Checkbox PRRO
creds) was already .env/Setting-driven, but ~13 spots still hardcoded the
literal string "Bober BBQ" instead of reading the existing cafe_name
Setting, and the webapp's static shell (index.html title, PWA manifest)
had no templating at all since Settings only load after JS boots.

- Route the remaining hardcoded strings through Setting.get("cafe_name",
  "Bober BBQ") — same pattern already used correctly in bot/handlers/
  start.py. Every fallback stays "Bober BBQ", so production is byte-
  identical with no cafe_name override.
- Template webapp/index.html via Vite's native %VITE_CAFE_NAME% HTML
  replacement, backed by a committed webapp/.env (default "Bober BBQ",
  no secrets) with a per-client override via gitignored .env.local.
- Add webapp/scripts/gen-manifest.mjs to generate manifest.json from a
  new manifest.template.json the same way, since Vite doesn't process
  public/ assets — wired into the build script.
- Parameterize deploy.sh's systemd unit names and the admin log-viewer's
  log paths via optional SERVICE_WEB/SERVICE_BOT/LOG_FILE_WEB/
  LOG_FILE_BOT env vars, defaulting to today's literal values.
- Rewrite docs/DEPLOYMENT.md into a repeatable new-client runbook (fixed
  an existing /opt/bober-bbq vs /opt/bober-bbq-bot inconsistency, added
  a rebranding checklist).

Verified via a smoke test that every changed string still renders
"Bober BBQ" with no overrides present (matching prod's actual .env/DB
state), and that webapp builds both with and without a VITE_CAFE_NAME
override produce the expected output — including a no-override rebuild
confirming byte-identical output to before this change.
2026-08-25 17:54:29 +03:00

32 lines
1.5 KiB
JavaScript

// Regenerates public/manifest.json from manifest.template.json, substituting
// the cafe name read the same way Vite resolves it (.env.local overrides
// .env). Needed because Vite's native %VAR% HTML replacement only applies
// to index.html — files under public/ are copied to the build as-is, never
// processed. Falls back to "Bober BBQ" if no env file overrides it, so a
// clone with no webapp/.env.local (like the current production instance)
// produces byte-identical output.
import { existsSync, readFileSync, writeFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
const root = dirname(dirname(fileURLToPath(import.meta.url)));
function readEnvFile(path) {
if (!existsSync(path)) return {};
const vars = {};
for (const line of readFileSync(path, "utf-8").split("\n")) {
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith("#")) continue;
const eq = trimmed.indexOf("=");
if (eq === -1) continue;
vars[trimmed.slice(0, eq).trim()] = trimmed.slice(eq + 1).trim();
}
return vars;
}
const merged = { ...readEnvFile(join(root, ".env")), ...readEnvFile(join(root, ".env.local")) };
const cafeName = merged.VITE_CAFE_NAME || "Bober BBQ";
const template = readFileSync(join(root, "public", "manifest.template.json"), "utf-8");
writeFileSync(join(root, "public", "manifest.json"), template.replaceAll("{{CAFE_NAME}}", cafeName));
console.log(`manifest.json generated (VITE_CAFE_NAME="${cafeName}")`);