Accessibility: EN 301 549 conformance table¶
Date: 2026-09-09 · Assessed release: calServer V2 (frontend-v2/, laravel/,
report-runner/) · Type of assessment: vendor self-assessment
This is the document a procuring body usually asks for as a "VPAT" or "accessibility conformance report": a statement per EN 301 549 clause, with reasons and without varnish. Germany's BITV 2.0, section 3, refers to this standard; its clause 9 reproduces WCAG 2.1 Level AA.
What this table is not
It is not a report by an independent body and not a declaration of conformity. No accredited BITV test has taken place. The statements come from an internal audit dated 2026-09-04 (222 raw findings, 24 of them refuted in a counter-check) and from automated checks that run in the build.
In short: calServer V2 does not fully meet EN 301 549 today. Where the gaps are is stated below. Anyone who needs a dependable statement for a tender gets the basis for one here, not the proof.
Rating levels¶
| Level | Meaning |
|---|---|
| Supported | The requirement is implemented; no open finding. |
| Partially supported | Implemented in principle, individual places do not meet it. |
| Not supported | Not implemented, or violated to a noteworthy extent. |
| Not applicable | The product does not have the function in question. |
Scope¶
Assessed: the calServer V2 web interface (signed-in area, sign-in page, public portal, QR views, legal texts), the API responses insofar as they determine interface behaviour, and the generated output files (PDF calibration certificates, grid exports as PDF and XLSX, outgoing email).
Not assessed: calServer V1 (httpdocs/, Yii). V1 is a separate application
with its own interface and is not covered by this document. A statement about V1
cannot be derived from this table.
The synchronisation component (calserver-sync, SymmetricDS) runs server-side as
a service and command-line tool and has no end-user interface.
Clause overview¶
| Clause | Subject | Rating | Note |
|---|---|---|---|
| 4.2 | Functional performance statements | partially supported | Operation without vision and without a mouse is possible throughout; the open contrast values affect use with limited vision (4.2.4). |
| 5.1 | Closed functionality | not applicable | All interfaces run in the browser with full assistive-technology access, including the kiosk and QR views. |
| 5.2 | Activation of accessibility features | partially supported | Colour scheme, high contrast, font size and reduced motion are reachable before signing in and persist without an account. Five layout-less pages do not carry the control. |
| 5.3 | Biometrics | not applicable | No biometric authentication. |
| 5.4 | Preservation of accessibility information during conversion | partially supported | Report PDFs preserve structure, language and title. The grid PDF export loses the header association because TCPDF cannot write a structure tree (see clause 10). |
| 5.5 – 5.9 | Operable parts, key repeat, simultaneous operation | not applicable | No hardware. |
| 6 | Two-way voice communication | not applicable | Not included. |
| 7 | Video capabilities | not applicable | The application ships no time-based media. Videos added by the operator (for example a sign-language explanation) are their content and their responsibility. |
| 8 | Hardware | not applicable | Software only. |
| 9 | Web | partially supported | Detailed below. |
| 10 | Non-web documents | partially supported | Report PDFs are tagged and carry title, language and a text alternative for every image; XLSX exports carry document properties and a marked-up header row; email carries a text alternative. Open: the grid PDF export through TCPDF. |
| 11 | Non-web software | not applicable | No native client, no desktop application. |
| 12 | Documentation and support services | partially supported | Detailed below. |
| 13 | Relay and emergency services | not applicable | Not included. |
Clause 9 in detail (WCAG 2.1, Levels A and AA)¶
Clause 9 of EN 301 549 refers to WCAG 2.1 criterion by criterion; 9.1.4.3 is WCAG 1.4.3 and so on.
Perceivable¶
| Criterion | Level | Rating | Note |
|---|---|---|---|
| 1.1.1 Non-text Content | A | supported | Icon controls carry a name, and a static check in the build holds that in place. All 99 loading indicators get their name from a single default on the library, translated and following the language choice; a call site with a more precise name keeps precedence. A measured run against the running application then found three more nameless images that a source check structurally cannot see: Chart.js puts role="img" on its own canvas without a name, right next to the wrapper that carries the text alternative. The canvas is now hidden from assistive technology. |
| 1.2.1 – 1.2.5 Time-based Media | A/AA | not applicable | The application ships neither audio nor video. |
| 1.3.1 Info and Relationships | A | partially supported | Label, help text, error text and required state are wired to the control centrally; option groups carry a group name. Open: individual tables without header association. |
| 1.3.2 Meaningful Sequence | A | supported | Checked, no finding. |
| 1.3.3 Sensory Characteristics | A | supported | Checked, no finding. |
| 1.3.4 Orientation | AA | supported | Nothing forces landscape or portrait. |
| 1.3.5 Identify Input Purpose | AA | supported | Sign-in, registration, the password flow and the profile carry autocomplete values. The remaining fields collect data about devices and customers, not about the person operating the application. |
| 1.4.1 Use of Colour | A | supported | Toggle buttons carry their state in aria-pressed, status buttons in their name. This was not spot-checked: every button whose colour depends on a state was listed from the source and assessed individually — where the information already appears as text nearby (such as the "Advanced filter active" banner), the button was left as it was. |
| 1.4.2 Audio Control | A | not applicable | No auto-playing audio. |
| 1.4.3 Contrast (Minimum) | AA | supported | 966 class lists carrying a fixed grey now use text-muted, which resolves per mode (4.76:1 light, 6.91:1 dark) and is raised further in high-contrast mode. The static scan in the build is at zero and no longer permits a fixed shade; the values are unit-tested. An axe run against the running application then found one more place a source check cannot see, because it comes from the preset: the label of the unselected toggle button sat at 4.34:1. It appears in the sidebar and above every grid, so it is the state you read most of the time; one shade darker gives 6.92:1. |
| 1.4.4 Resize Text | AA | supported | Relative units throughout, no zoom lock, plus font scaling up to 150 % in the application itself. |
| 1.4.5 Images of Text | AA | supported | No text images. |
| 1.4.10 Reflow | AA | supported | Measured at 320 px, not estimated: 103 of the 105 routes in the inventory were opened and checked for horizontal overflow — not one overflows. (Two detail routes had no record in the test data.) The dashboard reflows from 12 to 6 to 1 column, wide tables scroll in their own region, and dialogs with a fixed pixel width are capped by stylesheet at 95 % of the viewport width. |
| 1.4.11 Non-text Contrast | AA | partially supported | Borders of all form fields and the outline of switches are above 3:1; the values are bound to the design token and unit-tested. The measurement-history curves are now computed and pinned down as well: 4.76–5.48:1 in light mode, 6.91–9.22:1 in dark. What remains open are the segment colours of the status charts — they come from the operator's status configuration, the product does not choose them and cannot promise 3:1 for them. There, the toggleable data table next to every chart carries the same information. |
| 1.4.12 Text Spacing | AA | supported | Measured against the running application with the four prescribed overrides (line height 1.5, letter spacing 0.12 em, word spacing 0.16 em, paragraph spacing 2 em), across eight pages of the application. Only loss caused by the overrides was counted — text already shortened before them is a design decision with its own preview, not a loss. Three places lost text and are fixed (dashboard selector, column picker, widget heading); after that, no loss and no horizontal overflow. |
| 1.4.13 Content on Hover or Focus | AA | supported | Tooltips appear on keyboard focus as well, can be closed with Esc, stay while the focus stays, and can be reached with the pointer. All three conditions are met in one place for every call site, not per button. |
Operable¶
| Criterion | Level | Rating | Note |
|---|---|---|---|
| 2.1.1 Keyboard | A | supported | The four keyboard blocks found in the audit are fixed (password visibility toggle, file pickers, the DCC export's expert tabs, the migration module disclosure). Dragging, resizing and freehand drawing each have an equivalent second path, in-cell editing has the detail page. Column width is a number field in the column dialog — the same width a mouse drag writes, the arrow keys change it in steps of ten, and an empty field releases it again. |
| 2.1.2 No Keyboard Trap | A | supported | Checked, no finding. |
| 2.1.4 Character Key Shortcuts | A | supported | The only shortcut is Ctrl/Cmd + K, so with a modifier. |
| 2.2.1 Timing Adjustable | A | supported | Both automatic redirects are replaced by a link and a button respectively. There is no timing left. |
| 2.2.2 Pause, Stop, Hide | A | supported | No self-moving content; animations follow the system setting and can additionally be switched off in the profile. |
| 2.3.1 Three Flashes or Below Threshold | A | supported | Nothing flashes. |
| 2.4.1 Bypass Blocks | A | supported | Skip link in both layouts, named landmarks. |
| 2.4.2 Page Titled | A | partially supported | Every route sets a descriptive document title; the error page does not. |
| 2.4.3 Focus Order | A | supported | Focus moves into the main region after navigation. The overlays were walked through one by one — focus in, focus trapped, focus back to the trigger. PrimeVue does all three only for Dialog: Popover takes focus only if the content holds an autofocus (none of the nine does), and Drawer does not hand it back on close. Both gaps are closed at the library rather than at 14 call sites; all nine measured overlays now behave alike. |
| 2.4.4 Link Purpose (In Context) | A | partially supported | Value links in tables carry an addition for screen readers. Individual places remain open. |
| 2.4.5 Multiple Ways | AA | supported | Navigation, quick search and references from lists. |
| 2.4.6 Headings and Labels | AA | partially supported | Holds for the application; for operator-maintained content it depends on the operator. |
| 2.4.7 Focus Visible | AA | partially supported | A focus ring is present throughout, low in contrast in individual places. |
| 2.5.1 Pointer Gestures | A | supported | Moving a tile, drawing a signature, reordering columns and dragging the column width each have an equivalent second path (number fields, typing, arrow buttons). |
| 2.5.2 Pointer Cancellation | A | partially supported | A few surfaces act on the down-event. |
| 2.5.3 Label in Name | A | partially supported | The rule is documented and checked; individual buttons have an accessible name that differs from the visible one. |
| 2.5.4 Motion Actuation | A | supported | No motion-operated function. |
Understandable¶
| Criterion | Level | Rating | Note |
|---|---|---|---|
| 3.1.1 Language of Page | A | supported | <html lang> follows the language choice, and so do the guest pages now: registration, the password flow, email confirmation and initial setup including the password rules. The document title follows as well — a page states it additionally as a translation key. Until the language bundle arrives, a guest page briefly shows the English source text; for public pages the bundle is loaded non-blocking. |
| 3.1.2 Language of Parts | AA | partially supported | Legal texts are marked with the language they are actually served in. Other mixed-language places are not. |
| 3.2.1 On Focus | A | supported | No change of context on focus alone. |
| 3.2.2 On Input | A | supported | Checked, no finding. |
| 3.2.3 Consistent Navigation | AA | supported | The same navigation in the same place. |
| 3.2.4 Consistent Identification | AA | partially supported | A few identical actions are named differently. |
| 3.3.1 Error Identification | A | partially supported | Forms using the central contract report errors at the field and in a summary; the guest forms do not. |
| 3.3.2 Labels or Instructions | A | supported | Required fields carry aria-required on the control, set by SettingField; the asterisk there is decorative and hidden from assistive technology, otherwise "star" would be read on top of the announced "required". Where it stays visible, the explanation sits above the form. A check in the build reports a hand-written asterisk in the plain text of a label. |
| 3.3.3 Error Suggestion | AA | supported | Error messages name the expected input. |
| 3.3.4 Error Prevention | AA | partially supported | Deletions are confirmed; not every consequential action is reversible. |
Robust¶
| Criterion | Level | Rating | Note |
|---|---|---|---|
| 4.1.1 Parsing | A | supported | With the WCAG 2.1 erratum of September 2023 this criterion counts as always met. |
| 4.1.2 Name, Role, Value | A | supported | 136 controls received a name in a dedicated pass, and toggle buttons now carry their state as well. A static check in the build prevents regressions; since AP-7 it also catches a label that disappears on narrow viewports — the attribute is there, the name is not. A measured run against the running application then found two more places where an aria-label sat on an element without a role and therefore never arrived; they now carry role="img". |
| 4.1.3 Status Messages | AA | supported | The forms before sign-in carry role="status" or role="alert"; email confirmation has a region present in the document from the start. In the signed-in area, toasts and the DynamicForm error summary report. |
Clause 10: Non-web documents¶
| Requirement | Rating | Note |
|---|---|---|
| 10.1.1.1 Non-text content | supported | Outgoing email carries a text part next to the HTML — the template's maintained alternative, otherwise one derived from the HTML. Every image in a report PDF carries a text alternative: the template's, otherwise the element's name, otherwise a generic term in the report language. How good that text is remains the template's decision — a chart needs its key message, a barcode its value, and only the template author knows either (master reports). Purely decorative images could be taken out of the reading order as /Artifact; JasperReports offers no way to do that. |
| 10.1.3.1 Info and relationships | partially supported | Report PDFs (calibration certificates, certificates, labels) carry a structure tree. XLSX exports mark the header row as a table range and as repeating rows. Open: the grid PDF export — TCPDF cannot emit a structure tree (see below). |
| 10.2.4.2 Document titled | supported | Report PDFs carry the report name, grid exports the export name; DisplayDocTitle makes the reader show it instead of the file name. |
| 10.3.1.1 Language of document | supported | Report PDFs take the language of the job, grid PDFs and email that of the installation. With no job language, none is set rather than guessed. |
| 10.4.1.2 Name, role, value | supported | XLSX exports carry document properties and a table range with a header row, so a cell announces its column name. |
Two limits, named rather than claimed away:
- The grid PDF export stays untagged. It runs through TCPDF, and the library cannot write a structure tree — the line for it is commented out in its source. It does carry title and language; the header association is lost. If you need a tagged table, export to XLSX or use a report PDF.
- XLSX has no document language. OOXML core properties have no field for it; that is a limit of the format, not of the implementation.
Clause 12: Documentation and support services¶
| Requirement | Rating | Note |
|---|---|---|
| 12.1.1 Accessibility and compatibility features | supported | Described in the manual under User Profile → Display and accessibility and in this table. |
| 12.1.2 Accessible documentation | partially supported | The documentation is served as HTML (MkDocs Material), not as PDF, and is therefore scalable and readable in the browser. The documentation theme itself has not been checked against WCAG 2.1 AA; this statement rests on the format, not on a measurement. |
| 12.2.2 Information on accessibility features in support | partially supported | This table and the manual answer the question; a dedicated accessibility feedback channel is up to the operator (see below). |
| 12.2.3 Effective communication | operator | Support towards end users lies with the operator of the installation. |
| 12.2.4 Accessible documentation of support | operator | Likewise. |
What the operator is responsible for¶
This table assesses the product. A statement about a specific installation additionally needs:
- A completed accessibility statement with a contact point, legal basis, competent enforcement body and date. calServer ships a template; see Legal documents.
- A feedback mechanism under section 12b BGG through which affected people can report barriers.
- For public bodies: explanations in German Sign Language and in easy language under section 3 (2) BITV 2.0.
- An assessment of local changes: adapted report templates, own translations, embedded third-party content and customised interfaces are not covered by this table.
How this table is maintained¶
It is updated after every change with an effect on accessibility and reviewed against the code at least once a year. Its basis is:
- the internal audit report of 2026-09-04 (
docs/audit-bitv-2.0-luecken-2026-09.md), - the static check
npm run a11y:scan, which runs on every pull request and whose ceiling may only shrink, - the nightly axe run against WCAG 2.1 AA across the public pages, the dashboard, two tables, the administration area and an open dialog, in four display modes (dark, high contrast, 150 % font, 320 px width).
To put the tooling in perspective: an automated check finds roughly a third of the actual barriers. What is marked "supported" here is evidenced at code sites, not inferred from a tool staying quiet.