Skip to content

Changelog

Retail-operations release, driven by the ordereka-fashion-pos field study. The whole @porulle/* family is versioned in lockstep — the jump from v0.1.0 reflects intermediate releases whose notes live in each package’s CHANGELOG.md.

  • Store settings — org-scoped typed setting groups (general, branding, policies) at GET/PATCH /api/settings behind settings:manage, plus a kernel.services.settings.read(orgId, group) runtime API that plugins and modules read from. New store_settings table. See Store Settings.
  • Receipts & invoices — render an order as an HTML receipt, HTML invoice, or dependency-free PDF invoice (GET /api/orders/:id/{invoice.pdf,invoice.html,receipt.html}), plus POST .../invoice/email. Fiscal invoice numbers are allocated atomically per org and issued idempotently per order. New invoice_sequences, order_documents tables. See Receipts & Invoices.
  • Retail reports — a canned report pack at GET /api/analytics/reports/* (daily-journal, tax-summary, inventory-aging, sell-through, reorder-needed, staff-sales) with store-timezone calendar math and prior-period deltas, behind analytics:read. See Retail reports.
  • One-call variantsPOST /api/catalog/entities/:id/variants/quick and /bulk upsert option axes inline and seed a zero-stock inventory level so variants are sellable immediately.
  • Refund policy — line-level refunds (refunded_quantity column, order_refunds ledger) with an optional per-operator daily cap (policies.refundDailyCap, 403 when exceeded) and an audited undo window (policies.refundUndoWindowMinutes, default 15). Endpoints under /api/orders/:id/refunds. See Refunds & Exchanges.
  • Order notes & timelinePOST/GET/DELETE /api/orders/:id/notes (pinned-first) and GET /api/orders/:id/timeline merging status history, notes, and refund events newest-first. New order_notes table.
  • Product tax classes — first-class taxClass on entities and variants, /api/tax/classes CRUD behind tax:manage, and per-line checkout tax by class with order-level discounts pro-rated across lines. New tax_classes table; classes take precedence over region rates when defined. See Tax Classes.
  • Integrator quick winsconfig.routes(app, kernel, auth) now receives the Better Auth instance; requirePerm is a public export; orders and checkout accept an idempotencyKey (unique per org) so offline queues and retries replay exactly once.
  • Admin/operator API gaps — fulfillments with tracking, pricing-modifier CRUD, order line-item editing, cart listing + abandoned-checkout recovery, runtime shipping zones/rates + tax rates, and staff/RBAC admin REST. New scopes: cart:manage, shipping:manage, tax:manage, staff:manage.
  • PluginContext.auth — plugins now receive the Better Auth instance (when mounted by createServer) to mint/verify credentials.
  • Manifest apiKeyScopes — plugins register named API-key scopes (with keyExpiration bounds, in days) merged into config.auth.apiKeyScopes. See Plugin Contract.
  • @porulle/plugin-pos — PIN authentication (PUT/POST /api/pos/auth/*: set PIN, PIN login minting a short-lived per-shift API key, manager override; PBKDF2 via Web Crypto) and exchanges (POST /api/pos/exchanges running the return refund and replacement order in one transaction; even exchanges self-settle). See Point of Sale.
  • @porulle/plugin-layaway (new) — partial-payment plans: reserve stock with a deposit, record installments, auto-complete to a cross-linked core order at full payment, forfeit policy hook. See Layaway.
  • @porulle/adapter-neon (new) — Workers-grade Neon DatabaseAdapter: HTTP driver for queries, a fresh WebSocket pool per transaction, Hyperdrive-aware.
  • OfflineQueue — offline-first operation queue in @porulle/sdk with pluggable persistence, idempotency-key stamping (pairs with core replay for exactly-once), FIFO drain with exponential backoff, and observable state. See Offline queue.

Initial public release.

  • Kernel: createKernel / createServer factory with modular service container
  • Catalog: sellable_entities unified entity model — products, digital downloads, services, courses, gift cards, and custom types driven by configuration
  • Inventory: Per-warehouse stock tracking with optimistic locking (version column), movement ledger, and automatic reservation at checkout
  • Cart: Session-based carts with price snapshot on add, promotion application, and merge on sign-in
  • Checkout: Compensation-based pipeline — validate → reserve → price → tax → payment intent → order. Full rollback on failure.
  • Orders: State machine (pending → confirmed → processing → fulfilled/partially_fulfilled → refunded), fulfillment records (physical, digital download, service), and status history
  • Pricing: Time-bounded, quantity-tiered, customer-group prices; multiple currencies; modifier support
  • Promotions: Six promotion types — percentage_off_order, fixed_off_order, percentage_off_item, fixed_off_item, free_shipping, buy_x_get_y; usage limits; stackability rules
  • Search: SearchAdapter interface; built-in Meilisearch and PostgreSQL full-text implementations
  • Analytics: Semantic query compiler with built-in models for orders, line items, inventory, and customers; role-scoped query execution
  • Job queue: Durable commerce_jobs table with three runner strategies (cron endpoint, in-process polling, custom worker); exponential backoff; concurrency keys
  • Webhooks: HMAC-SHA256-signed delivery for 14 event types; retry with exponential backoff; delivery audit in webhook_deliveries
  • Audit log: Append-only commerce_audit_log for all commerce events with actor tracking
  • defineCommercePlugin: Config transform pattern — schema, hooks, routes, permissions, analytics models
  • @porulle/db: defineTable, column namespace with auto-injected id, organizationId, createdAt, updatedAt
  • router() builder: Fluent route registration with .auth(), .permission(), .input(), OpenAPI auto-documentation
  • createPluginTestApp: In-memory PGlite environment for plugin route testing

| Plugin | Status | |--------|--------| | @porulle/plugin-marketplace | Alpha | | @porulle/plugin-pos | Alpha | | @porulle/plugin-pos-restaurant | Alpha | | @porulle/plugin-uom | Alpha | | @porulle/plugin-procurement | Alpha | | @porulle/plugin-warehouse | Alpha | | @porulle/plugin-production | Alpha | | @porulle/plugin-notifications | Alpha | | @porulle/plugin-scheduled-orders | Alpha | | @porulle/plugin-reviews | Alpha | | @porulle/plugin-appointments | Alpha | | @porulle/plugin-gift-cards | Alpha |

| Adapter | Package | |---------|---------| | PostgreSQL (Drizzle) | @porulle/adapter-postgres | | AWS S3 | @porulle/adapter-s3 | | Cloudflare R2 | @porulle/adapter-r2 | | Local filesystem | @porulle/adapter-local-storage | | Stripe | @porulle/adapter-stripe | | Resend | @porulle/adapter-resend | | AWS SES v2 | @porulle/adapter-ses | | Meilisearch | @porulle/adapter-meilisearch | | PostgreSQL full-text search | @porulle/adapter-pg-search | | TaxJar | @porulle/adapter-taxjar | | Manual / flat-rate tax | @porulle/adapter-tax-manual |

  • Better Auth integration with email/password, social login, and organization plugin
  • Three-layer identity: auth identity (Better Auth), org membership, commerce profile (customer / vendor / staff)
  • Scoped API keys: catalog:read, orders:*, *:*, and custom scopes per plugin
  • Session-based customer portal (/api/me) with per-customer data isolation

None — this is the initial release.

  • Alpha: schema migrations are additive-only; no automated migration diffing for breaking column changes yet
  • @porulle/plugin-pos-restaurant and @porulle/plugin-production APIs are subject to change before stable
  • Analytics custom model joins are not yet supported (single-table models only)