@stacksjs/defaults 0.72.103 → 0.73.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.
Files changed (163) hide show
  1. package/ai/AGENTS.md +25 -4
  2. package/ai/README.md +26 -4
  3. package/ai/skills/stacks-actions/SKILL.md +1 -1
  4. package/ai/skills/stacks-ai/SKILL.md +1 -1
  5. package/ai/skills/stacks-alias/SKILL.md +1 -1
  6. package/ai/skills/stacks-analytics/SKILL.md +1 -1
  7. package/ai/skills/stacks-api/SKILL.md +1 -1
  8. package/ai/skills/stacks-arrays/SKILL.md +1 -1
  9. package/ai/skills/stacks-auto-imports/SKILL.md +1 -1
  10. package/ai/skills/stacks-browse/SKILL.md +1 -1
  11. package/ai/skills/stacks-browser/SKILL.md +1 -1
  12. package/ai/skills/stacks-buddy/SKILL.md +1 -1
  13. package/ai/skills/stacks-build/SKILL.md +79 -5
  14. package/ai/skills/stacks-cache/SKILL.md +1 -1
  15. package/ai/skills/stacks-calendar/SKILL.md +1 -1
  16. package/ai/skills/stacks-chat/SKILL.md +1 -1
  17. package/ai/skills/stacks-cli/SKILL.md +1 -1
  18. package/ai/skills/stacks-cloud/SKILL.md +1 -1
  19. package/ai/skills/stacks-cms/SKILL.md +1 -1
  20. package/ai/skills/stacks-codebase-design/DEEPENING.md +79 -0
  21. package/ai/skills/stacks-codebase-design/DESIGN-IT-TWICE.md +72 -0
  22. package/ai/skills/stacks-codebase-design/SKILL.md +180 -0
  23. package/ai/skills/stacks-collections/SKILL.md +1 -1
  24. package/ai/skills/stacks-commerce/SKILL.md +141 -35
  25. package/ai/skills/stacks-composables/SKILL.md +1 -1
  26. package/ai/skills/stacks-config/SKILL.md +1 -1
  27. package/ai/skills/stacks-configuration/SKILL.md +1 -1
  28. package/ai/skills/stacks-cron/SKILL.md +1 -1
  29. package/ai/skills/stacks-crosswind/SKILL.md +1 -1
  30. package/ai/skills/stacks-database/SKILL.md +1 -1
  31. package/ai/skills/stacks-datetime/SKILL.md +1 -1
  32. package/ai/skills/stacks-dependencies/SKILL.md +1 -1
  33. package/ai/skills/stacks-deploy/SKILL.md +1 -1
  34. package/ai/skills/stacks-desktop/SKILL.md +1 -1
  35. package/ai/skills/stacks-development/SKILL.md +1 -1
  36. package/ai/skills/stacks-dns/SKILL.md +1 -1
  37. package/ai/skills/stacks-docs/SKILL.md +1 -1
  38. package/ai/skills/stacks-domain-modeling/FORMATS.md +123 -0
  39. package/ai/skills/stacks-domain-modeling/SKILL.md +109 -0
  40. package/ai/skills/stacks-enums/SKILL.md +1 -1
  41. package/ai/skills/stacks-error-handling/SKILL.md +1 -1
  42. package/ai/skills/stacks-events/SKILL.md +1 -1
  43. package/ai/skills/stacks-faker/SKILL.md +1 -1
  44. package/ai/skills/stacks-flow/PHASE-BOUNDARIES.md +91 -0
  45. package/ai/skills/stacks-flow/SKILL.md +117 -0
  46. package/ai/skills/stacks-git/SKILL.md +37 -9
  47. package/ai/skills/stacks-grilling/SKILL.md +85 -0
  48. package/ai/skills/stacks-guard/SKILL.md +86 -11
  49. package/ai/skills/stacks-guard/scripts/block-destructive.sh +67 -0
  50. package/ai/skills/stacks-handoff/SKILL.md +70 -0
  51. package/ai/skills/stacks-health/SKILL.md +1 -1
  52. package/ai/skills/stacks-http/SKILL.md +1 -1
  53. package/ai/skills/stacks-i18n/SKILL.md +1 -1
  54. package/ai/skills/stacks-investigate/SKILL.md +234 -106
  55. package/ai/skills/stacks-investigate/scripts/hitl-loop.template.sh +47 -0
  56. package/ai/skills/stacks-jobs/SKILL.md +1 -1
  57. package/ai/skills/stacks-listeners/SKILL.md +1 -1
  58. package/ai/skills/stacks-logging/SKILL.md +1 -1
  59. package/ai/skills/stacks-mail/SKILL.md +1 -1
  60. package/ai/skills/stacks-middleware/SKILL.md +1 -1
  61. package/ai/skills/stacks-migrations/SKILL.md +1 -1
  62. package/ai/skills/stacks-models/SKILL.md +1 -1
  63. package/ai/skills/stacks-new-feature/SKILL.md +65 -5
  64. package/ai/skills/stacks-notifications/SKILL.md +1 -1
  65. package/ai/skills/stacks-objects/SKILL.md +1 -1
  66. package/ai/skills/stacks-office-hours/SKILL.md +16 -2
  67. package/ai/skills/stacks-orm/SKILL.md +1 -1
  68. package/ai/skills/stacks-path/SKILL.md +1 -1
  69. package/ai/skills/stacks-payments/SKILL.md +35 -1
  70. package/ai/skills/stacks-plan-review/SKILL.md +27 -6
  71. package/ai/skills/stacks-plugins/SKILL.md +1 -1
  72. package/ai/skills/stacks-prototype/LOGIC.md +103 -0
  73. package/ai/skills/stacks-prototype/SKILL.md +66 -0
  74. package/ai/skills/stacks-prototype/UI.md +112 -0
  75. package/ai/skills/stacks-push/SKILL.md +1 -1
  76. package/ai/skills/stacks-query-builder/SKILL.md +1 -1
  77. package/ai/skills/stacks-queue/SKILL.md +1 -1
  78. package/ai/skills/stacks-realtime/SKILL.md +1 -1
  79. package/ai/skills/stacks-registry/SKILL.md +1 -1
  80. package/ai/skills/stacks-repl/SKILL.md +1 -1
  81. package/ai/skills/stacks-retro/SKILL.md +121 -75
  82. package/ai/skills/stacks-review/SKILL.md +182 -74
  83. package/ai/skills/stacks-router/SKILL.md +1 -1
  84. package/ai/skills/stacks-routes/SKILL.md +1 -1
  85. package/ai/skills/stacks-scaffolding/SKILL.md +1 -1
  86. package/ai/skills/stacks-scheduler/SKILL.md +1 -1
  87. package/ai/skills/stacks-search-engine/SKILL.md +1 -1
  88. package/ai/skills/stacks-security/SKILL.md +1 -1
  89. package/ai/skills/stacks-security-audit/SKILL.md +1 -1
  90. package/ai/skills/stacks-server/SKILL.md +1 -1
  91. package/ai/skills/stacks-shell/SKILL.md +1 -1
  92. package/ai/skills/stacks-slug/SKILL.md +1 -1
  93. package/ai/skills/stacks-sms/SKILL.md +1 -1
  94. package/ai/skills/stacks-socials/SKILL.md +1 -1
  95. package/ai/skills/stacks-storage/SKILL.md +1 -1
  96. package/ai/skills/stacks-strings/SKILL.md +1 -1
  97. package/ai/skills/stacks-stx/SKILL.md +1 -1
  98. package/ai/skills/stacks-tdd/EXAMPLES.md +136 -0
  99. package/ai/skills/stacks-tdd/SKILL.md +125 -0
  100. package/ai/skills/stacks-testing/SKILL.md +13 -3
  101. package/ai/skills/stacks-tunnel/SKILL.md +1 -1
  102. package/ai/skills/stacks-types/SKILL.md +1 -1
  103. package/ai/skills/stacks-ui/SKILL.md +1 -1
  104. package/ai/skills/stacks-utils/SKILL.md +1 -1
  105. package/ai/skills/stacks-validation/SKILL.md +1 -1
  106. package/ai/skills/stacks-whois/SKILL.md +1 -1
  107. package/ai/skills/stacks-wizard/SKILL.md +127 -0
  108. package/ai/skills/stacks-wizard/scripts/template.sh +208 -0
  109. package/ai/skills/stacks-writing-for-agents/MECHANICS.md +125 -0
  110. package/ai/skills/stacks-writing-for-agents/SKILL.md +218 -0
  111. package/app/Actions/Auth/GenerateTwoFactorSecretAction.ts +12 -2
  112. package/app/Actions/Commerce/Shipping/{DriverDestroyAction.ts → CourierDestroyAction.ts} +6 -6
  113. package/app/Actions/Commerce/Shipping/{DriverIndexAction.ts → CourierIndexAction.ts} +3 -3
  114. package/app/Actions/Commerce/Shipping/CourierPingStoreAction.ts +61 -0
  115. package/app/Actions/Commerce/Shipping/{DriverShowAction.ts → CourierShowAction.ts} +5 -5
  116. package/app/Actions/Commerce/Shipping/{DriverStoreAction.ts → CourierStoreAction.ts} +4 -4
  117. package/app/Actions/Commerce/Shipping/{DriverUpdateAction.ts → CourierUpdateAction.ts} +6 -6
  118. package/app/Actions/Commerce/Shipping/DeliveryRouteStartAction.ts +38 -0
  119. package/app/Actions/Commerce/Shipping/DeliveryStopCompleteAction.ts +40 -0
  120. package/app/Actions/Commerce/Shipping/DeliveryStopFailAction.ts +44 -0
  121. package/app/Actions/Commerce/Shipping/DeliveryStopStartAction.ts +39 -0
  122. package/app/Actions/Commerce/Shipping/courier-session.ts +75 -0
  123. package/app/Actions/Commerce/commerce-action.test.ts +5 -5
  124. package/app/Actions/Dashboard/Commerce/CommerceDeliveryAction.ts +5 -5
  125. package/app/Actions/Dashboard/Commerce/CourierIndexAction.ts +24 -0
  126. package/app/Actions/Dashboard/Commerce/DeliveryRouteIndexAction.ts +7 -7
  127. package/app/Actions/Dashboard/Commerce/commerce-delivery.test.ts +11 -11
  128. package/app/Actions/Dashboard/Commerce/commerce-delivery.ts +29 -29
  129. package/app/Actions/Dashboard/Commerce/{driver-records.test.ts → courier-records.test.ts} +9 -9
  130. package/app/Actions/Dashboard/Commerce/{driver-records.ts → courier-records.ts} +14 -14
  131. package/app/Actions/Dashboard/Commerce/delivery-route-records.test.ts +13 -13
  132. package/app/Actions/Dashboard/Commerce/delivery-route-records.ts +25 -25
  133. package/app/Models/User.ts +1 -1
  134. package/app/Models/commerce/{Driver.ts → Courier.ts} +7 -7
  135. package/app/Models/commerce/{DriverPing.ts → CourierPing.ts} +7 -7
  136. package/app/Models/commerce/DeliveryRoute.ts +6 -6
  137. package/app/Models/commerce/DeliveryStop.ts +31 -8
  138. package/bootstrap.ts +7 -0
  139. package/functions/commerce/shippings/couriers.ts +19 -0
  140. package/ide/vscode/package.json +1 -1
  141. package/package.json +4 -3
  142. package/resources/components/Dashboard/Commerce/Delivery/{DriverDeleteDialog.stx → CourierDeleteDialog.stx} +5 -5
  143. package/resources/components/Dashboard/Commerce/Delivery/{DriverDialog.stx → CourierDialog.stx} +10 -10
  144. package/resources/components/Dashboard/Commerce/Delivery/{DriversDashboard.stx → CouriersDashboard.stx} +43 -43
  145. package/resources/components/Dashboard/Commerce/Delivery/{DriversTable.stx → CouriersTable.stx} +21 -21
  146. package/resources/components/Dashboard/Commerce/Delivery/DeliveryOverviewDashboard.stx +18 -18
  147. package/resources/components/Dashboard/Commerce/Delivery/DeliveryRouteDeleteDialog.stx +2 -2
  148. package/resources/components/Dashboard/Commerce/Delivery/DeliveryRouteDialog.stx +22 -22
  149. package/resources/components/Dashboard/Commerce/Delivery/DeliveryRoutesDashboard.stx +24 -24
  150. package/resources/components/Dashboard/Commerce/Delivery/DeliveryRoutesTable.stx +8 -8
  151. package/resources/components/Dashboard/Commerce/Delivery/TabNavigation.stx +1 -1
  152. package/resources/functions/dashboard/data.ts +1 -1
  153. package/resources/functions/dashboard/sidebar.ts +2 -2
  154. package/routes/dashboard-api.ts +6 -6
  155. package/routes/dashboard.ts +7 -7
  156. package/routes/delivery.ts +24 -0
  157. package/types/defaults.ts +3 -3
  158. package/views/dashboard/.discovered-models.json +18 -18
  159. package/views/dashboard/AUDIT.md +1 -1
  160. package/views/dashboard/commerce/delivery/{drivers.stx → couriers.stx} +2 -2
  161. package/views/dashboard/composables/useChart.ts +16 -2
  162. package/app/Actions/Dashboard/Commerce/DriverIndexAction.ts +0 -24
  163. package/functions/commerce/shippings/drivers.ts +0 -19
@@ -0,0 +1,180 @@
1
+ ---
2
+ name: stacks-codebase-design
3
+ description: Use when designing or restructuring code in a Stacks project - shaping an action or package interface, deciding where a seam goes, choosing between a trait and a helper, making code testable or navigable, or when another skill needs the deep-module vocabulary (module, interface, depth, seam, adapter, leverage, locality).
4
+ license: MIT
5
+ compatibility: Bun >= 1.3.0, TypeScript
6
+ allowed-tools: Read Edit Write Bash Grep Glob
7
+ ---
8
+
9
+ # Codebase design
10
+
11
+ Design **deep modules**: a lot of behaviour behind a small interface, placed at a
12
+ clean seam, testable through that interface. Use this language and these
13
+ principles wherever Stacks code is being designed or restructured. The aim is
14
+ leverage for callers, locality for maintainers, and testability for everyone.
15
+
16
+ Stacks is already built this way, which is why the vocabulary is worth sharing:
17
+ `defineModel()` puts a schema, validation, factories, relationships and a REST
18
+ surface behind one call. The driver packages (`cache`, `queue`, `storage`,
19
+ `email`, `ai`, `chat`, `search-engine`, `dns`) are ports with two or more
20
+ adapters each. Use the words below rather than inventing new ones per package.
21
+
22
+ Credit: the deep-module model here is adapted from Matt Pocock's
23
+ `codebase-design` skill (MIT), <https://github.com/mattpocock/skills>, itself
24
+ building on Ousterhout and Feathers.
25
+
26
+ ## Glossary
27
+
28
+ Use these terms exactly. Do not substitute "component", "service", "API" or
29
+ "boundary". Consistent language is the whole point.
30
+
31
+ **Module**: anything with an interface and an implementation. Deliberately
32
+ scale-agnostic: a function, an action, a model, a `@stacksjs/*` package, a
33
+ tier-spanning slice. *Avoid*: unit, component, service.
34
+
35
+ **Interface**: everything a caller must know to use the module correctly. The
36
+ type signature, but also invariants, ordering constraints, error modes, required
37
+ config, and performance characteristics. For a Stacks action the interface
38
+ includes its route, its middleware and its request shape, not just its `handle`
39
+ signature. *Avoid*: API, signature (too narrow, they name only the type surface).
40
+
41
+ **Implementation**: what is inside a module. Distinct from **adapter**: a thing
42
+ can be a small adapter over a large implementation (the S3 storage driver) or a
43
+ large adapter over a small one (an in-memory fake). Reach for "adapter" when the
44
+ seam is the topic, "implementation" otherwise.
45
+
46
+ **Depth**: leverage at the interface. How much behaviour a caller or a test can
47
+ exercise per unit of interface they have to learn. A module is **deep** when a
48
+ lot of behaviour sits behind a small interface, **shallow** when the interface is
49
+ nearly as complex as the implementation.
50
+
51
+ **Seam** (Michael Feathers): a place where you can alter behaviour without
52
+ editing in that place. The *location* at which a module's interface lives. Where
53
+ to put the seam is its own design decision, distinct from what goes behind it. In
54
+ Stacks the `app/` override model is a seam the framework hands you for free:
55
+ `app/Actions/Cms/PostIndexAction.ts` replaces the default without editing it.
56
+ *Avoid*: boundary (overloaded with DDD's bounded context).
57
+
58
+ **Adapter**: a concrete thing that satisfies an interface at a seam. Describes
59
+ *role* (which slot it fills), not substance (what is inside). `config/cache.ts`
60
+ picking `memory` or `redis` is adapter selection.
61
+
62
+ **Leverage**: what callers get from depth. More capability per unit of interface
63
+ learned. One implementation pays back across N call sites and M tests.
64
+
65
+ **Locality**: what maintainers get from depth. Change, bugs, knowledge and
66
+ verification concentrate in one place rather than spreading across callers. Fix
67
+ once, fixed everywhere.
68
+
69
+ ## Deep versus shallow
70
+
71
+ **Deep** = small interface, lots of implementation:
72
+
73
+ ```
74
+ ┌─────────────────────┐
75
+ │ Small interface │ ← few entry points, simple params
76
+ ├─────────────────────┤
77
+ │ │
78
+ │ Deep implementation│ ← complexity hidden
79
+ │ │
80
+ └─────────────────────┘
81
+ ```
82
+
83
+ **Shallow** = large interface, little implementation. Avoid:
84
+
85
+ ```
86
+ ┌─────────────────────────────────┐
87
+ │ Large interface │ ← many methods, complex params
88
+ ├─────────────────────────────────┤
89
+ │ Thin implementation │ ← mostly passes through
90
+ └─────────────────────────────────┘
91
+ ```
92
+
93
+ When designing an interface, ask: can I reduce the number of entry points? Can I
94
+ simplify the params? Can I hide more complexity inside?
95
+
96
+ The `useApi` trait is the canonical deep interface in this framework: one config
97
+ object, and the model gains five actions, five routes, an OpenAPI entry and a
98
+ dashboard view. `useSearch`, `useAuth` and `useSoftDeletes` are the same trade.
99
+ When you find yourself writing the fifth near-identical action, the question is
100
+ whether a trait wants to be born.
101
+
102
+ ## Principles
103
+
104
+ - **Depth is a property of the interface, not the implementation.** A deep module
105
+ can be internally composed of small, swappable parts. They just are not part of
106
+ the interface. A module can have **internal seams** (private, used by its own
107
+ tests) as well as the **external seam** at its interface.
108
+ - **The deletion test.** Imagine deleting the module. If complexity vanishes, it
109
+ was a pass-through. If complexity reappears across N callers, it was earning
110
+ its keep.
111
+ - **The interface is the test surface.** Callers and tests cross the same seam.
112
+ If you want to test *past* the interface, the module is probably the wrong
113
+ shape.
114
+ - **One adapter means a hypothetical seam. Two adapters means a real one.** Do
115
+ not introduce a seam unless something actually varies across it. Production
116
+ plus test counts as two.
117
+
118
+ ## Designing for testability
119
+
120
+ 1. **Accept dependencies, do not create them.**
121
+
122
+ ```typescript
123
+ // testable
124
+ export async function processOrder(order: Order, gateway: PaymentGateway) {}
125
+
126
+ // hard to test
127
+ export async function processOrder(order: Order) {
128
+ const gateway = new StripeGateway()
129
+ }
130
+ ```
131
+
132
+ 2. **Return results, do not produce side effects.**
133
+
134
+ ```typescript
135
+ // testable
136
+ function calculateDiscount(cart: Cart): Discount {}
137
+
138
+ // hard to test
139
+ function applyDiscount(cart: Cart): void { cart.total -= discount }
140
+ ```
141
+
142
+ 3. **Small surface area.** Fewer entry points means fewer tests. Fewer params
143
+ means simpler setup.
144
+
145
+ In a Stacks app the third dependency is almost always the database, and it does
146
+ not need injecting: `refreshDatabase()` plus model factories give you a real one
147
+ per suite. See `stacks-tdd` for where that line sits.
148
+
149
+ ## Relationships
150
+
151
+ - A **module** has exactly one **interface**, the surface it presents to callers
152
+ and tests.
153
+ - **Depth** is a property of a **module**, measured against its **interface**.
154
+ - A **seam** is where a **module**'s **interface** lives.
155
+ - An **adapter** sits at a **seam** and satisfies the **interface**.
156
+ - **Depth** produces **leverage** for callers and **locality** for maintainers.
157
+
158
+ ## Rejected framings
159
+
160
+ - **Depth as a ratio of implementation lines to interface lines** (Ousterhout):
161
+ rewards padding the implementation. Use depth-as-leverage instead.
162
+ - **"Interface" as the TypeScript `interface` keyword or a class's public
163
+ methods**: too narrow. Interface here includes every fact a caller must know.
164
+ - **"Boundary"**: overloaded with DDD's bounded context. Say **seam** or
165
+ **interface**.
166
+
167
+ ## Going deeper
168
+
169
+ - **Deepening a cluster given its dependencies**: [DEEPENING.md](DEEPENING.md)
170
+ covers the dependency categories, seam discipline, and replace-do-not-layer
171
+ testing.
172
+ - **Exploring alternative interfaces**: [DESIGN-IT-TWICE.md](DESIGN-IT-TWICE.md)
173
+ runs parallel sub-agents to design one interface several radically different
174
+ ways, then compares on depth, locality and seam placement.
175
+
176
+ ## Downstream
177
+
178
+ > Reach for `stacks-tdd` to write the tests at the seam you chose, and
179
+ > `stacks-domain-modeling` when the module needs a name the project does not
180
+ > have yet.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: stacks-collections
3
- description: Use when working with collection data structures in Stacks — chaining array operations, Laravel-style collection methods, mapping, filtering, reducing, or grouping. Covers @stacksjs/collections which wraps ts-collect.
3
+ description: Use when working with collection data structures in Stacks - chaining array operations, Laravel-style collection methods, mapping, filtering, reducing, or grouping. Covers @stacksjs/collections which wraps ts-collect.
4
4
  license: MIT
5
5
  compatibility: Bun >= 1.3.0, TypeScript
6
6
  allowed-tools: Read Edit Write Bash Grep Glob
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: stacks-commerce
3
- description: Use when building e-commerce features in Stacks — the commerce namespace with 13 sub-modules (products, orders, customers, coupons, payments, shipping, tax, gift cards, waitlists, devices, receipts, restaurant), 20+ commerce models, default commerce functions, or the commerce configuration. Covers @stacksjs/commerce.
3
+ description: Use when building e-commerce features in Stacks - the commerce namespace with 15 sub-modules (products, carts, orders, customers, coupons, payments, gift cards, auctions, shipping, tax, waitlists, restaurant, devices, receipts, errors), 20+ commerce models, checkout and redemption logic, or the commerce configuration. Covers @stacksjs/commerce.
4
4
  license: MIT
5
5
  compatibility: Bun >= 1.3.0, TypeScript
6
6
  allowed-tools: Read Edit Write Bash Grep Glob
@@ -8,7 +8,7 @@ allowed-tools: Read Edit Write Bash Grep Glob
8
8
 
9
9
  # Stacks Commerce
10
10
 
11
- Comprehensive e-commerce module with 13 sub-modules and 20+ models.
11
+ Comprehensive e-commerce module with 15 sub-modules and 20+ models.
12
12
 
13
13
  ## Key Paths
14
14
  - Core package: `storage/framework/core/commerce/src/`
@@ -20,30 +20,37 @@ Comprehensive e-commerce module with 13 sub-modules and 20+ models.
20
20
  ```typescript
21
21
  import { commerce } from '@stacksjs/commerce'
22
22
 
23
- // 13 sub-modules
24
- commerce.products // Product CRUD
25
- commerce.coupons // Coupon management
26
- commerce.customers // Customer management
27
- commerce.errors // Error tracking
28
- commerce.giftCards // Gift card management
29
- commerce.orders // Order management
30
- commerce.payments // Payment processing
31
- commerce.restaurant // Restaurant features
32
- commerce.shippings // Shipping management
33
- commerce.tax // Tax rate management
34
- commerce.waitlists // Waitlist management
23
+ // 15 sub-modules
24
+ commerce.products // Products, variants, units, manufacturers, reviews, categories
25
+ commerce.carts // The pre-checkout basket
26
+ commerce.orders // Orders, order items, export, checkout guards
27
+ commerce.customers // Customer records
28
+ commerce.coupons // Coupons, including atomic redemption
29
+ commerce.payments // Payment records, refunds
30
+ commerce.giftCards // Gift cards, balance, redemption and reload
31
+ commerce.auctions // Benefit auctions: lots, bids, proxy bidding, pledges
32
+ commerce.shippings // Methods, rates, zones, routes, couriers, live tracking
33
+ commerce.tax // Tax rates and breakdown
34
+ commerce.waitlists // Waitlists
35
+ commerce.restaurant // Restaurant features (lives at waitlists/restaurant)
35
36
  commerce.devices // Print device management
36
- commerce.receipts // Receipt management
37
+ commerce.receipts // Receipt records
38
+ commerce.errors // Error tracking
37
39
  ```
38
40
 
41
+ `restaurant` is re-exported from `waitlists/restaurant` rather than having a
42
+ directory of its own, which is why the source tree shows one fewer directory
43
+ than the namespace has keys. `tests/commerce.test.ts` asserts the exact key set,
44
+ so adding a sub-module means updating that count.
45
+
39
46
  ## Sub-Module Operations
40
47
 
41
48
  Each sub-module typically provides:
42
- - `index()` — list all
43
- - `fetch(id)` — get one
44
- - `store(data)` — create
45
- - `update(id, data)` — update
46
- - `destroy(id)` — delete
49
+ - `fetchAll()` - list all
50
+ - `fetchById(id)` - get one
51
+ - `store(data)` - create, plus `bulkStore`
52
+ - `update(id, data)` - update, plus `bulkUpdate`
53
+ - `destroy(id)` - delete, plus `bulkDestroy`
47
54
 
48
55
  ### Products Sub-Module
49
56
  - Products: items, variants, units
@@ -62,7 +69,7 @@ Each sub-module typically provides:
62
69
  - Shipping rates (weight-based)
63
70
  - Shipping zones
64
71
  - Delivery routes and their stops
65
- - Drivers
72
+ - Couriers
66
73
  - Digital deliveries
67
74
  - License keys
68
75
  - **Live tracking** (`commerce.shippings.tracking`) - see below
@@ -85,16 +92,77 @@ Each sub-module typically provides:
85
92
  | Manufacturer | manufacturer info | hasMany: Product |
86
93
  | Review | rating(1-5), content, isVerifiedPurchase, helpfulVotes | belongsTo: Product, Customer |
87
94
  | ShippingRate | weightFrom, weightTo, rate | belongsTo: ShippingMethod, ShippingZone |
88
- | DeliveryRoute | stops, totalDistance, status(planned/active/completed), startedAt | belongsTo: Driver; hasMany: DeliveryStop, DriverPing |
95
+ | DeliveryRoute | stops, totalDistance, status(planned/active/completed), startedAt | belongsTo: Courier; hasMany: DeliveryStop, CourierPing |
89
96
  | DeliveryStop | sequence, status, address, latitude, longitude, etaAt, arrivedAt | belongsTo: DeliveryRoute, Order |
90
- | Driver | name, phone, vehicleNumber, status, latitude, longitude, heading, lastPingAt | hasMany: DeliveryRoute, DriverPing |
91
- | DriverPing | latitude, longitude, heading, speed, accuracy, recordedAt | belongsTo: Driver, DeliveryRoute |
97
+ | Courier | name, phone, vehicleNumber, status, latitude, longitude, heading, lastPingAt | hasMany: DeliveryRoute, CourierPing |
98
+ | CourierPing | latitude, longitude, heading, speed, accuracy, recordedAt | belongsTo: Courier, DeliveryRoute |
92
99
  | TaxRate | name, rate(0-100), type(VAT/GST/Sales Tax) | |
93
100
  | LicenseKey | key(XXXX-XXXX-XXXX-XXXX-XXXX), template, status | belongsTo: Customer, Product, Order |
94
101
  | DigitalDelivery | downloadLimit, expiryDays, automaticDelivery | |
95
102
  | WaitlistProduct | product waitlist tracking | |
96
103
  | Receipt | receipt records | |
97
104
 
105
+ ## Money paths
106
+
107
+ Three operations move money, and all three are written as a **single conditional
108
+ UPDATE** rather than read-check-write. Concurrency here is not theoretical: two
109
+ parallel requests against a read-then-write redemption both see the pre-state
110
+ and both succeed, which is a coupon redeemed past its limit or a gift card spent
111
+ twice.
112
+
113
+ ### Redeeming a coupon
114
+
115
+ ```ts
116
+ const result = await commerce.coupons.redeem(couponId)
117
+
118
+ if (!result.ok) {
119
+ // 'not-found' | 'inactive' | 'expired' | 'limit-reached'
120
+ throw new HttpError(400, `Coupon cannot be redeemed: ${result.reason}`)
121
+ }
122
+ // result.coupon reflects the post-redemption state.
123
+ ```
124
+
125
+ `redeem` bumps `usage_count` and enforces `max_uses`, `is_active` and the
126
+ start/end dates in the WHERE clause, so the database decides the race. A
127
+ `max_uses` of `NULL` means unlimited. Do not fetch, check and then call
128
+ `update()` to increment: that is the exact pattern this replaced.
129
+
130
+ ### Spending or reloading a gift card
131
+
132
+ ```ts
133
+ await commerce.giftCards.updateBalance(cardId, -25) // redeem 25
134
+ await commerce.giftCards.updateBalance(cardId, 50) // reload 50
135
+ ```
136
+
137
+ One entry point for both directions, and they are deliberately asymmetric:
138
+
139
+ | | Redemption (`amount < 0`) | Reload (`amount > 0`) |
140
+ |---|---|---|
141
+ | Allowed status | `ACTIVE` | `ACTIVE`, or `USED` when the card is `isReloadable` |
142
+ | `lastUsedDate` | stamped | left alone |
143
+ | Balance floor | cannot go below 0 | n/a |
144
+ | Expiry | refused past `expiryDate` | refused past `expiryDate` |
145
+
146
+ The balance lands on 0 and the status flips to `USED` in the same statement. A
147
+ reloadable card can be revived from `USED`; a non-reloadable one cannot, and
148
+ throws `Gift card is not reloadable`. `deactivate(id)` is the terminal state and
149
+ reports whether a row actually changed.
150
+
151
+ ### Recording a refund
152
+
153
+ `commerce.payments.recordRefund(id, amount)` takes **integer minor units** and
154
+ enforces `refund_amount + amount <= amount` in the WHERE clause, so operators
155
+ cannot over-refund a payment by racing each other. It flips the status to
156
+ `refunded` or `partiallyRefunded` depending on where the total lands.
157
+
158
+ ## Carts
159
+
160
+ `commerce.carts` is the pre-checkout basket, with the same CRUD shape as every
161
+ other sub-module plus bulk variants. `commerce.orders` owns what happens after
162
+ checkout, and `orders/guards.ts` holds the pre-flight checks that run between
163
+ the two, including `cleanupAbandonedCarts({ olderThanDays, limit })` for the
164
+ sweeper you schedule daily.
165
+
98
166
  ## Live Delivery Tracking
99
167
 
100
168
  `commerce.shippings.tracking` is the moving part of shipping: position ingest,
@@ -116,22 +184,22 @@ const stop = await tracking.assignStop({
116
184
  await tracking.startRoute(route.id)
117
185
  await tracking.startStop(stop.id) // order -> OUT_FOR_DELIVERY
118
186
 
119
- // One call per position fix from the driver's device.
120
- await tracking.recordDriverPing({
121
- driverId, latitude, longitude, speed, accuracy,
187
+ // One call per position fix from the courier's device.
188
+ await tracking.recordCourierPing({
189
+ courierId, latitude, longitude, speed, accuracy,
122
190
  })
123
191
 
124
192
  await tracking.completeStop(stop.id) // order -> DELIVERED, route closes itself
125
193
  ```
126
194
 
127
- ### What `recordDriverPing` does
195
+ ### What `recordCourierPing` does
128
196
 
129
197
  One entry point, so a tracking page never shows a position its ETA disagrees
130
- with. Per fix it: appends to `driver_pings`, updates the driver's denormalised
198
+ with. Per fix it: appends to `courier_pings`, updates the courier's denormalised
131
199
  present position, recomputes the served stop's ETA, broadcasts the position,
132
200
  and latches `delivery:nearby` / `delivery:arrived` so each fires exactly once.
133
201
 
134
- A fix reporting worse than 250m accuracy is stored but does not move the driver
202
+ A fix reporting worse than 250m accuracy is stored but does not move the courier
135
203
  or trip a threshold.
136
204
 
137
205
  ### Two fan-outs, on purpose
@@ -159,7 +227,7 @@ back to `SHIPPED` when a drop fails and the parcel returns to the depot.
159
227
  `distanceInMeters`, `bearingInDegrees`, `estimateSecondsRemaining`, `isWithin`
160
228
  and `hasCoordinates` are exported for building dispatch views. The ETA pads
161
229
  straight-line distance by a detour factor and returns `null` for a stationary
162
- driver rather than `Infinity`.
230
+ courier rather than `Infinity`.
163
231
 
164
232
  ## Integration with Payments
165
233
  Commerce works with `@stacksjs/payments` for Stripe integration:
@@ -172,13 +240,51 @@ await Payment.charge(customer, order.totalAmount, paymentMethodId)
172
240
  All commerce models have dashboard views at `/dashboard/commerce/*`.
173
241
 
174
242
  ## Gotchas
175
- - Commerce models are auto-generated — edit definitions, not generated files
176
- - Use `buddy make:migration` when changing commerce schemas
243
+
244
+ ### Writing raw SQL here
245
+
246
+ Two dialect traps have each shipped a broken money path, so both are now guarded
247
+ by `src/tests/sql-dialect-portability.test.ts`:
248
+
249
+ - **Placeholders.** Postgres numbers them (`$1`); a literal `?` is a syntax
250
+ error. Render them with `sqlHelpers(env.DB_CONNECTION || 'sqlite').param(n)`.
251
+ - **Booleans.** A `schema.boolean()` attribute becomes a real `BOOLEAN` on
252
+ Postgres, so `is_active = 1` is `operator does not exist: boolean = integer`.
253
+ Use `sqlHelpers(...).boolTrue` / `.boolFalse`.
254
+
255
+ Both pass on SQLite, which is what the tests run against, so neither shows up
256
+ locally. That is the whole reason the source-level test exists.
257
+
258
+ ### Reading back a row you just inserted
259
+
260
+ Use `insertedId(result)` from `utils/inserted-id`. Couriers disagree: SQLite
261
+ reports `lastInsertRowid`, MySQL reports `insertId`, and Postgres reports
262
+ neither without a `RETURNING` clause (fall back to the `uuid` the row was
263
+ written with).
264
+
265
+ **Never read a row count as an id.** `numInsertedOrUpdatedRows` says how many
266
+ rows changed, not which one, so a successful single-row insert reports `1` and
267
+ the caller fetches row 1 of the table instead of the new record. `mutationCount`
268
+ is the helper for when the count is genuinely what you want.
269
+
270
+ ### Everything else
271
+
272
+ - Commerce models are auto-generated - edit definitions, not generated files
273
+ - Run `buddy generate:migrations` after changing a commerce model, and read the
274
+ SQL before applying it
177
275
  - Order `observe: true` emits events on create/update/delete
178
276
  - Products have JSON fields for allergens and nutritionalInfo
179
- - Cart expiry is tracked via `expiresAt` field
277
+ - Cart expiry is tracked via `expiresAt`; `cleanupAbandonedCarts` is the sweeper
180
278
  - Coupon types: `fixed_amount` or `percentage`
181
279
  - Gift card codes are unique and auto-generated
182
280
  - License keys follow XXXX-XXXX-XXXX-XXXX-XXXX format
183
281
  - Product dashboard is highlighted (`dashboard: { highlight: true }`)
184
- - Default seeder counts: Product(10), Order(20), Review(50), Payment(50)
282
+ - Default seeder counts: Product(10), Order(20), Review(50), Payment(50),
283
+ GiftCard(20), Customer(20), Coupon(15)
284
+ - `fetchById` in most sub-modules returns the raw row, so columns arrive
285
+ snake_cased even though the declared type is camelCase
286
+
287
+ ## Downstream
288
+
289
+ > Touching a money path? `/stacks-tdd` for the seam to test it at, and
290
+ > `/stacks-review` before it merges. `/stacks-payments` covers the Stripe side.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: stacks-composables
3
- description: Use when creating or using reactive composables in STX templates — 90+ composables for state management, DOM interaction, sensors, animation, browser APIs, async operations, or the complete list of auto-imported composables. Covers @stacksjs/composables.
3
+ description: Use when creating or using reactive composables in STX templates - 90+ composables for state management, DOM interaction, sensors, animation, browser APIs, async operations, or the complete list of auto-imported composables. Covers @stacksjs/composables.
4
4
  license: MIT
5
5
  compatibility: Bun >= 1.3.0, TypeScript
6
6
  allowed-tools: Read Edit Write Bash Grep Glob
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: stacks-config
3
- description: Use when working with Stacks configuration — the 44 config files, config helper functions, default values, environment-specific overrides, or the defineApp/defineDatabase/etc builder functions. Covers @stacksjs/config and the config/ directory.
3
+ description: Use when working with Stacks configuration - the 44 config files, config helper functions, default values, environment-specific overrides, or the defineApp/defineDatabase/etc builder functions. Covers @stacksjs/config and the config/ directory.
4
4
  license: MIT
5
5
  compatibility: Bun >= 1.3.0, TypeScript
6
6
  allowed-tools: Read Edit Write Bash Grep Glob
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: stacks-configuration
3
- description: Use when setting up or modifying Stacks project-level configuration — bunfig.toml preload order, the tsconfig chain and TypeScript 7 / tsgo type checking, workspace configuration, .env setup, package.json scripts, system requirements (Bun >= 1.3.0, SQLite >= 3.47.2), or the project bootstrap process. For individual feature configs (database, email, auth, etc.), see the specific package skills instead.
3
+ description: Use when setting up or modifying Stacks project-level configuration - bunfig.toml preload order, the tsconfig chain and TypeScript 7 / tsgo type checking, workspace configuration, .env setup, package.json scripts, system requirements (Bun >= 1.3.0, SQLite >= 3.47.2), or the project bootstrap process. For individual feature configs (database, email, auth, etc.), see the specific package skills instead.
4
4
  license: MIT
5
5
  compatibility: Bun >= 1.3.0, TypeScript
6
6
  allowed-tools: Read Edit Write Bash Grep Glob
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: stacks-cron
3
- description: Use when working with cron expressions in a Stacks application — parsing cron syntax, registering OS-level cron jobs, or low-level scheduling. Covers @stacksjs/cron. For higher-level scheduling, see stacks-scheduler.
3
+ description: Use when working with cron expressions in a Stacks application - parsing cron syntax, registering OS-level cron jobs, or low-level scheduling. Covers @stacksjs/cron. For higher-level scheduling, see stacks-scheduler.
4
4
  license: MIT
5
5
  compatibility: Bun >= 1.3.0, TypeScript
6
6
  allowed-tools: Read Edit Write Bash Grep Glob
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: stacks-crosswind
3
- description: Use when styling components in a Stacks application — utility-first CSS classes, theming, responsive design, variants, custom rules, or CSS generation. Crosswind is the CSS utility engine powering Stacks' Crosswind config.
3
+ description: Use when styling components in a Stacks application - utility-first CSS classes, theming, responsive design, variants, custom rules, or CSS generation. Crosswind is the CSS utility engine powering Stacks' Crosswind config.
4
4
  license: MIT
5
5
  compatibility: Bun >= 1.3.0, TypeScript
6
6
  allowed-tools: Read Edit Write Bash Grep Glob
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: stacks-database
3
- description: Use when working with databases in a Stacks application — configuring connections, running queries, migrations, seeding, SQL helpers, or using SQLite/MySQL/PostgreSQL/DynamoDB. Covers @stacksjs/database, bun-query-builder, config/database.ts, and the database/ migrations directory.
3
+ description: Use when working with databases in a Stacks application - configuring connections, running queries, migrations, seeding, SQL helpers, or using SQLite/MySQL/PostgreSQL/DynamoDB. Covers @stacksjs/database, bun-query-builder, config/database.ts, and the database/ migrations directory.
4
4
  license: MIT
5
5
  compatibility: Bun >= 1.3.0, TypeScript, SQLite >= 3.47.2
6
6
  allowed-tools: Read Edit Write Bash Grep Glob
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: stacks-datetime
3
- description: Use when working with dates and times in Stacks — the DateTime class with Carbon-like API (add/sub, comparison, formatting, start/end of day/month/year), date parsing, format tokens, or timezone handling. Covers @stacksjs/datetime.
3
+ description: Use when working with dates and times in Stacks - the DateTime class with Carbon-like API (add/sub, comparison, formatting, start/end of day/month/year), date parsing, format tokens, or timezone handling. Covers @stacksjs/datetime.
4
4
  license: MIT
5
5
  compatibility: Bun >= 1.3.0, TypeScript
6
6
  allowed-tools: Read Edit Write Bash Grep Glob
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: stacks-dependencies
3
- description: Use when managing dependencies in a Stacks project — system dependencies via Pantry, Bun workspaces, buddy-bot updates, better-dx tooling, or dependency configuration. Covers config/deps.ts, Pantry, and workspace management.
3
+ description: Use when managing dependencies in a Stacks project - system dependencies via Pantry, Bun workspaces, buddy-bot updates, better-dx tooling, or dependency configuration. Covers config/deps.ts, Pantry, and workspace management.
4
4
  license: MIT
5
5
  compatibility: Bun >= 1.3.0, TypeScript
6
6
  allowed-tools: Read Edit Write Bash Grep Glob
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: stacks-deploy
3
- description: Use when deploying a Stacks application — the deployment workflow (build → deploy), pre/post deploy hooks, server vs serverless mode selection, first-time deployment setup, deployment troubleshooting, or the buddy deploy command. For cloud infrastructure details (EC2, Lambda, CloudFormation, Route53, IAM), see stacks-cloud.
3
+ description: Use when deploying a Stacks application - the deployment workflow (build → deploy), pre/post deploy hooks, server vs serverless mode selection, first-time deployment setup, deployment troubleshooting, or the buddy deploy command. For cloud infrastructure details (EC2, Lambda, CloudFormation, Route53, IAM), see stacks-cloud.
4
4
  license: MIT
5
5
  compatibility: Bun >= 1.3.0, TypeScript, AWS
6
6
  allowed-tools: Read Edit Write Bash Grep Glob
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: stacks-desktop
3
- description: Use when building or publishing desktop applications with Stacks — Craft native windows, system tray, desktop packaging, or Mac App Store delivery.
3
+ description: Use when building or publishing desktop applications with Stacks - Craft native windows, system tray, desktop packaging, or Mac App Store delivery.
4
4
  license: MIT
5
5
  compatibility: Bun >= 1.3.0, TypeScript
6
6
  allowed-tools: Read Edit Write Bash Grep Glob
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: stacks-development
3
- description: Use when setting up or configuring the Stacks development environment — dev server, hot reload, development utilities, or IDE configuration. Covers the @stacksjs/development package, the dev server, CLI commands, reverse proxy, SSL, and dev workflow.
3
+ description: Use when setting up or configuring the Stacks development environment - dev server, hot reload, development utilities, or IDE configuration. Covers the @stacksjs/development package, the dev server, CLI commands, reverse proxy, SSL, and dev workflow.
4
4
  license: MIT
5
5
  compatibility: Bun >= 1.3.0, TypeScript
6
6
  allowed-tools: Read Edit Write Bash Grep Glob
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: stacks-dns
3
- description: Use when managing DNS in a Stacks application — Route53 hosted zones, domain records, nameserver management, or DNS configuration. Covers @stacksjs/dns (AWS Route53 driver), @stacksjs/dnsx, and config/dns.ts.
3
+ description: Use when managing DNS in a Stacks application - Route53 hosted zones, domain records, nameserver management, or DNS configuration. Covers @stacksjs/dns (AWS Route53 driver), @stacksjs/dnsx, and config/dns.ts.
4
4
  license: MIT
5
5
  compatibility: Bun >= 1.3.0, TypeScript
6
6
  allowed-tools: Read Edit Write Bash Grep Glob
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: stacks-docs
3
- description: Use when building or configuring documentation for a Stacks project — BunPress setup, doc generation, navigation, sidebar structure, or documentation meta/SEO. Covers @stacksjs/docs and config/docs.ts.
3
+ description: Use when building or configuring documentation for a Stacks project - BunPress setup, doc generation, navigation, sidebar structure, or documentation meta/SEO. Covers @stacksjs/docs and config/docs.ts.
4
4
  license: MIT
5
5
  compatibility: Bun >= 1.3.0, TypeScript
6
6
  allowed-tools: Read Edit Write Bash Grep Glob