Waste Services runs operators through 3-year certification
cycles, annual competency assessments, and level-up training
across a hierarchy of work areas. Tracking who is certified, on
what equipment, and when it expires was manual and error-prone —
and getting it wrong can put an uncertified operator on city
equipment. ION models the whole lifecycle, including
incident-driven recertification. Real app, real city operators.
Access control
Role-aware supervisor workflow
Supervisors see only their own work areas, with authority
cascading down a parent→child work-area tree. A data-driven
permission check gates the screen; a two-pane work-area
layout drives operator and path loading on selection.
Assessment engine
Assessment builder integration
Wired a custom JSON-driven assessment engine into a full
catalogue UI with active/inactive states, live save and
validation, and a scoring model. Root-caused two subtle bugs:
the engine only read its config on mount, and score
calculation broke on serialization.
Path lifecycle
Automated path creation
Designed the rule that completing a certification course
auto-creates the learner’s competency path (defaulted
inactive), removing manual supervisor overhead — with
duplicate-path guards per work area and multiple paths
permitted across areas.
CSS architecture
Reusable stylesheet layer
Owned the global stylesheet: reusable classes in a clean
split from screen-specific overrides, keeping the City of
Edmonton design system consistent across every screen.
What I learned
-
Idempotent writes. Always reassign the
returned
Id after a CreateOrUpdate
— skip it and repeated saves silently insert duplicates. I
root-caused a double-create bug exactly this way.
-
Scope correctness. Reading
.Current outside a list-row scope silently
resolves to row 0. Pass the full record as an explicit
parameter instead.