@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 +367 -0
- package/dist/index.d.mts +350 -0
- package/dist/index.d.ts +350 -0
- package/dist/index.js +236 -0
- package/dist/index.mjs +197 -0
- package/package.json +36 -0
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.
|