Brand schema
Every storefront template ships a `lib/brand.ts` that owns every visible string. Pages, components, JSON-LD, sitemap, `llms.txt`, and metadata all read from `brand`, so a rebrand is one file. The shape is enforced at boot by `BrandSchema`, and at test time by `assertBrand(brand)`.
Field reference
| Field | Required | Purpose |
|---|---|---|
name | yes | Full brand name; used in metadata, header, schema.org Organization |
shortName | yes | Compact form for tight spots (header, OG, app icons) |
microTag | yes | Tiny industry label shown beside the wordmark |
description | yes | Default OG / SEO description (≥ 20 chars) |
schemaType | yes | schema.org Organization subtype (Store, Bakery, …) |
currency | yes | ISO 4217 (e.g. GHS); used by every formatPrice |
locale | yes | BCP-47-ish, e.g. en_GH |
contact | yes | Address, email, phone, hours, country code |
socials[] | yes | Footer / contact chips with built-in icon keys |
header.nav | yes | Top nav links (label + href) |
hero | yes | Home hero: badge, title, subtitle, CTAs |
trustItems? | no | Hero trust strip (free shipping, warranty, …) |
brandStrip? | no | "Authorised dealer for…" strip |
promo? | no | Time-limited banner |
terms / privacy | yes | Standalone policy pages (eyebrow, sections, last updated) |
shipping / returns / accessibility | yes | Same shape as terms/privacy |
newsletter | yes | Footer signup copy |
about | yes | Eyebrow, title, paragraphs, sections |
faq | yes | Sectioned Q/A list |
account | yes | Login / signup / account eyebrows + titles (iframe owns the inputs) |
contactPage | yes | Eyebrow, title, body for /contact |
trackOrder | yes | Copy for the guest order lookup page |
footer | yes | Sitemap sections, blurb, optional "Powered by" |
llms.summary | yes | ≥ 20-char blurb that opens the /llms.txt index |
mock.seed | yes | Mock seed name (must match SeedNameSchema) |
mock.businessId | yes | Must start with bus_ |
A complete example
import type { Brand } from "@cimplify/sdk/testing";
export const brand: Brand = {
name: "Currents Electronics",
shortName: "Currents",
microTag: "ELECTRONICS",
description:
"Authorised dealer for Apple, Samsung, Sony, Bose. Same-day Accra delivery, two-year warranty.",
schemaType: "Store",
currency: "GHS",
locale: "en_GH",
contact: {
email: "hello@currentselectronics.test",
phone: "+233 244 000 000",
phoneTel: "+233244000000",
streetAddress: "Atomic Junction, East Legon",
city: "Accra",
countryCode: "GH",
hours: "Mon–Sat · 9am–8pm",
},
socials: [
{ label: "Instagram", href: "https://instagram.com/currentselectronics", icon: "instagram" },
{ label: "WhatsApp", href: "https://wa.me/233244000000", icon: "whatsapp" },
],
header: { nav: [
{ label: "Shop", href: "/shop" },
{ label: "Deals", href: "/categories/deals" },
{ label: "Support",href: "/faq" },
]},
hero: {
badge: "LAPTOPS · PHONES · AUDIO",
title: "The tech you want, in stock today.",
subtitle: "Same-day delivery in Accra. Two-year warranty on every product.",
primaryCtaLabel: "Shop now",
secondaryCtaLabel: "See deals",
secondaryCtaHref: "/categories/deals",
},
// …terms, privacy, shipping, returns, accessibility, about, faq, …
newsletter: {
title: "New drops, real prices, in your inbox.",
body: "One email a week. No newsletter chaff.",
eyebrow: "The shortlist",
},
account: {
loginEyebrow: "Welcome back", loginTitle: "Sign in to Currents",
signupEyebrow: "Welcome", signupTitle: "Create your Currents account",
accountEyebrow: "Your account", accountTitle: "Welcome back",
},
contactPage: { title: "Talk to a real human.", body: "We reply within a business day.", eyebrow: "Contact" },
trackOrder: { title: "Where's my order?", body: "Enter your order number and email.", eyebrow: "Track an order" },
footer: { sitemap: [/* … */], poweredBy: { label: "Cimplify", href: "https://app.cimplify.io" } },
llms: { summary: "Authorised dealer for Apple, Samsung, Sony, Bose. Two-year warranty." },
mock: { seed: "retail", businessId: "bus_currents_electronics" },
};Validation: assertBrand
Templates run assertBrand(brand) in their brand.test.ts. Failures list every offending field with its dot-path; drift between the template and the schema is impossible to ship by accident.
import { createBrandSuite } from "@cimplify/sdk/testing/suite";
import { brand } from "../lib/brand";
createBrandSuite({ brand });Industry-specific extensions
Need fields the base schema doesn't have (fashion's lookbook, services' bookingPolicy)? Extend, don't fork. The base shape stays canonical and your custom fields type-check alongside it.
import { BrandSchema } from "@cimplify/sdk/testing";
import { z } from "zod";
export const FashionBrandSchema = BrandSchema.extend({
lookbook: z.object({
eyebrow: z.string(),
title: z.string().min(1),
drops: z.array(z.object({
slug: z.string(),
title: z.string(),
heroImage: z.string().url(),
})),
}),
});
export type FashionBrand = z.infer<typeof FashionBrandSchema>;Next
-
Templates overview Six industry templates and what they ship
-
Customizing Beyond brand: ejection and schema extensions
Quickstart
From zero to a working storefront in 60 seconds. `cimplify init` scaffolds a Next.js app wired to the local mock; the same code points at your live business when you bring keys.
Customizing a template
The 95/5 split: ~95% of merchant changes are content (`lib/brand.ts`) and palette (`app/globals.css`). For the remaining 5% (restructured layouts, industry-specific sections, custom selectors), eject the SDK component or extend the brand schema.