@frt-platform/report-core 1.0.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/README.md ADDED
@@ -0,0 +1,367 @@
1
+ # @frt/report-core
2
+
3
+ Core engine for building, validating, and migrating **report templates**.
4
+
5
+ This package is framework-agnostic, React-free, and storage-agnostic. It gives you:
6
+
7
+ - A **typed schema** for report templates (templates → sections → fields)
8
+ - **Zod-based validation** and parsing from unknown / JSON input
9
+ - **Legacy schema migration** (flat `fields` → `sections`, old type names, etc.)
10
+ - **Normalization** helpers to ensure safe IDs & consistent structure
11
+ - **Field defaults** and **ID utilities** you can use to build your own UI
12
+
13
+ It’s the core that powers a flexible incident/report builder, but it’s generic enough to be reused in any app.
14
+
15
+ ---
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ # npm
21
+ npm install @frt/report-core zod
22
+
23
+ # yarn
24
+ yarn add @frt/report-core zod
25
+
26
+ # pnpm
27
+ pnpm add @frt/report-core zod
28
+ ````
29
+
30
+ `zod` is a peer dependency and is used for schema validation & parsing.
31
+
32
+ ---
33
+
34
+ ## Concepts
35
+
36
+ The core model looks like this:
37
+
38
+ * A **template** contains multiple **sections**
39
+ * A **section** contains multiple **fields**
40
+ * A **field** has a `type` (short text, long text, number, select, etc.) and optional constraints
41
+
42
+ Supported field types:
43
+
44
+ ```ts
45
+ import { REPORT_TEMPLATE_FIELD_TYPES } from "@frt/report-core";
46
+
47
+ console.log(REPORT_TEMPLATE_FIELD_TYPES);
48
+ // [
49
+ // "shortText",
50
+ // "longText",
51
+ // "number",
52
+ // "date",
53
+ // "checkbox",
54
+ // "singleSelect",
55
+ // "multiSelect",
56
+ // "starRating"
57
+ // ]
58
+ ```
59
+
60
+ ---
61
+
62
+ ## Quick Start
63
+
64
+ ### 1. Define a template in JSON
65
+
66
+ You can define templates statically or load them from DB / API:
67
+
68
+ ```ts
69
+ import type { ReportTemplateSchema } from "@frt/report-core";
70
+
71
+ const templateJson: ReportTemplateSchema = {
72
+ version: 1,
73
+ title: "Incident follow-up",
74
+ description: "Collect a quick summary after an incident has been resolved.",
75
+ sections: [
76
+ {
77
+ id: "section-overview",
78
+ title: "Incident overview",
79
+ fields: [
80
+ {
81
+ id: "summary",
82
+ type: "longText",
83
+ label: "What happened?",
84
+ required: true,
85
+ minLength: 10
86
+ },
87
+ {
88
+ id: "status",
89
+ type: "singleSelect",
90
+ label: "Incident status",
91
+ required: true,
92
+ options: ["Pending review", "Resolved", "Escalated"],
93
+ defaultValue: "Resolved"
94
+ }
95
+ ]
96
+ }
97
+ ]
98
+ };
99
+ ```
100
+
101
+ ### 2. Validate and normalize it
102
+
103
+ Use the helpers to safely parse and normalize unknown input:
104
+
105
+ ```ts
106
+ import {
107
+ parseReportTemplateSchema,
108
+ normalizeReportTemplateSchema
109
+ } from "@frt/report-core";
110
+
111
+ const raw = /* from DB, file, API, etc. */ templateJson;
112
+
113
+ // 1) parse + validate (throws on invalid input)
114
+ const parsed = parseReportTemplateSchema(raw);
115
+
116
+ // 2) optional extra normalization step (IDs, trimming, etc.)
117
+ const normalized = normalizeReportTemplateSchema(parsed);
118
+
119
+ console.log(normalized.sections[0].fields[0].id);
120
+ // always a non-empty, safe identifier
121
+ ```
122
+
123
+ ### 3. Serialize for storage
124
+
125
+ ```ts
126
+ import { serializeReportTemplateSchema } from "@frt/report-core";
127
+
128
+ const jsonString = serializeReportTemplateSchema(normalized);
129
+ // ready to store in DB, file, etc.
130
+ ```
131
+
132
+ ---
133
+
134
+ ## Parsing from a JSON string
135
+
136
+ If you have a JSON string (e.g. from a form textarea):
137
+
138
+ ```ts
139
+ import { parseReportTemplateSchemaFromString } from "@frt/report-core";
140
+
141
+ try {
142
+ const template = parseReportTemplateSchemaFromString(userInputString);
143
+ // valid template here
144
+ } catch (err) {
145
+ // invalid JSON or schema – show error to user
146
+ }
147
+ ```
148
+
149
+ ---
150
+
151
+ ## Using field defaults
152
+
153
+ The package includes core defaults for each field type (no UI, no icons):
154
+
155
+ ```ts
156
+ import {
157
+ CORE_FIELD_DEFAULTS,
158
+ DEFAULT_FIELD_LABEL,
159
+ type ReportTemplateFieldType
160
+ } from "@frt/report-core";
161
+
162
+ function createDefaultField(type: ReportTemplateFieldType) {
163
+ const defaults = CORE_FIELD_DEFAULTS[type] ?? {};
164
+ return {
165
+ id: "your-id-here",
166
+ type,
167
+ label: (defaults.label as string) ?? DEFAULT_FIELD_LABEL,
168
+ ...defaults
169
+ };
170
+ }
171
+
172
+ const field = createDefaultField("shortText");
173
+ ```
174
+
175
+ This is especially useful in a form builder UI when the user adds a new field of a given type.
176
+
177
+ ---
178
+
179
+ ## Generating unique IDs
180
+
181
+ The core package exposes a generic `createUniqueId` helper:
182
+
183
+ ```ts
184
+ import { createUniqueId } from "@frt/report-core";
185
+
186
+ const existingSectionIds = ["section-1", "section-2"];
187
+ const newId = createUniqueId("section", existingSectionIds);
188
+ // "section-3" (or the next available)
189
+ ```
190
+
191
+ You can use this for both section and field IDs when building templates dynamically.
192
+
193
+ ---
194
+
195
+ ## Legacy schema migration
196
+
197
+ If you had older templates that:
198
+
199
+ * Used a flat `fields` array instead of `sections`, or
200
+ * Used older field type names (`text`, `textarea`, `dropdown`, `multiselect`, …)
201
+
202
+ you can pass them through the migration pipeline:
203
+
204
+ ```ts
205
+ import {
206
+ migrateLegacySchema,
207
+ parseReportTemplateSchema
208
+ } from "@frt/report-core";
209
+
210
+ const legacy = {
211
+ title: "Old template",
212
+ description: "Using flat fields",
213
+ fields: [
214
+ { id: "summary", type: "textarea", label: "Summary" },
215
+ { id: "status", type: "dropdown", label: "Status", options: ["Open", "Closed"] }
216
+ ]
217
+ };
218
+
219
+ const migrated = migrateLegacySchema(legacy);
220
+ const parsed = parseReportTemplateSchema(migrated);
221
+
222
+ console.log(parsed.sections.length); // 1
223
+ console.log(parsed.sections[0].fields[0].type); // "longText"
224
+ ```
225
+
226
+ You don’t normally need to call `migrateLegacySchema` yourself – `parseReportTemplateSchema` already does:
227
+
228
+ ```ts
229
+ // internally:
230
+ const migrated = migrateLegacySchema(raw);
231
+ const parsed = ReportTemplateSchemaValidator.parse(migrated);
232
+ ```
233
+
234
+ ---
235
+
236
+ ## API Overview
237
+
238
+ ### Types
239
+
240
+ ```ts
241
+ import type {
242
+ ReportTemplateSchema,
243
+ ReportTemplateSection,
244
+ ReportTemplateField,
245
+ ReportTemplateFieldType
246
+ } from "@frt/report-core";
247
+ ```
248
+
249
+ * `ReportTemplateFieldType` – union of all field type strings
250
+ * `ReportTemplateField` – one question/field in a section
251
+ * `ReportTemplateSection` – a logical grouping of fields
252
+ * `ReportTemplateSchema` – full template
253
+
254
+ ### Constants
255
+
256
+ ```ts
257
+ import {
258
+ REPORT_TEMPLATE_VERSION,
259
+ REPORT_TEMPLATE_FIELD_TYPES,
260
+ DEFAULT_FIELD_LABEL,
261
+ CORE_FIELD_DEFAULTS
262
+ } from "@frt/report-core";
263
+ ```
264
+
265
+ * `REPORT_TEMPLATE_VERSION: number`
266
+ * `REPORT_TEMPLATE_FIELD_TYPES: readonly ReportTemplateFieldType[]`
267
+ * `DEFAULT_FIELD_LABEL: string`
268
+ * `CORE_FIELD_DEFAULTS: Record<ReportTemplateFieldType, Record<string, unknown>>`
269
+
270
+ ### Validation & parsing
271
+
272
+ ```ts
273
+ import {
274
+ ReportTemplateFieldSchema,
275
+ ReportTemplateSectionSchema,
276
+ ReportTemplateSchemaValidator,
277
+ parseReportTemplateSchema,
278
+ parseReportTemplateSchemaFromString,
279
+ normalizeReportTemplateSchema,
280
+ serializeReportTemplateSchema
281
+ } from "@frt/report-core";
282
+ ```
283
+
284
+ Use the Zod schemas directly if you want:
285
+
286
+ ```ts
287
+ import { ReportTemplateSchemaValidator } from "@frt/report-core";
288
+
289
+ const result = ReportTemplateSchemaValidator.safeParse(raw);
290
+ if (!result.success) {
291
+ // handle validation errors
292
+ }
293
+ ```
294
+
295
+ ### Migration
296
+
297
+ ```ts
298
+ import { migrateLegacySchema } from "@frt/report-core";
299
+ ```
300
+
301
+ Takes `unknown` legacy input and returns a shape better suited for current schema validation.
302
+
303
+ ### Utilities
304
+
305
+ ```ts
306
+ import { createUniqueId } from "@frt/report-core";
307
+ ```
308
+
309
+ ---
310
+
311
+ ## Integration Ideas
312
+
313
+ This package is intentionally minimal. You can layer it into:
314
+
315
+ * **Next.js / React** apps for:
316
+
317
+ * Template builders
318
+ * Dynamic report forms
319
+ * Admin panels for managing report templates
320
+ * **Node/Edge backends** for:
321
+
322
+ * Validating templates on save
323
+ * Migrating old template shapes
324
+ * Ensuring consistent data before persisting to a DB
325
+
326
+ Typical pattern in a full stack app:
327
+
328
+ 1. **Frontend**:
329
+
330
+ * Build a visual editor for templates
331
+ * Send template JSON to server
332
+
333
+ 2. **Backend**:
334
+
335
+ * `parseReportTemplateSchema` to validate
336
+ * Store `ReportTemplateSchema` JSON in your DB (e.g. Mongo via Prisma)
337
+
338
+ 3. **Runtime**:
339
+
340
+ * Load templates from DB
341
+ * Use them to render dynamic forms and validate responses (you can build a separate response schema per field, if you want).
342
+
343
+ ---
344
+
345
+ ## Roadmap / Extensions (ideas)
346
+
347
+ Things you might add on top (in a separate package, e.g. `@frt/report-react`):
348
+
349
+ * React components for:
350
+
351
+ * Template builder UI
352
+ * Field editors/renderers (short text, selects, star rating, etc.)
353
+ * Response schemas built from templates
354
+ * More advanced field types:
355
+
356
+ * File uploads
357
+ * Signature pads
358
+ * Matrix / grid fields
359
+ * Multi-language labels & descriptions
360
+
361
+ The core stays simple: schema + validation + migration.
362
+
363
+ ---
364
+
365
+ ## License
366
+
367
+ MIT – use it in your projects, commercial or not. Contributions welcome.