# Architecture overview (https://prood.com/docs/architecture/overview)

Prood is organized as a **layered architecture** where each package has a single responsibility and applications communicate through a well-defined HTTP API.

## System diagram [#system-diagram]

```mermaid
flowchart TB
  subgraph surfaces [Client surfaces]
    direction LR
    SF["Storefront :3000"]
    DB["Dashboard :3002"]
    CHK["Checkout :3004"]
    AGT["Agents / MCP / API keys"]
  end

  subgraph api [apps/api :3005]
    REST["REST /v1/* · OpenAPI · MCP · Agent Auth"]
    RESOLVE["resolveCaller() → orgId + scopes"]
    SVC[commerce-service.ts]
    REST --> RESOLVE --> SVC
  end

  subgraph commerce ["@prood/commerce"]
    DOM["catalog · cart · checkout · orders · admin · payments"]
    TENANT["withTenant(orgId) · cache tags"]
    DOM --> TENANT
  end

  subgraph platform ["@prood/platform"]
    ENG["CommerceAdapter · AdminAPI · RLS · migrate"]
  end

  NEON[(Neon Postgres<br/>RLS per organization_id)]

  SF -->|@prood/api-client| api
  DB -->|@prood/api-client + commerce*| api
  CHK -->|@prood/checkout-host| api
  AGT -->|JWT / API key / session| api

  SVC --> commerce --> platform --> NEON
```

\* Dashboard uses `@prood/commerce` directly only for integration config encryption and domain management helpers — all catalog/order CRUD goes through the API.

## Design principles [#design-principles]

### Platform commerce engine [#platform-commerce-engine]

The `CommerceAdapter` interface (from `@prood/types`) defines the contract implemented by the built-in **platform** adapter. The current runtime supports this Neon Postgres engine only; Medusa/Salla-style external adapters are not selectable by environment variable today.

```ts
// @prood/platform exports
const { adapter, admin } = await createPlatformAdapter()
const products = await adapter.getProducts({ page: 1, limit: 20 })
```

### Pluggable payment providers [#pluggable-payment-providers]

Payment providers implement the `PaymentProvider` interface. The checkout engine does not know which provider it uses:

```ts
interface PaymentProvider {
  createSession(input: CreatePaymentSessionInput): Promise<PaymentSession>
  confirmSession(sessionId: string): Promise<PaymentSession>
  refund?(input: RefundInput): Promise<void>
  verifyWebhook(event: PaymentWebhookEvent): Promise<boolean>
}
```

Swapping Stripe for Easypay requires changing the provider instantiation — not the checkout state machine.

### API-centric data access [#api-centric-data-access]

Client applications do not import `@prood/commerce` for catalog or order operations. **All commerce operations go through `apps/api`**:

| Benefit | Explanation |
| --- | --- |
| Single auth layer | One place to resolve tenant, scopes, and caller type |
| OpenAPI contract | Humans, `@prood/api-client`, MCP tools, and Agent Auth share the same schema |
| Thin storefront | BFF routes only where cookies or client-side UX require them (cart, search) |
| Agent-ready | Every `operationId` becomes an agent capability |

See [API-centric architecture](/docs/architecture/api-centric) for details.

### Multi-tenant by default [#multi-tenant-by-default]

Every merchant is a Better Auth **organization**. Postgres **row-level security** filters all commerce rows by `organization_id`. Any code path that forgets `withTenant()` fails closed — zero rows returned, writes blocked.

See [Multi-tenant platform](/docs/architecture/multi-tenant).

## Domain tiers [#domain-tiers]

The platform adapter organizes commerce domains by how commonly they are needed:

| Tier | Domains | Status |
| --- | --- | --- |
| **Universal** | `catalog`, `store` | Always present |
| **Common** | `cart`, `checkout`, `orders`, `customers`, `wishlist`, `reviews`, `promotions`, `brands`, `countries` | Implemented in platform |
| **Specialized** | `returns` | Implemented in platform |

## Layer responsibilities [#layer-responsibilities]

| Layer | Packages / Apps | Role |
| --- | --- | --- |
| **Types** | `@prood/types` | Shared vocabulary — interfaces only, no runtime |
| **Engine** | `@prood/platform` | Neon Postgres commerce backend + Admin API |
| **Data layer** | `@prood/commerce` | Server-only wrapper — caching, tenant scope, providers |
| **Checkout** | `@prood/checkout`, `@prood/checkout-host` | State machine + Redis session host |
| **Payments** | `@prood/payment-*` | Provider-specific implementations |
| **Storage** | `@prood/storage-*` | Tenant-namespaced file uploads |
| **UI** | `@prood/ui` | Shared React components |
| **Client** | `@prood/api-client` | Typed HTTP client from OpenAPI |
| **API** | `apps/api` | REST, MCP, Agent Auth, webhook ingress |
| **Apps** | storefront, dashboard, checkout | End-user surfaces |

## Checkout separation [#checkout-separation]

Payment UI is intentionally separated from the storefront:

1. **Storefront** collects customer info and places the order via the API
2. **Checkout app** handles payment provider interaction (Stripe Element, Multibanco references)
3. **Redis** persists checkout sessions between redirect hops
4. **Webhooks** reconcile async payment results back to order status

The checkout app runs as a separate Next.js surface with session state persisted in **Upstash Redis**, keeping payment provider credentials and UX isolated from the storefront. See [Checkout flow](/docs/architecture/checkout-flow).

## Caching strategy [#caching-strategy]

Catalog reads in `@prood/commerce` use Next.js Cache Components with **per-tenant cache tags**:

| Tag pattern | TTL (SWR) | Data |
| --- | --- | --- |
| `products-{orgId}` | 600s | Product listings |
| `categories-{orgId}` | 600s | Category tree |
| `store-{orgId}` | 3600s | Store info |

Cart, checkout, and account routes stay dynamic — they depend on cookies and session state.

## Related pages [#related-pages]

<Cards>
  <Card title="Multi-tenancy" href="/docs/architecture/multi-tenant" description="Organizations, host resolution, RLS, and per-tenant payments." />
  <Card title="Checkout flow" href="/docs/architecture/checkout-flow" description="CheckoutSession state machine and payment lifecycle." />
  <Card title="Unified types" href="/docs/architecture/unified-types" description="The shared data model across all packages." />
  <Card title="API-centric design" href="/docs/architecture/api-centric" description="Why commerce goes through apps/api." />
</Cards>
