fix(bbyy): isolate production branding from E2E defaults

This commit is contained in:
134 2026-08-20 22:12:33 +08:00
parent 1d84b1b1c0
commit d1582f33e8
11 changed files with 55 additions and 38 deletions

View File

@ -2182,7 +2182,7 @@ export function AdminSettingsClient() {
usageTimeEnabled: false,
usageTimeStart: "08:00",
usageTimeEnd: "20:00",
usageTimeMessage: "由壹点累了也是需要休息的",
usageTimeMessage: "BuYi 累了也是需要休息的",
defaultTheme: "system",
bannerEnabled: true,
bannerText: "限时特惠:升级会员最高立享 45% OFF!",
@ -2224,7 +2224,7 @@ export function AdminSettingsClient() {
agentWorkflowDefaultModelId: null,
canvasDetailDefaultModelId: null,
canvasDetailAgentModelId: null,
lovartComposerPrefix: "让「由壹点AI」",
lovartComposerPrefix: "让「𝗕𝘂𝗬𝗶」",
lovartComposerPreviewTexts: [
"打造引人注目的社交媒体视觉",
"帮我把这张产品图做成高级电商海报",
@ -2240,8 +2240,8 @@ export function AdminSettingsClient() {
lovartPromoText:
"现在升级,立享 Kling 3.0 与 Nano Banana Pro,最高 5 折优惠",
lovartPromoActionText: "立即升级",
lovartHeroTitle: "由壹点AI 让设计更简单",
lovartHeroSubtitle: "懂你的设计代理,帮你搞定一切",
lovartHeroTitle: "𝗕𝘂𝗬𝗶 让设计触手可及",
lovartHeroSubtitle: "下达指令,即刻呈现",
surpriseCategories: ["全部", "精选"],
membershipConfig: defaultMembershipConfig,
membershipUserOverrides: defaultMembershipUserOverrides,
@ -2302,7 +2302,7 @@ export function AdminSettingsClient() {
usageTimeStart: siteSettingsData.usageTimeStart || "08:00",
usageTimeEnd: siteSettingsData.usageTimeEnd || "20:00",
usageTimeMessage:
siteSettingsData.usageTimeMessage || "由壹点累了也是需要休息的",
siteSettingsData.usageTimeMessage || "BuYi 累了也是需要休息的",
defaultTheme: siteSettingsData.defaultTheme || "system",
bannerEnabled: siteSettingsData.bannerEnabled ?? true,
bannerText:
@ -2398,7 +2398,7 @@ export function AdminSettingsClient() {
(siteSettingsData as any).canvasDetailAgentModelId || null,
lovartComposerPrefix:
String((siteSettingsData as any).lovartComposerPrefix || "").trim() ||
"让「由壹点AI」",
"让「𝗕𝘂𝗬𝗶」",
lovartComposerPreviewTexts: Array.isArray(
siteSettingsData.lovartComposerPreviewTexts
)
@ -2500,9 +2500,9 @@ export function AdminSettingsClient() {
lovartPromoActionText:
siteSettingsData.lovartPromoActionText || "立即升级",
lovartHeroTitle:
siteSettingsData.lovartHeroTitle || "由壹点AI 让设计更简单",
siteSettingsData.lovartHeroTitle || "𝗕𝘂𝗬𝗶 让设计触手可及",
lovartHeroSubtitle:
siteSettingsData.lovartHeroSubtitle || "懂你的设计代理,帮你搞定一切",
siteSettingsData.lovartHeroSubtitle || "下达指令,即刻呈现",
surpriseCategories: Array.isArray(siteSettingsData.surpriseCategories)
? siteSettingsData.surpriseCategories
.map((item: any) => String(item).trim())
@ -10524,7 +10524,7 @@ export function AdminSettingsClient() {
lovartComposerPrefix: e.target.value.slice(0, 40),
})
}
placeholder="让「由壹点AI」"
placeholder="让「𝗕𝘂𝗬𝗶」"
value={siteSettings.lovartComposerPrefix}
/>
<div className="text-muted-foreground text-xs">
@ -10726,7 +10726,7 @@ export function AdminSettingsClient() {
lovartHeroTitle: e.target.value,
})
}
placeholder="由壹点AI 让设计更简单"
placeholder="𝗕𝘂𝗬𝗶 让设计触手可及"
value={siteSettings.lovartHeroTitle}
/>
</div>
@ -10740,7 +10740,7 @@ export function AdminSettingsClient() {
lovartHeroSubtitle: e.target.value,
})
}
placeholder="懂你的设计代理,帮你搞定一切"
placeholder="下达指令,即刻呈现"
value={siteSettings.lovartHeroSubtitle}
/>
</div>

View File

@ -399,7 +399,7 @@ function normalizeLovartComposerPreviewTexts(value: unknown): string[] {
function normalizeLovartComposerPrefix(value: unknown): string {
const normalized = String(value || "").trim();
if (!normalized) {
return "让「由壹点AI」";
return "让「𝗕𝘂𝗬𝗶」";
}
return normalized.slice(0, 40);
}
@ -573,7 +573,7 @@ const PUBLIC_SITE_SETTINGS_SCOPES = new Set<string>([
]);
const HOME_SITE_SETTINGS_FALLBACK: Record<string, unknown> = {
siteName: "AI Chatbot",
siteName: "𝗕𝘂𝗬𝗶",
siteLogo: null,
siteLogoDark: null,
favicon: null,
@ -583,11 +583,11 @@ const HOME_SITE_SETTINGS_FALLBACK: Record<string, unknown> = {
bannerText: "限时特惠:升级会员最高立享 45% OFF!",
bannerLink: null,
bannerActionText: "立即查看",
lovartHeroTitle: "由壹点AI 让设计更简单",
lovartHeroSubtitle: "懂你的设计代理,帮你搞定一切",
lovartHeroTitle: "𝗕𝘂𝗬𝗶 让设计触手可及",
lovartHeroSubtitle: "下达指令,即刻呈现",
surpriseCategories: ["全部", "精选"],
canvasDefaultModelId: null,
lovartComposerPrefix: "让「由壹点AI」",
lovartComposerPrefix: "让「𝗕𝘂𝗬𝗶」",
lovartComposerPreviewTexts: [],
lovartPromptTagVisibility: {},
contactConfig: normalizeContactConfig(undefined),
@ -664,7 +664,7 @@ async function readScopedSiteSettings(keys: string[]) {
function createBrandingSettings(settings: Record<string, unknown> | undefined) {
return {
siteName: String(settings?.siteName || "AI Chatbot"),
siteName: String(settings?.siteName || "𝗕𝘂𝗬𝗶"),
siteLogo: settings?.siteLogo || null,
siteLogoDark: settings?.siteLogoDark || null,
favicon: settings?.favicon || null,
@ -822,7 +822,7 @@ async function getScopedPublicSiteSettings(
usageTimeStart: typedSettings?.usageTimeStart || "08:00",
usageTimeEnd: typedSettings?.usageTimeEnd || "20:00",
usageTimeMessage:
typedSettings?.usageTimeMessage || "由壹点累了也是需要休息的",
typedSettings?.usageTimeMessage || "BuYi 累了也是需要休息的",
});
}
@ -953,9 +953,9 @@ async function getScopedPublicSiteSettings(
typedSettings?.lovartPromoText ||
"现在升级,立享 Kling 3.0 与 Nano Banana Pro,最高 5 折优惠",
lovartPromoActionText: typedSettings?.lovartPromoActionText || "立即升级",
lovartHeroTitle: typedSettings?.lovartHeroTitle || "由壹点AI 让设计更简单",
lovartHeroTitle: typedSettings?.lovartHeroTitle || "𝗕𝘂𝗬𝗶 让设计触手可及",
lovartHeroSubtitle:
typedSettings?.lovartHeroSubtitle || "懂你的设计代理,帮你搞定一切",
typedSettings?.lovartHeroSubtitle || "下达指令,即刻呈现",
surpriseCategories: normalizeSurpriseCategories(
valueByKey.get(HOME_SURPRISE_CATEGORIES_KEY)
),
@ -1476,7 +1476,7 @@ export async function GET(request: NextRequest) {
usageTimeEnabled: false,
usageTimeStart: "08:00",
usageTimeEnd: "20:00",
usageTimeMessage: "由壹点累了也是需要休息的",
usageTimeMessage: "BuYi 累了也是需要休息的",
bannerEnabled: true,
bannerText: "限时特惠:升级会员最高立享 45% OFF!",
bannerLink: null,
@ -1525,8 +1525,8 @@ export async function GET(request: NextRequest) {
canvasDetailAgentModelId: null,
lovartPromoText: "现在升级,立享 Kling 3.0 与 Nano Banana Pro,最高 5 折优惠",
lovartPromoActionText: "立即升级",
lovartHeroTitle: "由壹点AI 让设计更简单",
lovartHeroSubtitle: "懂你的设计代理,帮你搞定一切",
lovartHeroTitle: "𝗕𝘂𝗬𝗶 让设计触手可及",
lovartHeroSubtitle: "下达指令,即刻呈现",
surpriseCategories,
aiDetailGenerationEnabled,
lovartComposerPrefix,
@ -1546,8 +1546,8 @@ export async function GET(request: NextRequest) {
baseSettings.lovartPromoText ||
"现在升级,立享 Kling 3.0 与 Nano Banana Pro,最高 5 折优惠",
lovartPromoActionText: baseSettings.lovartPromoActionText || "立即升级",
lovartHeroTitle: baseSettings.lovartHeroTitle || "由壹点AI 让设计更简单",
lovartHeroSubtitle: baseSettings.lovartHeroSubtitle || "懂你的设计代理,帮你搞定一切",
lovartHeroTitle: baseSettings.lovartHeroTitle || "𝗕𝘂𝗬𝗶 让设计触手可及",
lovartHeroSubtitle: baseSettings.lovartHeroSubtitle || "下达指令,即刻呈现",
notification,
surpriseCategories,
aiDetailGenerationEnabled,
@ -3119,7 +3119,7 @@ export async function PUT(request: NextRequest) {
usageTimeEnabled: siteSettingsPayload.usageTimeEnabled ?? false,
usageTimeStart: siteSettingsPayload.usageTimeStart ?? "08:00",
usageTimeEnd: siteSettingsPayload.usageTimeEnd ?? "20:00",
usageTimeMessage: siteSettingsPayload.usageTimeMessage ?? "由壹点累了也是需要休息的",
usageTimeMessage: siteSettingsPayload.usageTimeMessage ?? "BuYi 累了也是需要休息的",
bannerEnabled: siteSettingsPayload.bannerEnabled ?? true,
bannerText: siteSettingsPayload.bannerText ?? "限时特惠:升级会员最高立享 45% OFF!",
bannerLink: siteSettingsPayload.bannerLink,
@ -3144,8 +3144,8 @@ export async function PUT(request: NextRequest) {
siteSettingsPayload.lovartPromoText ??
"现在升级,立享 Kling 3.0 与 Nano Banana Pro,最高 5 折优惠",
lovartPromoActionText: siteSettingsPayload.lovartPromoActionText ?? "立即升级",
lovartHeroTitle: siteSettingsPayload.lovartHeroTitle ?? "由壹点AI 让设计更简单",
lovartHeroSubtitle: siteSettingsPayload.lovartHeroSubtitle ?? "懂你的设计代理,帮你搞定一切",
lovartHeroTitle: siteSettingsPayload.lovartHeroTitle ?? "𝗕𝘂𝗬𝗶 让设计触手可及",
lovartHeroSubtitle: siteSettingsPayload.lovartHeroSubtitle ?? "下达指令,即刻呈现",
updatedBy: session.user.id,
})
.returning();

View File

@ -1334,7 +1334,7 @@ type VideoStoryboardStreamData =
// 建议卡片数据 - 已移除
const SUGGESTIONS: { title: string; desc: string; image: string }[] = [];
const CANVAS_COMPOSER_PREFIX_DEFAULT = "让「由壹点AI」";
const CANVAS_COMPOSER_PREFIX_DEFAULT = "让「𝗕𝘂𝗬𝗶」";
const CANVAS_COMPOSER_PREVIEW_TEXTS_DEFAULT = [
"打造引人注目的社交媒体视觉",
"帮我把这张产品图做成高级电商海报",

View File

@ -345,7 +345,7 @@ type LovartPromptTagKey = (typeof PROMPT_TAGS)[number]["key"];
type LovartPromptTagVisibility = Record<LovartPromptTagKey, boolean>;
const FEATURED_PAGE_SIZE = 24;
const COMPOSER_PREFIX_DEFAULT = "让「由壹点AI」";
const COMPOSER_PREFIX_DEFAULT = "让「𝗕𝘂𝗬𝗶」";
function SidebarSvgIcon({
iconUrl,

View File

@ -101,7 +101,7 @@ export type LovartPromptTagVisibility = Record<LovartPromptTagKey, boolean>;
export const MASONRY_HEIGHTS = [420, 290, 340, 470, 300, 360, 430, 320];
export const FEATURED_PAGE_SIZE = 24;
export const COMPOSER_PREFIX_DEFAULT = "让「由壹点AI」";
export const COMPOSER_PREFIX_DEFAULT = "让「𝗕𝘂𝗬𝗶」";
export function normalizeComposerPreviewTail(text: string, fixedPrefix: string) {
const trimmed = text.trim();

View File

@ -29,7 +29,7 @@ export function BrandTopBar({
showBrand = true,
siteName,
}: BrandTopBarProps) {
const resolvedSiteName = String(siteName || "").trim() || "由壹点AI";
const resolvedSiteName = String(siteName || "").trim() || "𝗕𝘂𝗬𝗶";
const positionClass =
position === "fixed"
? "fixed left-0 top-0 z-40 w-full"

View File

@ -1118,7 +1118,7 @@ export function StyleProWorkspace({
persistedState?.sourceImageUrl,
]);
const siteName = brandingData?.siteName || "由壹点AI";
const siteName = brandingData?.siteName || "𝗕𝘂𝗬𝗶";
const logo = brandingData?.siteLogoDark || brandingData?.siteLogo || "";
const selectedOptionLabels = useMemo(() => {

View File

@ -4725,8 +4725,8 @@ export async function getSiteSettings() {
canvasDetailAgentModelId: null,
lovartPromoText: "现在升级,立享 Kling 3.0 与 Nano Banana Pro,最高 5 折优惠",
lovartPromoActionText: "立即升级",
lovartHeroTitle: "由壹点AI 让设计更简单",
lovartHeroSubtitle: "懂你的设计代理,帮你搞定一切",
lovartHeroTitle: "𝗕𝘂𝗬𝗶 让设计触手可及",
lovartHeroSubtitle: "下达指令,即刻呈现",
};
try {
const [settings, videoCanvasEnabledSetting, videoCanvasSidebarEnabledSetting] =

View File

@ -475,7 +475,7 @@ export const siteSettings = pgTable("SiteSettings", {
usageTimeEnabled: boolean("usageTimeEnabled").notNull().default(false), // 是否启用时间限制
usageTimeStart: varchar("usageTimeStart", { length: 5 }).default("08:00"), // 开始时间(HH:mm)
usageTimeEnd: varchar("usageTimeEnd", { length: 5 }).default("20:00"), // 结束时间(HH:mm)
usageTimeMessage: text("usageTimeMessage").default("由壹点累了也是需要休息的"), // 超时提示词
usageTimeMessage: text("usageTimeMessage").default("BuYi 累了也是需要休息的"), // 超时提示词
// 广告横幅设置
bannerEnabled: boolean("bannerEnabled").notNull().default(true), // 是否显示广告横幅
bannerText: text("bannerText").default("限时特惠:升级会员最高立享 45% OFF!"), // 广告横幅文字
@ -505,8 +505,8 @@ export const siteSettings = pgTable("SiteSettings", {
"现在升级,立享 Kling 3.0 与 Nano Banana Pro,最高 5 折优惠"
),
lovartPromoActionText: varchar("lovartPromoActionText", { length: 32 }).default("立即升级"),
lovartHeroTitle: text("lovartHeroTitle").default("由壹点AI 让设计更简单"),
lovartHeroSubtitle: text("lovartHeroSubtitle").default("懂你的设计代理,帮你搞定一切"),
lovartHeroTitle: text("lovartHeroTitle").default("𝗕𝘂𝗬𝗶 让设计触手可及"),
lovartHeroSubtitle: text("lovartHeroSubtitle").default("下达指令,即刻呈现"),
updatedAt: timestamp("updatedAt").notNull().defaultNow(),
updatedBy: uuid("updatedBy").references(() => user.id),
});

View File

@ -7,6 +7,11 @@ candidate_dir="$(mktemp -d "${app_dir}/.next-candidate.XXXXXX")"
previous_dir="${app_dir}/.next-previous-$(date +%Y%m%dT%H%M%S)"
build_container="ai-chatbot-build-$(date +%s)"
if grep -Eq '^[[:space:]]*CANVAS_E2E_LOCAL[[:space:]]*=[[:space:]]*"?true"?[[:space:]]*$' "${app_dir}/.env.local"; then
echo "Refusing production deployment while CANVAS_E2E_LOCAL=true." >&2
exit 1
fi
cleanup_candidate() {
if [ -d "$candidate_dir" ]; then
rm -rf -- "$candidate_dir"

View File

@ -41,3 +41,15 @@ test("production deploy stages the main build and retains active static chunks",
);
expect(deployScript).toContain('curl -fsS "$MAIN_INTERNAL_URL/ping"');
});
test("atomic production deploy rejects the local E2E fallback switch", () => {
const deployScript = readFileSync(
resolve(process.cwd(), "scripts/deploy-production-atomic.sh"),
"utf8"
);
expect(deployScript).toContain("CANVAS_E2E_LOCAL");
expect(deployScript).toContain(
"Refusing production deployment while CANVAS_E2E_LOCAL=true."
);
});