> ## Documentation Index
> Fetch the complete documentation index at: https://docs.grantex.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Commerce V1 Operations

> Sandbox operations, import columns, and runbooks for Grantex Commerce V1.

# Commerce V1 Operations

This guide is the current operating baseline for Grantex Commerce V1 on
`grantex.dev`. It covers sandbox use, safe observability, the approved Shopify
live pilot, pilot readiness evidence, and runbooks. Production Commerce V1 is
deployed for `mch_shopify_mgx0n6_22` from `mgx0n6-22.myshopify.com`. The Plural
adapter is configured with credentials that authenticate against
UAT-compatible rails, so this guide does not claim production Plural settlement.

## Sandbox Playground Usage

Use `web/commerce-playground.html` against a local or sandbox API base URL.

1. Start the auth-service in a local sandbox with `COMMERCE_V1_ENABLED=true`.
2. Open the static playground file in a browser.
3. Set the API base URL, for example `http://localhost:3001`.
4. Paste bearer tokens and Commerce Passports only into the in-memory inputs.
5. Load `/.well-known/grantex-commerce`.
6. List `/mcp` tools.
7. Run read tools first: `merchant.get_profile`, `catalog.search`, `catalog.get_item`, and `inventory.check`.
8. Run write demo tools only in sandbox with explicit idempotency keys and, for payment-affecting tools, a checkout Commerce Passport.

The playground may store only non-secret connection settings such as API base URL and merchant ID.
It must not store bearer tokens, Commerce Passports, provider credentials, payment credentials, or
idempotency keys in `localStorage` or `sessionStorage`.

Production live-pilot mode is available for the approved Shopify merchant.
Plural hosted-checkout and webhook contracts are configured through stored
credentials, but production Plural settlement remains an external provider
claim that requires credentials accepted by production Plural rails.

## Security And Rate-Limit Evidence

Consent approval and denial use the dedicated consent host, an HttpOnly same-site principal session
cookie, CSRF bound to the session and consent request ID, and a verified single-use challenge before
a decision can be recorded. Consent HTML responses send `Content-Security-Policy` with
`frame-ancestors 'none'`, `X-Frame-Options: DENY`, `Cache-Control: no-store`, and
`Referrer-Policy: no-referrer`. Consent pages must not render bearer tokens, raw Commerce Passports,
provider credentials, or secrets.

Rate-limit evidence for M6C:

* JWKS is the only route allowlisted from the global rate limiter.
* `/.well-known/grantex-commerce` is limited to 60 requests per minute.
* `/mcp` is limited to 600 requests per minute.
* Provider webhooks are limited to 1000 requests per minute.
* Consent approval, denial, and challenge endpoints are limited to 60 requests per minute.
* Passport consent request, exchange, list, and revoke endpoints are limited to 120 requests per minute.
* Passport verify and policy evaluate endpoints are limited to 1000 requests per minute.
* Policy create, policy activate, payment intent create, checkout link create, manual reconcile, and
  ops health are limited to 60 requests per minute.
* Cart create is limited to 120 requests per minute.
* Catalog search is limited to 600 requests per minute.

These route-local limits are enforced with the existing Fastify rate-limit stack and do not weaken
the global 500 requests per minute safety net. Spec-level caller-keyed budgets per merchant, agent,
or provider remain an operations refinement if stricter production quota isolation is required.

## Pilot SLA And Readiness Dashboard

The portal route `/dashboard/commerce/ops` is the M7A API-backed operations dashboard. It reads:

* `/v1/commerce/ops/health` for API, database, provider adapter, reconciliation worker, and webhook backlog status.
* `/v1/commerce/payments/intents?status=payment_pending` for stuck pending payment visibility.
* `/v1/commerce/ops/provider-webhook-events?processing_status=failed` for safe failed provider webhook metadata.

Pilot SLA targets from the V1 spec:

* Payment intent create: `POST /v1/commerce/payments/intents`, 10 RPS, p95 under 500 ms excluding provider latency.
* Catalog search: `POST /v1/commerce/catalog/search`, 50 RPS, p95 under 300 ms for pilot catalog size.
* Provider webhooks: `POST /v1/webhooks/providers/{provider_key}`, 5 events/sec, p95 under 500 ms excluding provider verification latency.

M7B dashboard status:

* Health checks are measured from the API.
* SLA target cards are visible as target indicators; measured local load evidence is recorded in
  the internal local-pilot-load report (operator-internal artifact in
  `docs/internal/commerce-v1/`, available to authorized reviewers via
  `security@grantex.dev`).
* Live-pilot readiness is complete for the approved Shopify merchant.
* Plural adapter health must be read with the UAT-compatible credential caveat
  until production Plural credentials are accepted by production rails.
* Failed provider webhook replay is operator-only and mock-provider-only until non-mock replay storage,
  payload retention, and operator approval are separately cleared.
  Replay is available only for future failed events with valid original signatures and encrypted replay material.

## Local Pilot Load Harness

Use `scripts/commerce-pilot-load-harness.mjs` for local-only load evidence. The harness preserves
dry-run mode and refuses non-local API base URLs before it sends any request.

Local dev stack discovery:

* The repo's documented local stack is `docker compose up --build` from the repo root.
* That stack provides PostgreSQL on `localhost:5432`, Redis on `localhost:6379`, and auth-service on
  `http://localhost:3001`.
* Auth-service runs SQL migrations on startup through `apps/auth-service/src/db/migrate.ts`.
* M7C does not add Docker or external infrastructure. If Docker, local Postgres, or local Redis are
  unavailable, measured load remains blocked.

Local sandbox seed command:

```bash theme={null}
node scripts/commerce-pilot-seed-local.mjs --run \
  --migrate \
  --database-url=postgres://grantex:grantex@localhost:5432/grantex \
  --env-output=.tmp/commerce-pilot-load.env
```

The seed script refuses `NODE_ENV=production`, live commerce flags, live Plural flags, and non-local
or production-like database URLs. It creates synthetic local data only:

* sandbox tenant `cten_internal_sandbox`;
* mock-provider merchant `mch_internal_sandbox_pilot`;
* trusted agent `cag_internal_sandbox_pilot`;
* active policy `m7c-local-pilot-v1`;
* one pilot catalog product and variant;
* checkout Commerce Passport;
* 100 draft cart IDs;
* 51 pending mock provider payment references.

The generated `.tmp/commerce-pilot-load.env` file contains synthetic local bearer/passport values
for the harness. Do not commit it and do not replace those values with production secrets.

Dry-run validation:

```bash theme={null}
node scripts/commerce-pilot-load-harness.mjs --dry-run
```

Measured run command:

```bash theme={null}
node scripts/commerce-pilot-load-harness.mjs --run \
  --env-file=.tmp/commerce-pilot-load.env \
  --report=docs/internal/commerce-v1/commerce-v1-local-pilot-load.md
```

Optional target subset for staged local checks:

```bash theme={null}
node scripts/commerce-pilot-load-harness.mjs --run \
  --api-base=http://localhost:3001 \
  --targets=catalog_search
```

Run mode requires local seeded sandbox data and these environment variables, either in the process
environment or in `--env-file`:

* `COMMERCE_LOAD_API_BASE`
* `COMMERCE_LOAD_AUTH_TOKEN`
* `COMMERCE_LOAD_MERCHANT_ID`
* `COMMERCE_LOAD_AGENT_ID`
* `COMMERCE_LOAD_CART_IDS`
* `COMMERCE_LOAD_CHECKOUT_PASSPORT`
* `COMMERCE_LOAD_PROVIDER_PAYMENT_IDS`
* `COMMERCE_LOAD_MOCK_WEBHOOK_SECRET`

For the full M7B target run, seed at least:

* 100 unique draft carts for `payment_intent_create`.
* 51 pending mock provider payment references for `mock_provider_webhook`; the first reference is
  used for the duplicate event probe and the remaining 50 references are used for the 5 events/sec
  measured target.

The measured report includes request count, success count, error count, p50, p95, max latency,
per-target pass/fail, and duplicate webhook transition evidence. The report location is
`docs/internal/commerce-v1/commerce-v1-local-pilot-load.md`.

Do not use production credentials, real provider credentials, live payment mode, or real Plural calls
with this harness.

## Pilot Merchant Configuration Path

The internal sandbox pilot template is `docs/examples/commerce-pilot-merchant.sandbox.json`.

Setup path:

1. Create or select an internal sandbox tenant.
2. Create a sandbox merchant using the `electronics_appliances` category preset.
3. Keep provider key set to `mock`.
4. Create and activate a policy with explicit amount and scope caps.
5. Register only trusted CommerceAgents needed for the pilot.
6. Keep live Plural disabled. Enable Plural sandbox only for controlled credentialed validation with
   `PLURAL_SANDBOX_ENABLED=true`, stored sandbox credentials, and a scrubbed evidence report.
7. Confirm emergency disable ownership before any external pilot traffic.

## Support Ownership

Approved Shopify pilot owner references are stored in private operational
systems outside the repository. Future expansion must assign these roles before
traffic is widened:

* Product owner.
* Engineering owner.
* Security reviewer.
* Operations/on-call owner.
* Legal/compliance reviewer.

Do not place private names, phone numbers, escalation channels, or approval
artifacts in public docs.

## On-Call Escalation Template

Escalation fields:

* Incident ID.
* Request ID.
* Tenant ID.
* Merchant ID.
* Agent ID when available.
* Payment intent ID.
* Provider payment ID.
* Provider webhook event ID.
* Normalized error code.
* Whether emergency disable is active.
* Whether live mode, Plural, mock provider, or another provider was involved.

Initial response:

1. Check `/dashboard/commerce/ops`.
2. Verify `/v1/commerce/ops/health`.
3. If payments are stuck, use manual reconcile from the dashboard.
4. If provider webhooks failed, inspect metadata-only failed events.
5. Do not replay provider webhooks through ad hoc scripts.
6. Use emergency disable if protected actions must stop immediately.

## Backup Restore And RPO Notes

Live readiness requires reviewed backup and restore evidence for:

* Commerce tenants, merchants, agents, products, variants, policies, passports, provider credentials, carts, payment intents, provider webhook events, and audit events.
* Point-in-time restore for Postgres.
* Secret manager or KMS recovery for credential encryption keys.
* RPO target and RTO target approved by operations.
* Restore drill evidence in a non-production environment.

Historical M7A evidence did not certify live RPO or RTO. The approved Shopify
pilot uses private operations signoff; future expansion must refresh restore and
RPO/RTO evidence before rollout.

## Final V1 Sign-Off Checklist

* OpenAPI matches implemented V1 routes.
* Auth-service typecheck and full tests pass.
* Portal typecheck, tests, and build pass when dashboard files are touched.
* Docs and playground validators pass.
* Local pilot load harness dry-run passes.
* Local pilot load run is executed against seeded sandbox data and records p50, p95, max latency,
  success counts, error counts, and duplicate webhook transition evidence.
* First pilot merchant is named or internal sandbox pilot is approved.
* Support, security, legal, compliance, and operations owners are assigned.
* Plural adapter evidence is complete for the approved pilot or explicitly out
  of scope for a future target.
* Live payment mode remains controlled by legal, compliance, security,
  operations, provider, and runtime-readiness gates.

M7C internal-sandbox signoff status:

| Gate                                       | Status                               | Evidence                                                                                                                                                                                                                                          |
| ------------------------------------------ | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Dry-run harness validation                 | Passing                              | `node scripts/commerce-pilot-load-harness.mjs --dry-run`                                                                                                                                                                                          |
| Non-local URL refusal                      | Passing                              | Harness refuses production-like base URLs before network calls                                                                                                                                                                                    |
| Local sandbox seed path                    | Available                            | `node scripts/commerce-pilot-seed-local.mjs --run --migrate --env-output=.tmp/commerce-pilot-load.env`                                                                                                                                            |
| Measured local load report                 | Passing                              | `docs/internal/commerce-v1/commerce-v1-local-pilot-load.md` records localhost/mock run results: payment intent create 100/100 p95 16.53 ms, catalog search 500/500 p95 5.41 ms, mock provider webhook 52/52 p95 20.45 ms, duplicate transitions 0 |
| Historical internal sandbox recommendation | Superseded by approved Shopify pilot | Keep this localhost/mock evidence as regression coverage only                                                                                                                                                                                     |

## Expansion Not-Ready-If Checklist

V1 is not ready to expand beyond the approved Shopify live pilot if any item is
true:

* Production Plural settlement or real provider certification is required but
  production provider credentials do not authenticate.
* Plural sandbox E2E evidence, webhook verification evidence, or provider approval is missing for the target pilot.
* No named support or on-call owner exists.
* No approved sandbox pilot merchant exists.
* Local load evidence is missing or fails the p95 targets.
* Failed webhook replay is required for a non-mock provider.
* Failed webhook replay is required for an event that lacks valid original signature status or encrypted replay material.
* Emergency re-enable is required without operator review, active policy evidence, and audit.
* Backup/restore/RPO review is required for the pilot but not approved.

## CSV Product And Variant Import Columns

Commerce V1 exposes API-backed product and variant creation plus a local dry-run CSV
validator. The validator does not connect to a database, call Grantex APIs, create cloud
resources, or import data. Use it to normalize and validate catalog files before a later
operator-controlled importer exists:

```bash theme={null}
node scripts/commerce-catalog-csv-validate.mjs --input=docs/examples/commerce-catalog-import.sample.csv --dry-run
```

Required product columns:

| Column            | Type   | Notes                                    |
| ----------------- | ------ | ---------------------------------------- |
| `merchant_id`     | string | Existing merchant in the caller tenant.  |
| `product_id`      | string | Merchant catalog reference.              |
| `title`           | string | Customer-facing product title.           |
| `category_preset` | string | Must be `electronics_appliances` for V1. |

Optional product columns:

| Column                | Type      | Notes                     |
| --------------------- | --------- | ------------------------- |
| `brand`               | string    | Brand display name.       |
| `description`         | string    | Safe product description. |
| `image_url`           | HTTPS URL | Product image URL.        |
| `source_system`       | string    | Defaults to `manual`.     |
| `manually_maintained` | boolean   | Defaults to `false`.      |

Required variant columns:

| Column         | Type    | Notes                                             |
| -------------- | ------- | ------------------------------------------------- |
| `sku`          | string  | Unique variant SKU within the product import row. |
| `price_amount` | integer | Minor currency units.                             |

Optional variant columns:

| Column                  | Type        | Notes                                                                |
| ----------------------- | ----------- | -------------------------------------------------------------------- |
| `parent_sku`            | string      | Parent SKU where applicable.                                         |
| `model`                 | string      | Variant model reference.                                             |
| `variant_title`         | string      | Variant display title.                                               |
| `attributes`            | JSON object | Color, size, capacity, or other structured attributes.               |
| `currency`              | string      | ISO 4217 uppercase code. Defaults to `INR`.                          |
| `tax_inclusive`         | boolean     | Defaults to `true`.                                                  |
| `gst_slab`              | string      | GST slab label.                                                      |
| `tax_rate`              | number      | Tax rate when known.                                                 |
| `hsn_code`              | string      | HSN code when known.                                                 |
| `availability_status`   | string      | `in_stock`, `out_of_stock`, `pre_order`, `back_order`, or `unknown`. |
| `warranty_summary`      | string      | Short warranty text.                                                 |
| `return_policy_summary` | string      | Short return policy text.                                            |
| `source_system`         | string      | Source system for the variant row.                                   |

Importer safety requirements before write-mode implementation:

* Validate tenant and merchant ownership before inserting rows.
* Reject archived or duplicate variant references in the same import.
* Do not infer inventory guarantees when availability is `unknown`.
* Emit append-only audit events for created or updated products.
* Keep raw import files out of application logs.

M12B status: the local CSV validator covers column shape, required values, duplicate
SKUs within the file, JSON attributes, and secret-like content refusal. It intentionally
does not insert rows or upload files.

## Provider Outage Runbook

Signals:

* `/v1/commerce/ops/health` reports provider adapter status down or degraded.
* Payment intent creation or checkout link creation returns a provider error.
* Reconciliation stores a safe provider error on payment intents.

Immediate actions:

1. Confirm the outage is isolated to the provider adapter and not database or tenant auth.
2. Keep live payment mode disabled.
3. Verify emergency disable status for affected merchants.
4. For sandbox, switch only test traffic to the mock provider when appropriate.
5. Use `GET /v1/commerce/payments/intents` to inspect safe payment status fields.
6. Avoid manual database edits. Use reconciliation once the provider is healthy.

Escalation:

* Legal and payment operations must approve any real provider retry strategy.
* Plural production settlement remains unclaimed until legal, provider,
  security, operations, readiness-gate evidence, and production credential
  authentication are complete.

## Webhook Backlog And Failure Runbook

Signals:

* `/v1/commerce/ops/health` reports webhook backlog or recent failures.
* `commerce_provider_webhook_events.processing_status` is `received` or `failed`.
* Audit contains `provider.webhook.signature_failed` or denied webhook processing events.

Immediate actions:

1. Check whether failures are signature failures, stale replay timestamps, unsupported events, or invalid transitions.
2. Confirm no raw payload, raw signature, or webhook secret is present in logs or audit metadata.
3. Confirm duplicate provider event IDs are accepted idempotently without a second payment transition.
4. Do not replay failed events through ad hoc scripts.
5. Use `POST /v1/commerce/ops/provider-webhook-events/{event_id}/replay` only after operator review.

Safe replay rules:

* Ops health reports webhook backlog and failure counts; the replay endpoint rejects non-mock replay
  with `provider_replay_not_supported`.
* Replay is available only when the original provider signature was valid, the provider is `mock`,
  `processing_status=failed`, `replay_status=fresh`, and encrypted replay material exists.
* Do not replay invalid-signature, stale, unsupported-provider, malformed, or unauthenticated events.
* Dry-run with `{ "reason": "...", "dry_run": true }` before real replay when investigating.
* Real replay requires a non-empty reason, uses the payment state machine, and must not double-transition
  payments that already reached the target terminal state.
* Production non-mock replay remains blocked with
  `webhook_failed_event_list_and_replay_api_contract_deferred` until provider API and signature
  contracts are explicitly approved.
* Responses, logs, audit metadata, and portal UI must never include raw payloads, raw signatures,
  encrypted payload material, webhook secrets, provider credentials, bearer tokens, passports, or
  plaintext idempotency keys.
* Plural replay remains blocked until non-mock replay retention, provider approval, and operator controls
  are separately approved.

## Reconciliation Failure Runbook

Signals:

* Manual reconcile returns a provider error.
* Batch reconciliation reports failed results.
* Payment intents have `last_reconciliation_error` set.

Immediate actions:

1. Confirm the payment intent is still tenant-owned and not terminal.
2. Check `provider_payment_id`, `provider_raw_status`, `last_reconciliation_attempt_at`,
   `last_reconciliation_error`, and `last_reconciliation_retryable`.
3. Retry only retryable provider errors after provider health is restored.
4. Do not retry validation, auth, policy, tenant, or missing provider payment errors.
5. If pending longer than the timeout and provider remains pending, allow the normal expired transition.

Scheduler status:

* The reconciliation helper and disabled-by-default worker exist.
* Runtime scheduler enablement remains an operations gate controlled by configuration review.

## Audit Write Failure Runbook

Signals:

* `grantex_commerce_audit_write_failures_total` increases.
* State-changing requests fail where transactional audit write is required.

Immediate actions:

1. Treat the system as not release-ready for commerce state changes.
2. Check database availability, migration state, append-only trigger errors, and application role grants.
3. Do not bypass audit writes.
4. Retry only after database health and audit insert permissions are verified.
5. Preserve request IDs from structured logs for incident correlation.

Safe audit data:

* Audit events may include IDs, policy version, decision ID, idempotency key hash, provider reference ID,
  and normalized error codes.
* Audit events must not include bearer tokens, raw passports, raw credentials, webhook secrets, raw
  signatures, raw payment data, or plaintext idempotency keys.

## Emergency Disable Runbook

Signals:

* Merchant `agentic_commerce_enabled=false`.
* Merchant disabled timestamp is set.
* Active policy sets emergency disable.
* Protected payment-affecting action returns `emergency_disabled`.

Immediate actions:

1. Confirm the tenant and merchant in the request.
2. Keep protected commerce actions blocked.
3. Verify audit events for denied policy decisions.
4. Do not create payment intents or checkout links for the merchant until a new policy version and
   activation explicitly restore access.
5. Emergency re-enable is operator-only through
   `POST /v1/commerce/merchants/{merchant_id}/enable-agentic-commerce`.
6. Re-enable requires a non-empty reason, a reviewed active policy ID, and `confirm_reenable=true`.
7. Re-enable does not modify provider credentials, live payment flags, Plural flags, or production config.
8. Communicate sandbox or pilot status to the operator team.

Re-enable decision:

* M14 implements a reviewed operator-only recovery route and portal control.
* Merchant self-service re-enable remains blocked.
* Re-enable requires incident review, active policy evidence, and audit semantics.
* Re-enable must not enable live payments, live Plural, provider credentials, or production config.

## Legal And Live Mode Controls

Before expanding live provider behavior beyond the approved Shopify pilot,
require human signoff for:

* Confirmed production Plural account, credential fields, idempotency behavior, callback URLs, and webhook secret rotation.
* Legal review of user consent, payment authorization, refund handling, dispute handling, and customer support obligations.
* Compliance review for India payment requirements, strong customer authentication, data residency, and audit retention.
* Security review for provider credential vaulting, webhook secret rotation, and incident response.
* Operations review for provider outage handling, webhook replay tooling, reconciliation scheduler, dashboard coverage, and on-call ownership.
* Merchant pilot approval with explicit sandbox-to-live or pilot-to-broader
  promotion criteria.

### Machine-Readable Acknowledgement Gate

Live payment mode must remain controlled by the runtime live-readiness snapshot.
The snapshot may report only booleans, requirement keys, env
names, and blocker strings. It must not include tokens, passports, provider
payloads, credentials, DB URLs, Redis URLs, webhook secrets, raw signatures, or
plaintext idempotency values.

Feature flags alone are not sufficient. For the approved Shopify live pilot,
operators recorded all of these acknowledgement names in the approved runtime
configuration source, and future live-mode proposals must do the same:

* `COMMERCE_LIVE_LEGAL_APPROVED`
* `COMMERCE_LIVE_PROVIDER_CONTRACT_CONFIRMED`
* `COMMERCE_LIVE_PLURAL_SANDBOX_E2E_PASSED`
* `COMMERCE_LIVE_PLURAL_WEBHOOK_SIGNATURE_CONFIRMED`
* `COMMERCE_LIVE_INDIA_RESIDENCY_CONFIRMED`
* `COMMERCE_LIVE_FINAL_USER_CONFIRMATION_APPROVED`
* `COMMERCE_LIVE_PILOT_MERCHANT_APPROVED`
* `COMMERCE_LIVE_HOSTED_OACP_E2E_PASSED`
* `COMMERCE_LIVE_SECRETS_REVIEWED`
* `COMMERCE_LIVE_AUDIT_APPEND_ONLY_VERIFIED`
* `COMMERCE_LIVE_OPERATOR_RUNBOOK_APPROVED`
* `COMMERCE_LIVE_ROLLBACK_OWNER_ASSIGNED`

If any acknowledgement is absent, Commerce must return the
`live_readiness_blocked` reason and the release remains blocked.

Do not advertise external commerce protocol certification unless a separate conformance and legal review
has approved the exact claim.

## Human Review Gates

Required before Milestone 6 release signoff:

* Engineering review of OpenAPI drift, tenant filters, idempotency conflict handling, policy/passport enforcement, and webhook transition idempotency.
* Security review of logs, audit metadata, playground storage, credential handling, and provider webhook verification.
* Operations review of health, metrics, runbooks, reconciliation worker configuration, and alert thresholds.
* Legal and compliance review before any live payment mode or real Plural processing.
