Skip to content

Opt-in gates and events for customers-only (wholesale) stores - #837

Open
vitorrgg wants to merge 6 commits into
mainfrom
feat/customers-only-store
Open

Opt-in gates and events for customers-only (wholesale) stores#837
vitorrgg wants to merge 6 commits into
mainfrom
feat/customers-only-store

Conversation

@vitorrgg

Copy link
Copy Markdown
Member

Summary

Opt-in support for stores that only sell to registered/approved customers (wholesale, B2B). Nothing changes for stores without the new config keys.

  • firebase/types: new API events customers-enabledSet and customers-staffSignatureSet (mapped with modified_fields, like products-priceSet); parseEventName extracted to a side-effect-free module with tests; CheckoutGatesConfig / PassportConfig types on config.get().
  • passport: config.passport.newCustomer is merged into customers auto-created on first login (e.g. { enabled: false }); the issued token respects those login/enabled defaults.
  • modules: config.checkout.customersOnly rejects unknown or not-enabled customers (CKT804), requireStaffSignature (CKT805) and minSubtotal (CKT806); readOrSaveCustomer accepts { canCreate: false }.
  • storefront: JSON-LD omits offers when the product has no price > 0 (stores that strip prices from SSR must not advertise price: 0).
  • cli: store rewrites from conf/firebase.json are inserted before the SSR ** catch-all instead of appended after it (they never matched).

First consumer: the O Porto da Música wholesale store (functions/config.json with passport.newCustomer, checkout.customersOnly, checkout.minSubtotal, apps.atacado).

Test plan

  • turbo run build for types, firebase, passport, modules, storefront (31 tasks ok)
  • packages/modules/tests/3-customer-gates.test.ts, packages/firebase/tests/parse-event-name.test.ts, packages/passport/tests/new-customer.test.ts (vitest, 11 tests)
  • tsc -p tsconfig.test.json, eslint on changed files
  • Publish and validate in the Porto da Música store (checkout 403/400 codes, event delivery)

🤖 Generated with Claude Code

vitorrgg and others added 6 commits September 10, 2026 12:33
… config

Stores that must approve customers before selling can now subscribe to
`customers-staffSignatureSet` and `customers-enabledSet` API events
(mapped with `modified_fields`, same pattern as `products-priceSet`)
and declare `passport.newCustomer` / `checkout.*` gates in config.

- `parseEventName` moved to its own side-effect-free module with unit tests
- new `CheckoutGatesConfig` and `PassportConfig` types on `config.get()`

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Customers auto-created on first social/email-link login are merged with
`config.passport.newCustomer` (e.g. `{ enabled: false }`), so approval-based
stores don't hand out purchase-enabled accounts by default. The issued token
now respects those `login`/`enabled` defaults like existing customers.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
With `config.checkout` set, `@checkout` can reject orders from unknown
customers or customers not enabled (`CKT804`), without staff approval
(`staff_signature`, `CKT805`) or below a minimum subtotal (`CKT806`).
Without the config nothing changes: unknown customers are still created.

- `readOrSaveCustomer` accepts `{ canCreate: false }` and returns null
- gates isolated in `customer-gates.ts` with unit tests

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Stores that hide prices (wholesale, quote-based) strip `price` from the
SSR product doc; the structured data must not advertise `price: 0`.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Rewrites declared in the store `conf/firebase.json` for functions that don't
exist in the base config (e.g. a custom `/_api/<name>/**` endpoint) were
appended after the `**` catch-all and never matched. They are now inserted
right before it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
`cloudcommerce deploy --only functions:<codebase>` (what CI runs when a single
codebase changes) went without `--force`, so the first deploy of a pub/sub
function with failure policy aborted with "Pass the --force option".

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant