feat(mcp): customer_number on create_customer + Beta tags on webshop surfaces (#1677)

* feat(mcp): accept customer_number on gnubok_create_customer

Parity with gnubok_update_customer: a customer number no longer needs a
create-then-update two-step with two approvals. The staged params carry
the trimmed number, commitCreateCustomer inserts it, and the payload-size
ceiling is bumped 59.7K to 59.75K with a documented entry (the property
has no description; name + maxLength are the whole contract).

Requested by a user on Discord 2026-08-16.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(ui): mark webshop integrations and orders tab as Beta

WooCommerce and Shopify rows on the import page get a quiet Beta chip
next to the title, and the webshop /orders sidebar item sets the
existing betaBadge flag. Chip recipe matches the nav beta badge so
Beta reads identically everywhere.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(mcp): enforce customer_number invariants and show it on the approval card

Consolidated resolution pass for PR #1677:
- skeptic (correctness): maxLength 32 was advertisement-only on the create
  path; now enforced with a runtime guard in gnubok_create_customer execute
  (clean errors for non-string and >32) and a 400 guard in
  commitCreateCustomer, matching the web/v1 routes and commitUpdateCustomer.
- skeptic (correctness): CustomerPreview never rendered the staged
  customer_number, leaving the approver blind to the new field; added a
  conditional Kundnr row.
- CodeRabbit: reset the event bus in create-customer.test.ts beforeEach.
- Tests cover both new guards at the tool and executor layers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Mattsson
2026-08-18 10:46:34 +02:00
committed by GitHub
co-authored by Claude Fable 5
parent 387e1fb7f1
commit cfdddb2d7e
10 changed files with 216 additions and 2 deletions
+8
View File
@@ -347,6 +347,13 @@ async function commitCreateCustomer(
companyId: string,
params: Record<string, unknown>
): Promise<ExecutorResult> {
// Same 32-char invariant the web/v1 create routes and commitUpdateCustomer
// enforce; MCP hosts don't reliably enforce inputSchema maxLength.
const customerNumber = params.customer_number
if (customerNumber != null && (typeof customerNumber !== 'string' || customerNumber.length > 32)) {
return { error: 'customer_number must be a string of at most 32 characters', status: 400 }
}
const { data, error } = await supabase
.from('customers')
.insert({
@@ -354,6 +361,7 @@ async function commitCreateCustomer(
company_id: companyId,
name: params.name as string,
customer_type: params.customer_type as string,
customer_number: customerNumber || null,
email: (params.email as string) || null,
org_number: (params.org_number as string) || null,
vat_number: (params.vat_number as string) || null,