@base44/app-plugin-commerce 0.3.4 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/base44/functions/commerce/storefront-cart/cart-pricing.ts +1 -0
- package/base44/functions/commerce/storefront-checkout/cart-pricing.ts +1 -0
- package/package.json +1 -1
- package/skills/commerce/SKILL.md +45 -50
- package/skills/commerce/docs/api-storefront.md +1 -1
- package/skills/commerce/install/01-install.md +4 -1
- package/skills/commerce/install/02-storefront.md +182 -183
- package/skills/commerce/references/storefront-custom.md +150 -0
- package/skills/commerce/references/storefront-verification.md +4 -0
- package/src/commerce/storefront/StorefrontProvider.jsx +10 -3
- package/src/commerce/storefront/index.js +20 -0
- package/src/commerce/storefront/parts/cart.jsx +163 -0
- package/src/commerce/storefront/parts/checkout.jsx +471 -0
- package/src/commerce/storefront/parts/drawer.jsx +119 -0
- package/src/commerce/storefront/parts/labels.jsx +140 -0
- package/src/commerce/storefront/parts/orderReceived.jsx +186 -0
- package/src/commerce/storefront/parts/shared.jsx +127 -0
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ It provides a full-featured **commerce data model and behavior** (variant-driven
|
|
|
12
12
|
- **Shared commerce engine** (`base44/shared/commerce/`) — totals, tax, shipping, coupons, stock, order lifecycle, webhook dispatch (HMAC-signed), emails, card-payment plumbing, plus static country/currency/continent data.
|
|
13
13
|
- **Admin UI** (`src/commerce/admin/`) — a React/Tailwind/shadcn admin with a familiar store back-office information architecture: dashboard, orders, products, coupons, customers, reports, and full settings including webhooks. Admin-role gated.
|
|
14
14
|
- **Storefront helpers** (`src/commerce/utils/`) — framework-free, dependency-free modules for the shopfront you build: `storefront.js` is the API client (`createStorefront(base44)` — cart-token lifecycle, cached store-info, catalog/cart/checkout/reviews/return-page calls); `variants.js` maps an attribute selection (Size, Color) onto a `ProductVariation` and back, plus per-option availability and price ranges; `price.js` encodes the from-price and price-range rules; `totals.js` projects a cart *or* an order into one summary shape; `address-spec.js` is the checkout address form as data; `images.js` and `ribbons.js` normalize the two catalog fields that are arrays of objects (`{src, name, alt}` images, `{id, name}` ribbons) rather than strings; `types.js` writes the catalog shapes down as JSDoc typedefs (`StorefrontProduct` and the rest), so what a field holds is answerable from the frontend; `shipping-promos.js` reads the store's real free-shipping configuration so "Free shipping over €150" states a configured rule rather than an invented number.
|
|
15
|
-
- **Storefront React layer** (`src/commerce/storefront/`) —
|
|
15
|
+
- **Storefront React layer** (`src/commerce/storefront/`) — two tiers, and neither ships a look or a sentence. **The catalog tier is headless hooks** — `StorefrontProvider` (+ `useStorefront`/`useStoreInfo`/`useFormatMoney`/`useCountries`), `useProductList`/`useCategories`/`useRibbons`, `useProduct`/`useAddToCart`, `useCart`/`useCartLine`/`CartLine`, `useCheckout`/`CheckoutProvider`, `useOrderReturn`, the `ShippingMethodPicker`/`PaymentMethodPicker` render-prop components, and the framework-free view-model helpers re-exported so one import line covers a page (`variantAxes`, `productPrice`, `productImages`, `productRibbons`, `productSpecs`, `attributesLabel`, `cartTotalsLines`/`orderTotalsLines`, `addressFieldSpec`) — the product list and product page are built from these, entirely in the store's own markup, classes and words. **The commodity tier is parts** — `Cart.*`, `CartDrawer.*`, `Checkout.*`, `OrderReceived.*` compound components that render each section of the cart, drawer, checkout and receipt as correct semantic markup with **zero CSS, zero copy and zero navigation**: the store's page is the layout around them; styling comes via `data-part`/`data-state` selectors or `className`/`classes` props; every word (blocker lines, field labels, button text, aria names) comes from one agent-written copy file passed as `labels` (a missing key renders a visible `⟨copy: …⟩` placeholder — the code has no English fallback); and every navigation affordance (the cart's checkout link, `Checkout.Root`'s required `orderReceivedPath`, `OrderReceived.PaymentLink`'s render-prop child) is the store's own element and route. Parts compose the hooks, so replacing one section with a hook-built custom region is a normal move — and the parts are copied source, editable when a requirement outgrows their props. Needs React and nothing else.
|
|
16
16
|
- **StoreAdmin agent + bot** — an AI copilot (`base44/agents/commerce/StoreAdmin.jsonc`, registered as `commerce/StoreAdmin`) with the `commerce/*` functions attached directly as tools (calls run as the chatting user → `requireAdmin()` still applies), variant-aware order editing, plus a chat panel in the admin sidebar with GFM markdown-table rendering.
|
|
17
17
|
- **Docs** — this README plus the commerce skill folder [`skills/commerce/`](./skills/commerce/): [`SKILL.md`](./skills/commerce/SKILL.md) is the map every agent starts from (and the only path the platform needs to know); [`install/`](./skills/commerce/install/) holds the three stage files that are the whole install (`01-install` → `02-storefront` → `03-data`, each read at the moment its work starts and dropped when its checklist passes); [`references/`](./skills/commerce/references/) holds per-topic guides opened only on demand; [`docs/`](./skills/commerce/docs/) holds the data-model map ([`entities.md`](./skills/commerce/docs/entities.md)) and the two API references. The whole folder is installed into the app at `.agents/skills/commerce/` so agents pick it up natively.
|
|
18
18
|
|
|
@@ -104,7 +104,7 @@ If you build on Base44's hosted platform, use the Base44 agent/MCP to write the
|
|
|
104
104
|
|
|
105
105
|
## What's NOT included
|
|
106
106
|
|
|
107
|
-
- **No storefront *design*.** The parts of a shopfront that carry a brand — the home page, the collection grid, the product card, the product page's layout, the theme — ship as nothing at all, on purpose: that is the work a build should spend its effort on. Everything under those surfaces does ship: the storefront API
|
|
107
|
+
- **No storefront *design*.** The parts of a shopfront that carry a brand — the home page, the collection grid, the product card, the product page's layout, the theme, every customer-facing sentence — ship as nothing at all, on purpose: that is the work a build should spend its effort on. Everything under those surfaces does ship: the storefront API, the hooks that own the catalog's logic, and the commodity-surface parts (cart, drawer, checkout, receipt) that own those sections' *structure* — while their styling, words and layout stay the store's — see [`skills/commerce/install/02-storefront.md`](./skills/commerce/install/02-storefront.md) for how the two tiers fit together, [`skills/commerce/references/catalog-rendering.md`](./skills/commerce/references/catalog-rendering.md) for what each catalog call returns, and [`skills/commerce/docs/api-storefront.md`](./skills/commerce/docs/api-storefront.md) for the raw API.
|
|
108
108
|
- **No payment provider — and cards are off by default.** The order side of card payments is premade (see above), but charging a card needs a provider, so `commerce/seed-store` enables the manual **`offline`** method (bank transfer, cash on delivery, pickup — no code, no credentials) and leaves the **`card`** gateway **switched off**. **Enable cards only if a provider is wired, or is about to be** — implement the four functions in `base44/shared/commerce/card-payment.ts`, or for Stripe copy the shipped `card-payment.stripe.ts` over it and use it as-is (`skills/commerce/references/online-payments.md`), then enable the gateway via the seed's `payment_methods: ["offline", "card"]`; enabled with nothing behind it, checkout answers `503 no_card_payment_provider`. The rule and why it belongs at the end of a build rather than its start: `skills/commerce/install/03-data.md`.
|
|
109
109
|
- **No scheduled workflows shipped.** Base44 *does* have a scheduler, but this template ships no workflow files — time-based jobs (stock-hold release, cart expiry, webhook-log pruning) run **opportunistically** where possible, and for the rest you (or the Base44 agent) create scheduled workflows that call `commerce/admin-tools`/`commerce/admin-orders` actions — see [`skills/commerce/references/operations.md`](./skills/commerce/references/operations.md).
|
|
110
110
|
|
|
@@ -211,6 +211,7 @@ export async function priceCart(sr: any, cart: any, opts: { pricingData?: Pricin
|
|
|
211
211
|
quantity: r.item.quantity,
|
|
212
212
|
attributes: r.item.attributes ?? [],
|
|
213
213
|
name: r.product.name ?? "",
|
|
214
|
+
slug: r.product.slug ?? "",
|
|
214
215
|
sku: priced.sku ?? "",
|
|
215
216
|
image: r.variation?.image?.src || r.product.images?.[0]?.src || "",
|
|
216
217
|
price: priced.price ?? Number(src?.price ?? 0),
|
|
@@ -211,6 +211,7 @@ export async function priceCart(sr: any, cart: any, opts: { pricingData?: Pricin
|
|
|
211
211
|
quantity: r.item.quantity,
|
|
212
212
|
attributes: r.item.attributes ?? [],
|
|
213
213
|
name: r.product.name ?? "",
|
|
214
|
+
slug: r.product.slug ?? "",
|
|
214
215
|
sku: priced.sku ?? "",
|
|
215
216
|
image: r.variation?.image?.src || r.product.images?.[0]?.src || "",
|
|
216
217
|
price: priced.price ?? Number(src?.price ?? 0),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@base44/app-plugin-commerce",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Base44 Commerce plugin — entities, backend functions, shared commerce engine, admin UI and the commerce skill, shipped as copyable source",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"base44",
|
package/skills/commerce/SKILL.md
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: commerce
|
|
3
|
-
description: Base44 Commerce — commerce.* entities, commerce/* backend functions (storefront + admin APIs, payments, webhooks), the shared engine under base44/shared/commerce/, the Store Management UI at /store-admin, and the headless storefront hooks under src/commerce/. Read before working on store features: installing, building a storefront, seeding a catalog, shipping zones, payments, or the admin.
|
|
3
|
+
description: Base44 Commerce — commerce.* entities, commerce/* backend functions (storefront + admin APIs, payments, webhooks), the shared engine under base44/shared/commerce/, the Store Management UI at /store-admin, and the headless storefront layer (hooks + parts) under src/commerce/. Read before working on store features: installing, building a storefront, seeding a catalog, shipping zones, payments, or the admin.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Commerce
|
|
7
7
|
|
|
8
8
|
**This file is the map. It tells you what to read, when, and what you can skip.**
|
|
9
|
-
Nothing else in this skill needs to be open right now.
|
|
10
9
|
|
|
11
10
|
The kit ships, already written and tested: 20 `commerce.*` entities, the
|
|
12
11
|
`commerce/*` backend functions (storefront API, admin API, payments, webhooks,
|
|
@@ -16,16 +15,14 @@ emails), the shared engine, a complete admin back office at `/store-admin`, the
|
|
|
16
15
|
store's *UI and data*, not the plumbing.
|
|
17
16
|
|
|
18
17
|
**Paths in this skill** are relative to the skill's folder
|
|
19
|
-
(`.agents/skills/commerce/` in an installed app)
|
|
20
|
-
|
|
21
|
-
the file that mentioned them.
|
|
18
|
+
(`.agents/skills/commerce/` in an installed app) wherever they are named;
|
|
19
|
+
resolve them from the skill folder, never from the file that mentioned them.
|
|
22
20
|
|
|
23
21
|
## Installing right now?
|
|
24
22
|
|
|
25
|
-
Read **[`install/01-install.md`](./install/01-install.md)** and follow it
|
|
23
|
+
Read **[`install/01-install.md`](./install/01-install.md)** and follow it — it
|
|
26
24
|
routes you to `install/02-storefront.md` when you start the UI and
|
|
27
|
-
`install/03-data.md` when you seed
|
|
28
|
-
moments. Read nothing else up front.
|
|
25
|
+
`install/03-data.md` when you seed. Read nothing else up front.
|
|
29
26
|
|
|
30
27
|
## Four things to hold from the start
|
|
31
28
|
|
|
@@ -46,49 +43,49 @@ moments. Read nothing else up front.
|
|
|
46
43
|
takes manual (`offline`) payment and works end to end; cards are a late,
|
|
47
44
|
deliberate step ([`install/03-data.md`](./install/03-data.md)).
|
|
48
45
|
|
|
49
|
-
## The storefront:
|
|
46
|
+
## The storefront: two tiers
|
|
50
47
|
|
|
51
|
-
**The
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
48
|
+
**The catalog surfaces — product list and product page — are fully yours.**
|
|
49
|
+
Their logic ships as headless hooks (`@/commerce/storefront`): plain states
|
|
50
|
+
and handlers, you write every element, class and word. A brief like "make it
|
|
51
|
+
feel like <site>" is your work, done as with no kit; encode that identity
|
|
52
|
+
**once** — design classes in `index.css`, spent across every page —
|
|
56
53
|
[`install/02-storefront.md`](./install/02-storefront.md) opens with the
|
|
57
|
-
method.
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
54
|
+
method. **Never re-implement what a hook does** — that is where storefront
|
|
55
|
+
bugs cluster.
|
|
56
|
+
|
|
57
|
+
**The commodity surfaces — cart, cart drawer, checkout, order-received — are
|
|
58
|
+
placed, not written**: `Cart.*` / `CartDrawer.*` / `Checkout.*` /
|
|
59
|
+
`OrderReceived.*` parts render each section's correct markup with **zero CSS,
|
|
60
|
+
zero copy and zero navigation**. Your layout arranges the sections, your
|
|
61
|
+
`index.css` styles them (`[data-part]` selectors, `className`/`classes`
|
|
62
|
+
props), and every word comes from **one copy file** passed as `labels` — a
|
|
63
|
+
missing key renders a visible `⟨copy: …⟩`. The kit ships no look and no
|
|
64
|
+
sentence anywhere: a kit sentence rendered into every store is how storefronts
|
|
65
|
+
end up alike.
|
|
69
66
|
|
|
70
67
|
```jsx
|
|
71
|
-
import {
|
|
72
|
-
const { status, cart } = useCart(); // branch on status, map cart.items into YOUR rows
|
|
68
|
+
import { Cart, CartDrawer, Checkout, OrderReceived, useProduct } from "@/commerce/storefront";
|
|
73
69
|
```
|
|
74
70
|
|
|
75
|
-
The admin UI (`src/commerce/admin/`) is finished and **also yours to change**
|
|
76
|
-
|
|
77
|
-
|
|
71
|
+
The admin UI (`src/commerce/admin/`) is finished and **also yours to change**
|
|
72
|
+
([`docs/api-admin.md`](./docs/api-admin.md) is the backend it talks to). The
|
|
73
|
+
parts are the app's source too — usable from the docs' tables alone, editable
|
|
74
|
+
as a last resort when a user requirement outgrows their props.
|
|
78
75
|
|
|
79
76
|
Four rules the API enforces — a storefront that skips them cannot complete a
|
|
80
|
-
purchase. In React the hooks implement all four; your markup renders
|
|
81
|
-
hand back (API-level statements for non-React clients:
|
|
77
|
+
purchase. In React the hooks and parts implement all four; your markup renders
|
|
78
|
+
what they hand back (API-level statements for non-React clients:
|
|
82
79
|
[`docs/api-storefront.md`](./docs/api-storefront.md)):
|
|
83
80
|
|
|
84
81
|
1. A product with variants needs **one selector per attribute**, resolved to a
|
|
85
82
|
`variation_id` (`useProduct` + `variantAxes`).
|
|
86
83
|
2. Checkout must **recalculate shipping from the address and send a choice**
|
|
87
|
-
(`
|
|
88
|
-
3.
|
|
89
|
-
|
|
84
|
+
(the `Checkout.*` parts — automatic).
|
|
85
|
+
3. **The order-received route must exist** and render the return state — all
|
|
86
|
+
five `OrderReceived.*` gates, `PaymentInstructions` placed on unpaid.
|
|
90
87
|
4. **Never advertise what isn't configured** — no free-shipping banner without
|
|
91
|
-
a real rate, no coupon codes without a
|
|
88
|
+
a real rate, no coupon codes without a `CouponField` to redeem them in.
|
|
92
89
|
|
|
93
90
|
A fifth that breaks nothing but flattens the catalog, and is skipped most often:
|
|
94
91
|
**ribbons belong in both the grid and the product page**, each linking to its
|
|
@@ -115,6 +112,7 @@ Open a file when its work starts — not while planning.
|
|
|
115
112
|
| [`references/catalog-rendering.md`](./references/catalog-rendering.md) | field shapes each catalog call returns, variant edge cases | 16K |
|
|
116
113
|
| [`references/shipping-and-tax.md`](./references/shipping-and-tax.md) | zones beyond 03's recipe, taxes, day-2 edits | 8K |
|
|
117
114
|
| [`references/online-payments.md`](./references/online-payments.md) | enabling card payments, or wiring the provider — at install or any time later | 8K |
|
|
115
|
+
| [`references/storefront-custom.md`](./references/storefront-custom.md) | a custom cart row / checkout section on the raw hooks | 8K |
|
|
118
116
|
| [`references/storefront-verification.md`](./references/storefront-verification.md) | driving the storefront from a browser script | 3K |
|
|
119
117
|
| [`references/reviews.md`](./references/reviews.md) | review policies (login-gated, verified buyers), moderation | 5K |
|
|
120
118
|
| [`references/store-settings.md`](./references/store-settings.md) | changing store behavior through settings keys | 5K |
|
|
@@ -126,16 +124,13 @@ Open a file when its work starts — not while planning.
|
|
|
126
124
|
| [`docs/api-storefront.md`](./docs/api-storefront.md) | filters, customer accounts, refunds, a non-React client | 31K |
|
|
127
125
|
| [`docs/api-admin.md`](./docs/api-admin.md) | changing admin pages, automating admin functions, the full seed contract | 24K |
|
|
128
126
|
|
|
129
|
-
**The read budget.** Content
|
|
130
|
-
call
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
expensive way to answer a question the stage already answers. (The source is
|
|
140
|
-
still the final authority if a doc and the code ever disagree — report that
|
|
141
|
-
rather than working around it.)
|
|
127
|
+
**The read budget.** Content pulled into context is re-billed on every later
|
|
128
|
+
call — open one reference when its task starts, and when a stage's checklist
|
|
129
|
+
passes, record its carry-forward lines and treat the file as gone.
|
|
130
|
+
|
|
131
|
+
**The install stages are self-contained.** Every shape they build against is
|
|
132
|
+
written out in them — hook results, part contracts, the copy file. Never open
|
|
133
|
+
a file under `src/commerce/` while building; that is the most expensive way to
|
|
134
|
+
answer a question the stage already answers. (The source stays the final
|
|
135
|
+
authority if a doc and the code disagree — report that rather than working
|
|
136
|
+
around it.)
|
|
@@ -136,7 +136,7 @@ Token-scoped cart (guest + member). Every action **except `create`** takes `cart
|
|
|
136
136
|
"items": [ {
|
|
137
137
|
"item_key": "uuid", "product_id": "...", "variation_id": "", "quantity": 2,
|
|
138
138
|
"attributes": [ { "name": "Color", "option": "Red" } ],
|
|
139
|
-
"name": "T-Shirt", "sku": "TS-RED-M", "image": "https://...",
|
|
139
|
+
"name": "T-Shirt", "slug": "t-shirt", "sku": "TS-RED-M", "image": "https://...",
|
|
140
140
|
"price": 20, "subtotal": 40, "total": 36, "total_tax": 3.6,
|
|
141
141
|
"virtual": false, "sold_individually": false,
|
|
142
142
|
"purchasable": { "ok": true }
|
|
@@ -6,6 +6,7 @@ forget_when: "The checklist at the bottom of this file passes (admin mounts, / r
|
|
|
6
6
|
carry_forward:
|
|
7
7
|
- "Admin enforcement is three layers — AuthGuard (UI), admin-only entity RLS, requireAdmin() in every admin function. Never weaken any of them."
|
|
8
8
|
- "/order-received must exist as a route: every payment link returns there, and confirming is what marks an order paid."
|
|
9
|
+
- "The storefront header shows a visible \"Store manager\" link to /store-admin when the signed-in user's role is admin, and nothing for everyone else."
|
|
9
10
|
- "Interleave: start image generation first → mount admin + build the storefront while images render → seed when the URLs are back → payments last."
|
|
10
11
|
- "Entities are dotted + bracket-syntax only (`base44.entities[\"commerce.X\"]`); the map is ../docs/entities.md — never scan base44/entities/."
|
|
11
12
|
---
|
|
@@ -46,7 +47,8 @@ import { Navigate } from "react-router-dom";
|
|
|
46
47
|
|
|
47
48
|
- **The `/*` splat is required** — without it every nested admin link 404s. Mounting elsewhere: `<AdminApp basePath="/backoffice" />` (prefix without the splat).
|
|
48
49
|
- **Give `/` something** — a blank app has no `/` route, and "page not found" at the app's own URL reads like a broken install.
|
|
49
|
-
-
|
|
50
|
+
- **Link the admin from the storefront header** — otherwise the merchant has no way in but typing the URL. Resolve the signed-in user once (`base44.auth.me()`, rejection/no session = not an admin, never blocking the page) and render a plainly visible "Store manager" link to `/store-admin` in the header when `role === "admin"` — and nothing at all for everyone else.
|
|
51
|
+
- **`/order-received` is mandatory**, even offline-only: every payment link returns there, and confirming is what marks an order paid — without it a paying customer hits a 404 and the order stays unpaid. The page is the `OrderReceived.*` parts ([`./02-storefront.md`](./02-storefront.md)). A different path goes in Settings → General (`general.order_received_path`) *and* `Checkout.Root`'s `orderReceivedPath` — they must agree.
|
|
50
52
|
|
|
51
53
|
## Admin-role enforcement — do not weaken
|
|
52
54
|
|
|
@@ -62,6 +64,7 @@ Storefront functions are public on purpose (per-action verification, above). To
|
|
|
62
64
|
|
|
63
65
|
- [ ] `/store-admin/*` mounted with the splat, behind the shipped `AuthGuard`; the three enforcement layers untouched.
|
|
64
66
|
- [ ] `/` routes somewhere real; `/order-received` is a route.
|
|
67
|
+
- [ ] The storefront header shows a visible `/store-admin` link to signed-in admins, and to nobody else.
|
|
65
68
|
- [ ] Anonymous function invocation is allowed in the app's settings.
|
|
66
69
|
- [ ] Missing dependencies (if any) installed; image generation already running.
|
|
67
70
|
|