@base44/app-plugin-commerce 0.6.0 → 0.6.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@base44/app-plugin-commerce",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
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",
@@ -22,10 +22,12 @@ the file that mentioned them.
22
22
 
23
23
  ## Installing right now?
24
24
 
25
- Read **[`install/01-install.md`](./install/01-install.md)** and follow it. It
26
- routes you to `install/02-storefront.md` when you start the UI and
27
- `install/03-data.md` when you seed the catalog — in that order, at those
28
- moments. Read nothing else up front.
25
+ Read all three stages **in one turn** — [`install/01-install.md`](./install/01-install.md),
26
+ [`install/02-storefront.md`](./install/02-storefront.md),
27
+ [`install/03-data.md`](./install/03-data.md) then work them in that order:
28
+ install, then the storefront UI, then the catalog. Every install runs all three,
29
+ so fetching them one at a time defers nothing you will not read anyway and costs
30
+ a model round trip per file. Read nothing *else* up front.
29
31
 
30
32
  ## Four things to hold from the start
31
33
 
@@ -109,12 +111,14 @@ const { products, has_next } = res.data.data;
109
111
 
110
112
  ## Where to look for what
111
113
 
112
- Open a file when its work starts — not while planning.
114
+ Open a file when its work starts — not while planning. The exception is the
115
+ three `install/` stages: an install reads all of them, so they come as one
116
+ batch (above).
113
117
 
114
118
  | Topic | Open when | Size |
115
119
  |---|---|---|
116
- | [`install/01-install.md`](./install/01-install.md) | installing — routes you to 02 and 03 | 5K |
117
- | [`install/02-storefront.md`](./install/02-storefront.md) | building storefront pages | 34K |
120
+ | [`install/01-install.md`](./install/01-install.md) | installing — routes you to 02 and 03 | 6K |
121
+ | [`install/02-storefront.md`](./install/02-storefront.md) | building storefront pages | 35K |
118
122
  | [`install/03-data.md`](./install/03-data.md) | seeding catalog, shipping rates/zones, payments; re-callable per slice | 11K |
119
123
  | [`docs/entities.md`](./docs/entities.md) | any direct entity read/write ("which entity holds X") | 11K |
120
124
  | [`references/catalog-rendering.md`](./references/catalog-rendering.md) | field shapes each catalog call returns, variant edge cases | 16K |
@@ -132,10 +136,13 @@ Open a file when its work starts — not while planning.
132
136
  | [`docs/api-admin.md`](./docs/api-admin.md) | changing admin pages, automating admin functions, the full seed contract | 24K |
133
137
 
134
138
  **The read budget.** Content you pull into context is re-read on every later
135
- call, so a file opened while planning costs many times what it costs opened at
136
- the moment it is used. Open one reference when its task starts, take what you
137
- need, and when a stage's checklist passes, record its carry-forward lines and
138
- treat the file as gone.
139
+ call, so a file you *might* not need costs many times more when opened while
140
+ planning than at the moment it is used. That is the rule for `references/` and
141
+ `docs/`: open one when its task starts, take what you need, and when a stage's
142
+ checklist passes, record its carry-forward lines and treat the file as gone.
143
+ Deferring is worth a round trip only when it might save the read entirely — so
144
+ it is the wrong instinct for the three install stages, which every install
145
+ reads. Batch those.
139
146
 
140
147
  **The install stages are self-contained.** Every request and response shape they
141
148
  build against is written out in them — `install/02-storefront.md` carries a table
@@ -7,7 +7,7 @@ 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
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."
10
- - "Interleave: start image generation first → mount admin + build the storefront while images render → seed when the URLs are back → payments last."
10
+ - "Interleave: start image generation first → mount admin + build the storefront while images render → seed when the real image_url values are back (never the /__generating__/ placeholder) → payments last."
11
11
  - "Entities are dotted + bracket-syntax only (`base44.entities[\"commerce.X\"]`); the map is ../docs/entities.md — never scan base44/entities/."
12
12
  ---
13
13
 
@@ -24,6 +24,9 @@ carry_forward:
24
24
  Image generation is the slowest step and nothing depends on it until seed time; the storefront doesn't wait on live data either.
25
25
 
26
26
  1. **Start image generation first** — every product image, before anything else.
27
+ ⚑ The tool hands back a `/__generating__/…` placeholder immediately and the real
28
+ `image_url` only when it finishes. Never write the placeholder into a file or a
29
+ seed payload: it resolves to nothing and ships a broken image.
27
30
  2. **Mount the admin (below) and build the storefront** while images render. Every
28
31
  request and response shape the pages build against is written out in
29
32
  [`./02-storefront.md`](./02-storefront.md), so they are written from the docs,
@@ -116,7 +116,7 @@ import { useProductList, useCategories, useStoreInfo, useFormatMoney, productPri
116
116
 
117
117
  A card can render `name`, `productImages(row)[0]`, `productPrice(row, { formatMoney }).label` (already "From €19.99" when the product sells variants — there is no product `type` flag, and `product.price` alone is a rolled-up from-price), `on_sale`, `short_description`, `stock_status`, `average_rating`/`rating_count`, `productRibbons(row)`, `productSpecs(row)`. ⚑ **Images and ribbons are objects, either may be empty** — render your placeholder, never a broken `<img>` or a raw object. Field matrix: [`../references/catalog-rendering.md`](../references/catalog-rendering.md). That list is an inventory, not a card design and not an order to render in. An even grid of identical cards, each carrying the same name/price/stars trio, is where a generated store lands by default and almost never where this catalog belongs: give the grid a rhythm (a hero piece spanning two columns, an editorial break between rows, a denser tile for a large catalog), and lead each card with the one or two fields *these* products are judged on — carat weight, focal length, edition size, ABV — read off `productSpecs(row)`, not the fields every store shows.
118
118
 
119
- ⚑ **Ribbons belong in both views** — grid and product page. They are the merchant's own merchandising ("Limited", "Last pieces"), and each links to its filtered listing (`/collection?ribbon_id=<id>`). `productRibbons(row)` hands you `{id, name}` **objects** — render `r.name`, key the link on `r.id`; the entry itself in JSX is React's "Objects are not valid as a React child". Never render a bare "Ribbons:" label with nothing after it.
119
+ ⚑ **Ribbons belong in both views** — grid and product page. They are the merchant's own merchandising ("Limited", "Last pieces"), and each links to its filtered listing (`/collection?ribbon_id=<id>`). `productRibbons(row)` hands you `{id, name}` **objects** — render `r.name`, key the link on `r.id`; the entry itself in JSX is React's "Objects are not valid as a React child". Never render a bare "Ribbons:" label with nothing after it. ⚑ **A ribbon link inside a card that is itself a link nests `<a>` in `<a>`** — invalid HTML, and React warns. In the grid, either render the ribbons as plain labels, or link the card's image and title instead of wrapping the whole card; keep the links on the product page.
120
120
 
121
121
  **Rails** (featured row, "new in") are the same hook with a filter (`{ featured: true, per_page: 4 }`) — `featured` is the merchant's own flag, so the rail stays curated store data instead of hardcoded slugs. ⚑ Any filter may legitimately match nothing — render *nothing* then, never a heading over an empty row.
122
122