Skip to content
System story

Reports checked before submission, certificates people can verify

Australian training providers need to report student activity and issue certificates people can trust. I built report generators, checks that explain their limits, and a certificate workflow with public QR verification.

Market
Training providers, Australia
My role
Lead engineer
Users
Provider staff, students and employers
Reporting format
AVETMISS

ProblemProviders needed government report files checked before submission and certificates tied to completed study.

What I didI built report generation and validation, student identifier integration, and template-based certificates with QR verification.

ResultStaff can check report files, see which rules remain unchecked, and issue verifiable certificates in their own design.

The certificate journey

A printed certificate can lead back to its record

A certificate leaves the training provider's dashboard. A student downloads it, prints it or sends it to an employer. That person may never have used the student management system. I built public QR verification so the document could lead back to a record they could check. Verification needed to work beyond the staff account that created the file.

The QR code is part of the certificate generation workflow. Staff can place it using a visual editor or a placeholder in their document template. This matters because providers have their own designs. A verification code that covers a signature or collides with a footer is a document problem, even if the verification page works. I treated its placement as part of preparing the certificate, rather than an extra task after download.

The public check serves a different purpose from the eligibility check. Eligibility determines whether the system should issue the certificate. Verification gives someone outside the provider a way to check an issued document. I needed both. A readable PDF alone cannot explain whether a student met the course rules, and a staff-only record cannot help an employer checking the certificate later.

The problem

Student records had to become files other people could trust

Australian training providers manage students, classes, enrolments and results. They also need to turn those records into government reports and certificates. AVETMISS is the structured reporting format used for vocational education activity in Australia. Its files have fixed-width fields and rules linking records across files. A file can look readable to a person and still contain a format error or a broken link.

I was the lead engineer across the product, including the backend, dashboard and document workflows. I guided junior developers working on frontend design and integrated their work. My part here was making operational records produce useful outputs without asking staff to reconstruct the same information elsewhere. Reporting needed checks before submission. Certificates needed controlled templates, course eligibility and a way for employers to verify them after they left the system.

What made it hard

Correct fields can still make an incorrect report

The difficult part of reporting was the relationship between files. A student record, an enrolment record and a training activity record do not stand alone. A value can satisfy its own field rule while referring to a record that is absent elsewhere. I built checks for those links alongside format, duplicate and code-list checks. That gave the validator a view of the report package rather than isolated lines.

The destination also matters. National and state reporting have different requirements, and funding choices can affect the output. I kept destination and funding settings in the report workflow. Staff needed to make the reporting choice when generating the report, rather than change underlying student details simply to produce a different output. The stored record and its reporting representation have related but different jobs.

Some rules depend on government information that the product does not hold. I could not solve that by adding another local condition. A local validator has a boundary, and the interface needed to show it. I made those rules return an explicit unchecked result. That was a more useful answer than treating missing information as proof that everything was valid.

Certificates brought a different constraint. Providers already had Word templates with their own wording, fonts, tables and footers. Recreating the appearance in another format would create a second design to maintain. I kept the provider's document as the starting point and built the generation process around it. That moved the difficult work into document conversion and pagination, where the actual differences needed to be handled.

From enrolments

I generated reports from the operational records

The report generators read from a dedicated enrolments collection. Enrolment is where the student, class and study details come together. I used those records to produce the required files rather than ask staff to maintain a separate reporting spreadsheet. The same unit outcomes and dates that support everyday administration also feed the reporting workflow. That connection makes record quality part of daily use.

I also worked on the records before they reached export. Student fields include the details needed for vocational reporting. Enrolments store unit-level outcomes and dates. The backend checks enrolment conditions such as duplicates, selected units and class limits. These checks do not replace file validation. They address a different point in the process: keeping avoidable mistakes out of the operational data before they spread into documents and reports.

A report is an output with its own context. I added report metadata, file hashes and support for a nil return. A nil return represents the absence of reportable activity; it should not be confused with a broken export that produced no data. File hashes identify the generated files. These details help describe what was produced, but they do not make the contents correct by themselves. The validator still has to inspect the files.

Choose the destination

Report settings belong to the report being generated

I built the destination split for national and state submissions, with report-time funding choices and state formats. The output needed to follow the selected reporting path. This is easy to underestimate when an export starts as a download button. Once the same data can be reported under different conditions, that button needs a clear description of the output it will create.

An important distinction was between an address stored for a student and an address representation required by reporting rules. I handled reporting-specific address transformations at generation time. Changing the stored address to satisfy a particular report would make the student's ordinary record less useful. Keeping the transformation in the generator preserved the operational data while allowing the export to follow its own requirements.

I also added reporting code lists and the fields the files require. These are not decorative dropdown values. A code has meaning to the receiving system, and the generator must put it into the correct place. That is why I treated field mapping, padding and destination handling as part of the report implementation, rather than expecting staff to repair the downloaded files by hand.

Check the files

I validated the output rather than assuming generation was enough

The validator parses the generated fixed-width files and applies rulebook-driven checks. It checks field format, uniqueness, relationships across files, code lists and addresses. Parsing the files matters because these are the artefacts that leave the product. Checking only the database records would miss errors introduced while mapping values into the export format. A correct source record can still become an incorrectly padded field.

For addresses, I used an offline resolver as part of the validation work. For linked records, the validator checks referential integrity across the report files. These are different checks with different meanings. A report should not receive a single reassuring answer merely because its lines can be read. The staff member needs to know whether the structure and the relationships have been checked too.

I put validation before saving the report and built a validation page for the platform administrator. That made checking part of the product workflow. It was no longer just an expectation that someone would remember to inspect a download afterwards. The purpose was to catch problems where staff could still act on them, before taking the files to the official submission process.

I kept the claim about this work specific. The product can check the rules it implements against the information it has. Government acceptance remains a separate step. Passing the local checks is useful because it identifies avoidable errors earlier. It does not justify presenting the product as the final authority on every condition that may apply to a submission.

Show the limits

Not checked is a result staff need to see

I made rules that require live government data appear as not checked. This is more than an error message choice. A pass says the condition was evaluated and satisfied. An unchecked result says that evaluation could not be completed here. Those statements lead to different next actions. Combining them would make the report look more certain while giving the provider less useful information.

The trade-off is that the result is less simple than a green success screen. Staff still have work to do in the official validation process. I accepted that because the product should explain its part of the job accurately. A tool that points out its limits can still remove a great deal of manual checking. It does not need to imply that the remaining checks have disappeared.

That boundary also helped me keep the report generator and validator in perspective. Generating a file, checking its structure and obtaining acceptance are related stages. They are not interchangeable. I built the stages inside the product that I could support: generation, local checking and a clear account of gaps. The provider then takes the files through the required submission process with more information about their condition.

Student identity

I kept government protocol work behind a separate service

Student identifier verification was another part of the same operational problem. The dashboard needed a way to verify a student's Unique Student Identifier through a government service. I built the integration as a separate service. The main application handles the staff workflow and organisation context. The separate service handles the government protocol, relationship tokens and provider identifier generation and validation.

Keeping that boundary added a service to operate, but it kept protocol details out of the main product. The dashboard still needed request, generation, resend and status flows for provider identifiers. I built those flows with organisation scoping and role guards. A request belongs to a provider, and the staff interface needs to show its current state rather than expose the integration details directly.

I also handled students with a single name in the identifier verification flow. That was a concrete reminder that identity data cannot always fit the assumptions of a standard contact form. Reporting and verification depend on the real record, so the application needs to carry that record through the workflow without forcing staff to invent missing name parts just to satisfy a field.

Prepare the certificate

The provider's template remained the document design

I built template upload, preview, editing and finalisation. Staff prepare their own Word document, then the system fills it with the certificate details and converts it to PDF. Draft templates are excluded from generation. That separates work in progress from a template that is ready to issue. It also means the document workflow has a meaningful preparation stage before staff select students.

The conversion had to preserve the layout, including unit tables that could continue across pages. I added measured pagination that accounts for the footer. A table that contains the right units but runs into the footer is still an incorrect certificate for the person reading it. Document correctness includes the way the information is placed, not just whether the text exists somewhere in the output.

The pipeline also supports previews and re-rendering after edits. I added a local development conversion fallback so document work could continue without the production conversion server. That was an operational choice for development, rather than a claim that different conversion engines always render identically. The main workflow still needed to be checked against the provider's actual template and expected appearance.

Issue and maintain

Bulk generation still had to respect each student's eligibility

I built course-rule checks before certificate generation. For qualification enrolments, the checks cover competent core units and the required electives. Statements of attainment have separate handling. A class list is convenient for selecting students, but membership of that class does not prove completion. The generation path needed to make that distinction even when staff were working with a whole class.

Staff can generate certificates individually or in bulk, then download a ZIP or combined PDF. I also built editing and re-rendering of issued certificates. These capabilities sit around the eligibility and template controls. Making bulk work convenient should not remove the checks that make an individual certificate meaningful. I treated the convenience of selection and the permission to issue as separate concerns.

Deletion requires a reason, which is stored in the activity history. I added the reason prompt in the interface and the requirement in the backend. A certificate is an important output, so its removal should leave an explanation. The wider product has selective undo, but actions that permanently remove stored certificate files are excluded. I did not present a recorded reason as a promise that a deleted file could always be restored.

Decisions

I chose explicit limits and controlled document changes

What should happen when a rule needs external data?

Option

Treat the absence of a local error as a pass.

Chosen

Return not checked and keep that limitation visible.

Staff need to distinguish a completed check from a condition that still needs another system.

How should the provider keep its certificate design?

Option

Rebuild each document as a separate web layout.

Chosen

Fill the provider's Word template and convert it to PDF.

This keeps the design in the document staff already maintain, while accepting the work of conversion and pagination.

Should selecting a class be enough to issue certificates?

Option

Generate for everyone in the selected class.

Chosen

Check course eligibility for the selected students.

Class membership and completed study mean different things, especially when issuing documents in bulk.

What should remain after certificate deletion?

Option

Remove the file without requiring an explanation.

Chosen

Require a reason and record the removal in the activity history.

The provider needs to explain a document's removal, even when the stored file cannot be recovered through undo.

What changed

Staff can check reports and issue verifiable documents inside the product

Checks before submissionGenerated report files are checked for format and cross-file errors, with unchecked rules shown explicitly.
Provider-owned designsStaff can issue eligible students' certificates in bulk using their prepared Word templates.
Public verificationA certificate's QR code gives people outside the dashboard a route to verify the issued document.

Building software for a regulated industry?

Let's talk about the reports, documents and checks your staff need to get right.

Let's talk