01
ALL WORK
01

PLATFORM MIGRATION · 2024–PRESENT

Knock Examination Platform

Led the JSP/jQuery → React migration of a live medical licensing exam platform: built the design system and WCAG/AA component library from scratch, architected cross-module JWT auth with tenant impersonation via Module Federation, and co-designed the multi-tenant SaaS infrastructure. Zero exam disruptions. De facto tech lead on a part-time-managed team.

ReactTypeScriptTailwind CSSViteWebpackModule FederationJWTSpring Boot

$30–40K

MONTHLY SAVINGS TARGETED

0

EXAMS DROPPED DURING MIGRATION

~99%

JS BUNDLE SIZE REDUCTION

4

LAYERS OF ARCHITECTURAL SCOPE

MY CONTRIBUTION

Frontend Architecture

Led

Design System / UX

Led

Auth & Security

Led

Team Leadership

Led

Multi-tenant Architecture

Collaborated

Backend / API

Collaborated

Led
Collaborated
Supported

BEFORE / AFTER

BEFORE

JSP/jQuery monolith with no design system, no WCAG baseline. All clients in one shared database — data leakage risk. Canada-only AWS region. Single domain across all clients. $30–40K/month in vendor licensing.

AFTER

React + TypeScript SPA with a custom design system and WCAG/AA-compliant components. Per-tenant DB schemas, subdomain routing, multi-region capable. ~99% JS bundle reduction. Migration ongoing — zero exam disruptions.

01

Background

The original platform was built by a small team without a designer. The UX was underdeveloped, component patterns were inconsistent, and WCAG compliance wasn't on the radar. Bugs were shipping because there was no QA process or DevOps infrastructure to catch them before production. On the infrastructure side, the problems were more fundamental. All client data lived in one shared database with no tenant isolation — a security and compliance risk for a platform serving institutional medical licensing organizations. Every client shared one domain. The entire platform ran out of a single Canadian AWS region. The business motivation for migration was clear: eliminate $30–40K/month in vendor licensing fees and own the stack. The engineering constraint was doing it without disrupting daily live exams — where a mid-exam failure had real consequences for candidates awaiting licensure.

Written exam interface on the Knock test environment — split-screen layout with reading passage on the left and rich text answer panel with table support on the right, showing question 2 of a sample assessment
Sample assessment — written exam UI: reading passage (left) and rich text response panel with table support (right)
02

Component Strategy

The first component I built in the new system was a generic, reusable data table — the most-used UI element across the platform. That's a deliberate strategic choice, not a default. Building it first forced the team to answer foundational questions before anything else was added. How does the component consume data? How are columns defined externally? How do sorting and pagination behave? The answers became the pattern template for every component that followed. A junior developer picking up a new feature had a working model to follow immediately. The alternative — bespoke implementations per page — would have meant refactoring inconsistencies away later. Under a live-migration time constraint, paying that cost twice wasn't viable. The deeper meta-decision was about how much to plan ahead versus how fast to ship. The framework I used: let constraints do the work. Deadline, team size, and budget define how much architectural investment makes sense. When constraints are tight, you design extension points without fully implementing them. You don't build for hypothetical future requirements. That judgment call — YAGNI calibrated to real risk — recurred throughout the project.

Knock platform login page — new React UI on the test environment
New React login UI running on the tenant test environment (knock-acme.paradigmtesting.test)
03

Design System & Accessibility

The original platform had no design system and no accessibility baseline. I built both from scratch as part of the migration — not as a side project, but as the foundation the component library sits on top of. That meant establishing token-level decisions first: spacing scale, color system, typography hierarchy, interactive state patterns. Every component in the new platform draws from that system. A junior developer can build a new feature and have it look and behave consistently without needing a design review for every decision. WCAG/AA compliance was embedded at the component level, not retrofitted. Accessible focus states, color contrast ratios, and semantic HTML structure were non-negotiable from the start. Medical licensing exam platforms have real obligations to candidates who use assistive technology — and retrofitting accessibility is considerably more expensive than building it in from the beginning.

KEY DECISION

Phased migration over a hard cutover

DECISION

We built the new React app in parallel and migrated feature-by-feature, maintaining a compatibility layer throughout — rather than setting a cutover date and switching all at once.

REASONING

Medical exams run daily. A failed cutover would delay licensure for candidates and create legal exposure for the business. The phased approach let us ship incrementally, gate aggressively, and preserve trust with stakeholders who were already anxious about the change. Compatibility layers accrue debt fast — but the alternative was riskier.

AWS architecture diagram — GoDaddy DNS → Global Accelerator → WAF → ALB → EC2 Auto Scaling Group → RDS Multi-AZ / ElastiCache / S3 / Secrets Manager

FIG. 01 — Project overview

04

Auth Architecture

The most technically complex challenge was the authentication layer. We use Webpack Module Federation — a micro-frontend architecture where a shell application loads separately-deployed remote modules at runtime. Auth state has to flow across module boundaries, which is harder than standard single-app JWT implementation. The core flow: login issues an access token and a refresh token. When the access token expires, the app silently fetches a new one using the refresh token. If the refresh token has also expired — indicating 15+ minutes of inactivity — the user is logged out. Layered on top is an impersonation system: IT administrators can "act as" tenant-level admins to debug or manage a client's configuration without using that client's credentials. The JWT has to carry both the admin's real identity and the impersonated context, and every permission check has to respect which context is active. Getting this wrong would mean an IT admin having broad data access across all clients — a security failure, not just a bug. It took several iterations to get the token propagation and session expiry behavior correct across module boundaries. This is one of those problems where the solution looks obvious in retrospect and opaque at the start.

Sequence diagram showing the Admin Tenant Interaction Flow — login, JWT exchange, Module Federation module loading, and tenant JWT verification
Admin → React admin portal → Spring Boot control-plane → tenant-plane: JWT and Module Federation handshake
05

Multi-Tenant Infrastructure

The old platform had all clients in one shared database. Any query that didn't filter by the right identifier could return records belonging to another client. With medical licensing data, that's a compliance failure. It also meant one client's load could affect every other client — no isolation at all. The new architecture gives each client their own isolated database schema. A query within one schema cannot touch another. That isolation is enforced at the database level — not dependent on application-level WHERE clauses being correct in every case. Each client also gets their own subdomain: tenant.platform.com. This enables per-client branding, scopes auth tokens cleanly to each domain, and makes SSL, CORS, and cookie boundaries straightforward to reason about. The old platform's shared domain constrained every client-specific feature. Finally: multi-region AWS deployment. The old platform ran in a single Canadian region. The new architecture is built to serve clients across regions without a single point of failure.

Database schema diagram showing multi-tenancy structure — Admin table, Managed_Tenants join table, and Tenant table with per-tenant schema and domain fields
Multi-tenancy schema: Admin ↔ Managed_Tenants ↔ Tenant — database-enforced isolation per client
06

Team Dynamics

Our engineering manager is part-time. In practice, I operate as the day-to-day technical anchor: running standups, unblocking junior developers when they're stuck, QA-ing the full platform before releases, and translating requirements into actionable tasks. This isn't a formal title — it's the role the team needed, so I stepped into it. The practical outcome: decisions get made, tickets get prioritized, and there's someone to escalate to when something goes wrong during a live exam window. The platform keeps running. I also had to translate technical risk to non-technical stakeholders who were anxious about the migration. A consistent, lightweight status cadence — even just brief written updates — matters more than I expected early on. Stakeholder trust is infrastructure.

Bar chart comparing JS bundle sizes before and after route-level code splitting: Admin Portal 256 KB → 3.8 KB (−98.5%), Tenant Portal 1.86 MB → ≈100 KB (−99.7%)
JS bundle reduction across both portals — route splitting, SunEditor lazy, OpenTok WebRTC lazy. CI budget enforced per PR.
07

Outcome

The migration has run continuously with zero exam disruptions — the constraint that shaped every architectural decision from phased rollout to conservative release gating. The compliance risk from the background is resolved. Each client now has an isolated database schema, their own subdomain, and the platform is multi-region capable — the structural baseline the old system never had. The component system and WCAG/AA accessibility baseline built from scratch are actively used by the full team. New features ship consistently without per-feature design reviews. The business goal that started the project — eliminating $30–40K/month in third-party licensing costs — is on track to complete once migration finishes.