@sales-planner/http-client 0.12.0 → 0.13.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 (49) hide show
  1. package/README.md +298 -269
  2. package/dist/clients/api-keys-client.d.ts +2 -2
  3. package/dist/clients/api-keys-client.d.ts.map +1 -1
  4. package/dist/clients/api-keys-client.js +2 -2
  5. package/dist/clients/brands-client.d.ts +8 -8
  6. package/dist/clients/brands-client.d.ts.map +1 -1
  7. package/dist/clients/brands-client.js +9 -9
  8. package/dist/clients/categories-client.d.ts +8 -8
  9. package/dist/clients/categories-client.d.ts.map +1 -1
  10. package/dist/clients/categories-client.js +9 -9
  11. package/dist/clients/groups-client.d.ts +8 -8
  12. package/dist/clients/groups-client.d.ts.map +1 -1
  13. package/dist/clients/groups-client.js +9 -9
  14. package/dist/clients/marketplaces-client.d.ts +8 -8
  15. package/dist/clients/marketplaces-client.d.ts.map +1 -1
  16. package/dist/clients/marketplaces-client.js +9 -9
  17. package/dist/clients/roles-client.d.ts +3 -3
  18. package/dist/clients/roles-client.d.ts.map +1 -1
  19. package/dist/clients/roles-client.js +4 -4
  20. package/dist/clients/sales-history-client.d.ts +7 -7
  21. package/dist/clients/sales-history-client.d.ts.map +1 -1
  22. package/dist/clients/sales-history-client.js +8 -8
  23. package/dist/clients/sales-planner-client.d.ts +0 -126
  24. package/dist/clients/sales-planner-client.d.ts.map +1 -1
  25. package/dist/clients/sales-planner-client.js +1 -126
  26. package/dist/clients/shops-client.d.ts +3 -3
  27. package/dist/clients/shops-client.d.ts.map +1 -1
  28. package/dist/clients/shops-client.js +4 -4
  29. package/dist/clients/skus-client.d.ts +8 -8
  30. package/dist/clients/skus-client.d.ts.map +1 -1
  31. package/dist/clients/skus-client.js +9 -9
  32. package/dist/clients/statuses-client.d.ts +8 -8
  33. package/dist/clients/statuses-client.d.ts.map +1 -1
  34. package/dist/clients/statuses-client.js +9 -9
  35. package/dist/clients/suppliers-client.d.ts +8 -34
  36. package/dist/clients/suppliers-client.d.ts.map +1 -1
  37. package/dist/clients/suppliers-client.js +9 -9
  38. package/dist/clients/tenants-client.d.ts +4 -4
  39. package/dist/clients/tenants-client.d.ts.map +1 -1
  40. package/dist/clients/tenants-client.js +6 -6
  41. package/dist/clients/user-roles-client.d.ts +2 -2
  42. package/dist/clients/user-roles-client.d.ts.map +1 -1
  43. package/dist/clients/user-roles-client.js +2 -2
  44. package/dist/clients/users-client.d.ts +2 -2
  45. package/dist/clients/users-client.d.ts.map +1 -1
  46. package/dist/clients/users-client.js +2 -2
  47. package/dist/index.d.ts +1 -1
  48. package/dist/index.d.ts.map +1 -1
  49. package/package.json +2 -2
package/README.md CHANGED
@@ -17,7 +17,7 @@ import { SalesPlannerClient } from '@sales-planner/http-client';
17
17
 
18
18
  const client = new SalesPlannerClient({
19
19
  baseUrl: 'https://sales-planner-back.vercel.app',
20
- getAuthToken: () => 'your-api-key',
20
+ apiKey: 'your-api-key',
21
21
  });
22
22
 
23
23
  // Check if API is healthy
@@ -25,321 +25,314 @@ const health = await client.getHealth();
25
25
  console.log(health); // { status: 'ok', version: '1.0.0' }
26
26
  ```
27
27
 
28
+ ### Shop Context
29
+
30
+ Most operations require a shop context (`ctx`) as the **first argument**:
31
+
32
+ ```typescript
33
+ const ctx = { tenant_id: 1, shop_id: 1 };
34
+
35
+ // All entity methods follow: client.<entity>.<method>(ctx, ...args)
36
+ const skus = await client.skus.getSkus(ctx);
37
+ const sku = await client.skus.getSku(ctx, 123);
38
+ const brand = await client.brands.getBrandByCode(ctx, 'apple');
39
+ ```
40
+
28
41
  ### Namespaced Sub-Clients
29
42
 
30
43
  Access resources through domain-specific sub-clients:
31
44
 
32
45
  ```typescript
33
- // Users
46
+ // Users (system-level, no ctx)
34
47
  const users = await client.users.getUsers();
35
48
  const user = await client.users.getUser(1);
36
49
 
37
- // Tenants & Shops
50
+ // Tenants (system-level, no ctx)
38
51
  const tenants = await client.tenants.getTenants();
39
- const shops = await client.shops.getShops(tenantId);
40
52
 
41
- // SKUs with import/export
42
- const skus = await client.skus.getSkus({ tenantId, shopId });
43
- await client.skus.importJson(items, { tenantId, shopId });
44
- const csv = await client.skus.exportCsv({ tenantId, shopId });
45
-
46
- // Brands with import/export
47
- const brands = await client.brands.getBrands({ tenantId, shopId });
48
- await client.brands.importJson(items, { tenantId, shopId });
49
- const brandsCsv = await client.brands.exportCsv({ tenantId, shopId });
50
-
51
- // Categories with import/export
52
- const categories = await client.categories.getCategories({ tenantId, shopId });
53
- await client.categories.importJson(items, { tenantId, shopId });
53
+ // Shops (tenant-level)
54
+ const shops = await client.shops.getShops(tenantId);
54
55
 
55
- // Groups with import/export
56
- const groups = await client.groups.getGroups({ tenantId, shopId });
57
- await client.groups.importJson(items, { tenantId, shopId });
56
+ // Shop-scoped entities (require ctx)
57
+ const ctx = { tenant_id: 1, shop_id: 1 };
58
58
 
59
- // Statuses with import/export
60
- const statuses = await client.statuses.getStatuses({ tenantId, shopId });
61
- await client.statuses.importJson(items, { tenantId, shopId });
59
+ // SKUs
60
+ const skus = await client.skus.getSkus(ctx);
61
+ await client.skus.createSku(ctx, { code: 'SKU-001', title: 'Product 1' });
62
+ await client.skus.importJson(ctx, items);
63
+ const csv = await client.skus.exportCsv(ctx);
62
64
 
63
- // Suppliers with import/export
64
- const suppliers = await client.suppliers.getSuppliers({ tenantId, shopId });
65
- await client.suppliers.importJson(items, { tenantId, shopId });
66
- const suppliersCsv = await client.suppliers.exportCsv({ tenantId, shopId });
65
+ // Brands
66
+ const brands = await client.brands.getBrands(ctx);
67
+ await client.brands.importJson(ctx, [{ code: 'apple', title: 'Apple' }]);
67
68
 
68
- // Sales History
69
- const history = await client.salesHistory.getSalesHistory(
70
- { tenantId, shopId },
71
- { start: '2024-01', end: '2024-12' }
72
- );
69
+ // Categories, Groups, Statuses, Suppliers - same pattern
70
+ const categories = await client.categories.getCategories(ctx);
71
+ const groups = await client.groups.getGroups(ctx);
72
+ const statuses = await client.statuses.getStatuses(ctx);
73
+ const suppliers = await client.suppliers.getSuppliers(ctx);
73
74
 
74
75
  // Marketplaces
75
- const marketplaces = await client.marketplaces.getMarketplaces({ tenantId });
76
+ const marketplaces = await client.marketplaces.getMarketplaces(ctx);
76
77
 
77
- // Entity Metadata (for UI documentation)
78
+ // Sales History (with optional period filter)
79
+ const history = await client.salesHistory.getSalesHistory(ctx, {
80
+ start: '2024-01',
81
+ end: '2024-12',
82
+ });
83
+
84
+ // Entity Metadata (no auth required)
78
85
  const metadata = await client.metadata.getEntitiesMetadata();
79
- // Returns field definitions for brands, categories, groups, statuses, suppliers, marketplaces, skus, sales history
80
86
  ```
81
87
 
82
- ## Import/Export Pattern
88
+ ## API Conventions
89
+
90
+ ### Argument Order
83
91
 
84
- Resources that support bulk operations (SKUs, Brands, Categories, Groups, Statuses, Suppliers, Sales History, Marketplaces) follow a consistent pattern:
92
+ All methods follow a consistent pattern: **context first, then other arguments**.
85
93
 
86
94
  ```typescript
87
- // Import from JSON
88
- const result = await client.skus.importJson(
89
- [
90
- { code: 'SKU-001', title: 'Product 1' },
91
- { code: 'SKU-002', title: 'Product 2' },
92
- ],
93
- { tenantId, shopId }
94
- );
95
- // Returns: { created: 2, updated: 0, errors: [] }
96
-
97
- // Import from CSV file
98
- const csvContent = await fs.readFile('skus.csv', 'utf-8');
99
- const result = await client.skus.importCsv(csvContent, { tenantId, shopId });
95
+ // Get by ID
96
+ await client.skus.getSku(ctx, id);
97
+ await client.brands.getBrand(ctx, id);
100
98
 
101
- // Export to CSV
102
- const csv = await client.skus.exportCsv({ tenantId, shopId });
99
+ // Get by code
100
+ await client.skus.getSkuByCode(ctx, code);
101
+ await client.brands.getBrandByCode(ctx, code);
103
102
 
104
- // Get example templates (no auth required)
105
- const exampleCsv = await client.skus.getExampleCsv();
103
+ // Create
104
+ await client.skus.createSku(ctx, request);
105
+ await client.brands.createBrand(ctx, request);
106
106
 
107
- // Same pattern works for brands, categories, groups, statuses
108
- const brandResult = await client.brands.importJson(
109
- [{ code: 'apple', title: 'Apple' }],
110
- { tenantId, shopId }
111
- );
112
-
113
- const categoryResult = await client.categories.importJson(
114
- [{ code: 'electronics', title: 'Electronics' }],
115
- { tenantId, shopId }
116
- );
117
-
118
- const groupResult = await client.groups.importJson(
119
- [{ code: 'smartphones', title: 'Smartphones' }],
120
- { tenantId, shopId }
121
- );
122
-
123
- const statusResult = await client.statuses.importJson(
124
- [{ code: 'active', title: 'Active' }],
125
- { tenantId, shopId }
126
- );
127
- ```
107
+ // Update
108
+ await client.skus.updateSku(ctx, id, request);
109
+ await client.brands.updateBrand(ctx, id, request);
128
110
 
129
- ## Data Requirements
111
+ // Delete
112
+ await client.skus.deleteSku(ctx, id);
113
+ await client.brands.deleteBrand(ctx, id);
130
114
 
131
- ### SKUs
115
+ // Import
116
+ await client.skus.importJson(ctx, items);
117
+ await client.skus.importCsv(ctx, csvContent);
132
118
 
133
- **Create/Import:**
134
- - `code` (required): String, 1-100 characters, unique per shop
135
- - `title` (required): String, 1-200 characters
119
+ // Export
120
+ await client.skus.exportJson(ctx);
121
+ await client.skus.exportCsv(ctx);
122
+ ```
136
123
 
137
- **Update:**
138
- - `code` (optional): String, 1-100 characters
139
- - `title` (optional): String, 1-200 characters
124
+ ### IDs vs Codes
140
125
 
141
- ### Brands
126
+ - **Create/Update operations** use numeric IDs for references (e.g., `marketplace_id`)
127
+ - **Import/Export operations** use string codes for human readability (e.g., `marketplace: 'amazon'`)
142
128
 
143
- **Create/Import:**
144
- - `code` (required): String, 1-100 characters, unique per shop
145
- - `title` (required): String, 1-200 characters
129
+ ```typescript
130
+ // Create uses IDs
131
+ await client.salesHistory.createSalesHistory(ctx, {
132
+ sku_id: 123,
133
+ marketplace_id: 1,
134
+ period: '2026-01',
135
+ quantity: 100,
136
+ });
146
137
 
147
- **Update:**
148
- - `code` (optional): String, 1-100 characters
149
- - `title` (optional): String, 1-200 characters
138
+ // Import uses codes (auto-resolves to IDs)
139
+ await client.salesHistory.importJson(ctx, [
140
+ { sku: 'SKU-001', marketplace: 'amazon', period: '2026-01', quantity: 100 },
141
+ ]);
150
142
 
151
- ### Categories
143
+ // Export returns codes
144
+ const exported = await client.salesHistory.exportJson(ctx);
145
+ // [{ sku: 'SKU-001', marketplace: 'amazon', period: '2026-01', quantity: 100 }]
146
+ ```
152
147
 
153
- **Create/Import:**
154
- - `code` (required): String, 1-100 characters, unique per shop
155
- - `title` (required): String, 1-200 characters
148
+ ## Import/Export Pattern
156
149
 
157
- **Update:**
158
- - `code` (optional): String, 1-100 characters
159
- - `title` (optional): String, 1-200 characters
150
+ All shop-scoped entities support bulk import/export:
160
151
 
161
- ### Groups
152
+ ```typescript
153
+ const ctx = { tenant_id: 1, shop_id: 1 };
162
154
 
163
- **Create/Import:**
164
- - `code` (required): String, 1-100 characters, unique per shop
165
- - `title` (required): String, 1-200 characters
155
+ // Import from JSON array
156
+ const result = await client.skus.importJson(ctx, [
157
+ { code: 'SKU-001', title: 'Product 1' },
158
+ { code: 'SKU-002', title: 'Product 2' },
159
+ ]);
160
+ console.log(result); // { created: 2, updated: 0, errors: [] }
166
161
 
167
- **Update:**
168
- - `code` (optional): String, 1-100 characters
169
- - `title` (optional): String, 1-200 characters
162
+ // Import from CSV string
163
+ const csvContent = `code,title
164
+ SKU-001,Product 1
165
+ SKU-002,Product 2`;
166
+ const result = await client.skus.importCsv(ctx, csvContent);
170
167
 
171
- ### Statuses
168
+ // Export to JSON
169
+ const items = await client.skus.exportJson(ctx);
172
170
 
173
- **Create/Import:**
174
- - `code` (required): String, 1-100 characters, unique per shop
175
- - `title` (required): String, 1-200 characters
171
+ // Export to CSV
172
+ const csv = await client.skus.exportCsv(ctx);
176
173
 
177
- **Update:**
178
- - `code` (optional): String, 1-100 characters
179
- - `title` (optional): String, 1-200 characters
174
+ // Get example templates (no auth required)
175
+ const exampleJson = await client.skus.getExampleJson();
176
+ const exampleCsv = await client.skus.getExampleCsv();
177
+ ```
180
178
 
181
- ### Suppliers
179
+ **Supported entities:** SKUs, Brands, Categories, Groups, Statuses, Suppliers, Marketplaces, Sales History
182
180
 
183
- **Create/Import:**
184
- - `code` (required): String, 1-100 characters, unique per shop
185
- - `title` (required): String, 1-200 characters
181
+ ## Data Requirements
186
182
 
187
- **Update:**
188
- - `code` (optional): String, 1-100 characters
189
- - `title` (optional): String, 1-200 characters
183
+ ### SKUs
190
184
 
191
- ### Sales History
185
+ | Field | Create/Import | Update | Export |
186
+ |-------|---------------|--------|--------|
187
+ | `code` | Required, unique per shop | Optional | ✓ |
188
+ | `title` | Required | Optional | ✓ |
189
+ | `title2` | Optional | Optional | ✓ |
190
+ | `category` | Optional (code) | - | code |
191
+ | `group` | Optional (code) | - | code |
192
+ | `status` | Optional (code) | - | code |
193
+ | `supplier` | Optional (code) | - | code |
192
194
 
193
- **Create:**
194
- - `sku_id` (required): Number, must reference existing SKU
195
- - `period` (required): String, format `YYYY-MM` (e.g., "2026-01")
196
- - `quantity` (required): Number, integer
197
- - `marketplace_id` (required): Number, must reference existing marketplace
195
+ ### Brands, Categories, Groups, Statuses, Suppliers
198
196
 
199
- **Import (CSV/JSON):**
200
- - `sku_code` (required): String, must match existing SKU or will be auto-created
201
- - `period` (required): String, format `YYYY-MM` (e.g., "2026-01")
202
- - `quantity` (required): Number, integer
203
- - `marketplace` (required): String (marketplace code), must match existing marketplace or will be auto-created
197
+ | Field | Create/Import | Update | Export |
198
+ |-------|---------------|--------|--------|
199
+ | `code` | Required, unique per shop | Optional | ✓ |
200
+ | `title` | Required | Optional | ✓ |
204
201
 
205
- Note: Import endpoints accept marketplace codes for convenience, but the API internally uses numeric marketplace IDs. Export also returns marketplace codes.
202
+ ### Marketplaces
206
203
 
207
- **Update:**
208
- - `sku_id` (optional): Number
209
- - `period` (optional): String, format `YYYY-MM`
210
- - `quantity` (optional): Number
211
- - `marketplace_id` (optional): Number
204
+ | Field | Create/Import | Update | Export |
205
+ |-------|---------------|--------|--------|
206
+ | `code` | Required, unique per shop | Optional | ✓ |
207
+ | `title` | Required | Optional | ✓ |
212
208
 
213
- ### Users
209
+ ### Sales History
210
+
211
+ | Field | Create | Import | Update | Export |
212
+ |-------|--------|--------|--------|--------|
213
+ | `sku_id` | Required | - | Optional | - |
214
+ | `sku` | - | Required (code) | - | code |
215
+ | `marketplace_id` | Required | - | Optional | - |
216
+ | `marketplace` | - | Required (code) | - | code |
217
+ | `period` | Required (YYYY-MM) | Required | Optional | ✓ |
218
+ | `quantity` | Required | Required | Optional | ✓ |
214
219
 
215
- **Create:**
216
- - `email` (required): String, valid email format, unique
217
- - `name` (required): String, 1-200 characters
218
- - `default_shop_id` (optional): Number
220
+ ### Users
219
221
 
220
- **Update:**
221
- - `email` (optional): String, valid email format
222
- - `name` (optional): String, 1-200 characters
223
- - `default_shop_id` (optional): Number or null
222
+ | Field | Create | Update |
223
+ |-------|--------|--------|
224
+ | `email` | Required, unique | Optional |
225
+ | `name` | Required | Optional |
226
+ | `default_shop_id` | Optional | Optional (null to clear) |
224
227
 
225
228
  ### Tenants
226
229
 
227
- **Create:**
228
- - `title` (required): String, 1-200 characters
229
- - `owner_id` (optional): Number, user ID
230
-
231
- **Update:**
232
- - `title` (optional): String, 1-200 characters
233
- - `owner_id` (optional): Number or null
230
+ | Field | Create | Update |
231
+ |-------|--------|--------|
232
+ | `title` | Required | Optional |
233
+ | `owner_id` | Optional | Optional (null to clear) |
234
234
 
235
235
  ### Shops
236
236
 
237
- **Create:**
238
- - `title` (required): String, 1-200 characters
239
- - `tenant_id` (required): Number
240
-
241
- **Update:**
242
- - `title` (optional): String, 1-200 characters
243
-
244
- ### Marketplaces
245
-
246
- **Create:**
247
- - `code` (required): String, 1-100 characters, unique (e.g., "amazon", "ebay")
248
- - `title` (required): String, 1-200 characters
249
-
250
- **Update:**
251
- - `code` (optional): String, 1-100 characters
252
- - `title` (optional): String, 1-200 characters
237
+ | Field | Create | Update |
238
+ |-------|--------|--------|
239
+ | `title` | Required | Optional |
240
+ | `tenant_id` | Required | - |
253
241
 
254
242
  ## Available Sub-Clients
255
243
 
256
- Each sub-client is accessed via `client.<subClient>.<method>()`.
244
+ ### System-Level (no context required)
257
245
 
258
- ### `client.me`
246
+ #### `client.me`
259
247
  - `getMe()` - Get current user with roles and tenants
260
248
 
261
- ### `client.users`
262
- - `getUsers()`, `getUser(id)` - System admin or tenant admin (filtered by their tenants)
263
- - `createUser(dto)`, `deleteUser(id)` - Tenant admin or higher
264
-
265
- ### `client.tenants`
266
- - `getTenants()`, `getTenant(id)` - All authenticated users
267
- - `createTenant(dto)` - System admin only
268
- - `updateTenant(id, dto)`, `deleteTenant(id)` - Authenticated users (validation happens server-side)
269
- - `createTenantWithShopAndUser(dto)` - System admin only
270
-
271
- ### `client.shops`
272
- - `getShops(tenantId?)`, `getShop(id)`, `createShop(dto)`, `updateShop(id, dto)`, `deleteShop(id)` - Requires tenant access
249
+ #### `client.users`
250
+ - `getUsers()` - List users (system admin sees all, tenant admin sees their tenants)
251
+ - `getUser(id)` - Get user by ID
252
+ - `createUser(request)` - Create user
253
+ - `updateUser(id, request)` - Update user
254
+ - `deleteUser(id)` - Delete user
255
+
256
+ #### `client.tenants`
257
+ - `getTenants()` - List tenants
258
+ - `getTenant(id)` - Get tenant by ID
259
+ - `createTenant(request)` - Create tenant (system admin only)
260
+ - `updateTenant(id, request)` - Update tenant
261
+ - `deleteTenant(id)` - Delete tenant
262
+ - `createTenantWithShopAndUser(request)` - Create tenant with initial shop and user
263
+
264
+ #### `client.shops`
265
+ - `getShops(tenantId?)` - List shops (optionally filtered by tenant)
266
+ - `getShop(id)` - Get shop by ID
267
+ - `createShop(request)` - Create shop
268
+ - `updateShop(id, request)` - Update shop
269
+ - `deleteShop(id)` - Delete shop
273
270
  - `deleteShopData(id)` - Delete all data (SKUs, sales history) for a shop
274
271
 
275
- ### `client.skus`
276
- - `getSkus(ctx)`, `getSku(id, ctx)`, `getSkuByCode(code, ctx)` - Requires read access (viewer or higher)
277
- - `createSku(dto, ctx)`, `updateSku(id, dto, ctx)`, `deleteSku(id, ctx)` - Requires write access (editor or higher)
278
- - `importJson(items, ctx)`, `importCsv(csvContent, ctx)` - Requires write access
279
- - `exportJson(ctx)`, `exportCsv(ctx)` - Requires read access
280
- - `getExampleJson()`, `getExampleCsv()` - Get import format examples (no auth required)
281
-
282
- ### `client.brands`
283
- - `getBrands(ctx)`, `getBrand(id, ctx)`, `getBrandByCode(code, ctx)` - Requires read access (viewer or higher)
284
- - `createBrand(dto, ctx)`, `updateBrand(id, dto, ctx)`, `deleteBrand(id, ctx)` - Requires write access (editor or higher)
285
- - `importJson(items, ctx)`, `importCsv(csvContent, ctx)` - Requires write access (bulk upsert by code)
286
- - `exportJson(ctx)`, `exportCsv(ctx)` - Requires read access
287
- - `getExampleJson()`, `getExampleCsv()` - Get import format examples (no auth required)
288
-
289
- ### `client.categories`
290
- - `getCategories(ctx)`, `getCategory(id, ctx)`, `getCategoryByCode(code, ctx)` - Requires read access (viewer or higher)
291
- - `createCategory(dto, ctx)`, `updateCategory(id, dto, ctx)`, `deleteCategory(id, ctx)` - Requires write access (editor or higher)
292
- - `importJson(items, ctx)`, `importCsv(csvContent, ctx)` - Requires write access (bulk upsert by code)
293
- - `exportJson(ctx)`, `exportCsv(ctx)` - Requires read access
294
- - `getExampleJson()`, `getExampleCsv()` - Get import format examples (no auth required)
295
-
296
- ### `client.groups`
297
- - `getGroups(ctx)`, `getGroup(id, ctx)`, `getGroupByCode(code, ctx)` - Requires read access (viewer or higher)
298
- - `createGroup(dto, ctx)`, `updateGroup(id, dto, ctx)`, `deleteGroup(id, ctx)` - Requires write access (editor or higher)
299
- - `importJson(items, ctx)`, `importCsv(csvContent, ctx)` - Requires write access (bulk upsert by code)
300
- - `exportJson(ctx)`, `exportCsv(ctx)` - Requires read access
301
- - `getExampleJson()`, `getExampleCsv()` - Get import format examples (no auth required)
302
-
303
- ### `client.statuses`
304
- - `getStatuses(ctx)`, `getStatus(id, ctx)`, `getStatusByCode(code, ctx)` - Requires read access (viewer or higher)
305
- - `createStatus(dto, ctx)`, `updateStatus(id, dto, ctx)`, `deleteStatus(id, ctx)` - Requires write access (editor or higher)
306
- - `importJson(items, ctx)`, `importCsv(csvContent, ctx)` - Requires write access (bulk upsert by code)
307
- - `exportJson(ctx)`, `exportCsv(ctx)` - Requires read access
308
- - `getExampleJson()`, `getExampleCsv()` - Get import format examples (no auth required)
309
-
310
- ### `client.suppliers`
311
- - `getSuppliers(ctx)`, `getSupplier(id, ctx)`, `getSupplierByCode(code, ctx)` - Requires read access (viewer or higher)
312
- - `createSupplier(dto, ctx)`, `updateSupplier(id, dto, ctx)`, `deleteSupplier(id, ctx)` - Requires write access (editor or higher)
313
- - `importJson(items, ctx)`, `importCsv(csvContent, ctx)` - Requires write access (bulk upsert by code)
314
- - `exportJson(ctx)`, `exportCsv(ctx)` - Requires read access
315
- - `getExampleJson()`, `getExampleCsv()` - Get import format examples (no auth required)
316
-
317
- ### `client.salesHistory`
318
- - `getSalesHistory(ctx, query?)`, `getSalesHistoryItem(id, ctx)` - Requires read access (viewer or higher)
319
- - `createSalesHistory(dto, ctx)`, `updateSalesHistory(id, dto, ctx)`, `deleteSalesHistory(id, ctx)` - Requires write access (editor or higher)
320
- - `importJson(items, ctx)`, `importCsv(csvContent, ctx)` - Requires write access
321
- - `exportJson(ctx, query?)`, `exportCsv(ctx, query?)` - Requires read access
322
- - `getExampleJson()`, `getExampleCsv()` - Get import format examples (no auth required)
323
-
324
- ### `client.roles`
325
- - `getRoles()`, `getRole(id)` - System admin only
326
- - `createRole(dto)`, `updateRole(id, dto)`, `deleteRole(id)` - System admin only
327
-
328
- ### `client.userRoles`
329
- - `getUserRoles(query)`, `getUserRole(id)` - View roles for tenant
330
- - `createUserRole(dto)`, `deleteUserRole(id)` - Tenant admin or higher for their tenant
331
-
332
- ### `client.apiKeys`
333
- - `getApiKeys()`, `createApiKey(dto)`, `deleteApiKey(id)` - System admin only
334
-
335
- ### `client.marketplaces`
336
- - `getMarketplaces(ctx)`, `getMarketplace(id, ctx)`, `getMarketplaceByCode(code, ctx)` - Requires read access
337
- - `createMarketplace(dto, ctx)`, `updateMarketplace(id, dto, ctx)`, `deleteMarketplace(id, ctx)` - Requires write access (editor or higher)
338
- - `importJson(items, ctx)`, `importCsv(csvContent, ctx)` - Requires write access
339
- - `exportJson(ctx)`, `exportCsv(ctx)` - Requires read access
340
-
341
- ### `client.metadata`
342
- - `getEntitiesMetadata()` - Get field definitions for all entities (no auth required)
272
+ #### `client.roles`
273
+ - `getRoles()` - List roles (system admin only)
274
+ - `getRole(id)` - Get role by ID
275
+
276
+ #### `client.userRoles`
277
+ - `getUserRoles(query)` - List user roles
278
+ - `getUserRole(id)` - Get user role by ID
279
+ - `createUserRole(request)` - Create user role
280
+ - `deleteUserRole(id)` - Delete user role
281
+
282
+ #### `client.apiKeys`
283
+ - `getApiKeys()` - List API keys (system admin only)
284
+ - `createApiKey(request)` - Create API key
285
+ - `deleteApiKey(id)` - Delete API key
286
+
287
+ #### `client.metadata`
288
+ - `getEntitiesMetadata()` - Get field definitions for all entities (no auth)
289
+
290
+ ### Shop-Scoped (context required)
291
+
292
+ All shop-scoped clients follow the same pattern:
293
+
294
+ #### `client.skus`
295
+ - `getSkus(ctx)` - List SKUs
296
+ - `getSku(ctx, id)` - Get SKU by ID
297
+ - `getSkuByCode(ctx, code)` - Get SKU by code
298
+ - `createSku(ctx, request)` - Create SKU
299
+ - `updateSku(ctx, id, request)` - Update SKU
300
+ - `deleteSku(ctx, id)` - Delete SKU
301
+ - `importJson(ctx, items)` - Import from JSON array
302
+ - `importCsv(ctx, csvContent)` - Import from CSV string
303
+ - `exportJson(ctx)` - Export to JSON
304
+ - `exportCsv(ctx)` - Export to CSV
305
+ - `getExampleJson()` - Get JSON import example (no auth)
306
+ - `getExampleCsv()` - Get CSV import example (no auth)
307
+
308
+ #### `client.brands`, `client.categories`, `client.groups`, `client.statuses`, `client.suppliers`
309
+
310
+ Same methods as `client.skus`:
311
+ - `get<Entity>s(ctx)`, `get<Entity>(ctx, id)`, `get<Entity>ByCode(ctx, code)`
312
+ - `create<Entity>(ctx, request)`, `update<Entity>(ctx, id, request)`, `delete<Entity>(ctx, id)`
313
+ - `importJson(ctx, items)`, `importCsv(ctx, csvContent)`
314
+ - `exportJson(ctx)`, `exportCsv(ctx)`
315
+ - `getExampleJson()`, `getExampleCsv()`
316
+
317
+ #### `client.marketplaces`
318
+ - `getMarketplaces(ctx)` - List marketplaces
319
+ - `getMarketplace(ctx, id)` - Get marketplace by ID
320
+ - `getMarketplaceByCode(ctx, code)` - Get marketplace by code
321
+ - `createMarketplace(ctx, request)` - Create marketplace
322
+ - `updateMarketplace(ctx, id, request)` - Update marketplace
323
+ - `deleteMarketplace(ctx, id)` - Delete marketplace
324
+ - `importJson(ctx, items)`, `importCsv(ctx, csvContent)` - Import
325
+ - `exportJson(ctx)`, `exportCsv(ctx)` - Export
326
+
327
+ #### `client.salesHistory`
328
+ - `getSalesHistory(ctx, query?)` - List sales history (optional period filter)
329
+ - `getSalesHistoryItem(ctx, id)` - Get sales history item by ID
330
+ - `createSalesHistory(ctx, request)` - Create sales history
331
+ - `updateSalesHistory(ctx, id, request)` - Update sales history
332
+ - `deleteSalesHistory(ctx, id)` - Delete sales history
333
+ - `importJson(ctx, items)`, `importCsv(ctx, csvContent)` - Import
334
+ - `exportJson(ctx, query?)`, `exportCsv(ctx, query?)` - Export (optional period filter)
335
+ - `getExampleJson()`, `getExampleCsv()` - Examples (no auth)
343
336
 
344
337
  ## Error Handling
345
338
 
@@ -356,35 +349,71 @@ try {
356
349
  }
357
350
  ```
358
351
 
359
- Common HTTP status codes:
360
- - `409 Conflict` - Duplicate resource (email, SKU code, sales period)
361
- - `404 Not Found` - Resource not found
362
- - `403 Forbidden` - Insufficient permissions
352
+ **Common HTTP status codes:**
363
353
  - `400 Bad Request` - Validation error
354
+ - `401 Unauthorized` - Missing or invalid API key
355
+ - `403 Forbidden` - Insufficient permissions
356
+ - `404 Not Found` - Resource not found
357
+ - `409 Conflict` - Duplicate resource (email, code, period)
364
358
 
365
359
  ## Types
366
360
 
367
- Common types are re-exported from `@sales-planner/shared` for convenience:
361
+ Types are re-exported from `@sales-planner/shared`:
368
362
 
369
363
  ```typescript
370
- import type {
364
+ import type {
365
+ // Context
366
+ ShopContextParams,
367
+ PeriodQuery,
368
+
371
369
  // Entities
372
- User, Tenant, Shop, Sku, SalesHistory, Role, UserRole, ApiKey, Marketplace,
373
- // DTOs
374
- CreateUserDto, CreateTenantDto, CreateShopDto,
375
- CreateSkuDto, CreateSkuRequest, CreateSalesHistoryDto, CreateSalesHistoryRequest,
376
- CreateMarketplaceDto, CreateMarketplaceRequest,
377
- // Query types
378
- ShopContextParams, PeriodQuery,
370
+ User,
371
+ Tenant,
372
+ Shop,
373
+ Sku,
374
+ Brand,
375
+ Category,
376
+ Group,
377
+ Status,
378
+ Supplier,
379
+ Marketplace,
380
+ SalesHistory,
381
+ Role,
382
+ UserRole,
383
+ ApiKey,
384
+
385
+ // Request types (for create/update)
386
+ CreateUserRequest,
387
+ UpdateUserRequest,
388
+ CreateTenantRequest,
389
+ UpdateTenantRequest,
390
+ CreateShopRequest,
391
+ UpdateShopRequest,
392
+ CreateSkuRequest,
393
+ UpdateSkuRequest,
394
+ CreateBrandRequest,
395
+ UpdateBrandRequest,
396
+ CreateSalesHistoryRequest,
397
+ UpdateSalesHistoryRequest,
398
+ // ... etc
399
+
400
+ // Import types (for import operations)
401
+ ImportSkuItem,
402
+ ImportBrandItem,
403
+ ImportSalesHistoryItem,
404
+ // ... etc
405
+
379
406
  // Response types
380
- UserWithRolesAndTenants, TenantWithShopAndApiKey,
381
- ImportResult, DeleteDataResult,
382
- SkuExportItem, SalesHistoryExportItem,
407
+ UserWithRolesAndTenants,
408
+ TenantWithShopAndApiKey,
409
+ ImportResult,
410
+ SkuImportResult,
411
+ DeleteDataResult,
412
+
413
+ // Export types
414
+ SkuExportItem,
415
+ SalesHistoryExportItem,
383
416
  } from '@sales-planner/http-client';
384
-
385
- // For additional types (Brand, Category, Group, Status, Supplier, etc.)
386
- // import directly from @sales-planner/shared
387
- import type { Brand, Category, Group, Status, Supplier } from '@sales-planner/shared';
388
417
  ```
389
418
 
390
419
  ## License