@doswiftly/storefront-operations 6.1.0 → 7.1.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.
- package/AGENTS.md +183 -0
- package/CHANGELOG.md +230 -0
- package/README.md +673 -134
- package/fragments.graphql +137 -53
- package/llms-full.txt +4994 -0
- package/mutations.graphql +47 -3
- package/operations.json +3149 -0
- package/package.json +9 -2
- package/queries.graphql +55 -16
- package/schema.graphql +194 -25
package/AGENTS.md
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# @doswiftly/storefront-operations — AI Agent Guide
|
|
2
|
+
|
|
3
|
+
> Pre-built GraphQL operations and schema for the **DoSwiftly Storefront API**.
|
|
4
|
+
> Use this when building e-commerce storefronts that consume DoSwiftly platform.
|
|
5
|
+
|
|
6
|
+
This file is the entry point for AI coding agents (Cursor, Claude Code, GitHub
|
|
7
|
+
Copilot, Codex, Aider, etc.). It uses **progressive disclosure** — read the
|
|
8
|
+
sections you need, then fetch deeper references on demand.
|
|
9
|
+
|
|
10
|
+
## Intended use — this is a reference catalog, not a runtime library
|
|
11
|
+
|
|
12
|
+
This package is installed as a `devDependency` and ships only `.graphql` source
|
|
13
|
+
files plus Markdown / JSON / text reference documents. There is no JavaScript
|
|
14
|
+
to import — nothing here ends up in the storefront's runtime bundle.
|
|
15
|
+
|
|
16
|
+
**Your job when generating code**: read the catalog (this file + `llms-full.txt`
|
|
17
|
+
+ `queries.graphql` / `mutations.graphql` in the same directory), then write
|
|
18
|
+
operations directly into the consumer's `src/graphql/` directory (or wherever
|
|
19
|
+
their codegen `documents:` glob points). The consumer's storefront codegen will
|
|
20
|
+
produce `TypedDocumentNode`s from your written operations.
|
|
21
|
+
|
|
22
|
+
Do **not** suggest importing operations from `@doswiftly/storefront-operations`
|
|
23
|
+
in runtime code — the package has no such exports. Do **not** assume the
|
|
24
|
+
consumer's `codegen.ts` references this package's `.graphql` files as
|
|
25
|
+
`documents:` (that's an advanced, discouraged pattern — see the package README
|
|
26
|
+
"Advanced" section). The default expectation is: schema lives here, operations
|
|
27
|
+
live in the consumer's repo.
|
|
28
|
+
|
|
29
|
+
<!-- AUTOGEN:STATS:BEGIN — auto-regenerated, do not edit by hand -->
|
|
30
|
+
- **Schema version**: 7.1.0
|
|
31
|
+
- **Queries**: 48
|
|
32
|
+
- **Mutations**: 44
|
|
33
|
+
- **Fragments**: 108
|
|
34
|
+
<!-- AUTOGEN:STATS:END -->
|
|
35
|
+
|
|
36
|
+
## Loading order
|
|
37
|
+
|
|
38
|
+
When you need to build a storefront feature, load resources in this order:
|
|
39
|
+
|
|
40
|
+
1. **`schema.graphql`** — full GraphQL schema. Authoritative source for types,
|
|
41
|
+
fields, enums, input types, and directives. Read this first when you need
|
|
42
|
+
to know what's available.
|
|
43
|
+
2. **`AGENTS.md`** (this file) — critical conventions and anti-hallucination
|
|
44
|
+
notes. Read once per session.
|
|
45
|
+
3. **`llms-full.txt`** — full operation reference with descriptions, typed
|
|
46
|
+
variables, and ready-to-execute GraphQL bodies. Search this file when you
|
|
47
|
+
need to know which named operation to use for a task.
|
|
48
|
+
4. **`operations.json`** — same operations as structured JSON, useful when
|
|
49
|
+
you're calling tools programmatically (MCP servers, codegen).
|
|
50
|
+
5. **`queries.graphql`, `mutations.graphql`, `fragments.graphql`** — raw
|
|
51
|
+
`.graphql` source. Use these directly with `@graphql-codegen/cli` or any
|
|
52
|
+
GraphQL client tooling.
|
|
53
|
+
|
|
54
|
+
## Critical conventions — DO NOT hallucinate
|
|
55
|
+
|
|
56
|
+
These are conventions where LLMs **frequently hallucinate from training data**.
|
|
57
|
+
Verify against this list before generating queries.
|
|
58
|
+
|
|
59
|
+
### Cart mutation names
|
|
60
|
+
|
|
61
|
+
The DoSwiftly API uses `cart<Verb><Object>` naming. **Do not** generate
|
|
62
|
+
`cart<Object><Verb>` aliases — they do not exist in this API.
|
|
63
|
+
|
|
64
|
+
| ✅ Use | ❌ Do NOT use (hallucination) |
|
|
65
|
+
| ------------------------------- | ------------------------------------ |
|
|
66
|
+
| `cartCreate` | (same) |
|
|
67
|
+
| `cartAddLines` | `cartLinesAdd` |
|
|
68
|
+
| `cartUpdateLines` | `cartLinesUpdate` |
|
|
69
|
+
| `cartRemoveLines` | `cartLinesRemove` |
|
|
70
|
+
| `cartApplyDiscountCodes` | `cartDiscountCodesUpdate` |
|
|
71
|
+
| `cartUpdateBuyerIdentity` | `cartBuyerIdentityUpdate` |
|
|
72
|
+
| `cartUpdateNote` | `cartNoteUpdate` |
|
|
73
|
+
| `cartUpdateAttributes` | `cartAttributesUpdate` |
|
|
74
|
+
|
|
75
|
+
### `userErrors[]` is the global error envelope
|
|
76
|
+
|
|
77
|
+
Every mutation returns a `userErrors: [UserError!]!` field. The shape is:
|
|
78
|
+
|
|
79
|
+
```graphql
|
|
80
|
+
type UserError {
|
|
81
|
+
message: String!
|
|
82
|
+
code: String # NOT a typed enum at the global level
|
|
83
|
+
field: [String!]
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Always check `userErrors` BEFORE consuming the happy-path payload**:
|
|
88
|
+
|
|
89
|
+
```graphql
|
|
90
|
+
mutation {
|
|
91
|
+
cartAddLines(id: $id, lines: $lines) {
|
|
92
|
+
cart { id }
|
|
93
|
+
userErrors { code field message } # ← check this first
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
`userErrors[].code` is `String`, not an enum — handle it as a string. The
|
|
99
|
+
codes are listed in `llms-full.txt` and `operations.json` per-mutation.
|
|
100
|
+
|
|
101
|
+
**Domain-specific typed enums** exist for warnings (not for errors):
|
|
102
|
+
`CartWarningCode`, `DiscountErrorCode`, `GiftCardErrorCode`. These are used
|
|
103
|
+
in dedicated `warnings[]` fields on cart/discount/gift-card payloads — they
|
|
104
|
+
are **separate** from the generic `userErrors[]`.
|
|
105
|
+
|
|
106
|
+
### Authentication — pick ONE, never both
|
|
107
|
+
|
|
108
|
+
Two auth modes are supported:
|
|
109
|
+
|
|
110
|
+
- **Browser storefronts**: rely on the `customerAccessToken` httpOnly cookie
|
|
111
|
+
(set by the SDK after `customerLogin` mutation). The cookie is sent
|
|
112
|
+
automatically — no header needed.
|
|
113
|
+
- **Server-to-server / mobile**: send `Authorization: Bearer <token>` header,
|
|
114
|
+
where `<token>` is the `accessToken` field returned by `customerLogin`.
|
|
115
|
+
|
|
116
|
+
**Never send both.** Do **not** invent `X-Customer-Token`, `X-Auth-Token`, or
|
|
117
|
+
similar — they are ignored.
|
|
118
|
+
|
|
119
|
+
### `@inContext` directive
|
|
120
|
+
|
|
121
|
+
Pass storefront context (country, language, B2B buyer) via the `@inContext`
|
|
122
|
+
directive on operations:
|
|
123
|
+
|
|
124
|
+
```graphql
|
|
125
|
+
query Products @inContext(country: PL, language: pl, preferredLocationId: "...") {
|
|
126
|
+
products(first: 12) { ... }
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Available args: `country`, `language`, `preferredLocationId`,
|
|
131
|
+
`buyer { customerAccessToken, companyLocationId }`. The `buyer` arg is for
|
|
132
|
+
**B2B server-to-server** flows only — browser storefronts use cookie auth and
|
|
133
|
+
should not send `buyer.customerAccessToken` in the directive.
|
|
134
|
+
|
|
135
|
+
### `Money.amount` is a string, not a number
|
|
136
|
+
|
|
137
|
+
Money values use `Money { amount: String!, currencyCode: CurrencyCode! }`.
|
|
138
|
+
The `amount` is a **string** to preserve decimal precision. Never `parseFloat`
|
|
139
|
+
totals — use string-aware money math (e.g., `Decimal.js`) or pass the string
|
|
140
|
+
verbatim to display.
|
|
141
|
+
|
|
142
|
+
### Pagination is Relay-style on every list
|
|
143
|
+
|
|
144
|
+
Every list query (products, collections, orders, etc.) uses Relay Connection
|
|
145
|
+
shape: `edges { cursor, node { ... } }`, `nodes { ... }`, `pageInfo { ... }`,
|
|
146
|
+
`totalCount`. Variables: `first`, `after`, `last`, `before`, `sortKey`,
|
|
147
|
+
`reverse`. The `cursor` is opaque — pass it back as `after` for the next page.
|
|
148
|
+
|
|
149
|
+
The `query` argument (when present) is a **text-search filter**, not a
|
|
150
|
+
GraphQL operation. Don't confuse with operation name.
|
|
151
|
+
|
|
152
|
+
### `product(id, handle)` — both optional, one required
|
|
153
|
+
|
|
154
|
+
The `product` query accepts EITHER `id: ID` OR `handle: String`. Pass exactly
|
|
155
|
+
one. Do **not** invent `slug`, `productHandle`, `productId`, or `productSlug`
|
|
156
|
+
arg names.
|
|
157
|
+
|
|
158
|
+
### Customer order — singular, not plural
|
|
159
|
+
|
|
160
|
+
To fetch customer orders:
|
|
161
|
+
|
|
162
|
+
- `query Customer { customer { orders { ... } } }` — list of orders.
|
|
163
|
+
- `query CustomerOrder($orderId: ID!) { ... }` — single order by ID.
|
|
164
|
+
|
|
165
|
+
**Hallucinations to avoid**: `OrderById`, `Order(id)`, `CustomerOrders` (plural),
|
|
166
|
+
`CustomerAddresses` (use `CustomerProfile` for profile data),
|
|
167
|
+
`CustomerMetaPropertiesSet`/`CustomerMetaPropertyDelete` — these do not exist.
|
|
168
|
+
|
|
169
|
+
### Mutations are NOT auto-retried
|
|
170
|
+
|
|
171
|
+
`@doswiftly/storefront-sdk` retries **queries** on transient network errors
|
|
172
|
+
but does **NOT** retry mutations (that's a deliberate platform contract — at-most-once
|
|
173
|
+
semantics). Idempotency is the caller's responsibility. If you need retries
|
|
174
|
+
on a mutation, wrap with your own backoff logic and check `userErrors` to
|
|
175
|
+
decide whether to retry.
|
|
176
|
+
|
|
177
|
+
## When in doubt
|
|
178
|
+
|
|
179
|
+
- **Schema question** ("what fields are on `X`?") → grep `schema.graphql`
|
|
180
|
+
- **Operation question** ("which mutation does Y?") → grep `llms-full.txt` for the verb in `**Description**:` lines
|
|
181
|
+
- **Programmatic enumeration** → load `operations.json`
|
|
182
|
+
|
|
183
|
+
For codegen setup and runtime transport, see `README.md` and [`@doswiftly/storefront-sdk`](https://www.npmjs.com/package/@doswiftly/storefront-sdk).
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,235 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 7.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 0399ef8: Auto-generated, drift-proof docs and AI-agent context shipped inside the package.
|
|
8
|
+
|
|
9
|
+
The package now ships three new files alongside the `.graphql` sources, all
|
|
10
|
+
generated automatically and kept in sync with the schema:
|
|
11
|
+
- **`AGENTS.md`** — entry point for AI coding agents (Cursor, Claude Code,
|
|
12
|
+
GitHub Copilot, Codex, Aider, Gemini CLI, …). Critical conventions and
|
|
13
|
+
anti-hallucination notes — load this once per session.
|
|
14
|
+
- **`llms-full.txt`** — full operation reference: descriptions, typed variables,
|
|
15
|
+
ready-to-execute GraphQL bodies, fragment cross-references.
|
|
16
|
+
- **`operations.json`** — same operations as structured JSON for MCP servers
|
|
17
|
+
and programmatic tools.
|
|
18
|
+
|
|
19
|
+
The `Available Operations` section in `README.md` is now also auto-generated,
|
|
20
|
+
so it can never drift from the actual schema again.
|
|
21
|
+
|
|
22
|
+
**Anti-hallucination conventions** documented in `AGENTS.md`:
|
|
23
|
+
- Cart mutations are `cartAddLines` / `cartUpdateLines` / `cartRemoveLines`
|
|
24
|
+
(NOT the `cart<Object><Verb>` aliases — they do not exist in this API).
|
|
25
|
+
- `userErrors[].code` is a `String`, not an enum. Domain-typed enums exist
|
|
26
|
+
separately for warnings (`CartWarningCode`, `DiscountErrorCode`, etc.).
|
|
27
|
+
- Authentication uses **either** the `customerAccessToken` cookie **or** the
|
|
28
|
+
`Authorization: Bearer` header — never both.
|
|
29
|
+
- `Money.amount` is a string (decimal precision), not a number.
|
|
30
|
+
|
|
31
|
+
No code changes for existing consumers — `schema.graphql`, `queries.graphql`,
|
|
32
|
+
`mutations.graphql`, and `fragments.graphql` are unchanged in surface (only
|
|
33
|
+
non-functional `#` description comments were added in the operation files).
|
|
34
|
+
Codegen continues to produce identical typed documents.
|
|
35
|
+
|
|
36
|
+
## 7.0.0
|
|
37
|
+
|
|
38
|
+
### Major Changes
|
|
39
|
+
|
|
40
|
+
- 227629d: # Storefront GraphQL Operations 7.0 — Breaking changes + nowe rozszerzenia API
|
|
41
|
+
|
|
42
|
+
Major bump wprowadza zmiany breaking w schemie storefront GraphQL plus 3 znaczące nowe funkcjonalności: per-address tax info dla B2B, generic Meta Properties (extensible custom fields), oraz strukturalne userErrors[] z typed codes dla wszystkich mutacji.
|
|
43
|
+
|
|
44
|
+
## Breaking changes
|
|
45
|
+
|
|
46
|
+
### 1. `Product.category` (free-text) → `Product.categories` + `Product.primaryCategory` (structured)
|
|
47
|
+
|
|
48
|
+
Wcześniej `Product.category: String` zwracał free-text label — tekst nie był powiązany z entity Category. Klienci nie mogli pobrać slug/name kategorii ani zbudować breadcrumb. Po 7.0:
|
|
49
|
+
|
|
50
|
+
```graphql
|
|
51
|
+
# PRZED (6.x):
|
|
52
|
+
product { category } # → "Pop Vinyl" (free-text string, brak slug/parent)
|
|
53
|
+
|
|
54
|
+
# PO (7.0):
|
|
55
|
+
product {
|
|
56
|
+
categories { id slug name parent { slug } } # M2M lista (junction table)
|
|
57
|
+
primaryCategory { slug name } # categories[0] dla breadcrumb
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**Migration**:
|
|
62
|
+
- Klient renderujący breadcrumb po category name: zamień `product.category` na `product.primaryCategory.name`.
|
|
63
|
+
- Klient filtrujący kategorie z `Product.category` jako string: użyj `product.categories[]` array.
|
|
64
|
+
- Filter `productCategory` w `ProductFilter` usunięty — używaj `category: { id }` (junction lookup, działało wcześniej).
|
|
65
|
+
|
|
66
|
+
### 2. `categories` query — `CategoryTree` → `CategoryConnection` (Relay)
|
|
67
|
+
|
|
68
|
+
Wcześniej `categories` zwracał outlier shape `{ roots, totalCount }` vs reszta schemy używała Relay Connection. Klienci próbujący `categories { nodes }` dostawali GraphQL error. Po 7.0:
|
|
69
|
+
|
|
70
|
+
```graphql
|
|
71
|
+
# PRZED (6.x):
|
|
72
|
+
categories(first: 20, rootsOnly: true) {
|
|
73
|
+
roots { id name children { id name } }
|
|
74
|
+
totalCount
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
# PO (7.0):
|
|
78
|
+
categories(first: 20, rootsOnly: true) {
|
|
79
|
+
nodes { id name children { id name } }
|
|
80
|
+
edges { cursor node { id } }
|
|
81
|
+
pageInfo { hasNextPage hasPreviousPage startCursor endCursor }
|
|
82
|
+
totalCount
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Migration**:
|
|
87
|
+
- Zamień `categories.roots` na `categories.nodes`.
|
|
88
|
+
- Tree shape rebuild po stronie klienta — używaj `Category.parent` / `Category.children` field resolvers (DataLoader N+1 safe). Filtr `rootsOnly: true` zwraca tylko top-level (parent IS NULL).
|
|
89
|
+
- Pełen Relay args: `first/after/last/before` zamiast tylko `first/after`.
|
|
90
|
+
|
|
91
|
+
### 3. `Customer.defaultAddress` — czytelny stan (poprzednio zawsze null)
|
|
92
|
+
|
|
93
|
+
Wcześniej `Customer.defaultAddress` zwracał `null` mimo że adres miał `isDefault: true` w `addresses`. Niespójność łamała storefront breadcrumb i powodowała duplikaty w formularzu dostawy. Po 7.0 zwraca poprawnie wartość — single source of truth z `addresses[].isDefaultShipping` flag.
|
|
94
|
+
|
|
95
|
+
**Migration**: brak — klient po prostu zacznie dostawać poprawne wartości.
|
|
96
|
+
|
|
97
|
+
### 4. Apollo response — bez `extensions.stacktrace` w produkcji
|
|
98
|
+
|
|
99
|
+
Wcześniej w środowisku produkcyjnym GraphQL response zawierał stacktrace z absolutnymi ścieżkami systemu plików backendu. Po 7.0 production response strippuje wszystko poza `code`, `message`, `locations`, `path` + banner `extensions.environment`. Stacktrace dostępny **tylko** w dev/staging dla DX.
|
|
100
|
+
|
|
101
|
+
**Migration**: brak — klient produkcyjny nie powinien był polegać na stacktrace.
|
|
102
|
+
|
|
103
|
+
### 5. Validation errors → `userErrors[]` z typed codes (tech debt resolution)
|
|
104
|
+
|
|
105
|
+
Wcześniej walidacja DTO leciała jako `body.errors[].extensions.code = "INTERNAL_SERVER_ERROR"` envelope (wyglądało jak crash). Po 7.0 mutations zwracają strukturalne `userErrors[]` z explicit codes per validation rule:
|
|
106
|
+
|
|
107
|
+
```graphql
|
|
108
|
+
# Invalid NIP, password too short, malformed email — wszystkie zwracają payload
|
|
109
|
+
mutation {
|
|
110
|
+
customerUpdate(customer: { taxId: "1234567890" }) {
|
|
111
|
+
customer {
|
|
112
|
+
id
|
|
113
|
+
}
|
|
114
|
+
userErrors {
|
|
115
|
+
field
|
|
116
|
+
code
|
|
117
|
+
message
|
|
118
|
+
}
|
|
119
|
+
# → [{ field: ["taxId"], code: "INVALID_TAX_ID_CHECKSUM", message: "..." }]
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Typed codes** dla 25 walidatorów: `INVALID_TAX_ID_CHECKSUM`, `INVALID_VAT_NUMBER`, `INVALID_REGON`, `INVALID_EMAIL_FORMAT`, `INVALID_FORMAT`, `INVALID_PHONE_FORMAT`, `INVALID_UUID`, `INVALID_URL`, `INVALID_DATE`, `INVALID_ENUM_VALUE`, `INVALID_TYPE`, `INVALID_COUNTRY_CODE`, `INVALID_POSTAL_CODE`, `TOO_SHORT`, `TOO_LONG`, `TOO_MANY`, `TOO_FEW`, `OUT_OF_RANGE`, `REQUIRED`, `INVALID_NESTED`, `VALIDATION_ERROR`, etc.
|
|
125
|
+
|
|
126
|
+
**Migration**: klient widzący poprzednio `body.errors[].extensions.code = "INTERNAL_SERVER_ERROR"` — sprawdź `data.<mutation>.userErrors[]` zamiast envelope.
|
|
127
|
+
|
|
128
|
+
## New features
|
|
129
|
+
|
|
130
|
+
### 6. `MailingAddress.taxId` + `vatNumber` — per-address B2B tax info
|
|
131
|
+
|
|
132
|
+
Adres ma teraz opcjonalne `taxId` (polski NIP, 10 cyfr z checksumą) + `vatNumber` (VAT UE, np. PL5260250274). Use case: B2B z różnymi danymi firmowymi per adres dostawy/billing (faktura na firmę matkę, dostawa na oddział z osobnym NIP-em).
|
|
133
|
+
|
|
134
|
+
```graphql
|
|
135
|
+
mutation {
|
|
136
|
+
customerAddAddress(
|
|
137
|
+
address: {
|
|
138
|
+
streetLine1: "ul. Marszałkowska 100"
|
|
139
|
+
city: "Warszawa"
|
|
140
|
+
postalCode: "00-001"
|
|
141
|
+
country: PL
|
|
142
|
+
company: "GameGoods Sp. z o.o."
|
|
143
|
+
taxId: "5260250274"
|
|
144
|
+
vatNumber: "PL5260250274"
|
|
145
|
+
}
|
|
146
|
+
) {
|
|
147
|
+
address {
|
|
148
|
+
taxId
|
|
149
|
+
vatNumber
|
|
150
|
+
}
|
|
151
|
+
userErrors {
|
|
152
|
+
code
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Walidacja format/checksum aktywna — invalid NIP zwraca `userErrors` z `INVALID_TAX_ID_CHECKSUM`.
|
|
159
|
+
|
|
160
|
+
### 7. Meta Properties — extensible custom fields per encji
|
|
161
|
+
|
|
162
|
+
Generic mechanizm rozszerzania encji (Customer/Product/ProductVariant/Order) o storefront-specific dane bez wymogu zmian schematu po stronie platformy. Per-customer birthday, per-product warranty_years, per-order gift_message — wszystko jako typed key-value entries w polymorphic table.
|
|
163
|
+
|
|
164
|
+
```graphql
|
|
165
|
+
# Customer self-edit (Bearer token klienta)
|
|
166
|
+
mutation {
|
|
167
|
+
customerMetaPropertiesSet(
|
|
168
|
+
properties: [
|
|
169
|
+
{
|
|
170
|
+
namespace: "storefront"
|
|
171
|
+
key: "birthday"
|
|
172
|
+
value: "1990-05-15"
|
|
173
|
+
type: DATE
|
|
174
|
+
}
|
|
175
|
+
{
|
|
176
|
+
namespace: "storefront"
|
|
177
|
+
key: "favorite_color"
|
|
178
|
+
value: "#FF6600"
|
|
179
|
+
type: COLOR
|
|
180
|
+
}
|
|
181
|
+
]
|
|
182
|
+
) {
|
|
183
|
+
metaProperties {
|
|
184
|
+
id
|
|
185
|
+
namespace
|
|
186
|
+
key
|
|
187
|
+
value
|
|
188
|
+
type
|
|
189
|
+
}
|
|
190
|
+
userErrors {
|
|
191
|
+
code
|
|
192
|
+
message
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
# Read na każdej encji
|
|
198
|
+
query {
|
|
199
|
+
customer {
|
|
200
|
+
metaProperty(namespace: "storefront", key: "birthday") {
|
|
201
|
+
value
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
product(id: "...") {
|
|
205
|
+
metaProperties(first: 10, namespace: "warranty") {
|
|
206
|
+
nodes {
|
|
207
|
+
key
|
|
208
|
+
value
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
10 typed values: `STRING/TEXT/INTEGER/DECIMAL/BOOLEAN/JSON/DATE/DATE_TIME/URL/COLOR`. Visibility flag `isPrivate` (storefront API filtruje `isPrivate=true` na public encjach jak Product/ProductVariant). Reserved namespace prefix `doswiftly:` dla platform fields.
|
|
216
|
+
|
|
217
|
+
**Faza 1 MVP scope**: Customer self-edit only (`customerMetaPropertiesSet` / `customerMetaPropertyDelete` z auth Bearer token klienta). Cross-resource writes (Product/Order/Variant) wymagają Admin layer (Faza 2).
|
|
218
|
+
|
|
219
|
+
### 8. NIP/REGON sanity guard — odrzucone all-zeros / repeated-digit patterns
|
|
220
|
+
|
|
221
|
+
Walidator NIP wcześniej akceptował `'0000000000'` (suma kontrolna 0=0). Po 7.0 odrzucamy wszystkie repeated-digit patterns (`'0000000000'`, `'1111111111'`, ..., `'9999999999'`) — to oczywiste fake test data / NULL placeholders, żaden urząd ich nie wystawia. Analogicznie REGON 9-digit i 14-digit.
|
|
222
|
+
|
|
223
|
+
### 9. Empty string clear-value semantyka (wszystkie nullable input fields)
|
|
224
|
+
|
|
225
|
+
Customer kasujący wartość w UI inputie (np. `<input value="" />`) wysyła `phone: ""` zamiast `null`. Po 7.0 backend traktuje empty string jako "wyczyść pole" (DB → null) — natywne form library behavior, klient nie wymaga specjalnej logiki rozróżniającej `null` vs `""`.
|
|
226
|
+
|
|
227
|
+
Pokrycie: wszystkie nullable string/enum fields w `CustomerCreateInput`, `CustomerUpdateInput`, `MailingAddressInput`.
|
|
228
|
+
|
|
229
|
+
## Notes
|
|
230
|
+
- 7.0 jest cumulative — kumulacja zmian z 6.x patches (B2B fields w `customerUpdate`, marketing consent flow) + breaking changes opisane wyżej.
|
|
231
|
+
- Wszystkie zmiany pokryte test coverage — backend integration tests gwarantują regression-free contract.
|
|
232
|
+
|
|
3
233
|
## 6.1.0
|
|
4
234
|
|
|
5
235
|
### Minor Changes
|