@ram_28/kf-ai-sdk 1.0.0 → 1.0.1
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/README.md +236 -747
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,839 +1,328 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @ram_28/kf-ai-sdk
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
A type-safe SDK for building modern web applications with React hooks for forms, tables, kanban boards, and filtering.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Installation
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
- **Expression Caching**: LRU cache with dependency tracking for optimized performance
|
|
11
|
-
- **BDO Schema Support**: Full compatibility with Business Data Object schemas
|
|
12
|
-
|
|
13
|
-
### ✅ **Role-Based Field Permissions (NEW)**
|
|
14
|
-
- **Field-Level Control**: Editable, readable, and hidden field permissions per role
|
|
15
|
-
- **Compile-Time Safety**: TypeScript enforcement of permission boundaries
|
|
16
|
-
- **Dynamic UI**: Automatic form field disable/hide based on permissions
|
|
17
|
-
|
|
18
|
-
### ✅ **Optimized API Integration (NEW)**
|
|
19
|
-
- **POST-Based Operations**: Correct implementation per BDO specification
|
|
20
|
-
- **Enhanced Count API**: Efficient counting with same payload structure as list
|
|
21
|
-
- **Advanced Filtering**: Complex filter conditions with logical operators
|
|
22
|
-
- **Type-Safe Responses**: Full TypeScript coverage for all operations
|
|
23
|
-
|
|
24
|
-
### ✅ **Amazon Product Master Implementation (NEW)**
|
|
25
|
-
- **Complete BDO Example**: Full implementation of Amazon Product Master schema
|
|
26
|
-
- **Business Rules**: Auto-calculations, validation, and permission enforcement
|
|
27
|
-
- **Role-Based Views**: Admin, Seller, Buyer, InventoryManager, WarehouseStaff access levels
|
|
28
|
-
- **Real-World Example**: Production-ready e-commerce product management
|
|
29
|
-
|
|
30
|
-
## 📚 Documentation
|
|
31
|
-
|
|
32
|
-
- **[Implementation Guide](./IMPLEMENTATION_GUIDE.md)** - Comprehensive setup and usage guide
|
|
33
|
-
- **[Quick Reference](./QUICK_REFERENCE.md)** - Developer cheat sheet and API reference
|
|
34
|
-
- **[Examples](./examples/)** - Real-world usage examples including Amazon Product demo
|
|
35
|
-
|
|
36
|
-
## Architecture Overview
|
|
37
|
-
|
|
38
|
-
The KF AI SDK is built on a clear separation between reusable SDK core and user-configurable application logic:
|
|
39
|
-
|
|
40
|
-
### 🔧 SDK Core (`sdk/`)
|
|
41
|
-
|
|
42
|
-
**Fixed, Reusable Components**
|
|
43
|
-
|
|
44
|
-
- **Types**: 11 Backend BO field types (IdField, StringField, CurrencyField, etc.)
|
|
45
|
-
- **API Client**: Runtime CRUD operations with structured filtering and sorting
|
|
46
|
-
- **Utilities**: Validation and formatting helpers
|
|
47
|
-
- **Components**: React hooks for forms and tables (Phase 2)
|
|
48
|
-
|
|
49
|
-
### 🏗️ App Layer (`app/`)
|
|
50
|
-
|
|
51
|
-
**User-Configurable Business Logic**
|
|
7
|
+
```bash
|
|
8
|
+
npm install @ram_28/kf-ai-sdk
|
|
9
|
+
```
|
|
52
10
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
11
|
+
**Peer Dependencies:**
|
|
12
|
+
```bash
|
|
13
|
+
npm install react @tanstack/react-query
|
|
14
|
+
```
|
|
57
15
|
|
|
58
|
-
|
|
16
|
+
## Features
|
|
59
17
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
├── app/ # User-configurable layer
|
|
68
|
-
│ ├── types/roles.ts # Role definitions
|
|
69
|
-
│ ├── sources/ # Business objects
|
|
70
|
-
│ └── index.ts # App exports
|
|
71
|
-
├── config/ # Development configuration
|
|
72
|
-
└── examples/ # Usage examples
|
|
73
|
-
```
|
|
18
|
+
- **useForm** - Dynamic schema-driven forms with backend validation
|
|
19
|
+
- **useTable** - Data tables with sorting, pagination, and React Query integration
|
|
20
|
+
- **useKanban** - Kanban board state management with drag-drop support
|
|
21
|
+
- **useFilter** - Advanced filtering with logical operators and payload builders
|
|
22
|
+
- **API Client** - Type-safe CRUD operations with structured filtering and sorting
|
|
23
|
+
- **Type System** - 11 semantic field types (IdField, StringField, CurrencyField, etc.)
|
|
24
|
+
- **Utilities** - Formatting helpers for currency, dates, numbers, and more
|
|
74
25
|
|
|
75
26
|
## Quick Start
|
|
76
27
|
|
|
77
|
-
### Usage Example
|
|
78
|
-
|
|
79
28
|
```tsx
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
29
|
+
import {
|
|
30
|
+
useForm,
|
|
31
|
+
useTable,
|
|
32
|
+
useKanban,
|
|
33
|
+
useFilter,
|
|
34
|
+
api,
|
|
35
|
+
setApiBaseUrl,
|
|
36
|
+
formatCurrency,
|
|
37
|
+
formatDate
|
|
38
|
+
} from '@ram_28/kf-ai-sdk';
|
|
39
|
+
|
|
40
|
+
// Configure API base URL
|
|
41
|
+
setApiBaseUrl('https://api.example.com');
|
|
42
|
+
```
|
|
89
43
|
|
|
90
|
-
|
|
91
|
-
const isValid = isValidCurrencyField(orderData.Data[0].totalAmount);
|
|
92
|
-
const formatted = formatCurrency(orderData.Data[0].totalAmount);
|
|
44
|
+
## Hooks
|
|
93
45
|
|
|
94
|
-
|
|
95
|
-
// Type-safe order client with role-based access
|
|
96
|
-
const order = new Order(Roles.Admin);
|
|
46
|
+
### useTable
|
|
97
47
|
|
|
98
|
-
|
|
99
|
-
const table = useTable<AdminOrder>({
|
|
100
|
-
source: "orders",
|
|
101
|
-
enableSorting: true,
|
|
102
|
-
enablePagination: true,
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
// Form with backend-driven validation
|
|
106
|
-
const form = useForm<AdminOrder>({
|
|
107
|
-
source: "order-validation",
|
|
108
|
-
operation: "create",
|
|
109
|
-
onSuccess: () => table.refetch(),
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
return (
|
|
113
|
-
<div>
|
|
114
|
-
{/* Create Form */}
|
|
115
|
-
<form onSubmit={form.handleSubmit()}>
|
|
116
|
-
<input {...form.register("customerId")} placeholder="Customer ID" />
|
|
117
|
-
<input {...form.register("totalAmount")} placeholder="Total Amount" type="number" />
|
|
118
|
-
<input {...form.register("profitMargin")} placeholder="Profit Margin" type="number" />{" "}
|
|
119
|
-
{/* Admin can see profit margin */}
|
|
120
|
-
<button type="submit">Create Order</button>
|
|
121
|
-
</form>
|
|
122
|
-
|
|
123
|
-
{/* Orders Table */}
|
|
124
|
-
<table>
|
|
125
|
-
<thead>
|
|
126
|
-
<tr>
|
|
127
|
-
<th>ID</th>
|
|
128
|
-
<th>Customer</th>
|
|
129
|
-
<th>Amount</th>
|
|
130
|
-
<th>Profit Margin</th> {/* Admin can see profit margin */}
|
|
131
|
-
<th>Actions</th>
|
|
132
|
-
</tr>
|
|
133
|
-
</thead>
|
|
134
|
-
<tbody>
|
|
135
|
-
{table.rows.map((order: AdminOrder) => (
|
|
136
|
-
<tr key={order._id}>
|
|
137
|
-
<td>{order._id}</td>
|
|
138
|
-
<td>{order.customerId}</td>
|
|
139
|
-
<td>${order.totalAmount}</td>
|
|
140
|
-
<td>{order.profitMargin}%</td>{" "}
|
|
141
|
-
{/* TypeScript knows this exists for Admin */}
|
|
142
|
-
<td>
|
|
143
|
-
<button onClick={() => order.delete(order._id)}>Delete</button>
|
|
144
|
-
</td>
|
|
145
|
-
</tr>
|
|
146
|
-
))}
|
|
147
|
-
</tbody>
|
|
148
|
-
</table>
|
|
149
|
-
</div>
|
|
150
|
-
);
|
|
151
|
-
}
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
### Role-Based Access Control
|
|
48
|
+
Data table hook with sorting, pagination, and React Query integration.
|
|
155
49
|
|
|
156
50
|
```tsx
|
|
157
|
-
|
|
158
|
-
import { Order, Roles, UserOrder } from "@ram_28/kf-ai-sdk";
|
|
159
|
-
|
|
160
|
-
function UserOrderList() {
|
|
161
|
-
const order = new Order(Roles.User);
|
|
51
|
+
import { useTable } from '@ram_28/kf-ai-sdk';
|
|
162
52
|
|
|
163
|
-
|
|
164
|
-
|
|
53
|
+
function ProductTable() {
|
|
54
|
+
const table = useTable({
|
|
55
|
+
source: 'products',
|
|
165
56
|
enableSorting: true,
|
|
57
|
+
enablePagination: true,
|
|
58
|
+
pageSize: 25,
|
|
166
59
|
});
|
|
167
60
|
|
|
168
61
|
return (
|
|
169
62
|
<table>
|
|
170
63
|
<thead>
|
|
171
64
|
<tr>
|
|
172
|
-
<th>
|
|
173
|
-
<th>
|
|
174
|
-
<th>Amount</th>
|
|
175
|
-
{/* <th>Profit Margin</th> */} {/* User cannot see profit margin */}
|
|
65
|
+
<th onClick={() => table.toggleSort('name')}>Name</th>
|
|
66
|
+
<th onClick={() => table.toggleSort('price')}>Price</th>
|
|
176
67
|
</tr>
|
|
177
68
|
</thead>
|
|
178
69
|
<tbody>
|
|
179
|
-
{table.rows.map((
|
|
180
|
-
<tr key={
|
|
181
|
-
<td>{
|
|
182
|
-
<td
|
|
183
|
-
<td>${order.totalAmount}</td>
|
|
184
|
-
{/* <td>{order.profitMargin}%</td> */}{" "}
|
|
185
|
-
{/* ❌ TypeScript Error: Property doesn't exist */}
|
|
70
|
+
{table.rows.map((product) => (
|
|
71
|
+
<tr key={product._id}>
|
|
72
|
+
<td>{product.name}</td>
|
|
73
|
+
<td>${product.price}</td>
|
|
186
74
|
</tr>
|
|
187
75
|
))}
|
|
188
76
|
</tbody>
|
|
77
|
+
<tfoot>
|
|
78
|
+
<button onClick={table.previousPage} disabled={!table.hasPreviousPage}>
|
|
79
|
+
Previous
|
|
80
|
+
</button>
|
|
81
|
+
<span>Page {table.currentPage}</span>
|
|
82
|
+
<button onClick={table.nextPage} disabled={!table.hasNextPage}>
|
|
83
|
+
Next
|
|
84
|
+
</button>
|
|
85
|
+
</tfoot>
|
|
189
86
|
</table>
|
|
190
87
|
);
|
|
191
88
|
}
|
|
192
89
|
```
|
|
193
90
|
|
|
194
|
-
###
|
|
91
|
+
### useForm
|
|
92
|
+
|
|
93
|
+
Schema-driven form hook with backend validation support.
|
|
195
94
|
|
|
196
95
|
```tsx
|
|
197
|
-
import {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
_id: "ORDER_456", // Optional custom ID
|
|
207
|
-
customerId: "CUST_001",
|
|
208
|
-
totalAmount: 299.99,
|
|
209
|
-
status: "pending",
|
|
96
|
+
import { useForm } from '@ram_28/kf-ai-sdk';
|
|
97
|
+
|
|
98
|
+
function ProductForm() {
|
|
99
|
+
const form = useForm({
|
|
100
|
+
source: 'products',
|
|
101
|
+
operation: 'create',
|
|
102
|
+
onSuccess: (data) => {
|
|
103
|
+
console.log('Created:', data);
|
|
104
|
+
},
|
|
210
105
|
});
|
|
211
|
-
console.log(createResponse._id); // "ORDER_456"
|
|
212
106
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
});
|
|
107
|
+
return (
|
|
108
|
+
<form onSubmit={form.handleSubmit()}>
|
|
109
|
+
<input {...form.register('name')} placeholder="Product Name" />
|
|
110
|
+
{form.errors.name && <span>{form.errors.name.message}</span>}
|
|
218
111
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
console.log(deleteResponse.status); // "success"
|
|
112
|
+
<input {...form.register('price')} type="number" placeholder="Price" />
|
|
113
|
+
{form.errors.price && <span>{form.errors.price.message}</span>}
|
|
222
114
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
{
|
|
229
|
-
Operator: "EQ",
|
|
230
|
-
LHSField: "status",
|
|
231
|
-
RHSValue: "pending"
|
|
232
|
-
},
|
|
233
|
-
{
|
|
234
|
-
Operator: "GTE",
|
|
235
|
-
LHSField: "totalAmount",
|
|
236
|
-
RHSValue: 100
|
|
237
|
-
}
|
|
238
|
-
]
|
|
239
|
-
},
|
|
240
|
-
Sort: [
|
|
241
|
-
{ Field: "_created_at", Order: "DESC" },
|
|
242
|
-
{ Field: "totalAmount", Order: "ASC" }
|
|
243
|
-
],
|
|
244
|
-
Page: 1,
|
|
245
|
-
PageSize: 50
|
|
246
|
-
});
|
|
115
|
+
<button type="submit" disabled={form.isSubmitting}>
|
|
116
|
+
{form.isSubmitting ? 'Creating...' : 'Create Product'}
|
|
117
|
+
</button>
|
|
118
|
+
</form>
|
|
119
|
+
);
|
|
247
120
|
}
|
|
248
121
|
```
|
|
249
122
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
The KF AI SDK supports comprehensive filtering and sorting through the Runtime API. Here are detailed examples using both Order and Product models:
|
|
123
|
+
### useKanban
|
|
253
124
|
|
|
254
|
-
|
|
125
|
+
Kanban board state management with drag-drop support.
|
|
255
126
|
|
|
256
127
|
```tsx
|
|
257
|
-
import {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
{
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
}
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
// String contains filter
|
|
288
|
-
const electronicsProducts = await new Product(Roles.Admin).list({
|
|
289
|
-
Filter: {
|
|
290
|
-
Operator: "AND",
|
|
291
|
-
Condition: [
|
|
292
|
-
{
|
|
293
|
-
Operator: "Contains",
|
|
294
|
-
LHSField: "description",
|
|
295
|
-
RHSValue: "electronic"
|
|
296
|
-
}
|
|
297
|
-
]
|
|
298
|
-
}
|
|
299
|
-
});
|
|
128
|
+
import { useKanban, Kanban, KanbanColumn, KanbanCard } from '@ram_28/kf-ai-sdk';
|
|
129
|
+
|
|
130
|
+
function TaskBoard() {
|
|
131
|
+
const kanban = useKanban({
|
|
132
|
+
source: 'tasks',
|
|
133
|
+
groupByField: 'status',
|
|
134
|
+
columns: [
|
|
135
|
+
{ id: 'todo', title: 'To Do' },
|
|
136
|
+
{ id: 'in-progress', title: 'In Progress' },
|
|
137
|
+
{ id: 'done', title: 'Done' },
|
|
138
|
+
],
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
return (
|
|
142
|
+
<Kanban>
|
|
143
|
+
{kanban.columns.map((column) => (
|
|
144
|
+
<KanbanColumn key={column.id} column={column}>
|
|
145
|
+
{column.cards.map((card) => (
|
|
146
|
+
<KanbanCard key={card.id} card={card}>
|
|
147
|
+
{card.title}
|
|
148
|
+
</KanbanCard>
|
|
149
|
+
))}
|
|
150
|
+
</KanbanColumn>
|
|
151
|
+
))}
|
|
152
|
+
</Kanban>
|
|
153
|
+
);
|
|
154
|
+
}
|
|
300
155
|
```
|
|
301
156
|
|
|
302
|
-
###
|
|
157
|
+
### useFilter
|
|
158
|
+
|
|
159
|
+
Advanced filtering with logical operators.
|
|
303
160
|
|
|
304
161
|
```tsx
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
{
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
{
|
|
316
|
-
Operator: "GTE",
|
|
317
|
-
LHSField: "totalAmount",
|
|
318
|
-
RHSValue: 1000
|
|
319
|
-
},
|
|
320
|
-
{
|
|
321
|
-
Operator: "GTE",
|
|
322
|
-
LHSField: "profitMargin",
|
|
323
|
-
RHSValue: 20
|
|
324
|
-
}
|
|
325
|
-
]
|
|
326
|
-
}
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
// OR conditions - any can be true
|
|
330
|
-
const urgentOrders = await new Order(Roles.Admin).list({
|
|
331
|
-
Filter: {
|
|
332
|
-
Operator: "OR",
|
|
333
|
-
Condition: [
|
|
334
|
-
{
|
|
335
|
-
Operator: "EQ",
|
|
336
|
-
LHSField: "status",
|
|
337
|
-
RHSValue: "pending"
|
|
338
|
-
},
|
|
339
|
-
{
|
|
340
|
-
Operator: "EQ",
|
|
341
|
-
LHSField: "status",
|
|
342
|
-
RHSValue: "processing"
|
|
343
|
-
}
|
|
344
|
-
]
|
|
345
|
-
}
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
// Nested AND/OR conditions
|
|
349
|
-
const complexProductFilter = await new Product(Roles.Admin).list({
|
|
350
|
-
Filter: {
|
|
351
|
-
Operator: "AND",
|
|
352
|
-
Condition: [
|
|
353
|
-
{
|
|
354
|
-
Operator: "EQ",
|
|
355
|
-
LHSField: "inStock",
|
|
356
|
-
RHSValue: true
|
|
357
|
-
},
|
|
358
|
-
{
|
|
359
|
-
Operator: "OR",
|
|
360
|
-
Condition: [
|
|
361
|
-
{
|
|
362
|
-
Operator: "EQ",
|
|
363
|
-
LHSField: "category",
|
|
364
|
-
RHSValue: "electronics"
|
|
365
|
-
},
|
|
366
|
-
{
|
|
367
|
-
Operator: "EQ",
|
|
368
|
-
LHSField: "category",
|
|
369
|
-
RHSValue: "clothing"
|
|
370
|
-
}
|
|
371
|
-
]
|
|
372
|
-
},
|
|
373
|
-
{
|
|
374
|
-
Operator: "Between",
|
|
375
|
-
LHSField: "price",
|
|
376
|
-
RHSValue: [50, 500]
|
|
377
|
-
}
|
|
378
|
-
]
|
|
379
|
-
}
|
|
380
|
-
});
|
|
381
|
-
```
|
|
162
|
+
import { useFilter, buildFilterPayload } from '@ram_28/kf-ai-sdk';
|
|
163
|
+
|
|
164
|
+
function ProductFilter() {
|
|
165
|
+
const filter = useFilter({
|
|
166
|
+
fields: {
|
|
167
|
+
name: { type: 'string' },
|
|
168
|
+
price: { type: 'number' },
|
|
169
|
+
category: { type: 'select', options: ['electronics', 'clothing', 'books'] },
|
|
170
|
+
},
|
|
171
|
+
});
|
|
382
172
|
|
|
383
|
-
|
|
173
|
+
const handleApply = () => {
|
|
174
|
+
const payload = buildFilterPayload(filter.conditions);
|
|
175
|
+
// Use payload with API
|
|
176
|
+
};
|
|
384
177
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
}
|
|
398
|
-
});
|
|
399
|
-
|
|
400
|
-
// List membership
|
|
401
|
-
const specificCategories = await new Product(Roles.Admin).list({
|
|
402
|
-
Filter: {
|
|
403
|
-
Operator: "AND",
|
|
404
|
-
Condition: [
|
|
405
|
-
{
|
|
406
|
-
Operator: "IN",
|
|
407
|
-
LHSField: "category",
|
|
408
|
-
RHSValue: ["electronics", "books", "sports"]
|
|
409
|
-
}
|
|
410
|
-
]
|
|
411
|
-
}
|
|
412
|
-
});
|
|
413
|
-
|
|
414
|
-
// Exclusion filters
|
|
415
|
-
const nonCancelledOrders = await new Order(Roles.Admin).list({
|
|
416
|
-
Filter: {
|
|
417
|
-
Operator: "AND",
|
|
418
|
-
Condition: [
|
|
419
|
-
{
|
|
420
|
-
Operator: "NE",
|
|
421
|
-
LHSField: "status",
|
|
422
|
-
RHSValue: "cancelled"
|
|
423
|
-
}
|
|
424
|
-
]
|
|
425
|
-
}
|
|
426
|
-
});
|
|
427
|
-
|
|
428
|
-
// Empty/Non-empty checks
|
|
429
|
-
const ordersWithNotes = await new Order(Roles.Admin).list({
|
|
430
|
-
Filter: {
|
|
431
|
-
Operator: "AND",
|
|
432
|
-
Condition: [
|
|
433
|
-
{
|
|
434
|
-
Operator: "NotEmpty",
|
|
435
|
-
LHSField: "internalNotes"
|
|
436
|
-
}
|
|
437
|
-
]
|
|
438
|
-
}
|
|
439
|
-
});
|
|
440
|
-
|
|
441
|
-
// String length validation
|
|
442
|
-
const detailedProducts = await new Product(Roles.Admin).list({
|
|
443
|
-
Filter: {
|
|
444
|
-
Operator: "AND",
|
|
445
|
-
Condition: [
|
|
446
|
-
{
|
|
447
|
-
Operator: "MinLength",
|
|
448
|
-
LHSField: "description",
|
|
449
|
-
RHSValue: 50
|
|
450
|
-
}
|
|
451
|
-
]
|
|
452
|
-
}
|
|
453
|
-
});
|
|
178
|
+
return (
|
|
179
|
+
<div>
|
|
180
|
+
<button onClick={() => filter.addCondition('name', 'contains', '')}>
|
|
181
|
+
Add Name Filter
|
|
182
|
+
</button>
|
|
183
|
+
<button onClick={() => filter.addCondition('price', 'gte', 0)}>
|
|
184
|
+
Add Price Filter
|
|
185
|
+
</button>
|
|
186
|
+
<button onClick={handleApply}>Apply Filters</button>
|
|
187
|
+
</div>
|
|
188
|
+
);
|
|
189
|
+
}
|
|
454
190
|
```
|
|
455
191
|
|
|
456
|
-
|
|
192
|
+
## API Client
|
|
193
|
+
|
|
194
|
+
Type-safe API client for CRUD operations.
|
|
457
195
|
|
|
458
196
|
```tsx
|
|
459
|
-
|
|
460
|
-
const ordersByDate = await new Order(Roles.Admin).list({
|
|
461
|
-
Sort: [
|
|
462
|
-
{ Field: "_created_at", Order: "DESC" }
|
|
463
|
-
]
|
|
464
|
-
});
|
|
465
|
-
|
|
466
|
-
// Multi-field sorting
|
|
467
|
-
const productsCatalog = await new Product(Roles.Admin).list({
|
|
468
|
-
Sort: [
|
|
469
|
-
{ Field: "category", Order: "ASC" }, // First by category
|
|
470
|
-
{ Field: "price", Order: "DESC" }, // Then by price (high to low)
|
|
471
|
-
{ Field: "name", Order: "ASC" } // Finally by name
|
|
472
|
-
]
|
|
473
|
-
});
|
|
474
|
-
|
|
475
|
-
// Sorting with filtering
|
|
476
|
-
const topSellingProducts = await new Product(Roles.Admin).list({
|
|
477
|
-
Filter: {
|
|
478
|
-
Operator: "AND",
|
|
479
|
-
Condition: [
|
|
480
|
-
{
|
|
481
|
-
Operator: "EQ",
|
|
482
|
-
LHSField: "inStock",
|
|
483
|
-
RHSValue: true
|
|
484
|
-
},
|
|
485
|
-
{
|
|
486
|
-
Operator: "GTE",
|
|
487
|
-
LHSField: "price",
|
|
488
|
-
RHSValue: 100
|
|
489
|
-
}
|
|
490
|
-
]
|
|
491
|
-
},
|
|
492
|
-
Sort: [
|
|
493
|
-
{ Field: "margin", Order: "DESC" },
|
|
494
|
-
{ Field: "price", Order: "ASC" }
|
|
495
|
-
]
|
|
496
|
-
});
|
|
497
|
-
```
|
|
197
|
+
import { api, setApiBaseUrl } from '@ram_28/kf-ai-sdk';
|
|
498
198
|
|
|
499
|
-
|
|
199
|
+
// Configure base URL
|
|
200
|
+
setApiBaseUrl('https://api.example.com');
|
|
500
201
|
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
Filter: {
|
|
506
|
-
Operator: "AND",
|
|
507
|
-
Condition: [
|
|
508
|
-
{
|
|
509
|
-
Operator: "GTE",
|
|
510
|
-
LHSField: "totalAmount",
|
|
511
|
-
RHSValue: 200
|
|
512
|
-
},
|
|
513
|
-
{
|
|
514
|
-
Operator: "OR",
|
|
515
|
-
Condition: [
|
|
516
|
-
{
|
|
517
|
-
Operator: "EQ",
|
|
518
|
-
LHSField: "status",
|
|
519
|
-
RHSValue: "completed"
|
|
520
|
-
},
|
|
521
|
-
{
|
|
522
|
-
Operator: "EQ",
|
|
523
|
-
LHSField: "status",
|
|
524
|
-
RHSValue: "pending"
|
|
525
|
-
}
|
|
526
|
-
]
|
|
527
|
-
}
|
|
528
|
-
]
|
|
529
|
-
},
|
|
530
|
-
// Multi-field sorting
|
|
531
|
-
Sort: [
|
|
532
|
-
{ Field: "totalAmount", Order: "DESC" },
|
|
533
|
-
{ Field: "_created_at", Order: "DESC" }
|
|
534
|
-
],
|
|
535
|
-
// Pagination
|
|
536
|
-
Page: 1,
|
|
537
|
-
PageSize: 25,
|
|
538
|
-
// Specific fields only (optional)
|
|
539
|
-
Field: ["_id", "customerId", "totalAmount", "status", "_created_at"]
|
|
540
|
-
});
|
|
541
|
-
|
|
542
|
-
// Process results
|
|
543
|
-
console.log(`Found ${paginatedResults.Data.length} orders`);
|
|
544
|
-
paginatedResults.Data.forEach(order => {
|
|
545
|
-
console.log(`Order ${order._id}: $${order.totalAmount} - ${order.status}`);
|
|
546
|
-
});
|
|
547
|
-
```
|
|
202
|
+
// CRUD Operations
|
|
203
|
+
async function productOperations() {
|
|
204
|
+
// Get single record
|
|
205
|
+
const product = await api('products').get('PROD_123');
|
|
548
206
|
|
|
549
|
-
|
|
207
|
+
// Create record
|
|
208
|
+
const created = await api('products').create({
|
|
209
|
+
name: 'New Product',
|
|
210
|
+
price: 99.99,
|
|
211
|
+
category: 'electronics',
|
|
212
|
+
});
|
|
550
213
|
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
Operator: "AND",
|
|
556
|
-
Condition: [
|
|
557
|
-
{
|
|
558
|
-
Operator: "GTE",
|
|
559
|
-
LHSField: "margin", // Admin-only field
|
|
560
|
-
RHSValue: 25
|
|
561
|
-
},
|
|
562
|
-
{
|
|
563
|
-
Operator: "Contains",
|
|
564
|
-
LHSField: "supplier", // Admin-only field
|
|
565
|
-
RHSValue: "Premium"
|
|
566
|
-
}
|
|
567
|
-
]
|
|
568
|
-
},
|
|
569
|
-
Sort: [
|
|
570
|
-
{ Field: "margin", Order: "DESC" },
|
|
571
|
-
{ Field: "cost", Order: "ASC" } // Admin-only field
|
|
572
|
-
]
|
|
573
|
-
});
|
|
574
|
-
|
|
575
|
-
// User sees limited data and can only filter on public fields
|
|
576
|
-
const userProducts = await new Product(Roles.User).list({
|
|
577
|
-
Filter: {
|
|
578
|
-
Operator: "AND",
|
|
579
|
-
Condition: [
|
|
580
|
-
{
|
|
581
|
-
Operator: "EQ",
|
|
582
|
-
LHSField: "category", // Public field
|
|
583
|
-
RHSValue: "electronics"
|
|
584
|
-
},
|
|
585
|
-
{
|
|
586
|
-
Operator: "EQ",
|
|
587
|
-
LHSField: "inStock", // Public field
|
|
588
|
-
RHSValue: true
|
|
589
|
-
}
|
|
590
|
-
]
|
|
591
|
-
},
|
|
592
|
-
Sort: [
|
|
593
|
-
{ Field: "price", Order: "ASC" }, // Public field
|
|
594
|
-
{ Field: "name", Order: "ASC" } // Public field
|
|
595
|
-
]
|
|
596
|
-
});
|
|
597
|
-
|
|
598
|
-
// Note: User cannot filter by margin, cost, or supplier - those fields don't exist in UserProduct type
|
|
599
|
-
```
|
|
214
|
+
// Update record
|
|
215
|
+
const updated = await api('products').update('PROD_123', {
|
|
216
|
+
price: 89.99,
|
|
217
|
+
});
|
|
600
218
|
|
|
601
|
-
|
|
219
|
+
// Delete record
|
|
220
|
+
await api('products').delete('PROD_123');
|
|
602
221
|
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
async function searchProducts(searchTerm: string, category?: string, maxPrice?: number) {
|
|
606
|
-
const conditions = [
|
|
607
|
-
{
|
|
608
|
-
Operator: "EQ" as const,
|
|
609
|
-
LHSField: "inStock",
|
|
610
|
-
RHSValue: true
|
|
611
|
-
}
|
|
612
|
-
];
|
|
613
|
-
|
|
614
|
-
if (searchTerm) {
|
|
615
|
-
conditions.push({
|
|
616
|
-
Operator: "Contains" as const,
|
|
617
|
-
LHSField: "name",
|
|
618
|
-
RHSValue: searchTerm
|
|
619
|
-
});
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
if (category) {
|
|
623
|
-
conditions.push({
|
|
624
|
-
Operator: "EQ" as const,
|
|
625
|
-
LHSField: "category",
|
|
626
|
-
RHSValue: category
|
|
627
|
-
});
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
if (maxPrice) {
|
|
631
|
-
conditions.push({
|
|
632
|
-
Operator: "LTE" as const,
|
|
633
|
-
LHSField: "price",
|
|
634
|
-
RHSValue: maxPrice
|
|
635
|
-
});
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
return new Product(Roles.User).list({
|
|
222
|
+
// List with filtering and sorting
|
|
223
|
+
const products = await api('products').list({
|
|
639
224
|
Filter: {
|
|
640
|
-
Operator:
|
|
641
|
-
Condition:
|
|
225
|
+
Operator: 'AND',
|
|
226
|
+
Condition: [
|
|
227
|
+
{ Operator: 'EQ', LHSField: 'category', RHSValue: 'electronics' },
|
|
228
|
+
{ Operator: 'GTE', LHSField: 'price', RHSValue: 50 },
|
|
229
|
+
],
|
|
642
230
|
},
|
|
643
231
|
Sort: [
|
|
644
|
-
{ Field:
|
|
232
|
+
{ Field: 'price', Order: 'DESC' },
|
|
645
233
|
],
|
|
646
|
-
|
|
234
|
+
Page: 1,
|
|
235
|
+
PageSize: 25,
|
|
647
236
|
});
|
|
648
|
-
}
|
|
649
237
|
|
|
650
|
-
//
|
|
651
|
-
|
|
652
|
-
const conditions = [
|
|
653
|
-
{
|
|
654
|
-
Operator: "Between" as const,
|
|
655
|
-
LHSField: "_created_at",
|
|
656
|
-
RHSValue: [dateRange.start, dateRange.end]
|
|
657
|
-
}
|
|
658
|
-
];
|
|
659
|
-
|
|
660
|
-
if (minAmount) {
|
|
661
|
-
conditions.push({
|
|
662
|
-
Operator: "GTE" as const,
|
|
663
|
-
LHSField: "totalAmount",
|
|
664
|
-
RHSValue: minAmount
|
|
665
|
-
});
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
return new Order(Roles.Admin).list({
|
|
238
|
+
// Count records
|
|
239
|
+
const count = await api('products').count({
|
|
669
240
|
Filter: {
|
|
670
|
-
Operator:
|
|
671
|
-
Condition:
|
|
241
|
+
Operator: 'AND',
|
|
242
|
+
Condition: [
|
|
243
|
+
{ Operator: 'EQ', LHSField: 'inStock', RHSValue: true },
|
|
244
|
+
],
|
|
672
245
|
},
|
|
673
|
-
Sort: [
|
|
674
|
-
{ Field: "totalAmount", Order: "DESC" },
|
|
675
|
-
{ Field: "_created_at", Order: "DESC" }
|
|
676
|
-
],
|
|
677
|
-
PageSize: 50
|
|
678
246
|
});
|
|
679
247
|
}
|
|
680
248
|
```
|
|
681
249
|
|
|
682
|
-
##
|
|
683
|
-
|
|
684
|
-
## Development Setup
|
|
250
|
+
## Type System
|
|
685
251
|
|
|
686
|
-
|
|
687
|
-
- Node.js 18+
|
|
688
|
-
- npm or yarn
|
|
689
|
-
|
|
690
|
-
### Installation
|
|
691
|
-
```bash
|
|
692
|
-
# Clone or download the SDK template
|
|
693
|
-
git clone kf-ai-sdk my-project
|
|
694
|
-
cd my-project
|
|
252
|
+
The SDK provides semantic field types for type-safe data modeling:
|
|
695
253
|
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
254
|
+
```tsx
|
|
255
|
+
import type {
|
|
256
|
+
IdField,
|
|
257
|
+
StringField,
|
|
258
|
+
TextAreaField,
|
|
259
|
+
NumberField,
|
|
260
|
+
BooleanField,
|
|
261
|
+
DateField,
|
|
262
|
+
DateTimeField,
|
|
263
|
+
CurrencyField,
|
|
264
|
+
PercentageField,
|
|
265
|
+
SelectField,
|
|
266
|
+
} from '@ram_28/kf-ai-sdk';
|
|
267
|
+
|
|
268
|
+
// Define your data types
|
|
269
|
+
interface Product {
|
|
270
|
+
_id: IdField;
|
|
271
|
+
name: StringField<string>;
|
|
272
|
+
description: TextAreaField;
|
|
273
|
+
price: CurrencyField;
|
|
274
|
+
quantity: NumberField<0>;
|
|
275
|
+
inStock: BooleanField;
|
|
276
|
+
category: SelectField<'electronics' | 'clothing' | 'books'>;
|
|
277
|
+
createdAt: DateTimeField;
|
|
278
|
+
}
|
|
711
279
|
```
|
|
712
280
|
|
|
713
|
-
|
|
714
|
-
The SDK uses configuration files in the `config/` directory:
|
|
715
|
-
- `tsconfig.json` - TypeScript configuration with path mapping
|
|
716
|
-
- `vite.config.js` - Build and development server config
|
|
717
|
-
- `eslint.config.js` - Code linting rules
|
|
718
|
-
- `prettier.config.js` - Code formatting rules
|
|
719
|
-
|
|
720
|
-
### Layer Documentation
|
|
721
|
-
|
|
722
|
-
- **[SDK Core](docs/sdk-core.md)** - Field types, API client, and utilities
|
|
723
|
-
- **[App Layer](docs/app-layer.md)** - Roles and business object creation
|
|
724
|
-
- **[Examples](docs/examples.md)** - Usage patterns and best practices
|
|
725
|
-
|
|
726
|
-
### Migration Guide
|
|
727
|
-
|
|
728
|
-
- **[Migration Guide](MIGRATION.md)** - Upgrading from the previous structure
|
|
729
|
-
|
|
730
|
-
## Features
|
|
281
|
+
## Utilities
|
|
731
282
|
|
|
732
|
-
###
|
|
283
|
+
### Formatting
|
|
733
284
|
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
### Development Experience
|
|
751
|
-
|
|
752
|
-
- ✅ **Modern Build Tools** - Vite, TypeScript, ESLint, Prettier
|
|
753
|
-
- ✅ **Path Mapping** - Clean imports with `@sdk/` and `@app/` aliases
|
|
754
|
-
- ✅ **Hot Reload** - Fast development with instant feedback
|
|
755
|
-
- ✅ **Type Checking** - Comprehensive TypeScript validation
|
|
756
|
-
- ✅ **Code Quality** - Automated linting and formatting
|
|
757
|
-
|
|
758
|
-
## Key Benefits
|
|
759
|
-
|
|
760
|
-
### For AI Code Generation
|
|
761
|
-
|
|
762
|
-
- **Single Source of Truth**: App layer provides all type definitions in one place
|
|
763
|
-
- **Role Awareness**: AI generates code that respects user permissions
|
|
764
|
-
- **Type Safety**: Any TypeScript error indicates incorrect AI generation
|
|
765
|
-
- **Self-Documenting**: Type definitions serve as API documentation
|
|
766
|
-
|
|
767
|
-
### For Developers
|
|
768
|
-
|
|
769
|
-
- **Three-Layer Architecture**: Clear separation of concerns
|
|
770
|
-
- **Role-Based Security**: Compile-time enforcement of data access
|
|
771
|
-
- **Modern React**: Hooks, React Query, and TypeScript throughout
|
|
772
|
-
- **Extensible**: Easy to add new data sources and roles
|
|
773
|
-
|
|
774
|
-
### For Applications
|
|
775
|
-
|
|
776
|
-
- **Performance**: React Query caching and background updates
|
|
777
|
-
- **Reliability**: Type-safe operations prevent runtime errors
|
|
778
|
-
- **Scalability**: Consistent patterns across all data operations
|
|
779
|
-
- **Maintainability**: Single file per data model, clear structure
|
|
780
|
-
|
|
781
|
-
## Example: AI-Generated Admin Page
|
|
285
|
+
```tsx
|
|
286
|
+
import {
|
|
287
|
+
formatCurrency,
|
|
288
|
+
formatDate,
|
|
289
|
+
formatDateTime,
|
|
290
|
+
formatNumber,
|
|
291
|
+
formatPercentage
|
|
292
|
+
} from '@ram_28/kf-ai-sdk';
|
|
293
|
+
|
|
294
|
+
formatCurrency(99.99); // "$99.99"
|
|
295
|
+
formatDate(new Date()); // "Jan 11, 2024"
|
|
296
|
+
formatDateTime(new Date()); // "Jan 11, 2024, 10:30 AM"
|
|
297
|
+
formatNumber(1234.56, 2); // "1,234.56"
|
|
298
|
+
formatPercentage(0.156); // "15.6%"
|
|
299
|
+
```
|
|
782
300
|
|
|
783
|
-
|
|
301
|
+
### Class Names
|
|
784
302
|
|
|
785
303
|
```tsx
|
|
786
|
-
import {
|
|
787
|
-
import { useTable, useForm } from "@ram_28/kf-ai-sdk";
|
|
304
|
+
import { cn } from '@ram_28/kf-ai-sdk';
|
|
788
305
|
|
|
789
|
-
//
|
|
790
|
-
|
|
791
|
-
|
|
306
|
+
// Merge Tailwind classes with conflict resolution
|
|
307
|
+
cn('px-4 py-2', 'px-6'); // "py-2 px-6"
|
|
308
|
+
cn('text-red-500', condition && 'text-blue-500');
|
|
309
|
+
```
|
|
792
310
|
|
|
793
|
-
|
|
794
|
-
source: "orders",
|
|
795
|
-
enableSorting: true,
|
|
796
|
-
});
|
|
311
|
+
## Documentation
|
|
797
312
|
|
|
798
|
-
|
|
799
|
-
<table>
|
|
800
|
-
<thead>
|
|
801
|
-
<tr>
|
|
802
|
-
<th>ID</th>
|
|
803
|
-
<th>Customer</th>
|
|
804
|
-
<th>Total Amount</th> {/* Admin can see financial data */}
|
|
805
|
-
<th>Profit Margin</th> {/* Admin can see profit */}
|
|
806
|
-
<th>Internal Notes</th> {/* Admin can see internal notes */}
|
|
807
|
-
</tr>
|
|
808
|
-
</thead>
|
|
809
|
-
<tbody>
|
|
810
|
-
{table.rows.map((order: AdminOrder) => (
|
|
811
|
-
<tr key={order._id}>
|
|
812
|
-
<td>{order._id}</td>
|
|
813
|
-
<td>{order.customerId}</td>
|
|
814
|
-
<td>${order.totalAmount}</td>{" "}
|
|
815
|
-
{/* ✅ TypeScript knows this exists */}
|
|
816
|
-
<td>{order.profitMargin}%</td> {/* ✅ TypeScript knows this exists */}
|
|
817
|
-
<td>{order.internalNotes}</td>{" "}
|
|
818
|
-
{/* ✅ TypeScript knows this exists */}
|
|
819
|
-
</tr>
|
|
820
|
-
))}
|
|
821
|
-
</tbody>
|
|
822
|
-
</table>
|
|
823
|
-
);
|
|
824
|
-
}
|
|
313
|
+
Detailed documentation for each hook:
|
|
825
314
|
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
315
|
+
- [useForm Documentation](./docs/useForm.md)
|
|
316
|
+
- [useTable Documentation](./docs/useTable.md)
|
|
317
|
+
- [useKanban Documentation](./docs/useKanban.md)
|
|
318
|
+
- [useFilter Documentation](./docs/useFilter.md)
|
|
319
|
+
- [Quick Reference](./docs/QUICK_REFERENCE.md)
|
|
830
320
|
|
|
831
|
-
|
|
832
|
-
// Property 'profitMargin' does not exist on type 'UserOrder'
|
|
833
|
-
}
|
|
834
|
-
```
|
|
321
|
+
## Requirements
|
|
835
322
|
|
|
836
|
-
|
|
323
|
+
- Node.js >= 18.0.0
|
|
324
|
+
- React >= 16.8.0
|
|
325
|
+
- @tanstack/react-query >= 5.0.0
|
|
837
326
|
|
|
838
327
|
## License
|
|
839
328
|
|