fayzfayz sdk
PTEN

Configuration

app.manifest.json describes the entire app in a single JSON file. It's the source of truth: surfaces, theme, locale, backend, and plugins. This page is the map of every top-level block — what it does and what fayz doctor validates.

The shape of the manifest

A freshly created admin app looks like this (manifestVersion is always 2 in this generation):

{
  "manifestVersion": 2,
  "id": "my-store",
  "name": "My Store",
  "backend": { "provider": "mock" },
  "locale": { "default": "pt-BR", "supported": ["pt-BR", "en"], "currency": "BRL" },
  "theme": { "brand": "violet" },
  "surfaces": {
    "admin": {
      "scaffold": "admin",
      "plugins": [{ "id": "dashboard" }],
      "pages": []
    }
  }
}

The four required fields are manifestVersion, id, name, and surfaces. Everything else is optional and has a sensible default.

The top-level blocks

FieldRole
idIdentifier in kebab-case (^[a-z0-9][a-z0-9-]*$).
nameThe app's display name.
backendWhere the data comes from. A { provider, ... } object — detailed below.
localeLanguage, supported languages, and currency.
themeThe brand: brand, radius, mode (see Theming).
permissionsDeclaration of features and actions (deny-by-default in multi-tenant).
surfacesThe faces of the app. At least one is required.

The backend block

provider decides where the data comes from. The accepted values:

providerWhat for
mockIn-memory sample data, zero configuration. This is the scaffold default. When you consume the packages in code, mock providers start out empty — see Mock and sample data to seed them.
supabaseA real Supabase project. Comes with projectRef.
fayz-apiThe managed Fayz API.
fayz-shopThe Fayz e-commerce backend.
customYour own adapter, referenced by adapterId.

Switching from mock to supabase is the middle step of the tutorial — see Supabase:

{ "backend": { "provider": "supabase", "projectRef": "your-project-ref" } }

Surfaces and plugins

Inside surfaces, each surface declares a scaffold (required), a list of plugins, and a list of pages. Wiring up a capability means adding { "id": "..." } to the plugins list — the packages already ship in the generated app's dependencies, so there's nothing to install and nothing to edit in src/plugins.generated.ts. Each pluginRef accepts config (plugin options) and enabled (to switch it off without removing it).

Since routes and the menu are derived from that list, the details live in Routing and navigation.

Two ways to configure

The scaffold gives you the manifest-first shape: you edit JSON and the platform renders it. There's also the code-first shape, where configuration lives in src/ (via defineSaas / defineStorefront). fayz doctor recognizes both: an app without an app.manifest.json but with a package.json is treated as a code-first app — doctor runs the boundary checks and passes. Start with the manifest shape; it covers most cases and it's the one the platform edits live.

Always validate

After any edit, run doctor. It checks the manifest structure, the referenced plugins, and the architecture boundaries:

npx @fayz-ai/cli doctor

An off-pattern id or a surface without a scaffold makes doctor exit with an error — on purpose, so you catch the problem before shipping. Today doctor validates the structure of the manifest and the architecture boundaries; validation of enum values (like backend.provider or theme.brand) is on the way — an SDK fix is in PR.


Next: apply your brand in Theming.