VeloxFactory The Basics What VeloxFactory is, how it is installed and configured, and a first look at the frontend and the API. What is VeloxFactory? VeloxFactory takes the JasperReports template format, JRXML, and puts a lightweight render engine of its own underneath it. The templates you already know, designed in Jaspersoft Studio as before, run on a slim, modern stack, render fast, and are one HTTP call away from a finished report. Around that engine sits a web application to manage and render them - via a clean frontend, a powerful REST API, or both. ๐Ÿ–ฅ๏ธ Built for the desk, usable on the move. VeloxFactory's views are optimised for desktop browsers, a resolution of 1600ร—900 or more gives the most comfortable working experience. The pages work on tablets and phones as well, which is what Scan2Print is built for: a scan station is a mobile device in the warehouse, not a workstation. Screenshot placeholder: report-config.index.png Report Config overview, the landing page after login, with context badges and thumbnails. Where VeloxFactory Fits JasperReports is a mature, battle-tested report engine. It produces high-quality PDFs, supports complex layouts, barcodes, images, and dynamic data - and it has been doing so reliably for decades. Integrating it directly requires a JVM on your server and Java code to drive it - which is a natural fit for Java stacks, but an overhead most PHP, Python, or C# teams prefer to avoid. VeloxFactory keeps the template format and replaces what runs beneath it. Its render engine is lightweight and runs in pure PHP - no JVM process required on your application server - and its capabilities are exposed via a clean REST API and a management frontend. You design your report templates in Jaspersoft Studio as usual, upload them once, and from that point on, rendering is just a POST request. POST /api/v1/report-config/A5_KanBan/render Content-Type: application/json Authorization: Bearer { "outputType": "base64", "parameters": { "P_ARTICLE_NUMBER": "4561287-154" }, "data": [...], "createHistoryRecord": true } That is the entire integration. Where It Came From VeloxFactory was built by someone with a logistics and IT background who needed a simple, reliable way to generate article labels on demand - from whatever system was running at the time, without caring about the underlying report engine. The original idea was modest: a small API wrapper around JasperReports, nothing more. It grew. A frontend to manage templates. Connection configs for live SQL data. History records for traceability. Print task dispatching, printer master data, a scan station. Mail delivery with its own mailers, templates and dispatch queue. A job scheduler, so the recurring work runs itself. A permission system. What started as "just get me a label PDF" is now a full suite, capable of enterprise integration on demand. What VeloxFactory Does At its core, VeloxFactory does six things: Manages report templates. You upload .jrxml files, and VeloxFactory analyses them automatically, detecting parameters, data fields, and image resources. Everything is stored, versioned, and ready to render. Connects to your data. VeloxFactory can execute SQL queries against live databases at render time. MySQL, MariaDB, PostgreSQL, and SQL Server are all supported. No live connection needed either - you can deliver data directly in the render request as a JSON array, which makes it equally useful for applications that already have the data in memory. Renders on demand. A single API call produces a PDF. You choose the output format - Base64-encoded inline, a file URL, or silent output for print-only flows. Rendering is synchronous and fast. Dispatches print jobs. Rendered PDFs can be forwarded directly to a print service via WebSocket, creating a traceable ReportPrintTask with status tracking. Labels off the printer, not just on the screen. Printers are maintained as master data and picked by name, and with Scan2Print a barcode scan on a phone or a handheld is enough to turn a scanned value into a printed label. Delivers by mail. A rendering can be sent straight to whoever needs it. A render request carries an optional mailing segment, and VeloxFactory sends an HTML mail through a configured mailer, using a configured template, with the PDF attached and, on request, an xlsx export of the same data. Sending is synchronous or queued, every mail is logged as a traceable ReportMailTask. Works on a schedule. Not every document has somebody waiting for it. The shift report that belongs in a mailbox at six in the morning, the weekly stock list, the cleanup that keeps the history from growing without bound: recurring work is configured as a schedule with a crontab expression, maintained in the frontend or through the API like everything else. A scheduled render is a complete render request, printing and mailing included, and every run is logged with its trace id. Who It Is For VeloxFactory is for anyone who needs to generate documents - labels, reports, delivery notes, production sheets, certificates - reliably and programmatically. The typical home is in logistics, production, and warehousing, where printing article labels, kanban cards, or shipment documents is a daily operational need and downtime is not an option. More broadly: if your application needs to produce a PDF from structured data, and you do not want to build and maintain a report engine yourself, VeloxFactory is the answer. Deployment VeloxFactory is a standard Laravel application. It runs wherever PHP runs, which is nearly everywhere. Scenario Works? Cloud VM or VPS Yes On-premise server Yes Docker container Yes Raspberry Pi on the shop floor Yes Jaspersoft Server Not needed The setup is intentionally slim. PHP 8.2 or newer, a MySQL or MariaDB database for VeloxFactory itself, and Redis for the queue that carries thumbnails, background mails and scheduled jobs, that is the stack. Two small helpers complete it: poppler-utils draws the report thumbnails, and Supervisor keeps the background processes running. The render engine and every other library come with the application and are installed by Composer. No application server, no JVM process to manage, no separate Jaspersoft infrastructure. The complete list is on Installing VeloxFactory. โ„น๏ธ Want to try it first? A live demo is available at demo.veloxfactory.dev. Login: demo@veloxfactory.dev ย ยทย  Password: demo Our Vision VeloxFactory exists because good software should not be complicated, expensive, or opaque. This page explains what we are building towards and how we think about working with the people who use it. Simple by Design The goal behind VeloxFactory has always been the same: take a powerful but complex technology and make it accessible to teams who just need it to work. Not teams with a dedicated Java architect. Not teams with a six-figure infrastructure budget. Teams with a problem to solve and a deadline to meet. That philosophy shapes every decision in VeloxFactory, from the API design to the frontend workflows. Concepts should be easy to grasp. Setup should be fast. Day-to-day use should feel obvious, even for someone who has never heard of JasperReports. Reliable and Performant Simple does not mean limited. VeloxFactory is designed to handle real production workloads - in logistics, on the shop floor, in warehouses where a label printer needs to respond in milliseconds and cannot afford to fail during a shift. The architecture reflects this. The stack is intentionally slim - no unnecessary layers, no bloat. Rendering is synchronous and fast. The application runs comfortably on modest hardware, including single-board computers deployed directly in production environments. When VeloxFactory is running, it runs. That is the expectation we build to. No Lock-In VeloxFactory is built exclusively on open-source components. There is no proprietary cloud dependency, no mandatory subscription, no remote kill switch. You run it where you want - on your own server, in your own cloud account, on a machine on your shop floor - and it stays yours. The report templates you design in Jaspersoft Studio are standard .jrxml files. The database you connect to is your own. The PDFs it produces belong to you. VeloxFactory is infrastructure you own and control, not a service you rent. Grows With You Most customers start with a single, focused use case - generating an article label, a delivery note, a production sheet. VeloxFactory handles that out of the box. But as requirements evolve, the platform grows with them. History records for traceability. Print task dispatching via WebSocket. A scan station for the warehouse floor. Mail delivery with its own templates and dispatch queue. Multi-report management with a structured permission system. API access for any system that can make an HTTP call. None of these need to be in scope on day one, but they are all there when the time comes. Beyond the built-in capabilities, VeloxFactory is extended on request. If a workflow requires something specific, it can be built in. Licenses include continued development and updates, the software does not freeze at the point of purchase. A Real Partner VeloxFactory is not sold by a faceless vendor with a tiered support portal. It is built and maintained by someone with deep hands-on experience in logistics IT, system integration, and shop floor environments, and that experience is available directly to every customer. This means practical help where it matters: rolling out the application, connecting it to existing ERP or WMS systems, adapting report templates to operational realities, and making sure the implementation actually works in the environment it needs to run in, not just in a demo. The goal is not a one-time sale. It is a long-term working relationship with customers who have real problems and need a partner who understands them. The Full Picture To put it plainly: VeloxFactory is powerful software at a reasonable price, built on open foundations, designed to be simple to operate, and backed by someone who will pick up the phone. If that sounds like what you need, welcome. Installing VeloxFactory VeloxFactory is a standard Laravel application. The setup is intentionally slim - pull the repository, install dependencies, configure the environment, migrate the database. A standard installation is up and running in under 30 minutes. What You Don't Need Before listing what is required, it is worth being explicit about what is not: No Java - the render engine is pure PHP. No JVM, no Java runtime, no Java SQL drivers. No Node.js / npm / Vite - the frontend assets are pre-built and bundled with the repository. No Jaspersoft Server - VeloxFactory is entirely self-contained. No Docker - optional for the database only, not required for the application itself. System Requirements Requirement Notes PHP >= 8.2 Required extensions: ctype, curl, fileinfo, filter, hash, mbstring, openssl, pcntl, pdo, pdo_sqlite, posix, redis, session, simplexml, tokenizer, zip, gd, xml. For report database connections, additionally: pdo_mysql (MySQL / MariaDB), pdo_pgsql (PostgreSQL). SQL Server is listed separately below. Composer PHP dependency manager - getcomposer.org MySQL or MariaDB VeloxFactory's own application database. A Docker container works fine if no local instance is available. Redis Required for the queue driver (Laravel Horizon). Install via apt install redis-server or run as a Docker container. The php-redis extension must also be installed: apt install php-redis. See Background Job Processing for details. poppler-utils Provides pdftoppm, used for generating report thumbnails. Install via apt install poppler-utils. Supervisor Keeps the three background processes running: Horizon (queue workers), Reverb (WebSocket server), and the Scheduler. See Background Job Processing for the full Supervisor configuration. SMTP access Only required for report mailing. The server has to reach the SMTP host of each configured mailer, usually on port 587 or 465. Credentials are not set up here, they are maintained as Mailers inside the application. Apache2 or nginx Optional reverse proxy. Not required for local or development setups. php-sqlsrv / pdo_sqlsrv Only required when connecting to Microsoft SQL Server as a report data source. Not needed otherwise. Bundled Dependencies The following components are bundled with VeloxFactory, no separate installation required: Component Purpose VeloxFactory render engine Pure PHP render engine, our maintained fork of JasperPHP - parses .jrxml and generates PDFs via TCPDF. Installed automatically by Composer. Laravel Horizon Redis-backed queue manager with built-in dashboard. Manages worker pools for thumbnail generation, background mail dispatch and the nightly purge jobs. Installed automatically by Composer. PhpSpreadsheet Builds the xlsx export that a report mailing can attach next to the PDF. Needs the PHP extensions zip, gd and xml. Installed automatically by Composer. Log Viewer In-browser Laravel log viewer for monitoring application logs. Scribe Generates the interactive API documentation from source annotations. Material Design Icons Icon set used throughout the frontend. Ace Editor In-browser code editor for writing SQL queries. Logo & Color Concept Visual identity by sinister-labs. Jaspersoft Studio 6.21.5 Desktop IDE for designing .jrxml report templates. Installed separately on the designer's machine, not on the server. Download here. First Setup php artisan setup:base prepares the storage folders and creates the administrator admin@veloxfactory.dev. Its password is generated at random and printed to the console exactly once, it is not stored anywhere in clear text. Copy it down. The first sign-in forces a password change before anything else in the instance is usable. Nothing below storage is executed Rendered documents, report templates and resource files are served as static files from storage/app/public. The web server must never execute anything in that directory. The repository ships storage/app/public/.htaccess for Apache; add the matching directive to your virtual host: php_admin_flag engine off Options -Indexes -ExecCGI AllowOverride All For nginx: location ^~ /storage/ { location ~ \.(php|phar|phtml)$ { deny all; } add_header X-Content-Type-Options "nosniff" always; } Administrative routes The Log Viewer is reachable at admin/log-viewer (configurable through LOG_VIEWER_ROUTE) and requires global:admin. The API reference generated by Scribe is at /docs and requires global:use-api. Deployment Options VeloxFactory can be deployed in two ways: self-hosted on your own infrastructure, or fully managed and operated by kiwi software. Both options deliver identical functionality, the choice depends on your team's operational preferences and existing infrastructure. Self-Hosted You run VeloxFactory on your own servers. The infrastructure footprint is intentionally small - no Java runtime, no application server, no container orchestration required. A single modest Linux VPS covers all but the most demanding workloads. Component Minimum Recommended Notes VeloxFactory server (Linux) 1 vCPU, 1 GB RAM 2 vCPU, 4 GB RAM A Hetzner CX22 (2 vCPU, 4 GB RAM, 40 GB NVMe) is more than sufficient for most deployments. Any comparable entry-level VPS or on-premises Linux server works equally well. Disk 10 GB 40 GB Application and report thumbnails. Scale with report volume and history retention period. VeloxFactory Print Service (Windows) Windows 10/11 or Windows Server 2019 or newer, x64, .NET 10 Desktop Runtime, with the target printers installed Runs headless from the Windows Task Scheduler under its own service account, with an optional window for setup and monitoring. Low memory and CPU use; in most deployments an existing Windows PC on the shop floor or in the office serves as the print host. No dedicated hardware required. See Installation and updates. โ„น๏ธ MySQL and VeloxFactory can share the same VM for small to medium deployments. A dedicated database server is only worth considering when multiple VeloxFactory instances share one database, or under very high render throughput. Managed Hosting If you prefer not to manage infrastructure yourself, VeloxFactory can be hosted and operated for you. Instances run exclusively in Germany on Hetzner hardware - reliable, fast, and GDPR-compliant by location. Updates, monitoring, and backups are handled on your behalf. Managed hosting works well for most use cases. Depending on your network connection to the hosting location, render requests may see slightly higher latency compared to a locally deployed instance, typically not noticeable, but worth considering for high-frequency, latency-sensitive workloads such as real-time label printing on the shop floor. For managed hosting enquiries, get in touch directly. Configuration and data models VeloxFactory is built around a small set of interconnected models. Understanding them is the key to understanding everything else, from how reports are set up, to how renderings are stored, to how print jobs and mails are dispatched, to how recurring work is scheduled. Field Naming Conventions VeloxFactory uses two naming styles consistently throughout the system. Database columns and Laravel model attributes are always snake_case, for example broadcast_id, report_config_id, created_by_token_id. The API and frontend use camelCase for all request and response fields, the same fields become broadcastId, reportConfigId, createdByTokenId. This split is consistent without exception: whenever you are working with the API or the frontend, use camelCase. Whenever you are looking at raw database records, migration files, or server-side model attributes, expect snake_case. Throughout this documentation, all field names and JSON examples follow the API convention: camelCase. The Model Hierarchy Every piece of data in VeloxFactory fits into a clear hierarchy. At the top sits the ReportConfig, the central entity. Everything else either belongs to it, describes it, or records what happened when it was used. ReportContext โ† Organisational label for grouping reports ReportConnectionConfig โ† Optional live database connection ReportConfig โ† The report template + all its metadata โ”œโ”€โ”€ ReportParameter โ† Input values passed at render time โ”œโ”€โ”€ ReportField โ† Output columns from the SQL query or data payload โ””โ”€โ”€ ReportResource โ† Graphic file asset (image, logo) โ””โ”€โ”€ (links to) CommonReportResource โ† Shared asset, used by reports and mails ReportHistoryRecord โ† Record of a past rendering (optional) โ”œโ”€โ”€ ReportPrintTask โ† A print job dispatched from a history record โ”‚ โ””โ”€โ”€ (uses) Printer โ† Master data of the target printer โ””โ”€โ”€ ReportMailTask โ† A mail dispatched from a history record โ”œโ”€โ”€ (uses) Mailer โ† SMTP account the mail is sent through โ”œโ”€โ”€ (uses) MailTemplate โ† Subject and body of the mail โ””โ”€โ”€ (embeds) CommonReportResource โ† Graphics placed in the mail body ScheduledJob โ† A scheduled job: a render request, or the cleanup โ”œโ”€โ”€ (renders) ReportConfig โ† Render jobs only โ”œโ”€โ”€ (runs as) User + PersonalAccessToken โ† Owner and token a render job authenticates with โ”œโ”€โ”€ (notifies via) Mailer โ† Mailer the failure mail is sent through โ””โ”€โ”€ ScheduledJobRun โ† Record of one execution, with trace id and result Three of these are master data: Printer, Mailer and MailTemplate are maintained once under Configuration and then picked by name whenever a rendering is printed or mailed. They exist independently of any report. ReportContext A context is a visual label you assign to report configurations to group and identify them at a glance. It carries no functional logic, it is purely organisational. Field Description context_name Display name of the context context_description Short description context_text_color Hex color for the label text context_badge_color Hex color for the badge background context_border_color Hex color for the badge border Every ReportConfig requires a context. A single context can be shared across any number of report configurations. ReportConnectionConfig A connection config represents a live database connection that VeloxFactory can use as a data source when rendering a report. When assigned to a ReportConfig, VeloxFactory executes the report's SQL query against this connection at render time and feeds the result rows into the report as field data. Field Description connection_name Friendly name for this connection connection_driver Database driver (see table below) connection_host IP address of the database server connection_port Port (required) connection_database Database / schema name connection_username Username (stored encrypted) connection_password Password (stored encrypted) connection_test_query SQL query used to verify the connection connection_tested Whether the connection has been successfully tested Supported drivers: Driver Database mysql MySQL mariadb MariaDB pgsql PostgreSQL sqlsrv Microsoft SQL Server Connection status is derived from connection_tested: Status Meaning approved Connection has been tested successfully unapproved Never tested or last test failed โš ๏ธ A report can only be rendered with a live connection if its status is approved. VeloxFactory will reject render requests for reports whose connection has not been successfully tested. Network Requirements VeloxFactory establishes the database connection directly from the server it runs on. The target database must therefore be reachable from that host, ideally within the same network or at minimum via a secured private channel. โš ๏ธ Do not expose your database to the public internet. Configuring a publicly accessible database (or opening firewall ports to make one reachable) is a significant security risk and is strongly discouraged. If VeloxFactory and your database run in separate networks, use an encrypted VPN tunnel instead: WireGuard or OpenVPN are both well-suited for this purpose. When is a ReportConnectionConfig needed? A ReportConnectionConfig is optional per ReportConfig. Whether you need one depends on how your report gets its data: Scenario Connection needed? Report has no detail band (purely static layout) No Report has a detail band, data delivered via API at render time No Report has a detail band and fetches data via SQL Yes ReportConfig The ReportConfig is the core entity of VeloxFactory. It represents a single JasperReports template (the .jrxml file) together with all the metadata VeloxFactory maintains about it. Field Description report_name Display name of the report report_description Optional description report_file_name Internal filename of the stored .jrxml report_width Page width in mm (extracted from the .jrxml on upload) report_height Page height in mm (extracted from the .jrxml on upload) report_query SQL query, defined in VeloxFactory and stored in the database report_has_detail_band Whether the template contains a detail band (extracted on upload) report_context_id FK โ†’ ReportContext report_connection_config_id FK โ†’ ReportConnectionConfig (nullable) report_preview_base64 Base64-encoded preview image report_thumbnail_base64 Base64-encoded thumbnail image โ„น๏ธ The SQL query is not defined in the .jrxml file. It is written and managed directly in VeloxFactory and stored in the database as part of the ReportConfig. The .jrxml only defines which fields the query result maps to. When a .jrxml file is uploaded, VeloxFactory automatically analyses it and creates the associated ReportParameter, ReportField, and ReportResource records. You then review and complete the auto-generated data, for example setting example values or uploading resource files. ReportParameter Parameters are the inputs passed into a report at render time: dates, IDs, filter values, flags, and so on. Field Description parameter_name Parameter name as defined in the .jrxml parameter_data_type Java class name (e.g. java.lang.String, java.lang.Integer) parameter_required Read from the required custom property in the .jrxml parameter_evaluation Evaluation time, extracted from the .jrxml parameter_example_value Read from the exampleValue custom property in the .jrxml Both parameter_required and parameter_example_value are sourced from custom properties embedded in the .jrxml parameter definition. They can also be set manually in VeloxFactory after upload. Three parameter name prefixes carry meaning beyond the render itself: Prefix Meaning P_RESOURCE_ The parameter holds a graphic file asset, VeloxFactory creates a ReportResource for it P_SCAN_ The parameter is filled by a barcode scan in Scan2Print P_STATIC_ The parameter is preset once per Scan2Print session and stays untouched between scans P_SCAN_ and P_STATIC_ are what makes a report usable in Scan2Print. Everything else about the report stays the same, the prefixes are a convention, not a separate model. ReportField Fields represent the data columns that populate the report's detail band, either from an SQL query result or from a data array delivered at render time. Field Description field_name Field name as defined in the .jrxml field_data_type Java class name (e.g. java.lang.String, java.math.BigDecimal) field_example_value Read from the exampleValue custom property in the .jrxml field_example_value is used when rendering a preview without a live database connection. ReportResource Resources are graphic file assets (images and logos) embedded in the report template. They are referenced in the .jrxml via parameters following the P_RESOURCE_ naming convention. Field Description parameter_name The P_RESOURCE_ parameter name as referenced in the .jrxml resource_file_name Filename of the directly uploaded file (nullable) common_report_resource_id FK โ†’ CommonReportResource (nullable) A ReportResource either holds its own uploaded file or it is linked to a CommonReportResource, never both at the same time. When linking to a common resource, the resource's own file is deleted and the common file is used in its place. CommonReportResource A CommonReportResource is a shared graphic asset (a company logo, a standard header image) that multiple report configurations can reference. Instead of uploading the same file to each report individually, you upload it once and link individual ReportResource records to it. Field Description resource_name Display name, unique, and at the same time the placeholder token used in a mail body resource_description Optional description resource_file_name Internal filename of the stored file resource_mime_type Detected mime type, filled on upload resource_width / resource_height Pixel dimensions, read from the file resource_display_width Optional width the graphic is rendered with in a mail resource_alt_text Alternative text for the mail graphic A common resource serves two purposes. In a report it is the file behind a P_RESOURCE_ parameter. In a mail template it is an inline graphic: the body references it by [image.], and at send time the file is embedded into the mail itself, not linked from a server. A resource is mail capable when it is a real PNG or JPEG with readable dimensions, which is why the name has to be unique. โ„น๏ธ Linking is a one-way action. When a ReportResource is linked to a CommonReportResource, its own file is permanently deleted. Unlinking removes the reference but does not restore the file, you will need to re-upload it. ReportHistoryRecord A ReportHistoryRecord captures the full context of a rendering: what was requested, what was returned, and whether it succeeded. Creating a history record is optional and controlled by the createHistoryRecord flag in the render request. Field Description report_config_id FK โ†’ ReportConfig trace_id Unique identifier for this rendering run output_type How the PDF was returned (see below) report_api_payload The exact request payload sent to the render call report_api_response The full API response, stored for traceability report_pdf_base64 Base64-encoded PDF content report_pdf_file_name Filename of the PDF on disk report_excel_file_name Filename of the xlsx export on disk, written when a mailing asked for one (nullable) report_thumbnail_base64 Base64-encoded thumbnail of the first page (generated asynchronously) status Outcome of the rendering (see below) Output types ( output_type): Value Description base64 PDF returned inline as a Base64 string url PDF stored as a file, a URL is returned preview Rendered for preview; file is not persisted none No PDF output (used for print-only flows) Status values ( status): Value Description ok Rendering succeeded, PDF received render_fail No errors reported, but no PDF received error JasperReports returned one or more errors unknown Status cannot be determined History records are retained for a configurable number of days, set as a retention on the Purge Job. Thumbnails are generated asynchronously after rendering completes. Deleting a history record removes its PDF and its xlsx from disk together with the record. ReportPrintTask A ReportPrintTask represents a print job dispatched to a physical printer. It is always linked to a ReportHistoryRecord, you always print a specific past rendering, not a report config directly. Field Description report_config_id FK โ†’ ReportConfig report_history_record_id FK โ†’ ReportHistoryRecord printer_id FK โ†’ Printer (nullable, set when the printer was picked from the master data) trace_id Unique identifier for this print run broadcast_id WebSocket channel ID for real-time status updates (nullable) printer_name Target printer name copies Number of copies to print output_file_name Filename of the PDF sent to the printer output_base64_string Base64-encoded PDF (consumed by the print service) error_message Error detail if printing failed status Current print status (see below) Status values ( status): Value Description pending Created, waiting for the print service printed Successfully printed and confirmed error Printing failed unknown Status cannot be determined โ„น๏ธ Real-time updates via WebSocket only apply when broadcastId is provided in the render request. The C# print service subscribes to that channel, picks up the task, executes the print job, and reports status back. Without a broadcastId, the task is created silently, the print service must poll for new tasks. Printer A Printer is master data for a physical printer. A printer is configured once and then picked from a list, so nobody has to know the exact queue name of the print server by heart. Field Description printer_display_name The name people see, for example Warehouse Label 01. Unique, 3 to 50 characters printer_name The queue name on the print server, for example WH-LABEL-01. This is what the print service receives. Unique printer_type label-printer, a4-printer, mfc-printer or digital-printer. Descriptive, it drives icon and filter printer_location Where the machine stands, for example Hall 2, Shipping (nullable) printer_broadcast_id WebSocket channel of the print service instance that serves this printer (nullable) printer_description Free note, for example the loaded media (nullable) printer_is_active Inactive printers keep working in existing configurations but are no longer offered in pickers The master data is a convenience, not a requirement. A render request may name a printer by its display name or by its queue name, VeloxFactory resolves both and fills in the broadcast channel. A name that matches no master data record is passed through to the print service unchanged, so an integration can route straight to any queue of the print server by its name, without a Printer record. Mailer A Mailer is master data for one SMTP account. It is to mailing what a ReportConnectionConfig is to data: the credentials live in one place, are tested from the UI, and are then referenced by name. Field Description mailer_name Unique name used to reference the mailer in a request mailer_transport Transport, smtp by default mailer_host / mailer_port SMTP server and port mailer_scheme smtp, smtps or empty for the transport default mailer_username / mailer_password Credentials, stored encrypted mailer_from_address / mailer_from_name Sender of every mail sent through this mailer mailer_reply_to Optional reply-to address mailer_timeout / mailer_local_domain Optional transport details mailer_rate_limit_per_minute Max mails per minute, empty means the window is not enforced mailer_rate_limit_per_hour Max mails per hour, 500 by default mailer_rate_limit_per_day Max mails per day, empty means the window is not enforced mailer_is_active Inactive mailers are not offered and are refused by the API mailer_tested Whether a test mail has been sent successfully mailer_description Free note โ„น๏ธ The three rate limit windows are independent and all have to allow a send. Providers cap differently: Office 365 counts per minute, most hosters per hour, Gmail per day. A blocked send is not lost, it is queued and goes out when the window opens. The global MAIL_* variables of Laravel are not used by the mailing pipeline. Every mail goes through a Mailer record, registered as a runtime mail connection for the duration of the send and removed again afterwards, exactly the way a ReportConnectionConfig handles its database connection. MailTemplate A MailTemplate holds the subject and the body of a mail, both written once and filled with placeholders at send time. Field Description mail_template_name Unique name used to reference the template in a request mail_template_subject Subject line, placeholders allowed mail_template_body_html HTML body, written in a rich text editor, placeholders allowed. Buttons and callouts are stored as data-mail-button and data-mail-callout markers mail_template_header_color Optional override of the header bar colour, also used for table headers, the default button background and the Info callout border mail_template_header_line_color Optional override of the colour of the line beneath the header mail_template_hide_header_line Hides the line beneath the header mail_template_body_color Optional override of the body background mail_template_hide_logo Hides the logo in the header mail_template_logo_resource_id FK โ†’ CommonReportResource, an own logo for this template (nullable) mail_template_footer_text Optional override of the global footer text, placeholders allowed mail_template_is_active Inactive templates are not offered and are refused by the API mail_template_description Free note Placeholders use the [token] syntax and cover the render ( [traceId], [reportFileName]), the report, the history record, the user, the API token, the printer, every parameter ( [parameters.]), the data rows ( [data.first.]), the current time ( [now.date]), the recipients and the graphics ( [image.]). The full catalog is available in the editor. An unknown token resolves to an empty string and is reported, it never fails a mail. The whitelabel fields are each an override of a global default. Left empty or off, the mail uses the theme colours read from the application's own stylesheet, a dark header bar with a line in the primary colour beneath it, so a mail looks like the application without anything being configured twice. ReportMailTask A ReportMailTask represents one mail. Like a ReportPrintTask it belongs to a ReportHistoryRecord, you always mail a specific past rendering. Field Description report_history_record_id FK โ†’ ReportHistoryRecord (nullable if no history record was created) mailer_id FK โ†’ Mailer mail_template_id FK โ†’ MailTemplate trace_id Unique identifier for this mail run recipients_to / recipients_cc / recipients_bcc Resolved address lists mail_subject The rendered subject, placeholders already resolved mail_body_html The rendered body, stored so the UI can show what was actually sent attachment_pdf_file_name The PDF on the history disk, always .pdf attachment_excel_file_name The xlsx on the history disk, always .xlsx attachment_pdf_name The name the PDF carries as an attachment of the mail attachment_excel_name The name the xlsx carries as an attachment of the mail send_async Whether the mail was queued instead of sent synchronously dispatch_after Set when the rate limit pushed the send into the future sent_at Timestamp of the successful send error_message Error detail if sending failed status Current mail status (see below) Status values ( status): Value Description pending Created, not sent yet, or waiting for a rate limit window sent Handed over to the SMTP server successfully error Sending failed unknown Status cannot be determined โ„น๏ธ A mail task never owns a file. The PDF and the xlsx belong to the history record, stay downloadable from it and are deleted with it. The two attachment name columns only say what the files are called inside the mail. Mail tasks have their own retention on the Purge Job, independent of the history records. The address columns hold what was actually used: a recipient given as a placeholder is stored resolved, so the mail task shows the addresses the mail went to. ScheduledJob A ScheduledJob is one scheduled job: either a render request, or the consolidated cleanup that keeps the database and the disk from growing without bound. Both live in the same table and differ in their type and their payload. Either kind fires on a crontab expression or once at a fixed date and time. Field Description schedule_name Display name, unique schedule_description Optional description schedule_type render or purge schedule_cron Five-field crontab expression. Empty means the schedule never fires on its own and can only be run manually schedule_timezone Timezone the expression and the single date are evaluated in. Empty means the application timezone schedule_run_at Date and time of a single run. Set in place of a cron expression, never beside one schedule_deactivate_after_run Whether the schedule sets itself inactive once its single run is done schedule_is_active An inactive schedule is never dispatched report_config_id FK โ†’ ReportConfig, render jobs only schedule_payload JSON. Render jobs: the render request body. Purge jobs: the retention map owner_user_id FK โ†’ User, the user a render job runs as owner_token_id FK โ†’ PersonalAccessToken, the token a render job authenticates with error_mailer_id FK โ†’ Mailer, the mailer the failure mail goes through (nullable) error_recipients_to / error_recipients_cc / error_recipients_bcc Address lists of the failure mail, plain addresses without placeholders schedule_last_run_at When the schedule last fired schedule_next_run_at When it fires next. Indexed, this is what the minute tick selects on. Empty once a single run has happened schedule_last_status Status of the most recent run โ„น๏ธ The owner and the token are references, not copies. Both are foreign keys with a delete restriction, so a user or a token that a schedule runs with cannot be removed while the schedule exists. A revoked token or a deactivated owner does not delete anything, it parks the schedule and is recorded as a skipped run. A purge job carries its retentions in schedule_payload, one key per step: printTaskDays, mailTaskDays, historyDays, orphanedFileDays and runLogDays. A key set to null switches its step off. ScheduledJobRun A ScheduledJobRun is the record of one execution. It belongs to its schedule and is deleted with it. Field Description scheduled_job_id FK โ†’ ScheduledJob, cascading delete trace_id Identifier of this run, the same id the rendering and its mail carry status Outcome of the run (see below) trigger schedule for a run the cron fired, manual for Run now started_at /ย  finished_at / duration_ms Timing of the run run_as_user_id The user the run authenticated as, kept even after the schedule's owner changed report_history_record_id FK โ†’ ReportHistoryRecord the run produced (nullable) response_status HTTP status the internal render call answered with result_summary JSON summary: what a render returned, or how many records each purge step deleted error_message Error detail if the run failed error_mail_sent Whether a failure mail went out for this run error_mail_suppressed How many failure mails the throttle held back Status values ( status): Value Description running The run started and has not finished yet success Everything the run was asked to do went through warning The main work succeeded, something attached to it did not, for example the mail error The run failed skipped The run was not executed, for example because the owner is inactive or the token revoked โ„น๏ธ The history record is referenced, never owned. report_history_record_id is nulled when the record is deleted, so the history retention stays free to clean up what a run produced. The run log itself is cleaned up by the Purge Job. User The account a person or an integration signs in with. Only the field that governs the first sign-in is listed here, the permissions themselves are described in Meet the frontend. Field Description password_change_required Set when an account must change its password before it can use the instance. setup:base sets it on the administrator it creates Audit Trail Every model in VeloxFactory tracks who created and last updated a record, and which API token was used. This information is available on all records via the withAudit=true query parameter in the API. Field Description created_at Timestamp of creation created_by User ID of the creator created_by_token_id API token ID used (if created via API) updated_at Timestamp of last update updated_by User ID of the last updater updated_by_token_id API token ID used (if updated via API) The creationMethod and updateMethod fields in the API response ( "Frontend" vs. "API") are derived automatically, based on whether a token was present on the request. Security Log Alongside jobs, VeloxFactory writes a security channel to storage/logs/security/, kept for 90 days. It records sign-ins and failed attempts, sign-outs, password changes, permission changes and the creation and revocation of API tokens. Environment Configuration VeloxFactory's runtime behaviour is controlled via environment variables in .env or as container environment variables. Application Variable Default Description APP_SCHEME http URL scheme for generated links ( http or https) API_RATE_LIMIT_PER_MINUTE 10 Max API requests per minute per token PAGINATION_DEFAULT_COUNT 25 Rows per page in the lookups of the frontend API_PER_PAGE_DEFAULT 25 Records per page of an API list endpoint when the request sends no perPage API_PER_PAGE_MAX 100 Largest perPage an API list endpoint accepts, a larger value is answered with 422 Security Variable Default Description SANCTUM_EXPIRATION 525600 Lifetime of an API token in minutes, one year by default. Applies to tokens that already exist DB_TRUST_SERVER_CERTIFICATE false Accept a self-signed certificate on a report database. Only for closed networks DB_ENCRYPT true Encrypted connection to the report database OUTBOUND_HOST_ALLOWLIST empty Comma separated hosts that Report Connection Configs and Mailers may point at. Empty means everything except loopback and link-local LOG_VIEWER_ROUTE admin/log-viewer URL path of the Log Viewer Queue & Redis Variable Default Description QUEUE_CONNECTION database Queue driver (must be set to redis for Horizon) REDIS_CLIENT phpredis Redis client library ( phpredis required) REDIS_HOST 127.0.0.1 Redis server hostname or IP REDIS_PORT 6379 Redis server port REDIS_PASSWORD null Redis password (leave null if not set) REDIS_QUEUE_RETRY_AFTER 360 Seconds before a reserved job on the redis connection is handed to another worker. Must stay above the longest worker timeout REDIS_SCHEDULER_QUEUE_RETRY_AFTER 1860 The same for the redis-scheduler connection, which carries the long-running scheduled jobs Horizon Variable Default Description HORIZON_PATH horizon URL path for the Horizon dashboard HORIZON_PREFIX derived from APP_NAME Redis key prefix for all Horizon data HORIZON_DOMAIN - Optional custom domain for the Horizon dashboard Job Scheduler Variable Default Description SCHEDULER_CATCHUP_GRACE_MINUTES 60 A due run older than this is dropped instead of fired late, for example after the scheduler process was down SCHEDULER_RUN_LOCK_SECONDS 1800 How long one run may hold its schedule's lock before another run may start SCHEDULER_ERROR_MAIL_THROTTLE_MINUTES 60 At most one failure mail per schedule within this window SCHEDULER_PREVIEW_COUNT 5 How many upcoming run dates the cron preview shows PURGE_SCHEDULER_RUNS_DAYS 90 Retention of the run log, written into the Purge Job when it is created Mailing Variable Default Description MAIL_LOGO_RESOURCE - Name of a mail capable CommonReportResource, embedded inline in the mail header MAIL_LOGO_URL - Fallback used when MAIL_LOGO_RESOURCE is empty: an absolute, publicly reachable URL. Empty falls back to the application name as text MAIL_FOOTER_TEXT Sent automatically by VeloxFactory. Footer of every mail, overridable per template MAIL_RATE_LIMIT_PER_MINUTE 0 Default minute limit for a newly created mailer. 0 means not enforced. MAIL_RATE_LIMIT_PER_HOUR 500 Default hour limit for a newly created mailer MAIL_RATE_LIMIT_PER_DAY 0 Default day limit for a newly created mailer MAIL_THROTTLE_FALLBACK_TO_QUEUE true A throttled synchronous send is queued instead of answered with an error MAIL_MAX_ASSET_SIZE_KB 2048 Maximum size of a graphic that can be embedded into a mail The standard Laravel MAIL_* keys stay untouched. They are the framework fallback and are not used for report mails. Retention & Purge The retentions themselves live on the Purge Job, where they are edited in the frontend or through the API. These variables supply the values the Purge Job is created with, which makes them the right place to preconfigure an instance before it is set up. Changing one afterwards has no effect on an existing schedule. Variable Default Description PURGE_HISTORY_DAYS 30 Age in days after which history records are deleted. -1 creates the step switched off. PURGE_PRINTTASKS_DAYS 30 Age in days after which print tasks are deleted. -1 creates the step switched off. PURGE_MAILTASKS_DAYS 30 Age in days after which mail tasks are deleted. -1 creates the step switched off. PURGE_ORPHANED_FILES_DAYS 30 Age in days after which orphaned files on disk are deleted. -1 creates the step switched off. Meet the frontend VeloxFactory comes with a built-in web frontend that gives you full access to every feature without writing a single line of code. It is built with Laravel Livewire, a reactive framework that delivers a dynamic, app-like feel while keeping everything server-rendered. No separate JavaScript build, no SPA complexity. Screenshot placeholder: report-config.index.png Report Config overview, the landing page after login, with context badges and thumbnails. Navigation After logging in you land directly on the Report Configs overview, the central workspace. Dedicated scan users without edit rights for report configurations land on Scan2Print instead. All other sections are reachable from the main navigation. Section What you manage here Report Configs Your report templates, the heart of VeloxFactory Report History Records Every past rendering with status, payload, and PDF Report Print Tasks Print jobs dispatched to the print service Mail Queue Every mail that was sent or is waiting to go out, see Report Mailing Job Scheduler Recurring renders and the cleanup run, plus the log of every run, see The Job Scheduler Scan2Print Mobile scan station that turns every barcode scan into a print job, see Scan2Print: Printing labels by scanning Report Contexts Organisational labels and visual tags for reports Report Connection Configs Live database connections for SQL-driven reports Common Report Resources Shared graphic assets, used by reports and as inline graphics in mails Printers Master data for your physical printers, see Printers Mailers Master data for your SMTP accounts, see Mailers Mail Templates Subject, body and whitelabeling of your mails, see Mail Templates Users User accounts and API token management The last seven entries are grouped under Configuration in the main navigation. They are master data you set up once and then pick by name everywhere else. The Lookup Pattern Every section opens with a list view, powered by a Livewire Lookup component. These views work the same way across all sections, so once you know one, you know them all. Screenshot placeholder: report-config.index.filtered.png Report Config overview with the filter bar open and active filter badges. Full-Text Search A search bar at the top filters records instantly as you type, no page reload, no submit button. Depending on the section, the search covers names, descriptions, file names, and query text. Column Filters Each list view offers contextual filter dropdowns tailored to the entity. For Report Configs, for example, you can filter by Context, Data Adapter, Creator, or date ranges for creation and last update. Active filters are indicated by a badge count on the respective dropdown so you always see at a glance which filters are in play. Pagination Results are paginated. The default page size is controlled by the PAGINATION_DEFAULT_COUNT environment variable (default: 25). See Configuration and Data Models for all available environment settings. Persistent Filters and Paging Every list view remembers its state. The search term, all column filters (checkboxes, dropdown selections, date ranges) and the current page are stored in your session as soon as you change them. You can open a record, switch to another section and come back later, the list shows exactly the same filters and the same page as before. The state is kept separately for each list view. Filters set on History Records do not affect Report Configs or any other section. To start over, click the reset button of the respective list view, the dark button with the curved arrow icon between the search bar and the green Filter button. It clears the search term and all filters of this view and returns to the first page. All other views keep their filters. โ„น๏ธ Filters are stored per user session. They survive page reloads and navigation, but are cleared on logout or when the session expires. Filters are never shared with other users or other browser sessions. Working with Report Configs The Report Config section has the richest set of actions and is where most of your day-to-day work happens. Screenshot placeholder: report-config.edit.png Report Config edit view with parameters, fields and resources. Uploading a Template Report templates are designed in Jaspersoft Studio (compatible version: 6.21.5) and exported as .jrxml files. Once you have a .jrxml ready, you upload it to VeloxFactory to create a new Report Config. VeloxFactory immediately analyses the file and automatically creates all associated Parameters, Fields, and Resources, based on what is defined in the template. You do not need to add these manually. After upload you review the auto-generated records: set example values where missing, assign a Data Adapter if the report uses SQL, and upload any resource files that were detected. Managing Parameters, Fields, and Resources Parameters, Fields, and Resources each have their own section within the Report Config edit view. You can edit example values, mark parameters as required, upload resource files, or link a resource to a Common Report Resource, all from the same screen. Screenshot placeholder: report-resource.edit.png Report Resource edit view with the file upload and the link to a Common Report Resource. Generating Previews Once all example values are set and all resource files are uploaded, you can generate a preview rendering directly from the edit view. VeloxFactory renders the report using the stored example values and stores the result as a preview image and thumbnail on the Report Config. Rendering from the Frontend You can trigger a full render directly from the frontend, without touching the API. A render dialog lets you fill in parameter values, choose an output type, and optionally dispatch a print job or a mail in the same step. The result is shown inline and logged as a History Record if desired. Screenshot placeholder: generate-pdf.create.png Generate PDF page with the parameter inputs and the output settings. Report Connection Configs When creating or editing a Connection Config, the form includes a Test Connection button. Use it before saving, a connection must be in status approved before VeloxFactory will use it for rendering. An untested or failed connection will cause render requests to be rejected. Screenshot placeholder: report-connection-config.edit.png Report Connection Config edit form with the Test Connection button. Report History Records The History Records section gives you a full log of every rendering that was saved. For each record you can see the status, the exact parameters and data that were submitted, the raw JasperReports response, and, if the rendering succeeded, the resulting PDF. From a History Record you can: Download the PDF directly to your browser, and the xlsx export if the record has one Trigger a print job, creates a new Print Task for this specific rendering and dispatches it to the print service Send it by mail, opens a dialog for mailer, template, recipients and attachments and creates a new Mail Task Screenshot placeholder: report-history-record.show.png Report History Record detail page with status, payload, PDF preview and the actions. โ„น๏ธ Downloads follow the read permission. Downloading a rendered PDF, an xlsx export, a report template or a resource file requires the read permission for that resource. Being signed in is not enough. Report Print Tasks The Print Tasks section shows all dispatched print jobs and their current status. For each task you can inspect the target printer, number of copies, and any error messages if printing failed. If a task ended up in error state, you can reset it, the task returns to pending and the print service will pick it up again. Screenshot placeholder: report-print-task.index.png Report Print Task overview with status badges, printer and the reset action. Mailing A rendered document can be mailed as well as printed. Three sections work together, and all three behave like every other list view described above. Mailers hold your SMTP accounts: host, port, credentials, sender address and the dispatch rate limits. The form has a Test Mailer button and a Send test mail action, the same idea as Test Connection on a Connection Config. A mailer has to be active before it is offered anywhere. Mail Templates hold subject and body. The body is written in a built-in rich text editor, so no HTML knowledge is needed. A button opens the placeholder catalog, a searchable table of every token the template can use, each one copyable with a click. A preview shows the finished mail exactly as a recipient will see it, including the colours and the logo, which can be overridden per template. Mail Queue lists every mail task with recipients, subject, attachments, mode and status. Opening one shows the mail that was actually sent, rendered in place. From there a mail can be repeated: a dialog lets you correct the mailer or the recipients before it goes out again, so a mail sent to the wrong address is fixed rather than cloned. Screenshot placeholder: mail-template.edit.png Mail Template edit view with the rich text editor, the placeholder button and the whitelabel toggles. Mailing itself is never configured here. It is requested per rendering, in the Generate PDF page, in the Scan2Print settings, in the mail dialog of a History Record, in a render job of the Job Scheduler, or in the mailing segment of a render request. The three sections above only provide the building blocks. Screenshot placeholder: mailing.history-record-modal.png The mail dialog of a Report History Record with mailer, template, recipients and attachments. โ„น๏ธ Full detail is on the dedicated pages: Report Mailing, Mailers and Mail Templates. Scheduling Work that repeats has its own section. Job Scheduler lists every schedule with its type, its crontab expression, the next and the last run, and how that run ended. A Run Log button opens the full history of every run of every schedule, each with its trace id. Creating a schedule starts with the type, a render job or the cleanup run, and the form follows from there. The expression is entered either in a guided mode with frequency, time and weekday pickers or as plain crontab syntax; both write the same field, and the next five run times are shown while you type. A render job additionally takes the report, an API token, the output and print settings, and the same parameter and data row tables as the Generate PDF page, here with a switch per field for entering a placeholder such as [now.date] instead of a fixed value. Run now starts a schedule immediately without moving its next slot, which is how a new one is tried before it is switched on. Screenshot placeholder: scheduler.overview.png The Job Scheduler overview with type, cron expression, next run, last run and status per schedule. โ„น๏ธ Full detail is on the dedicated pages: The Job Scheduler, Render Jobs and The Purge Job. Users and API Tokens User accounts are managed under the Users section, accessible to administrators only. Each user can hold one or more named API tokens, which grant API access under that user's identity. From the user edit view you can: Create a new token and copy it immediately after generation (it is only shown once) Revoke any existing token with immediate effect Reset another user's password, or change your own after confirming the current one Screenshot placeholder: user.edit1.png User edit view, account data and API token management. Screenshot placeholder: user.edit2.png User edit view, the permission sections. Screenshot placeholder: create-token.modal.png Create API token dialog, the token is shown once. โš ๏ธ Copy your token immediately after creation. VeloxFactory only displays the token value once. If you lose it, you will need to revoke the old token and create a new one. โš ๏ธ Tokens are issued and revoked here, never through the API. A request that authenticates with an API token cannot create or revoke tokens and is answered with 403 API tokens can only be managed from the web interface. That is deliberate: a token that could issue another one would survive its own revocation, and revoking a leaked token would not actually lock it out. Permissions Every user in VeloxFactory has a set of permissions that controls what they can see and do, both in the frontend and via the API. Since both use the same underlying controllers, a permission that restricts an action in the frontend restricts the exact same action via API, and vice versa. There is no way to grant API-only or frontend-only access to a resource. Permissions fall into two categories: global and per-resource. Global permissions: Permission Effect global:admin Full access to everything, including user management. Only an administrator may grant or withdraw permissions, activate or deactivate accounts, and manage other users' API tokens global:use-api Required for every API request. Without it, each call answers 403 This user is not permitted to use the API. Also allows managing one's own API tokens in the web interface Per-resource permissions, available for each of the following resources: report-config, report-connection-config, report-context, report-history-record, report-print-task, report-mail-task, common-report-resource, printer, mailer, mail-template, scheduled-job: Permission Effect :full Full read/create/update/delete access to this resource :read View records only :create Create new records :update Edit existing records :delete Delete records global:admin always implies full access to all resources and overrides any per-resource setting. scheduled-job:* also covers the run log. Changing or starting a render job is limited to its owner and to administrators, because it acts with the owner's permissions; reading it is not. Feature permissions: Permission Effect scan2print:use Access to Scan2Print. Implicitly includes report-config:read, report-print-task:read and :create, report-history-record:create and :update scheduled-job:create Creating a schedule means rendering, printing and mailing with it, so it implicitly includes report-config:read, report-print-task:create, report-mail-task:create and report-history-record:create and :update. scheduled-job:full does the same โ„น๏ธ Permissions are administrator territory. Users can edit their own name and e-mail address, but not their own permissions. The permission section is not shown to them, and a request that carries a permission list is answered with the user's current set instead. The same applies to activating and deactivating an account. VeloxFactory also refuses to let the last remaining administrator give up global:admin or be deactivated, so an instance can never end up without one. โ„น๏ธ API token permissions are inherited from the user. A token does not have its own permission set, it acts with exactly the permissions of the user it belongs to, evaluated on every single request. Withdrawing a permission takes effect on the next call, there is nothing to re-issue. Deactivating a user revokes all of their tokens at once, and tokens expire after the period configured in SANCTUM_EXPIRATION (one year by default). Signing in The login form answers every failed attempt the same way, with Invalid credentials. Whether the address belongs to an account, whether that account is deactivated and whether the password was wrong are deliberately indistinguishable, so the form cannot be used to find out which addresses exist on an instance. Attempts are limited to five per minute, counted per source address and per e-mail address. Beyond that the form answers 429 Too Many Requests until the minute is over. Successful and failed sign-ins, sign-outs, password changes, permission changes and token operations are written to a dedicated security log channel. โ„น๏ธ Changing your own password needs the current one. An administrator resetting someone else's password does not. Either way, every API token of that account is revoked afterwards, so a password change really does end all access that was granted before it. Frontend vs. API - What is the Difference? The short answer: there is no feature difference. The frontend calls the exact same controller methods as the API. Everything you can do in the UI, you can also automate via API. The frontend is optimised for interactive, human-driven workflows, exploring reports, reviewing history records, testing connections. The API is the right choice when you want to integrate rendering into external systems, automate repetitive tasks, or process results programmatically. โ„น๏ธ Ready to explore the API? See Meet the API for authentication, query parameters, and a practical render example. Meet the API VeloxFactory ships with a fully capable REST API, and it is not an afterthought. Every action you can perform in the frontend can also be performed via the API, because the frontend and the API share the same controller methods. There is no separate implementation, no feature gap, no second-class citizen. This makes the API a genuine alternative to the UI, not just an integration bolt-on. Automate report rendering in your CI pipeline, trigger prints from your ERP, manage report configurations programmatically, have VeloxFactory run the whole thing on a schedule, all with the same logic that powers the frontend you already know. โ„น๏ธ For the full endpoint reference including all parameters and response schemas, explore the live demo API documentation at demo.veloxfactory.dev. Login: demo@veloxfactory.dev ย ยทย  Password: demo Authentication The API uses token-based authentication via Laravel Sanctum. Every request must include a Bearer token in the Authorization header. Authorization: Bearer your-api-token โš ๏ธ Every API request requires global:use-api. The permission is checked on each call, not only when a token is issued. A token whose user does not hold it is answered with 403, even if the token itself is valid and the user has the resource permissions. Tokens are issued and revoked per user in the user management section of the frontend. A request authenticated by a token cannot create or revoke tokens, so a leaked token cannot renew itself and revoking it actually locks it out. A revoked token is rejected immediately, there is no grace period. { "success": false, "errors": ["This API token has been revoked."], "status": 401 } The audit trail records which token was used for every create and update operation across all models, so every API action is fully traceable. Authentication Errors Status Message When 401 This user account is disabled. The account behind the token was deactivated 401 This API token has been revoked. The token was revoked, or every token of the user was revoked by a password change or a deactivation 401 Token expired The token is older than SANCTUM_EXPIRATION 403 This user is not permitted to use the API. The user is missing global:use-api 403 API tokens can only be managed from the web interface. A token tried to create or revoke a token Base URL All API v1 endpoints are prefixed with: /api/v1/ Referencing Records Wherever a request points at another record, it accepts either the numeric ID or the unique name of that record. These two are the same call: POST /api/v1/report-config/12/render POST /api/v1/report-config/Shift Report/render The same holds inside request bodies, for report contexts, connection configs, mailers, mail templates and schedules alike, so a payload stays readable without a lookup table of IDs. A Report History Record is addressed by its ID or by its trace id, which is what makes a trace id worth carrying through your own systems. โ„น๏ธ A value of digits only is always read as an ID. That is why a name cannot consist of digits only. VeloxFactory refuses such a name when a record is created or renamed, so 4711 is never ambiguous. Response Structure All API responses follow a consistent envelope format. Success, list endpoint: { "success": true, "count": 25, "data": [ { ... }, { ... } ], "links": { "first": "https://your-instance/api/v1/report-print-task?status=pending&page=1", "last": "https://your-instance/api/v1/report-print-task?status=pending&page=3", "prev": null, "next": "https://your-instance/api/v1/report-print-task?status=pending&page=2" }, "meta": { "pagination": { "currentPage": 1, "lastPage": 3, "perPage": 25, "total": 61, "from": 1, "to": 25, "hasMorePages": true, "path": "https://your-instance/api/v1/report-print-task" } }, "status": 200 } Success, single record: { "success": true, "count": 1, "data": { ... }, "links": { "first": null, "last": null, "prev": null, "next": null }, "meta": { "pagination": { "currentPage": 1, "lastPage": 1, "perPage": 1, "total": 1, "from": 1, "to": 1, "hasMorePages": false, "path": "https://your-instance/api/v1/report-print-task/256" } }, "status": 200 } Error: { "success": false, "errors": ["Descriptive error message"], "meta": {}, "status": 404 } Every success response that carries data has the same shape, whether it returns a list, a single record, a freshly created record or a render result. A client parses one envelope for every endpoint. count is the number of records in data: the records on the current page for a list, 1 for a single record. links point to the first, last, previous and next page. A link that does not exist is null. Responses that are not paginated have all four links null. meta.pagination describes the page, see Pagination. A response that is not paginated reports exactly one page. meta carries further contextual information next to pagination, such as the traceId of a render run or the mailing result. Error responses have no links and no pagination block. Pagination All list endpoints ( GET /user, GET /report-config, GET /report-print-task and every other GET on a resource without an id) return their records page by page. Two query parameters control the page: Parameter Type Default Description page integer 1 Page to return, starting at 1. perPage integer 25 Records per page, 1 to 100. The values of the pagination block: Field Meaning currentPage The page in this response. lastPage Number of the last page, at least 1. perPage Page size used for this response. total Number of all records matching the request, across all pages. from / to Position of the first and last record of this page within total, null on an empty page. hasMorePages true as long as a next page exists. path URL of the endpoint without query string. Filters such as status, type or isActive apply before the records are split into pages, so total counts the filtered result. The links in links carry all query parameters of the request, a client follows links.next until it is null and keeps its filters on every page. A page behind the last one returns 200 with an empty data array. A page below 1, a perPage above 100 or a non-numeric value returns 422, and so does a filter value the endpoint does not know, for example status=foo on GET /report-print-task. To read every record, request perPage=100 and follow links.next. Every page is a request of its own and counts against the rate limit. The two placeholder catalogs ( GET /mail-template/placeholders, GET /scheduled-job/placeholders) are not paginated and always return one page. The page size default and maximum are set with API_PER_PAGE_DEFAULT and API_PER_PAGE_MAX, see Configuration and Data Models. A default above the maximum is reduced to the maximum. โ„น๏ธ limit is a deprecated alias of perPage and will be removed in a future version. perPage takes precedence when both are sent, and limit=0 returns the maximum page size. There is no request that returns all records at once. A response to a request that uses limit without perPage carries the header Deprecation: true and a note in meta.messages. Query Parameters Most GET endpoints and the render endpoint share a common set of query parameters that control what is included in the response. They are additive, combine them freely. Parameter Type Default Description page, perPage integer 1, 25 Page and page size on list endpoints, see Pagination. withRelations boolean false Include related models (e.g. parameters, fields, resources on a ReportConfig). recursiveRelations boolean false Include nested relations within relations. withMedia boolean false Include Base64-encoded file content, previews, and thumbnails. withAudit boolean false Include the audit segment on each record (timestamps, users, token, method). Example, retrieve a single report config with all relations, media, and audit data: GET /api/v1/report-config/1?withRelations=true&withMedia=true&withAudit=true Audit Segment When withAudit=true is set, every record in the response carries an audit block: "audit": { "createdAt": "2026-05-08 11:26:30", "createdByUser": 2, "createdByToken": null, "creationMethod": "Frontend", "updatedAt": "2026-05-08 13:31:35", "updatedByUser": 1, "updatedByToken": "Postman", "updateMethod": "API" } creationMethod and updateMethod are derived automatically, "API" when a token was used, "Frontend" when the action came through the UI. A run of a scheduled job fills these exactly like a direct call does, with the owner of the schedule and the token it runs with. Render-Specific Request Body The render endpoint ( POST /api/v1/report-config/{id}/render) accepts the following fields in the request body (JSON). Field Type Required Description outputType string โœ… How to return the PDF: base64, url, preview, or none createHistoryRecord boolean โœ… Whether to persist a ReportHistoryRecord for this render createPrintTask boolean โœ… Whether to create a ReportPrintTask after rendering printerName string if createPrintTask Name of the target printer useExampleValues boolean ย  Use stored example values instead of supplying parameters manually parameters object ย  Key-value map of parameter names to values resourceOverrides object ย  Per-render override for P_RESOURCE_* image parameters, keyed by parameter name. A path has to point at a readable file inside the resources folder, a URL has to be https://, or the image is supplied as a Base64 upload. See Rendering with our powerful API for the full reference. data array ย  Array of data rows, for reports without a live DB connection numberOfCopies integer ย  Number of print copies (default: 1) broadcastId string ย  WebSocket channel ID, triggers real-time status updates for the print task traceId string ย  Custom trace ID; auto-generated as UUID if omitted. Unique across all history records laconicResponse boolean ย  Strip the response to just the PDF output (see below) mailing object ย  Send the rendering by mail once it succeeded: mailer, mail template, recipients, attachments and sync or queued dispatch. See Report Mailing for the full reference. โš ๏ธ Output type none requires createPrintTask: true. Rendering without any output and without a printer to send it to is rejected, and a mailing segment does not take the place of the print task. preview and mailing are refused together as well, a preview render deletes its own file immediately and has nothing to attach. Laconic Responses By default, a render response is fully populated, it includes the echoed input, the PDF output, the linked ReportConfig, the created ReportHistoryRecord, and the ReportPrintTask and ReportMailTask if applicable. In high-frequency or bandwidth-sensitive scenarios, add laconicResponse=true to strip everything down to just the PDF output. The Same Body on a Schedule This body is also what a render job of the Job Scheduler stores. A request you have tested here can be dropped into the payload of a schedule unchanged, minus traceId, which every run generates for itself. See Render Jobs. Rate Limiting The API enforces a configurable rate limit per token. The default is 10 requests per minute. When the limit is exceeded: { "success": false, "message": "Too many requests! The current rate limiting is 10 requests per minute.", "status": 429 } The limit is adjusted via the API_RATE_LIMIT_PER_MINUTE environment variable, see Configuration and Data Models. Endpoints Overview Resource Available operations User List, show, create, update, change password, enable/disable, create/revoke tokens (web interface only) ReportContext List, show, create, update, delete ReportConnectionConfig List, show, create, update, delete, test connection CommonReportResource List, show, create, update, delete ReportConfig List, show, create, update, delete, update resources / parameters / fields, generate previews, render ReportResource Link / unlink CommonReportResource ReportHistoryRecord List, show, create, update, delete, print, mail ReportPrintTask List, show, create, update, delete, set printed, set status ReportMailTask List, show, create, delete, repeat Printer List, show, create, update, delete Mailer List, show, create, update, delete, test configuration, send test mail MailTemplate List, show, create, update, delete, placeholder catalog, preview ScheduledJob List, show, create, update, delete, run now, cron preview, placeholder catalog ScheduledJobRun List, show, delete A Practical Example: The Full Render Response A render call returns a ReportRendering object. By default it is fully populated, you see the input you sent, the PDF output, and the linked records that were created. { "success": true, "count": 1, "data": { "model": "ReportRendering", "traceId": "a3f9c1d2-4e87-4b2a-9f1c-d3e8b7a20f61", "input": { "parameters": { "P_ARTICLE_NUMBER": "4561287-154" }, "data": null }, "output": { "reportPdfFileName": "a3f9c1d2-4e87-4b2a-9f1c-d3e8b7a20f61.pdf", "reportPdfBase64": "JVBERi0xLjQ...", "reportUrl": null }, "reportConfig": { "..." }, "reportHistoryRecord": { "..." }, "reportPrintTask": null }, "links": { "first": null, "last": null, "prev": null, "next": null }, "meta": { "traceId": "a3f9c1d2-4e87-4b2a-9f1c-d3e8b7a20f61", "pagination": { "currentPage": 1, "lastPage": 1, "perPage": 1, "total": 1, "from": 1, "to": 1, "hasMorePages": false, "path": "https://your-instance/api/v1/report-config/12/render" } }, "status": 200 } Add laconicResponse=true and the response collapses to just output, no echoed input, no embedded related records. Ideal for automated pipelines that only need the PDF. Try it out The demo instance gives you a fully functional VeloxFactory environment, pre-loaded with report templates and example data. Everything you can do in a production setup you can do here, with one exception: print tasks do not reach a real printer. Screenshot placeholder: report-config.index.png Report Config overview, the landing page after login, with context badges and thumbnails. Access Demo URL: demo.veloxfactory.dev Login: demo@veloxfactory.dev ย ยทย  Password: demo The demo account has full access to all report data, Report Configs, History Records, Print Tasks, Mail Tasks, Connection Configs, Contexts, Common Resources, Printers, Mailers and Mail Templates. It can also generate and use API tokens. User management is not available. Guided Tour Work through these steps in order for a complete first look at VeloxFactory. Step 1 - Browse the Report Configs After logging in you land on the Report Configs list. This is the central workspace. Each card shows a thumbnail preview of the report and its context badge. Use the search bar to filter by name, or use the dropdown filters to narrow by context or data adapter. Try typing part of a report name, the list updates instantly, no page reload. Screenshot placeholder: report-config.index.filtered.png Report Config overview with the filter bar open and active filter badges. Step 2 - Explore a Report Config Click any report to open its detail view. Here you can inspect: Parameters - the inputs the report expects at render time, with their data types and example values Fields - the data columns that populate the report body Resources - image assets embedded in the template (logos, icons) Preview - the rendered thumbnail, generated from the stored example values Scroll through the sections to get a feel for what VeloxFactory extracts from a .jrxml file automatically on upload. Screenshot placeholder: report-config.edit.png Report Config edit view with parameters, fields and resources. Step 3 - Render a Report from the Frontend From within a Report Config, click the Generate PDF button. A dialog opens with pre-filled parameter values (taken from the example values stored on the config). You can edit any of them before rendering. Select an output type, Base64 is fine for a quick look, and click Generate PDF. VeloxFactory processes the request and shows the resulting PDF inline within seconds. No API call needed, no setup required. Screenshot placeholder: generate-pdf.create.png Generate PDF page with the parameter inputs and the output settings. Step 4 - Check the History Record Navigate to Report History Records. Your render from Step 3 appears at the top of the list (if you left createHistoryRecord enabled in the dialog). Open it to see the full log: the exact request payload, the API response, the rendered PDF, and a thumbnail. From here you can download the PDF directly, trigger a reprint, which creates a new Print Task, or send the document by mail, which creates a new Mail Task. Screenshot placeholder: report-history-record.show.png Report History Record detail page with status, payload, PDF preview and the actions. Try It Yourself Once you have completed the tour, these are good next things to explore on your own. Upload Your Own Template If you have a .jrxml file designed in Jaspersoft Studio, you can upload it directly to the demo. Go to Report Configs โ†’ Create, attach the file, and let VeloxFactory analyse it. Within seconds, all parameters, fields, and resources are detected and listed automatically. โ„น๏ธ Use Jaspersoft Studio 6.21.5. This is the version compatible with VeloxFactory's render engine. Download it from the Jaspersoft Community. Reports created with a significantly newer version may use features the render engine does not support. After upload, set any missing example values, upload resource files if needed, and click Generate Preview to produce a thumbnail. The report is then ready to render. Call the API Directly The demo account has API access enabled. To get a token, open the user menu in the top right corner and go to Account Settings โ†’ API Tokens, copy it immediately, it is only shown once. With the token in hand, render any report with a single HTTP request: curl -X POST \ https://demo.veloxfactory.dev/api/v1/report-config/{reportName}/render \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "outputType": "base64", "useExampleValues": true, "createHistoryRecord": true }' Replace {reportName} with the report_name of any config from the list (visible in the detail view). The useExampleValues flag tells VeloxFactory to use the stored example values instead of requiring you to pass parameters and data manually, ideal for a first test. The response contains the rendered PDF as a Base64 string and a trace ID you can look up in History Records. Send a Report by Mail Mailing is the second way a rendering leaves VeloxFactory. Two mailers are waiting for you under Configuration. Mailer What it is for Demo Log Mailer Writes every mail into the application log instead of sending it. Ready to use, and the safe way to follow the whole path from render to mail task without anything leaving the machine. Demo SMTP Mailer The starting point for a real send. It carries placeholder values, smtp.example.com on port 587 with scheme smtp, user and sender change-me@example.com, and it is inactive so nobody picks it before it works. To send for real, open the SMTP mailer, replace host, port, credentials and sender with the data of a mailbox you own, send a test mail from the form, and set it active. Then write a Mail Template with a subject and a body. The editor has a placeholder button that lists every token the template can use. With a mailer and a template in place, open any History Record and click Mail, or switch on Send results via Mail in the Output Settings of the Generate PDF page. The mail goes out with the PDF attached, and optionally with an xlsx export of the same data. Every mail shows up in the Mail Queue with its status, its recipients and the body that was actually sent. Explore Print Tasks When rendering via the frontend or API, enable the print task option and provide any printer name (e.g. demo-printer). VeloxFactory creates a ReportPrintTask record with status pending. Since no print service is connected to the demo, the task stays pending, but you can inspect the full record and see how status tracking works. Completed print tasks are purged automatically after a configurable retention period. Demo Limitations What Behaviour in the demo Print tasks Created and traceable, but no real printer connected, tasks remain pending. Completed tasks are purged automatically. Mail dispatch Mailers and Mail Templates can be created freely and a mailing can be configured end to end. The log mailer records the mail instead of sending it; whether a real mail is delivered depends on the SMTP account you enter, the demo has no mailbox of its own. Live SQL connections Connection Configs can be created and tested, but no external databases are reachable from the demo environment. User management The demo account does not have admin rights, user accounts and permissions cannot be managed. Data persistence Uploaded templates, history records, and other data may be reset periodically. โ„น๏ธ Ready to go further? See Meet the Frontend for a full walkthrough of the UI, or Meet the API for complete API documentation. Open Source Attribution VeloxFactory and its companion VeloxFactory Print Service are built on open source software. We are grateful to the authors and contributors of the following packages. VeloxFactory Package License Description laravel/framework MIT The Laravel PHP framework routing, ORM, queues, and the application foundation. laravel/horizon MIT Queue manager and dashboard for the Redis queues that run thumbnails, mail dispatch and the nightly purge jobs. laravel/reverb MIT First-party Laravel WebSocket server used to broadcast print task events in real time. laravel/sanctum MIT API token authentication for the VeloxFactory REST API. laravel/tinker MIT REPL for the Laravel application. livewire/livewire MIT Full-stack component framework for the VeloxFactory frontend. opcodesio/log-viewer MIT In-browser Laravel log viewer. knuckleswtf/scribe MIT Automatic API documentation generator. phpoffice/phpspreadsheet MIT Spreadsheet library used to build the xlsx export that a report mailing can attach alongside the PDF. quilhasoft/jasperphp MIT Pure-PHP JasperReports renderer. The VeloxFactory render engine is our maintained fork of this project, extended with a Java expression interpreter, Java-style formatting, full style support and numerous layout fixes. The original MIT license and copyright notice are retained. tecnickcom/tcpdf LGPL-3.0 PDF library used by the render engine to write the PDF files, including barcodes. VeloxFactory Print Service The VeloxFactory Print Service 2.0 runs on .NET 10 (Windows Desktop Runtime) and bundles the following packages. Package License Description PDFtoImage MIT Ships the native PDFium library; used for page sizes and previews. PDFium BSD 3-Clause Google's PDF engine, draws every page directly onto the printer. Microsoft.Extensions.Hosting / Http MIT Generic host, dependency injection, options and HTTP client factory. Microsoft.Data.Sqlite MIT SQLite access for the job journal, outbox, statistics and log buffer in state.db. SQLite itself is public domain. Serilog Apache 2.0 Structured logging to rolling files, console and the Windows event log ( Serilog.Extensions.Hosting, Serilog.Sinks.File, Serilog.Sinks.Console, Serilog.Sinks.EventLog, Serilog.Formatting.Compact). TaskScheduler MIT Creates and reads the Windows scheduled task of the headless service. CommunityToolkit.Mvvm MIT MVVM base for the window. MaterialDesignThemes MIT Material Design controls and themes for the WPF window. ScottPlot.WPF MIT Charts on the statistics page. SkiaSharp MIT 2D graphics library used by ScottPlot and PDFtoImage. Material Symbols Rounded Apache 2.0 Icon font of the window, the same icons as in the VeloxFactory frontend. Get VeloxFactory Interested in using VeloxFactory in your own environment? Get in touch, we'll figure out the right setup together. Contact Name Benjamin Fischer E-Mail bfischer@kiwi-software.dev Website www.kiwi-software.dev What to Expect Drop a short message explaining your use case, what you need to generate, how often, and whether you'd prefer self-hosted or managed. You'll hear back within one business day. If you want to explore the product first, the live demo is open: โ„น๏ธ Want to try it first? A live demo is available at demo.veloxfactory.dev. Login: demo@veloxfactory.dev ย ยทย  Password: demo Smarter Code. Frischer Blick. Report Configurations From a JRXML in Jaspersoft Studio to a Report Config in VeloxFactory, including the data adapters. Creating reports in Jaspersoft Studio VeloxFactory renders reports defined as .jrxml files โ€” the native format of JasperReports. These files are designed in Jaspersoft Studio, a free desktop IDE built specifically for this purpose. This page explains how to set up a .jrxml file so that VeloxFactory can analyse it correctly, register all its parts, and render it reliably. โ„น๏ธ Which bands, elements and expressions does VeloxFactory support? VeloxFactory renders with its own pure-PHP render engine, not with the Java JasperReports library. The supported feature set, the expression syntax and the formatting rules are listed in Render engine: supported features and expressions. Jaspersoft Studio Jaspersoft Studio is an Eclipse-based visual report designer. You use it to lay out the report template โ€” define what data goes where on the page, how it is formatted, and which inputs the report expects. The resulting .jrxml file is then uploaded to VeloxFactory, which takes over everything from there: storing it, analysing it, connecting it to a data source, and rendering it on demand. โ„น๏ธ Use version 6.21.5. This is the version compatible with VeloxFactory. Download it from the Jaspersoft Community. Reports created with a significantly newer version may use features that VeloxFactory's render engine does not support. The division of responsibilities between Jaspersoft Studio and VeloxFactory is clear: Jaspersoft Studio defines the layout, the parameters, the fields, and the visual design of the report. VeloxFactory manages the SQL query, the data connection, and the actual rendering at runtime. This means you will see a element in Jaspersoft Studio โ€” but as explained below, you leave it empty. VeloxFactory supplies the query separately. The Report Name Every Jaspersoft Studio project has a Report Name โ€” the name attribute on the root element. This is not just a filename: VeloxFactory reads it directly from the .jrxml on upload and stores it as report_name on the ReportConfig. This name must be unique across all report configurations in VeloxFactory. If you try to upload a .jrxml whose report name already exists, the upload will be rejected. The same applies to the file name itself. โš ๏ธ Set a descriptive, unique report name in Jaspersoft Studio before uploading. You can change it in Jaspersoft Studio via File โ†’ Report Properties โ†’ Report Name, or directly in the XML. Changing it after upload requires re-uploading the file. Parameters Parameters are input values passed into the report at render time. They are used inside the report layout via $P{PARAMETER_NAME} expressions โ€” for example to display a customer name in the title, filter by a date range, or pass a document number into a barcode expression. You define parameters in Jaspersoft Studio via the Report Inspector โ†’ Parameters section. Each parameter has a name and a Java data type. Custom Properties: exampleValue and required VeloxFactory reads two custom properties from each parameter definition: exampleValue and required. These are not standard Jaspersoft features โ€” they are custom elements you add manually to the parameter in the .jrxml. VeloxFactory's analyser ( JasperFunctions::analyzeReportFile) extracts them on upload. Property Value type Purpose exampleValue string A representative value used when rendering a preview of the report without real data. Also pre-fills the parameter input in the frontend render form. required boolean ( true / false) Whether this parameter must be provided in every render request. VeloxFactory rejects render requests that are missing a required parameter. Both properties can also be set or updated manually in VeloxFactory after upload โ€” they do not have to come from the .jrxml. But embedding them in the file means they are automatically picked up every time the report is uploaded or re-uploaded. To add these properties in Jaspersoft Studio, open the parameter in the Report Inspector, switch to the Properties panel, and add a new custom property via the green + button. Supported Data Types VeloxFactory supports the following Java class types for parameters. The type determines how the input field is rendered in the frontend and how the value is handled at render time. Java class Frontend input Notes java.lang.String Text field General-purpose text input java.lang.Boolean Toggle Rendered as a checkbox/toggle switch java.lang.Short Integer input Range: โˆ’32,768 to 32,767 java.lang.Integer Integer input Range: โˆ’2,147,483,648 to 2,147,483,647 java.lang.Long Integer input 64-bit integer java.lang.Float Decimal input Single-precision floating point java.lang.Double Decimal input Double-precision floating point java.math.BigDecimal Decimal input Arbitrary-precision decimal; preferred for monetary values java.sql.Date Date picker Date only (no time) java.util.Date Date picker Date only (no time) java.sql.Time Time picker Time only (HH:mm) java.sql.Timestamp Date + time picker Combined date and time (datetime-local) Fields Fields represent the data columns that populate the report's detail band โ€” the repeating section that produces one row of output per data record. Each field corresponds to a column in the SQL query result (when using a live connection) or a key in the data array delivered at render time via the API. You define fields in Jaspersoft Studio via the Report Inspector โ†’ Fields section. In the report layout, you reference them via $F{FIELD_NAME} expressions inside text fields in the detail band. Custom Property: exampleValue Fields support one custom property: exampleValue. It works the same way as for parameters โ€” a representative value used when rendering a preview of the report without a live data connection. VeloxFactory collects these example values and assembles a synthetic data row from them for preview rendering. You add exampleValue to a field the same way as for parameters: open the field in the Report Inspector, go to the Properties tab, and add the custom property. โ„น๏ธ Set meaningful example values for all fields. Without them, VeloxFactory cannot generate a preview or thumbnail for the report configuration. The values do not need to be real data โ€” they just need to be type-compatible and representative enough to make the preview look sensible. Fields support the same Java data types as parameters (see the table above). Use the type that matches the column type your SQL query or data array will produce. Using Parameters as SQL Variables When a ReportConfig has a ReportConnectionConfig assigned, VeloxFactory executes the SQL query defined in the report configuration against that live database connection. Parameters passed in the render request are available as named bindings inside that query โ€” using the standard :parameterName syntax from Laravel's Eloquent database layer. This means you can reference any parameter directly in your SQL to filter, sort, or limit the result set: SELECT article_number AS articleNumber, description, moq, delivery_time AS deliveryTime, supplier, barcode FROM articles WHERE article_number = :P_ARTICLE_NUMBER In this example, :P_ARTICLE_NUMBER is replaced at query execution time with the value of the P_ARTICLE_NUMBER parameter from the render request. The binding is handled natively by PDO โ€” values are passed as proper prepared statement parameters, not interpolated as strings. โ„น๏ธ Only parameters that are actually referenced in the query are bound. VeloxFactory scans the query for :name placeholders before execution and silently drops any parameters that are not needed. Passing extra parameters in the render request will never cause a query error. The parameter name in the query binding must match the parameter name exactly as defined in the .jrxml โ€” including case. For example, a parameter named P_ARTICLE_NUMBER in the report must be referenced as :P_ARTICLE_NUMBER in the SQL query. You can use as many parameters as needed across WHERE, ORDER BY, LIMIT, or any other clause that accepts a value binding. Note that named bindings cannot be used for identifiers like table or column names โ€” only for values. Resources (Images and Logos) If your report contains images โ€” a company logo, a header graphic, a product photo โ€” these are defined as resource parameters in the .jrxml. VeloxFactory detects them automatically on upload and creates a ReportResource record for each one. The naming convention is strict: every resource parameter must start with P_RESOURCE_ and must have the Java class java.lang.String. At render time, VeloxFactory replaces the parameter value with the actual file path of the uploaded image on the server. In the report layout, you then bind this parameter to an image element: The is used only in Jaspersoft Studio for design-time preview purposes. VeloxFactory ignores it at render time โ€” it always uses the uploaded file path instead. You can point it to a local file on your design machine. โš ๏ธ Resource parameters are not treated as regular parameters in VeloxFactory. They do not appear in the Parameters section โ€” they appear in the Resources section. In the vast majority of render requests you do not pass them at all; VeloxFactory fills them in automatically from the linked resource file. โ„น๏ธ Exception: per-render overrides. A render request can optionally supply resourceOverrides to swap a resource parameter's image for that single call only โ€” a local path, a remote http(s):// URL, or a Base64 upload โ€” without changing the report configuration's linked default. This is an opt-in override on top of the linked resource described above, not a replacement for it: a default file or CommonReportResource still has to be linked before the report can render at all. See Rendering with our powerful API for the full reference. After uploading the .jrxml, you must go to the Resources section of the report configuration in VeloxFactory and upload the actual image file for each detected resource. A report cannot be rendered until all its resources have files assigned. The Detail Band The detail band is the repeating section of the report โ€” the part that outputs one row per data record. If your report displays a list of items, a table, or any kind of repeating structure, it lives in the detail band. VeloxFactory checks whether a detail band is present when analysing the .jrxml: If a detail band exists, VeloxFactory expects data to be provided at render time โ€” either via a live SQL connection or via the data array in the API request. If no detail band exists, the report is treated as a static layout โ€” no data is needed, only parameters. โš ๏ธ If you add a detail band, it must contain at least one text field element that uses a field expression ( $F{...}). A detail band that exists but displays no field data will be rejected on upload. VeloxFactory uses the presence of text fields in the band as a basic integrity check. Reports without a detail band are perfectly valid โ€” they are useful for documents like cover pages, summary sheets, or any report whose content is entirely driven by parameters rather than repeated rows. The SQL Query Jaspersoft Studio has a built-in element where you would normally write the SQL query for the report. In VeloxFactory, this element is ignored. The SQL query is instead defined and stored directly in VeloxFactory as part of the ReportConfig โ€” not in the .jrxml file. This means you should leave the empty when creating a .jrxml for VeloxFactory: You write the actual SQL query in VeloxFactory after uploading the report, in the Query field of the report configuration. This design keeps the query where it can be managed, versioned, and changed without touching the report template file. The query result columns must match the field names you defined in the .jrxml. For example, if your report has a field named articleNumber, your SQL query must return a column called articleNumber. The Data Adapter Jaspersoft Studio uses Data Adapters to connect to a live database so you can preview your report during design. This is entirely a design-time feature โ€” the data adapter you configure in Jaspersoft Studio has no effect in VeloxFactory and is not stored in the .jrxml. At render time, VeloxFactory always uses its own internal array-based adapter to pass data to the render engine. Whether that data comes from an SQL query executed against a ReportConnectionConfig or from a data array in the API request, VeloxFactory always handles the data handoff itself. You still benefit from configuring a data adapter in Jaspersoft Studio during development โ€” it lets you see a realistic preview while designing the layout. Just be aware that the adapter configuration stays local to your machine. Annotated Example The following is a complete, minimal .jrxml that demonstrates everything discussed on this page. It is the actual A5_KanBan report included in the VeloxFactory demo. Inline comments explain each relevant element. pageWidth="595" pageHeight="842" ...> โ„น๏ธ This example has been simplified for clarity. A real `.jrxml` contains many additional attributes, layout elements, and Studio-specific property annotations. The elements shown here are the ones VeloxFactory actively reads and acts on. Everything else is interpreted by the render engine as described in Render engine: supported features and expressions. Pre-Upload Checklist Before uploading a .jrxml to VeloxFactory, verify the following: The Report Name ( name attribute on ) is set, descriptive, and unique. All resource parameters follow the P_RESOURCE_ naming convention and have class java.lang.String. All regular parameters have exampleValue and required custom properties set where applicable. All fields have an exampleValue custom property set. The is empty โ€” the SQL is managed in VeloxFactory. If the report has a detail band, it contains at least one with a $F{...} expression. Every band has splitType="Stretch", including an explicit empty band, and the bands follow the JasperReports XSD order ( pageFooter and lastPageFooter before summary). The template only uses features listed in Render engine: supported features and expressions (no charts, no crosstabs, no $R{...}). The report previews correctly in Jaspersoft Studio using the local data adapter โ€” this confirms the layout and expressions are valid before upload. After the upload, render it once in VeloxFactory with realistic data, including enough rows for more than one page. The rendering in VeloxFactory is the reference, not the Studio preview. Render engine: supported features and expressions VeloxFactory renders .jrxml templates with its own render engine: a pure-PHP implementation of JasperReports, based on the open source project JasperPHP and maintained by us as an independent fork. It needs no Java runtime, but it implements a defined subset of JasperReports rather than the full Java engine. This page lists exactly what that subset is, so you can design templates in Jaspersoft Studio that render the same way in VeloxFactory. How to set up parameters, fields, resources and the query is described in Creating reports in Jaspersoft Studio. This page covers what happens inside the template: bands, elements, styles, expressions and formatting. โ„น๏ธ This page describes render engine 1.2. If a template behaves differently from what is described here, the render engine is the reference, not Jaspersoft Studio's preview. Always check a real rendering in VeloxFactory before you release a template. Two rules for every template Every band needs splitType="Stretch", including an explicit empty . Bands must follow the JasperReports XSD order: background, title, pageHeader, columnHeader, detail, columnFooter, pageFooter, lastPageFooter, summary. Jaspersoft Studio refuses to open a file with a different order. Bands Band Behaviour background Printed once per page at the top edge, behind the content. Does not push other bands down. title Printed once on the first page. $F{...} shows the first data row. pageHeader Printed on every page. On the first page it follows the title. columnHeader Printed on every page that contains detail rows, also after a manual . detail Printed once per data row. Grows with stretching text fields. groupHeader / groupFooter Printed whenever the value of the groupExpression changes. columnFooter Printed below the detail rows of a page. pageFooter Printed at the bottom of every page. lastPageFooter Replaces the pageFooter on the last page. Also works without a pageFooter: then a footer appears on the last page only. summary Printed once at the end. $F{...} shows the last data row, variables hold their final values. If the summary does not fit and moves to a page of its own, that page has no page header, column header or footer, and the lastPageFooter appears on the page before. With isSummaryWithPageHeaderAndFooter="true" on , the summary page gets page header and footer (the lastPageFooter), but still no column header. This is JasperReports behaviour. noData Not supported. Elements Element Supported textField, staticText Horizontal and vertical alignment, rotation, markup="html", line spacing (Single, 1_1_2, Double, Proportional), textAdjust (StretchHeight, ScaleFont, CutText), , pattern / patternExpression, hyperlinks rectangle radius, mode, forecolor and backcolor, pen width, colour and style (Solid, Dashed, Dotted), fractional sizes such as height="0.8" line Pen as for rectangles. Lines thinner than 1 pt are drawn straight. frame Background, border, child elements positioned relative to the frame image Path or URL as an expression, Base64 data URIs ( data:image/png;base64,...), JPG and PNG. In VeloxFactory, images normally come from P_RESOURCE_ parameters. Barcodes QR Code, DataMatrix, PDF417, Code 128, Code 39, Code 93, EAN-8, EAN-13, Interleaved 2 of 5, Postnet. The code is an expression. subreport Data source from a list field ( $F{items}, also new JRBeanCollectionDataSource($F{items})), file name as an expression, .jasper is resolved to .jrxml break Page break, prints page footer, page header and column header jr:table Basic tables Every element respects printWhenExpression, evaluated for each row. Layout rules StretchHeight makes the band taller, never the elements beside it. The next band starts below the lowest stretched field. Vertical alignment with StretchHeight: if the text fits into the field, Top, Middle and Bottom apply as usual. Only overflowing text grows downwards from the top. positionType="Float" moves an element down by the growth of the stretched fields above it. All other elements keep their position. ScaleFont reduces the font size until the text fits into the box. Line breaks are allowed. Page breaks fill the page down to the page footer. The decision uses the declared band height. : applies to all four sides, topPen, leftPen, bottomPen and rightPen override it. The colour falls back from the side pen to the box pen, then to forecolor, then to black. padding sets all four paddings, leftPadding etc. override it. Defaults are the same as in JasperReports: Rectangle: Opaque, white background, 1 pt black border. Line: 1 pt. A pen width of 0 draws nothing. Pen colour: lineColor takes precedence over forecolor. Styles Assignment: style="Name" on the reportElement. A style with isDefault="true" applies to all elements without a style of their own. Inheritance: