diff --git a/apps/backend/prisma/migrations/20260929123000_add_brand_prompt/migration.sql b/apps/backend/prisma/migrations/20260929123000_add_brand_prompt/migration.sql
new file mode 100644
index 0000000..3b1f78a
--- /dev/null
+++ b/apps/backend/prisma/migrations/20260929123000_add_brand_prompt/migration.sql
@@ -0,0 +1,5 @@
+-- AlterTable
+ALTER TABLE "StoreSettings" ADD COLUMN "brandPrompt" TEXT;
+
+-- AlterTable
+ALTER TABLE "StoreSettingsTranslation" ADD COLUMN "brandPrompt" TEXT;
diff --git a/apps/backend/prisma/migrations/20260929124500_add_brand_knowledge/migration.sql b/apps/backend/prisma/migrations/20260929124500_add_brand_knowledge/migration.sql
new file mode 100644
index 0000000..7429054
--- /dev/null
+++ b/apps/backend/prisma/migrations/20260929124500_add_brand_knowledge/migration.sql
@@ -0,0 +1,18 @@
+-- CreateTable
+CREATE TABLE "BrandKnowledge" (
+ "id" INTEGER NOT NULL DEFAULT 1,
+ "brandName" TEXT NOT NULL DEFAULT 'AKÉRIA',
+ "tagline" TEXT,
+ "story" TEXT,
+ "targetAudience" TEXT,
+ "toneOfVoice" TEXT,
+ "visualArtPrompt" TEXT,
+ "productUsps" TEXT,
+ "marketingGuidelines" TEXT,
+ "customRules" TEXT,
+ "masterPromptOverride" TEXT,
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" TIMESTAMP(3) NOT NULL,
+
+ CONSTRAINT "BrandKnowledge_pkey" PRIMARY KEY ("id")
+);
diff --git a/apps/backend/prisma/schema.prisma b/apps/backend/prisma/schema.prisma
index f0241fb..42d15e6 100644
--- a/apps/backend/prisma/schema.prisma
+++ b/apps/backend/prisma/schema.prisma
@@ -288,6 +288,7 @@ model StoreSettings {
defaultSeoTitle String?
defaultSeoDescription String?
defaultOgImage String?
+ brandPrompt String?
translations StoreSettingsTranslation[]
updatedAt DateTime @updatedAt
}
@@ -304,6 +305,7 @@ model StoreSettingsTranslation {
newsletterButtonText String?
defaultSeoTitle String?
defaultSeoDescription String?
+ brandPrompt String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@ -317,6 +319,22 @@ model NewsletterSubscriber {
createdAt DateTime @default(now())
}
+model BrandKnowledge {
+ id Int @id @default(1)
+ brandName String @default("AKÉRIA")
+ tagline String?
+ story String?
+ targetAudience String?
+ toneOfVoice String?
+ visualArtPrompt String?
+ productUsps String?
+ marketingGuidelines String?
+ customRules String?
+ masterPromptOverride String?
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+}
+
model Order {
id Int @id @default(autoincrement())
channel String @default("ONLINE") // "ONLINE" | "POS"
diff --git a/apps/backend/src/index.ts b/apps/backend/src/index.ts
index 98c92f1..6e3764e 100644
--- a/apps/backend/src/index.ts
+++ b/apps/backend/src/index.ts
@@ -32,6 +32,7 @@ import { backupRoute } from "./routes/backup";
import { businessAnalyticsRoute } from "./routes/businessAnalytics";
import { toolsRoute } from "./routes/tools";
import { crmRoute } from "./routes/crm";
+import { brandKnowledgeRoute } from "./routes/brandKnowledge";
const PORT = process.env.PORT ? parseInt(process.env.PORT) : 3051;
const CORS_ORIGIN = process.env.CORS_ORIGIN || "http://localhost:5173";
const JWT_SECRET = process.env.JWT_SECRET || "homaroma_secret_2026_brand";
@@ -139,7 +140,7 @@ const app = new Elysia()
return file;
})
.group("/api", (app) =>
- app.use(authRoute).use(categoriesRoute).use(productsRoute).use(productAttributesRoute).use(uploadRoute).use(ordersRoute).use(settingsRoute).use(articlesRoute).use(tiktokRoute).use(rawMaterialsRoute).use(shopeeRoute).use(tiktokOrderRoute).use(lazadaOrderRoute).use(customersRoute).use(couponsRoute).use(reviewsRoute).use(promotionsRoute).use(pagesRoute).use(paymentsRoute).use(profileRoute).use(lineRoutes).use(menusRoute).use(newsletterRoute).use(mediaRoute).use(contactsRoute).use(backupRoute).use(businessAnalyticsRoute).use(toolsRoute).use(crmRoute)
+ app.use(authRoute).use(categoriesRoute).use(productsRoute).use(productAttributesRoute).use(uploadRoute).use(ordersRoute).use(settingsRoute).use(articlesRoute).use(tiktokRoute).use(rawMaterialsRoute).use(shopeeRoute).use(tiktokOrderRoute).use(lazadaOrderRoute).use(customersRoute).use(couponsRoute).use(reviewsRoute).use(promotionsRoute).use(pagesRoute).use(paymentsRoute).use(profileRoute).use(lineRoutes).use(menusRoute).use(newsletterRoute).use(mediaRoute).use(contactsRoute).use(backupRoute).use(businessAnalyticsRoute).use(toolsRoute).use(crmRoute).use(brandKnowledgeRoute)
)
.listen({ port: PORT, hostname: "0.0.0.0" });
diff --git a/apps/backend/src/routes/brandKnowledge.ts b/apps/backend/src/routes/brandKnowledge.ts
new file mode 100644
index 0000000..2891bd6
--- /dev/null
+++ b/apps/backend/src/routes/brandKnowledge.ts
@@ -0,0 +1,262 @@
+import { Elysia, t } from "elysia";
+import prisma from "../lib/prisma";
+import { adminOnly } from "../middleware/auth";
+
+export const DEFAULT_AKERIA_KNOWLEDGE = {
+ brandName: "AKÉRIA",
+ tagline: "Soft Asian Elegance & Mindful Beauty Sanctuary",
+ story: `AKÉRIA is a modern beauty e-commerce and lifestyle brand born from a reverence for soft Asian/Japanese-inspired serenity.
+
+We believe that beauty and well-being are intimate daily rituals of self-restoration. Every product is thoughtfully curated to transform ordinary spaces and skincare routines into luminous, tranquil sanctuaries. Our design and philosophy balance modern minimalism with gentle, time-honored botanical sensibilities.`,
+ targetAudience: `• Primary Persona: Modern women & young professionals (ages 20–38) seeking refined, gentle, and aesthetic lifestyle products.
+• Demographics: Urban, design-conscious, value self-care rituals, clean beauty, and sensory living.
+• Psychographics: Drawn to Japanese/Korean soft minimalism, pastel elegance, gentle glow, and mindful calm.
+• Pain Points: Tired of overly aggressive, dark, or cluttered beauty branding; desires products that feel like a breath of fresh air.`,
+ toneOfVoice: `• Core Personality: Bright, feminine, clean, fresh, premium-friendly, elegant, youthful, soft, luminous.
+• Language Style: Warm, welcoming, sensory-rich, gentle, and polished. Uses evocative yet accessible phrasing.
+• Words & Phrases We Love: Serenity, luminous glow, gentle ritual, mindful calm, airy softness, blossom, delicate harmony.
+• Words & Phrases We Avoid: Hyperbolic sales hype ("cheapest", "best ever"), harsh slang, aggressive discount urgency, dark/cynical humor.`,
+ visualArtPrompt: `You are the Visual Art Director for AKÉRIA.
+
+AKÉRIA is a modern beauty e-commerce and lifestyle brand with a soft Asian/Japanese-inspired sensibility.
+
+BRAND MOOD
+Bright, feminine, clean, fresh, premium-friendly, elegant, youthful, soft, luminous.
+
+COLOR PALETTE
+Primary:
+- Coral Rose #F28F96
+- Sakura Blush #F5C2C9
+- Warm Ivory #F7EFE6
+
+Secondary:
+- Soft Lavender #DCCDE3
+- Soft Peach #F4D4C2
+- Pure White #FFFFFF
+
+Contrast:
+- Charcoal #2D2D2D
+
+COLOR DISTRIBUTION
+- 55–65% Warm Ivory / White
+- 15–20% Coral Rose / Sakura Blush
+- 10–15% Soft Peach / Lavender
+- 5–10% Charcoal for contrast
+
+LIGHTING
+Soft diffused beauty lighting.
+Bright but not overexposed.
+Warm-neutral white balance.
+Luminous skin.
+Soft highlights.
+Low-to-medium contrast.
+Fresh commercial beauty campaign feel.
+
+PHOTOGRAPHY STYLE
+Modern Asian beauty editorial.
+Clean skin texture.
+Natural glossy makeup.
+Soft floral details.
+Elegant product styling.
+Light airy composition.
+Premium e-commerce campaign photography.
+
+MATERIALS & TEXTURES
+Frosted glass.
+Clear acrylic.
+Soft satin.
+Glossy cosmetic packaging.
+Light marble.
+Soft petals.
+Minimal reflective surfaces.
+
+BACKGROUND
+Prefer:
+Warm ivory.
+Soft blush gradient.
+White.
+Very pale peach.
+Subtle lavender.
+
+WARDROBE
+Prefer:
+White.
+Ivory.
+Blush.
+Soft beige.
+Dusty rose.
+Pale lavender.
+
+ACCENT ELEMENTS
+Use cherry blossom, soft petals, subtle glow, fine sparkles, or clean beauty props.
+Keep these subtle and refined.
+
+AVOID
+Hot pink.
+Neon colors.
+Strong red.
+Electric blue.
+Bright green.
+Strong yellow.
+Dark dramatic backgrounds.
+Heavy black.
+Cyberpunk lighting.
+Overly luxurious gold.
+Overly mature fashion styling.
+
+IMAGE COMPOSITION
+Keep generous negative space for typography or website UI.
+Use clean commercial framing.
+Hero subject should feel approachable, polished, and aspirational.
+
+IMPORTANT
+All backgrounds, props, flowers, clothing, packaging accents, and decorative elements must remain within the AKÉRIA color palette.
+
+The final image must immediately feel like AKÉRIA:
+bright beauty commerce, soft Asian elegance, modern, friendly, and premium.`,
+ productUsps: `• Hero Product Lines: Pure Aroma & Botanical Oils, Reed Diffusers, Ambient Room Sprays, Gentle Skincare Rituals.
+• Core Differentiators: 100% gentle botanical extractions, alcohol-free and safe for sensitive spaces.
+• Formulations: Cruelty-free, clean ingredients, sustainable frosted glass packaging.
+• Emotional Outcome: Instant sense of relaxation, soft luxurious ambiance, mindful mental clarity.`,
+ marketingGuidelines: `• TikTok: Short ASMR unboxing, soft aesthetic morning routines, relaxing evening wind-downs, visual calm reels.
+• Instagram: Clean feed aesthetic, generous white space, soft sakura/ivory color theme, product macro shots with soft natural light.
+• Website Copy: Storytelling focus, serene headlines, sensory product descriptions, clear value propositions.
+• Calls-to-Action (CTAs): "Discover Your Ritual", "Explore the Collection", "Embrace Serenity", "Begin Your Glow".
+• Core Hashtags: #AKERIA #SoftBeauty #AromaRitual #MindfulLiving #AsianElegance #CleanAesthetic`,
+ customRules: `1. Always keep visual and verbal assets strictly within the soft Asian/Japanese beauty aesthetic.
+2. Never introduce harsh contrast, neon highlights, or aggressive dark palettes.
+3. Every response or content generated should feel polite, premium, approachable, and calming.`
+};
+
+export function compileBrandPrompt(knowledge: any): string {
+ if (knowledge.masterPromptOverride && knowledge.masterPromptOverride.trim()) {
+ return knowledge.masterPromptOverride.trim();
+ }
+
+ const sections: string[] = [];
+
+ sections.push(`# BRAND KNOWLEDGE DIRECTIVE: ${knowledge.brandName || "AKÉRIA"}`);
+ if (knowledge.tagline) {
+ sections.push(`**Tagline:** ${knowledge.tagline}`);
+ }
+
+ if (knowledge.story) {
+ sections.push(`## 1. BRAND STORY & CORE PHILOSOPHY\n${knowledge.story.trim()}`);
+ }
+
+ if (knowledge.targetAudience) {
+ sections.push(`## 2. TARGET AUDIENCE & PERSONA\n${knowledge.targetAudience.trim()}`);
+ }
+
+ if (knowledge.toneOfVoice) {
+ sections.push(`## 3. TONE OF VOICE & MESSAGING STYLE\n${knowledge.toneOfVoice.trim()}`);
+ }
+
+ if (knowledge.visualArtPrompt) {
+ sections.push(`## 4. VISUAL ART DIRECTION & PHOTOGRAPHY DIRECTIVE\n${knowledge.visualArtPrompt.trim()}`);
+ }
+
+ if (knowledge.productUsps) {
+ sections.push(`## 5. PRODUCTS, SIGNATURE NOTES & USPs\n${knowledge.productUsps.trim()}`);
+ }
+
+ if (knowledge.marketingGuidelines) {
+ sections.push(`## 6. MARKETING CHANNELS & CONTENT GUIDELINES\n${knowledge.marketingGuidelines.trim()}`);
+ }
+
+ if (knowledge.customRules) {
+ sections.push(`## 7. STRICT BRAND COMPLIANCE & RULES\n${knowledge.customRules.trim()}`);
+ }
+
+ sections.push(`---\n*This document is the single source of truth for all LLM, AI Image, and Copywriting tasks representing ${knowledge.brandName || "AKÉRIA"}.*`);
+
+ return sections.join("\n\n");
+}
+
+export const brandKnowledgeRoute = new Elysia({ prefix: "/brand-knowledge" })
+ .get("/", async () => {
+ let knowledge = await prisma.brandKnowledge.findFirst();
+ if (!knowledge) {
+ knowledge = await prisma.brandKnowledge.create({
+ data: DEFAULT_AKERIA_KNOWLEDGE,
+ });
+ }
+ return {
+ ...knowledge,
+ compiledPrompt: compileBrandPrompt(knowledge),
+ };
+ })
+ .get("/compiled-prompt", async () => {
+ let knowledge = await prisma.brandKnowledge.findFirst();
+ if (!knowledge) {
+ knowledge = await prisma.brandKnowledge.create({
+ data: DEFAULT_AKERIA_KNOWLEDGE,
+ });
+ }
+ return {
+ brandName: knowledge.brandName,
+ compiledPrompt: compileBrandPrompt(knowledge),
+ updatedAt: knowledge.updatedAt,
+ };
+ })
+ .use(adminOnly)
+ .put(
+ "/",
+ async ({ body, set }) => {
+ try {
+ const data = body as any;
+ let knowledge = await prisma.brandKnowledge.findFirst();
+
+ if (!knowledge) {
+ knowledge = await prisma.brandKnowledge.create({
+ data: {
+ ...DEFAULT_AKERIA_KNOWLEDGE,
+ ...data,
+ },
+ });
+ } else {
+ knowledge = await prisma.brandKnowledge.update({
+ where: { id: knowledge.id },
+ data: {
+ brandName: data.brandName !== undefined ? data.brandName : knowledge.brandName,
+ tagline: data.tagline !== undefined ? data.tagline : knowledge.tagline,
+ story: data.story !== undefined ? data.story : knowledge.story,
+ targetAudience: data.targetAudience !== undefined ? data.targetAudience : knowledge.targetAudience,
+ toneOfVoice: data.toneOfVoice !== undefined ? data.toneOfVoice : knowledge.toneOfVoice,
+ visualArtPrompt: data.visualArtPrompt !== undefined ? data.visualArtPrompt : knowledge.visualArtPrompt,
+ productUsps: data.productUsps !== undefined ? data.productUsps : knowledge.productUsps,
+ marketingGuidelines: data.marketingGuidelines !== undefined ? data.marketingGuidelines : knowledge.marketingGuidelines,
+ customRules: data.customRules !== undefined ? data.customRules : knowledge.customRules,
+ masterPromptOverride: data.masterPromptOverride !== undefined ? data.masterPromptOverride : knowledge.masterPromptOverride,
+ },
+ });
+ }
+
+ return {
+ success: true,
+ data: {
+ ...knowledge,
+ compiledPrompt: compileBrandPrompt(knowledge),
+ },
+ };
+ } catch (err) {
+ console.error("[BrandKnowledge] Update error:", err);
+ set.status = 500;
+ return { success: false, error: "Failed to update brand knowledge" };
+ }
+ },
+ {
+ body: t.Object({
+ brandName: t.Optional(t.String()),
+ tagline: t.Optional(t.Nullable(t.String())),
+ story: t.Optional(t.Nullable(t.String())),
+ targetAudience: t.Optional(t.Nullable(t.String())),
+ toneOfVoice: t.Optional(t.Nullable(t.String())),
+ visualArtPrompt: t.Optional(t.Nullable(t.String())),
+ productUsps: t.Optional(t.Nullable(t.String())),
+ marketingGuidelines: t.Optional(t.Nullable(t.String())),
+ customRules: t.Optional(t.Nullable(t.String())),
+ masterPromptOverride: t.Optional(t.Nullable(t.String())),
+ }),
+ }
+ );
diff --git a/apps/backend/src/routes/settings.ts b/apps/backend/src/routes/settings.ts
index 6f793ff..58c4cd1 100644
--- a/apps/backend/src/routes/settings.ts
+++ b/apps/backend/src/routes/settings.ts
@@ -18,6 +18,7 @@ export async function saveStoreSettingsTranslations(settingsId: number, payload:
if (item.newsletterButtonText !== undefined) updateData.newsletterButtonText = item.newsletterButtonText;
if (item.defaultSeoTitle !== undefined) updateData.defaultSeoTitle = item.defaultSeoTitle;
if (item.defaultSeoDescription !== undefined) updateData.defaultSeoDescription = item.defaultSeoDescription;
+ if (item.brandPrompt !== undefined) updateData.brandPrompt = item.brandPrompt;
const existing = await prisma.storeSettingsTranslation.findUnique({
where: { storeSettingsId_langCode: { storeSettingsId: settingsId, langCode: lang } }
@@ -82,6 +83,12 @@ export async function saveStoreSettingsTranslations(settingsId: number, payload:
? (lang === 'th' ? payload.defaultSeoDescription : undefined)
: payload.defaultSeoDescription?.[lang];
+ const brandPrompt = typeof langObj?.brandPrompt === 'string' || langObj?.brandPrompt === null
+ ? langObj.brandPrompt
+ : typeof payload.brandPrompt === 'string' || payload.brandPrompt === null
+ ? (lang === 'th' ? payload.brandPrompt : undefined)
+ : payload.brandPrompt?.[lang];
+
if (
footerDescription === undefined &&
newsletterTitle === undefined &&
@@ -89,7 +96,8 @@ export async function saveStoreSettingsTranslations(settingsId: number, payload:
newsletterPlaceholder === undefined &&
newsletterButtonText === undefined &&
defaultSeoTitle === undefined &&
- defaultSeoDescription === undefined
+ defaultSeoDescription === undefined &&
+ brandPrompt === undefined
) {
continue;
}
@@ -102,6 +110,7 @@ export async function saveStoreSettingsTranslations(settingsId: number, payload:
if (newsletterButtonText !== undefined) updateData.newsletterButtonText = newsletterButtonText;
if (defaultSeoTitle !== undefined) updateData.defaultSeoTitle = defaultSeoTitle;
if (defaultSeoDescription !== undefined) updateData.defaultSeoDescription = defaultSeoDescription;
+ if (brandPrompt !== undefined) updateData.brandPrompt = brandPrompt;
const existing = await prisma.storeSettingsTranslation.findUnique({
where: { storeSettingsId_langCode: { storeSettingsId: settingsId, langCode: lang } }
@@ -155,6 +164,7 @@ export const settingsRoute = new Elysia({ prefix: "/settings" })
const localizedDescription = translation?.footerDescription;
const localizedSeoTitle = translation?.defaultSeoTitle;
const localizedSeoDescription = translation?.defaultSeoDescription;
+ const localizedBrandPrompt = translation?.brandPrompt;
const headerBehavior = (settings.themeTokens as any)?.headerBehavior ?? 'hide_on_scroll';
const mobileHeaderBehavior = (settings.themeTokens as any)?.mobileHeaderBehavior ?? headerBehavior;
@@ -169,6 +179,7 @@ export const settingsRoute = new Elysia({ prefix: "/settings" })
defaultSeoTitle: localizedSeoTitle ?? settingsData.defaultSeoTitle,
defaultSeoDescription: localizedSeoDescription ?? settingsData.defaultSeoDescription,
defaultOgImage: settingsData.defaultOgImage,
+ brandPrompt: localizedBrandPrompt ?? settingsData.brandPrompt,
};
} catch (err) {
console.error("[Settings] Error:", err);
@@ -342,6 +353,7 @@ export const settingsRoute = new Elysia({ prefix: "/settings" })
defaultSeoTitle: t.Optional(t.Nullable(t.String())),
defaultSeoDescription: t.Optional(t.Nullable(t.String())),
defaultOgImage: t.Optional(t.Nullable(t.String())),
+ brandPrompt: t.Optional(t.Nullable(t.String())),
translations: t.Optional(t.Any()),
})
})
@@ -426,6 +438,7 @@ export const settingsRoute = new Elysia({ prefix: "/settings" })
defaultSeoTitle: t.Optional(t.Nullable(t.String())),
defaultSeoDescription: t.Optional(t.Nullable(t.String())),
defaultOgImage: t.Optional(t.Nullable(t.String())),
+ brandPrompt: t.Optional(t.Nullable(t.String())),
translations: t.Optional(t.Any()),
})
})
diff --git a/apps/mcp-server/index.ts b/apps/mcp-server/index.ts
index 81b2d9b..1064016 100644
--- a/apps/mcp-server/index.ts
+++ b/apps/mcp-server/index.ts
@@ -1012,6 +1012,38 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
}
}
},
+ {
+ name: "get_brand_knowledge",
+ description: "Fetch structured Brand Knowledge, Core Directives, Visual Art Direction, and optionally the Master Compiled System Prompt for LLMs / AI Agents.",
+ inputSchema: {
+ type: "object",
+ properties: {
+ includeCompiledPrompt: {
+ type: "boolean",
+ description: "Whether to include the compiled markdown prompt in the response"
+ }
+ }
+ }
+ },
+ {
+ name: "update_brand_knowledge",
+ description: "Update Brand Knowledge and Directives (Identity, Tone of Voice, Visual Art Prompt, USPs, Marketing Guidelines, Custom Rules, Master Prompt Override).",
+ inputSchema: {
+ type: "object",
+ properties: {
+ brandName: { type: "string" },
+ tagline: { type: "string" },
+ story: { type: "string" },
+ targetAudience: { type: "string" },
+ toneOfVoice: { type: "string" },
+ visualArtPrompt: { type: "string" },
+ productUsps: { type: "string" },
+ marketingGuidelines: { type: "string" },
+ customRules: { type: "string" },
+ masterPromptOverride: { type: "string" }
+ }
+ }
+ },
],
};
});
@@ -1736,6 +1768,22 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }] };
}
+ case "get_brand_knowledge": {
+ const res = await api.get("/brand-knowledge");
+ let result = res.data;
+ if (params.includeCompiledPrompt) {
+ const compiledRes = await api.get("/brand-knowledge/compiled-prompt");
+ result = {
+ ...result,
+ compiledPrompt: compiledRes.data?.compiledPrompt ?? "",
+ };
+ }
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
+ }
+ case "update_brand_knowledge": {
+ const res = await api.put("/brand-knowledge", params);
+ return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
+ }
default:
throw new Error(`Unknown tool: ${request.params.name}`);
}
diff --git a/packages/types/index.ts b/packages/types/index.ts
index d8a928c..8ab9684 100644
--- a/packages/types/index.ts
+++ b/packages/types/index.ts
@@ -182,6 +182,7 @@ export interface StoreSettingsTranslation {
newsletterButtonText?: string | null
defaultSeoTitle?: string | null
defaultSeoDescription?: string | null
+ brandPrompt?: string | null
createdAt?: string
updatedAt?: string
}
@@ -217,9 +218,26 @@ export interface StoreSettings {
defaultSeoTitle?: string | null
defaultSeoDescription?: string | null
defaultOgImage?: string | null
+ brandPrompt?: string | null
translations?: StoreSettingsTranslation[]
}
+export interface BrandKnowledge {
+ id: number
+ brandName: string
+ tagline?: string | null
+ story?: string | null
+ targetAudience?: string | null
+ toneOfVoice?: string | null
+ visualArtPrompt?: string | null
+ productUsps?: string | null
+ marketingGuidelines?: string | null
+ customRules?: string | null
+ masterPromptOverride?: string | null
+ createdAt?: string
+ updatedAt?: string
+}
+
export interface FooterBrand {
brandName: string
logoUrl?: string | null