Packages

@prood/platform

Built-in commerce engine — Neon Postgres, Drizzle ORM, row-level security, and Admin API.

@prood/platform is the default commerce engine. It provides a full CommerceAdapter and AdminAPI backed by Neon Postgres with Drizzle ORM and row-level security.

Installation

Workspace package. Available from the source repo for now.

Requires DATABASE_URL environment variable pointing to a Neon Postgres instance.

Quick start

ts
import { createPlatformAdapter } from '@prood/platform'

const { adapter, admin } = await createPlatformAdapter()

// Catalog (storefront scope)
const products = await adapter.getProducts({ page: 1, limit: 20 })
const product = await adapter.getProduct('prod_abc')
const categories = await adapter.getCategories()
const store = await adapter.getStoreInfo()

// Admin operations
const stats = await admin.getDashboardStats()
const newProduct = await admin.createProduct({ name: { en: 'T-Shirt' }, ... })

Tenant scoping

All operations must run inside a tenant scope:

ts
import { withTenant } from '@prood/platform'

await withTenant('org_demo', async () => {
  const products = await adapter.getProducts({ page: 1, limit: 10 })
  // RLS filters to org_demo rows only
})

withTenant() opens a transaction, sets app.current_org_id and switches to the prood_app role, so the tenant_isolation RLS policies filter every query. See Multi-tenant platform.

Database setup

packages/platform owns the only migrations folder for the database (packages/platform/drizzle). It is generated by drizzle-kit from the commerce schema (src/database/drizzle/schema/) and the Better Auth schema (packages/auth/src/schema.ts).

zsh
# From repo root
pnpm db:migrate   # drizzle-kit migrate — applies pending migrations only
pnpm db:seed      # seeds org_demo, countries and the demo catalog (idempotent)

Changing the schema

  1. Edit the Drizzle schema files
  2. pnpm db:generate — writes the next NNNN_<name>.sql migration and snapshot
  3. Review and commit the SQL, then pnpm db:migrate

For SQL Drizzle cannot express (roles, grants, data fixes), create an empty migration with pnpm db:generate --custom --name=<name> and fill it in.

Implemented domains

DomainAdapter methodsAdmin methods
CataloggetProducts, getProduct, getCategoriesCRUD products, categories
StoregetStoreInfoUpdate store settings
CartFull cart lifecycle—
CheckoutplaceOrder—
OrdersgetOrders, getOrderList, fulfill, refund
CustomersgetCustomerList, detail
Inventory—Update stock levels
Dashboard—getDashboardStats

Schema

Drizzle schema in packages/platform/src/database/drizzle/schema/:

TableTenant-scopedDescription
productsYesProduct catalog
product_variantsYesSKU variants
categoriesYesCategory tree
cartsYesShopping carts
cart_itemsYesCart line items
ordersYesPlaced orders
order_itemsYesOrder line items
customersYesCustomer profiles
store_infoYes (composite PK)Store settings per org
couponsYesDiscount codes

Exports

ts
// Adapter factory
export { createPlatformAdapter } from '@prood/platform'

// Tenant scoping
export { withTenant, getDb, initDrizzle } from '@prood/platform'

// Admin API
export { createAdminAPI } from '@prood/platform'

// Demo seed
export { seedDrizzle, DEMO_ORG_ID } from '@prood/platform'

// Schema (for direct queries)
export * from '@prood/platform/database/drizzle'

Configuration

VariableDefaultDescription
DATABASE_URL—Neon Postgres connection string
ADMIN_EMAIL—Seed admin email
ADMIN_PASSWORD—Seed admin password