nextgenSOFTWARE
SOFTWARE NEXT GENERATION

Authoring reports with Codex or another agent

Authoring reports with Codex or another agent — exampleExplore this topic with included sample inputs and engine-generated results
Open example ↗

Templates are editable JSON files, not UI state. No model-specific SDK or API key is needed. The current engine supports text, tables, embedded PNG/JPEG, parameters, flow pagination, fixed frames, page breaks and optional TypeScript events. Numeric table expressions and flow master-detail tables and horizontal/vertical grouped, stacked and percentage bar charts and categorical line charts with up to three series and a shared-scale legend and Code 39, Code 128 B, EAN-13, EAN-8, UPC-A, QR Code and Data Matrix barcodes and flow cross-tabs with up to three measures and three levels per axis are supported (see template-format.md). Do not invent inline SQL queries or credentials (use configured source IDs), unsupported chart/barcode types, general-purpose formulas or MRT compatibility.

Workflow

  1. Read the user's requested content, page format and actual data structure. Read docs/template-format.md and the schema at /schemas/report-template-v1.schema.json (also in Studio/wwwroot/schemas). The schema describes authoring structure; the engine is authoritative for cross-field constraints, bindings, text fitting and pagination.

  2. Create or edit a .nrtemplate file. Preserve unrelated fields. Keep data and parameter values in separate JSON files. Use fictional data for examples. Do not insert $schema into a template: unknown fields are rejected.

  3. Bind text with {{data.path}} / {{parameters.name}}. Table source is a data array path, and column field paths are relative to each row. Use flow tables for variable-length lists. Fixed frames use points relative to the content area of the current page and reject height overflow.

  4. Validate against a running local Studio with the client below. On nonzero exit, read the JSON error, correct the template and rerun.

  5. Inspect calculated pages in Preview and inspect exported PDF for printing. Browser SVG text placement may differ slightly from PDF rasterization. Deliver the template, sample data and requested outputs; report limitations.

    python3 scripts/report-tool.py --template samples/positioned-table.nrtemplate --data samples/positioned-table.data.json python3 scripts/report-tool.py --template samples/positioned-table.nrtemplate --data samples/positioned-table.data.json --output artifacts/preview.json python3 scripts/report-tool.py --template samples/positioned-table.nrtemplate --data samples/positioned-table.data.json --format pdf --output artifacts/report.pdf

Add --parameters parameters.json for parameter values, --base for another local endpoint. Success returns {"ok":true,"pages":1,...}; failures return {"ok":false,"error":"..."} on stderr and exit 1. No output file is touched until the server succeeds. Running without --output validates without saving.

HTTP contract

POST /api/preview and POST /api/render accept {"template":{...},"data":{...},"parameters":{...}}. Preview returns {title,pages:[{width,height,commands:[...]}]}. Commands are tagged with type=text|rect|image|line|polygon; coordinates are points; image bytes are base64; text includes its resolved style. Lines use x1/y1/x2/y2, color and strokeWidth; consumers must render them for line charts. Polygon commands contain points [{x,y},...] and fill; close the shape and use even-odd fill for circular-chart holes. PDF export returns application/pdf with X-Report-Pages. Validation failures return HTTP 400 Problem Details with a detail string. Preview validates layout; PDF export additionally validates PDF image decoding.

GET /schemas/report-template-v1.schema.json exposes the authoring schema. This is a local, unauthenticated workbench. Do not send private datasets to an external model or expose the server publicly without explicit authorization.

This foundation lets Codex create reports through files and API today. An in-app prompt assistant, MCP server and automatic template application are not implemented yet.

Portable Studio project

Create a validated bundle for the user to open with Studio's Open project:

Text
python3 scripts/report-tool.py --template samples/positioned-table.nrtemplate --data samples/positioned-table.data.json --format project --output output/example.nrproject.json

A project is UTF-8 JSON containing kind="nextgen-report-project", version=1, template, data and optional parameters. The schema is available at /schemas/report-project-v1.schema.json. The template schema remains unchanged. The CLI validates layout through the API before writing a project. Projects are limited to 8 MB and include the data, so share them deliberately.

Open project validates layout and decodes browser images before replacing the current document, then opens Preview. A rejected file leaves current edits intact. A successful import resets template-only Undo/Redo history, avoiding restoration of a previous template against unrelated data. Save project saves the current draft including unsaved edits and parameters; it does not validate layout. Use Save template when data should not be included. No server storage is used.

TypeScript authoring

Read docs/report-logic-manual.md before creating logic. Only named synchronous validateParameters, beforeRender, afterRender, dialogLoad, parameterChanged, dialogButtonClick, dialogPageChanged and dialogPageChanging handlers exist. Use /api/logic/check for types, then /api/preview with actual data/parameters. Script hosts must explicitly enable trusted scripts. For dialog drafts use DialogContext / ParameterChangedContext and return DialogUpdate; verify with /api/dialog/event. Do not invent imports, arbitrary DOM events, C# callbacks, decimal helpers or undocumented component APIs. Store source in logic.source.

For custom buttons set kind="button", action="custom" and a unique id. Use DialogButtonContext.componentId to dispatch actions and return DialogUpdate. POST /api/dialog/event uses event="dialogButtonClick" and componentId="button-id".

DialogUpdate also accepts components: { "component-id": { visible?: boolean, enabled?: boolean } }. Patches merge for the open dialog only; closing/resetting clears them. Containers propagate state to children; individual TabPage patches are not supported. Use existing unique IDs. Hidden/disabled values still undergo server validation.

Use DialogUpdate.options keyed by parameter name to replace choices of select/list/radio/checkedList controls. Values are 0–200 unique nonblank single-line strings, each at most 500 characters. Return parameters in the same patch to select new values; nonempty selections must belong to the new options. Otherwise Studio preserves valid selections and clears removed ones. Cancel discards options. Generate uses an effective template with updated options for server validation and PDF; Save project includes those choices, while Save template keeps the design.

Use dialogPageChanged(ctx: DialogPageContext): DialogUpdate for user-selected TabPage changes. ctx.componentId is the selected page ID. Initial selection, validation reveals and design previews do not execute this handler. The event notifies after selection; it cannot cancel navigation.

For step buttons, use kind: "button" and action: "next" or "back" inside a TabPage (optionally in a nested Panel/GroupBox). Navigation uses the nearest TabControl's page order. Next validates current-page browser constraints, Back preserves incomplete drafts, and boundary buttons are disabled. Direct tab selection remains available; server validation still runs on Generate.

Set sequential: true on a tabs component to require Next for forward user navigation. Add Next buttons inside intermediate pages. Back/earlier headers remain available; forward headers are re-blocked after returning. The default is false. Automatic validation reveals may open any page; this setting is not a server-side workflow or authorization boundary.

Use dialogPageChanging(ctx: DialogPageChangingContext): DialogNavigationResult to veto user tab/Back/Next navigation. Source is previousComponentId, destination is componentId; both must be distinct pages of one TabControl. Return only {cancel?: boolean, message?: string}. No patches are allowed here. Initial selection, validation reveals and design preview bypass the handler; validate final report requirements separately in validateParameters.

For nested cross-tabs use rowFields/columnFields (up to three distinct paths, outermost first). See template-format.md and samples/cross-tab-hierarchy.nrtemplate. Row labels repeat on separate lines. Set mergeColumnHeaders: true to merge column-axis parent headings across children and measures (default false); complete headers repeat on each page. Set mergeRowLabels: true for separate level columns and page-local vertical merging; parent labels repeat on continuation pages. Each label column has weight 2 and counts toward the 50-column limit. Each matrix row must fit below the header in this mode, otherwise generation fails. Optional showRowSubtotals/showColumnSubtotals (default false) add parent subtotals after their children, using source records. Count these extra column groups when checking width and the 50-column limit.

Delimited data can be imported through POST /api/data/import or scripts/import-delimited.py; see data-import.md. Preview normalized keys/types before binding them. This is a one-time conversion, not a live connector.

Standalone HTML: Studio Preview → Export HTML, report-tool.py --format html, or .html output from the .NET CLI. All pages, fonts and images are embedded. See authoring manual for workflow and limitations.

Nested table filters: filterGroup combines AND/OR subgroups with typed constants and run parameters (3 levels, 10 groups, 20 conditions). Use Use grouped filters in table properties; sample: samples/nested-filters.nrtemplate with samples/grouped-orders.data.json. See the authoring manual for steps and limits.

Calculations and conditional cell styling: samples/conditional-table.nrtemplate with samples/conditional-table.data.json demonstrates if/coalesce/isNull, numeric comparisons/logic, guarded division, parameterized discounts and ordered color rules. In Design, use column Expression and Add style rule; see the authoring manual for precedence, null behavior, priority and limits.

Repeated document sections: samples/repeated-sections.nrtemplate with samples/repeated-sections.data.json creates two complete order packs. Use Insert → Repeat section and Edit section; data/root/parent bindings, nested Flow blocks and navigation are described in the authoring manual/template format. Save/export always includes the whole report, even while editing a child section.

Text/calendar expressions: samples/text-dates.nrtemplate and matching data demonstrate inline {{= ... }} and table textExpression, strings, null fallback, number/date formatting and calendar deadlines. See the manuals for functions, contexts, ISO dates, numeric-column compatibility and limits.

Matrix barcode labels: samples/matrix-barcodes.nrtemplate and matching data create independent repeated QR/Data Matrix labels. Set symbology to qr or dataMatrix; module width determines automatic square size, QR correction uses L/M/Q/H, and optional captions wrap below the quiet zone. UTF-8 payload limit is 512 bytes. See the authoring manual/template format for print sizing and limits.

Composition charts: samples/circular-charts.nrtemplate with matching data shows pie/donut charts. Choose Chart type, Slice colors, Show percentages and Donut hole ratio in Design. Up to 12 nonnegative rows and one measure; see manuals for legends, zero data, rounding, sizing and the polygon preview command.

Static diagnostics are available through POST /api/template/check with {"template": {...}}. The response is {"diagnostics":[{"path":"$.blocks[0]", "message":"..."}]} (HTTP 200 even for template issues). Paths are zero-based; $ denotes a parse/global error. The endpoint reports the first error per invalid block, stops on global errors, and never executes scripts or validates data/layout. An empty list does not replace validation of the actual template/data pair.

For XLSX source data, use scripts/import-xlsx.py --list-sheets, then select a worksheet with --sheet and write a data JSON using --table/--output. Review warnings; --use-cached-formulas is explicit and never recalculates formulas. Validate the resulting actual template/data pair with report-tool.py as usual. See XLSX import contract.

For PNG/SVG delivery, validate the actual template/data pair with report-tool.py using --format png|svg, --first-page/--last-page and --dpi. ZIP is the default; --single-image requires a one-page selection for a standalone image. Use the correct output extension and inspect the exported artifact. SVG outlines are not searchable text. See page image export.

Office delivery

Use --format xlsx|docx --office-mode editable|pages in report-tool.py; ranges and DPI follow image export. Editable mode exports displayed text strings, not typed source cells or formulas, and omits graphics. Page mode embeds complete PNG pages. Explain these limits when delivering Office files; validate the actual input pair and inspect output. See Office export.

Interactive detail reports

Table drillDown embeds a v1 template; it is not an external subreport. Detail inputs are data.row (original selected record) and data.source (parent data after beforeRender), plus same-named inherited parameters. See Row drill-down. Validate both the parent and actual child requests: report-tool.py --drill-row 13 --drill-row 1 selects nested interactive rows using 1-based render-order indexes. Static exports use only the selected view; preserve the root project separately.

Prepare derived data without scripts

Use template dataTables for filter/sort/project/decimal-expression and grouped aggregate pipelines. Output names must be new root identifiers; later definitions may read earlier outputs. Point report blocks to these derived table names. Rules run before trusted script events; keep raw data in project data. Do not feed prepared output back into the same template. Validate the actual template/data pair with scripts/report-tool.py; --format prepared-data additionally returns the computed arrays without scripts/layout. See data-preparation.md for semantics, bounded limits, example and API contract.

HTTP source snapshots

Use connections only with host-configured source IDs. Keep URLs/headers/secrets out of templates and project files. The saved raw snapshot supports offline rendering. HTTP refresh may be explicit or opted in with refreshOnRender:true. Use report-tool.py --use-snapshot for offline validation of such projects. report-tool.py --refresh refreshes before generating/saving, while --format refreshed-data retrieves only the candidate response. Validate/render the actual updated template/data pair before delivery. See http-connections.md for bindings and limits.

SQL, JSON and object sources

See data-sources.md for all five SQL providers, JSON files, .NET object callbacks and direct POCO/JSON inputs. Connections keep only host IDs, target arrays, paths and report-parameter bindings. SQL query overrides require allowQueryEditing:true in the host catalog; credentials and file paths stay on the host. SQL uses an empty path; JSON/objects may select a nested array. Refresh previews a candidate; Apply saves the snapshot. Server generation refreshes opted-in HTTP connections; useSnapshot:true bypasses it. Validate the template against its actual saved data, including when the source is unavailable. The manual includes an offline example with total 10.00 and configured refresh to 290.00.

Host library

Validated portable projects may be saved to the host library through POST /api/library; see report-library.md. Library saves perform structural validation only, so continue to validate the actual template/data pair with report-tool before delivery. Respect expectedVersion conflicts; never automatically resubmit against a newer base. Downloaded projects remain portable and contain no library identity.

Authenticated server

Use report-tool --user NAME --password-env ENVIRONMENT_NAME for Author/Admin sessions; passwords are never command arguments. Viewer can read stored reports and generated artifacts, but cannot submit arbitrary templates. Admin schedules pin an explicit library version; updates never silently follow latest. See server-operations.md for roles, CSRF and schedule APIs.

.NET / Blazor integration

Use NextgenReports.Client for session-aware HTTP generation with JSON or .NET objects; NextgenReports.Blazor supplies an Interactive Server viewer. See the integration guide and examples/BlazorDemo. One client/cookie jar per user; Author/Admin required for POST generation. Construct a new ReportInput for edits; exports use the successful input snapshot but rerun generation. Flutter has a separate Dart/Flutter SDK; WebAssembly is not covered by the .NET SDK.

Compose report packs

Use section for independent page settings and subreports plus a subreport block for imported v1 template snapshots. See the template format for data scopes, parameter inheritance and limits. Import files into the dictionary before delivery; never invent a runtime file/URL resolver. Validate the complete combined pair with report-tool.py --template samples/composed-report.nrtemplate --data samples/composed-report.data.json. Expect four pages: cover, landscape overview, portrait order and closing page.