# Concepts

Six concepts make every Fayz app click into place. Master these and you can read any Fayz project without getting lost: the **plugin and its manifest**, the **multi-tenant core library**, **providers**, the **two paths** to building, **version channels** and **incubator plugins**. Each one gets a paragraph and, where it helps, a snippet of code.

## 1. Plugin and manifest

A plugin is a packaged capability — scheduling, CRM, finance. You create it by calling its factory (`createAgendaPlugin`, `createCrmPlugin`, …), which returns a **manifest**: a description, in data, of everything that plugin contributes to the app. Routes, navigation, dashboard widgets, database migrations, AI tools — all declared in one object, not scattered across the code.

```ts
import { createAgendaPlugin } from '@fayz-ai/plugin-agenda'

const agenda = createAgendaPlugin()
// → { id, name, icon, version, navigation, routes, widgets?,
//     dashboardWidgets?, migrations?, ... }  = PluginManifest
```

The app composes a list of these manifests and the runtime does the rest: it builds the navigation, resolves the routes, registers the widgets and orders the migrations. The rule that keeps this sound: a plugin **emits nothing app-specific by default** — whatever it contributes to a shared surface is opt-in. The app decides what shows up.

## 2. Multi-tenant core library

Every Fayz app sits on the **core library** (formerly called `saas_core`): the base tables every business needs — `tenants`, `people`, `tenant_members`, `role_permissions`, `appointments`, `transactions`. These tables don't live in a separate `core.` schema — they all live in `public.*`. On top of them, the model has just two more layers:

```
public.*      shared base tables (tenants, people, tenant_members, role_permissions, appointments…)
plg_*         tables a plugin installs and owns (plg_shop_products, plg_courses_*…)
your tables   whatever your app/incubator creates on top
```

A plugin installs its own tables with the `plg_` prefix and **reuses** the core tables it needs instead of copying them; if finance needs to know "who got paid", it references `public.people` rather than keeping a copy. One source of truth per entity.

The **tenant** is your SaaS customer (a salon, a clinic). **Every table** — core, plugin or your own — carries `tenant_id`, and isolation is enforced by Postgres **RLS** (Row-Level Security) keyed on that `tenant_id`. RLS **is** the boundary, not schema separation: you don't filter by tenant in the application — the database refuses rows from another tenant. You bring your own Supabase (**BYOS**) and it gets exactly this shape; it's the same one the platform hosts at scale. Full details in [Data → Model](/en/docs/data/model) and [RLS and multi-tenancy](/en/docs/data/rls).

## 3. Providers (mock-first)

A **provider** is a plugin's backend abstraction: same interface, two implementations. Every app starts with `backend.provider: "mock"` — sample data, simulated auth, **zero environment variables** — so you can build and demo without touching infrastructure. When you're ready, you *flip*: switch the provider to `supabase` and the same plugin starts talking to real Postgres.

```jsonc
// app.manifest.json — mock to real is one line:
"backend": { "provider": "mock" }
"backend": { "provider": "supabase", "projectRef": "<your-ref>" }
```

At the plugin level this shows up as a safe provider that picks Supabase when credentials are present and falls back to mock when they aren't — the same interface on both sides, so nothing else in the plugin changes on the flip. How to connect a real Supabase is in [Data → Supabase](/en/docs/data/supabase).

## 4. The two paths

There are two ways to build. With the **Fayz App** you get a complete admin shell ready to go — generated navigation, tenant switching, permissions, CRUD — straight from your config. With **Fayz Headless** you consume the core and the plugin bundles inside your own site, owning the shell yourself. Both use the same plugins and the same backend; what changes is who assembles the interface around them.

Picking the right path up front saves rework — the full comparison, with when to use each, is in [The two paths](/en/docs/two-paths).

## 5. Version channels

Two different things use similar names, so keep them apart:

- **Release channels** (`stable`, `latest`, `preview`) are *sets of versions* — coherent groups of `@fayz-ai/*` packages you install together. `fayz create` pins your app to the `stable` channel by default.
- **Maturity tiers** (`stable`, `beta`, `preview`, `internal`) are a property of *each package* — how much you can lean on it today.

{% callout type="warn" %}
Be honest with yourself: **nothing is tier `stable` yet**. Fayz is pre-1.0, and while a package is on `0.x`, a *minor* bump (`0.4.0` → `0.5.0`) can carry breaking changes — and we use that room. The core and the plugins already running day to day are tier **`beta`**. Pin exact versions in production and read the changelog before upgrading.
{% /callout %}

The full tier table, with versioning guarantees and bug response times, is in [Reference → versions and channels](/en/docs/reference/versions-and-channels).

## 6. Incubator plugins

Not every capability needs to become a published package. An **incubator plugin** is a plugin that lives inside your own app (in `src/plugins/`), following the **same contract** as the official plugins — same manifest, same routes, migrations and providers. It's where you put logic specific to your product, or incubate a new plugin before eventually graduating it to the catalog.

```bash
fayz create plugin my-plugin
```

Because the contract is identical, an incubator plugs into the SDK's UI exactly like an official plugin — the only difference is who owns the code. The patterns for writing one are in [Building plugins → incubator](/en/docs/building-plugins/incubator).

## Next step

{% cards %}
{% card title="The two paths" href="/en/docs/two-paths" icon="🍴" %}
Decide between the Fayz App and Headless mode before writing your first line.
{% /card %}
{% card title="Full tutorial" href="/en/docs/tutorial" icon="🧭" %}
From the first command to deploy, in seven steps.
{% /card %}
{% /cards %}
