From 164a4f4ef604826a31baa4c7fcbac494b6d23b03 Mon Sep 17 00:00:00 2001 From: openhands Date: Thu, 27 Aug 2026 16:35:00 +0200 Subject: [PATCH] refactor: remove hotel-name fallback, fail fast when unconfigured Drop the hardcoded FALLBACK_HOTEL_NAME ("Atom") preset and the brand.ts module. HOTEL_NAME is now a required env var: if it (and the CMS hotel_name setting) is missing the site fails validation at startup/build with a clear message instead of silently rendering a placeholder hotel name. resolveHotelName() resolves CMS hotel_name -> required HOTEL_NAME only. Callers that used the preset (api/home route catch branch, CMS settings form default, mobile-nav/logo-generator prop defaults) now use the configured name or an empty default; the real name is already passed in by server parents. --- src/app/admin/settings/cms-settings-config.ts | 3 +-- src/app/api/home/route.ts | 4 ++-- src/components/mobile-nav.tsx | 3 +-- src/components/public/logo-generator.tsx | 3 +-- src/env.ts | 8 ++++++-- src/lib/brand.ts | 10 ---------- src/lib/hotel-name.ts | 15 +++++++-------- src/lib/services/site-settings.ts | 3 +-- 8 files changed, 19 insertions(+), 30 deletions(-) delete mode 100644 src/lib/brand.ts diff --git a/src/app/admin/settings/cms-settings-config.ts b/src/app/admin/settings/cms-settings-config.ts index 825ee15b9a..7b099f10b8 100644 --- a/src/app/admin/settings/cms-settings-config.ts +++ b/src/app/admin/settings/cms-settings-config.ts @@ -1,4 +1,3 @@ -import { FALLBACK_HOTEL_NAME } from "@/lib/brand"; import { HABBO_GAMEDATA_HOTELS } from "@/lib/habbo-gamedata-hotel"; export type FieldType = @@ -50,7 +49,7 @@ export const SETTINGS_GROUPS: SettingsGroup[] = [ label: "Hotel name", type: "text", placeholder: "Epicnabbo", - defaultValue: FALLBACK_HOTEL_NAME, + defaultValue: "", }, { key: "cms_logo", diff --git a/src/app/api/home/route.ts b/src/app/api/home/route.ts index fca4e88c27..92593e056f 100644 --- a/src/app/api/home/route.ts +++ b/src/app/api/home/route.ts @@ -1,6 +1,6 @@ import { count, desc, eq } from "drizzle-orm"; +import { env } from "@/env"; import { apiJson } from "@/lib/api"; -import { FALLBACK_HOTEL_NAME } from "@/lib/brand"; import { db, User, WebsiteArticles } from "@/lib/db"; import { resolveHotelName } from "@/lib/hotel-name"; import { apiCacheKey, cacheSafe, redisCache } from "@/lib/redis-cache"; @@ -38,7 +38,7 @@ export async function GET(_req: Request) { return apiJson(data); } catch { return apiJson( - { articles: [], online: 0, hotelName: FALLBACK_HOTEL_NAME }, + { articles: [], online: 0, hotelName: env.HOTEL_NAME }, { status: 200 }, ); } diff --git a/src/components/mobile-nav.tsx b/src/components/mobile-nav.tsx index e0bdd9d827..8ec245388c 100644 --- a/src/components/mobile-nav.tsx +++ b/src/components/mobile-nav.tsx @@ -3,7 +3,6 @@ import { AnimatePresence, motion } from "motion/react"; import Image from "next/image"; import { type ReactNode, useRef, useState } from "react"; -import { FALLBACK_HOTEL_NAME } from "@/lib/brand"; import { mobileMenuVariants } from "@/lib/motion"; interface MobileNavProps { @@ -17,7 +16,7 @@ export function MobileNav({ children, menuLabel = "Open menu", closeLabel = "Close menu", - brandLabel = FALLBACK_HOTEL_NAME, + brandLabel = "", }: MobileNavProps) { const [open, setOpen] = useState(false); const detailsRef = useRef(null); diff --git a/src/components/public/logo-generator.tsx b/src/components/public/logo-generator.tsx index 322aff7437..a654989a68 100644 --- a/src/components/public/logo-generator.tsx +++ b/src/components/public/logo-generator.tsx @@ -16,10 +16,9 @@ import { renderToCanvas, } from "@/components/public/sprite-font"; import { ContentCard } from "@/components/public/ui"; -import { FALLBACK_HOTEL_NAME } from "@/lib/brand"; export default function LogoGenerator({ - initialText = FALLBACK_HOTEL_NAME, + initialText = "", }: { initialText?: string; }) { diff --git a/src/env.ts b/src/env.ts index 4b6e751a74..06059814a0 100644 --- a/src/env.ts +++ b/src/env.ts @@ -1,5 +1,4 @@ import { z } from "zod"; -import { FALLBACK_HOTEL_NAME } from "@/lib/brand"; // Minimal validated env for the foundation. When the Next.js app is added this // will move to @t3-oss/env-nextjs (the habbo-next pattern), but the data layer @@ -25,7 +24,12 @@ const schema = z .int() .positive() .default(10_000), - HOTEL_NAME: z.string().default(FALLBACK_HOTEL_NAME), + HOTEL_NAME: z + .string() + .min( + 1, + "HOTEL_NAME is not set — the site has not been configured/built yet.", + ), APP_URL: z.string().url().default("http://localhost:3000"), NEXT_PUBLIC_APP_URL: z.string().url().default("http://localhost:3000"), // Public imager URL — overrides the default /imaging relative path. diff --git a/src/lib/brand.ts b/src/lib/brand.ts deleted file mode 100644 index 8c3551beba..0000000000 --- a/src/lib/brand.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Single hardcoded fallback hotel brand. - * Override order at runtime: - * 1. website_settings.hotel_name - * 2. HOTEL_NAME env - * 3. this constant - * - * Safe for client components (no env / DB imports). - */ -export const FALLBACK_HOTEL_NAME = "Atom"; diff --git a/src/lib/hotel-name.ts b/src/lib/hotel-name.ts index ddf7a547c7..2ec742c6bf 100644 --- a/src/lib/hotel-name.ts +++ b/src/lib/hotel-name.ts @@ -1,17 +1,16 @@ import "server-only"; import { env } from "@/env"; -import { FALLBACK_HOTEL_NAME } from "@/lib/brand"; import { siteSettings } from "@/lib/services/site-settings"; /** - * Resolve the public hotel name: CMS setting → HOTEL_NAME env → FALLBACK_HOTEL_NAME. + * Resolve the public hotel name: CMS `hotel_name` setting, falling back to the + * required HOTEL_NAME env var. There is no hardcoded preset — the site must be + * configured, otherwise HOTEL_NAME fails validation at startup. */ export async function resolveHotelName(): Promise { - const fromSettings = await siteSettings.get("hotel_name", env.HOTEL_NAME); - const trimmed = fromSettings?.trim(); - if (trimmed) return trimmed; - const fromEnv = env.HOTEL_NAME?.trim(); - if (fromEnv) return fromEnv; - return FALLBACK_HOTEL_NAME; + const fromSettings = ( + await siteSettings.get("hotel_name", env.HOTEL_NAME) + )?.trim(); + return fromSettings || env.HOTEL_NAME; } diff --git a/src/lib/services/site-settings.ts b/src/lib/services/site-settings.ts index 92cf885ad5..42abc845d4 100644 --- a/src/lib/services/site-settings.ts +++ b/src/lib/services/site-settings.ts @@ -1,12 +1,11 @@ import "server-only"; -import { FALLBACK_HOTEL_NAME } from "@/lib/brand"; import { db, WebsiteSetting } from "@/lib/db"; import { logger } from "@/lib/logger"; import { redis } from "@/lib/redis"; const DEFAULTS: Record = { - hotel_name: FALLBACK_HOTEL_NAME, + hotel_name: "", habbo_imaging_url: "/imaging", logo_url: "", nitro_client_url: "",