Case study
ComplyLoop — Accessibility Compliance
A compliance tool built around one loop: find the problem, explain it, fix it, verify the fix and keep the proof.
Design & development · 2026

Accessibility checks
Unit-test files
E2E specs
Standards
Overview
The problem & the approach
Most accessibility scanners stop at a list of findings. ComplyLoop is built around what happens next: each finding says what failed, where and why it matters, a fix is proposed as a draft pull request, and the finding is only closed once a new run confirms it.
It targets React, Next.js and TypeScript projects and the French RGAA 4 standard alongside WCAG 2.2. You connect a GitHub repository, it scans the source, and with a preview URL it also audits the rendered pages for what a source scan cannot see, such as contrast and reflow.
The product is in private preview: the landing page is public, while sign-in and the workspace stay behind a password because the workspace runs scans. The source is public to read.
What I owned
Defined the product scope: the loop from requirement to evidence, and who it is for
Designed the domain model, the module boundaries and the durable job architecture
Built the analysis engine, the GitHub App integration, the workspace UI and the evidence exports
Set up Postgres with Drizzle migrations, deployment on Vercel, CI and production checks
Product
What it does
Source scan
01Custom AST checks together with eslint-plugin-jsx-a11y, over a shallow clone of the repository that is deleted when the job ends. Re-runs skip files that have not changed.
Runtime audit
02With a preview URL, Playwright and axe audit the running pages for rules a source scan cannot decide, like colour contrast, landmarks and reflow.
Findings you can act on
03Each finding gives what failed, why, where, the impact, a confidence level and which engine found it, so a developer can act without opening the standard.
Fixes as draft pull requests
04Where a patch can be generated and verified, it is opened as a draft PR. Runtime findings get guidance for the call site instead of a generic attribute.
Verification and evidence
05Only a re-run can mark a finding verified. Every assessment, fix and decision is appended to an evidence log that exports as JSON, Markdown or HTML.
Continuous monitoring
06Pushes to the default branch trigger a new assessment through webhooks, using short-lived GitHub App tokens, so checks keep running with nobody signed in.
Organisations and roles
07Owner, admin, member and viewer roles, invites by GitHub login, a personal organisation on first sign-in and an organisation switcher.
Screens
Product walkthrough


Engineering
How it is built
Deterministic analysis, advisory AI
Statuses come from checks, not from a model. AI can explain a finding or suggest a patch, but a patch has to pass the same checks before a PR is offered, and it never sets a requirement status.
One registry for every check
Each of the 132 checks is registered once, with its authority, the engines that can report it and the catalog control it backs. Coverage tests cross-check that registry against the AST checks, the rule maps and the catalog, so a check cannot ship without an engine or guidance.
Assessments as durable jobs
A run is queued in Postgres and picked up by a GitHub Actions worker, claimed with FOR UPDATE SKIP LOCKED. A 15-minute schedule picks up jobs whose dispatch failed or whose lease expired, so nothing needs a long-running server.
A single write path
Mutations go through write helpers that take a per-project lock and guard against stale writes. Server actions never touch the database directly, and ESLint enforces it.
Evidence that cannot be edited
The evidence log is append-only: a record can be superseded, never changed. GitHub tokens are encrypted at rest with AES-256-GCM.
Boundaries enforced by lint
The shared contract sits at the bottom, the app core imports only from it, and the AI module cannot import server code. ESLint fails the build when a layer reaches across.
Delivery
A per-request Content-Security-Policy with a nonce, a Basic-auth preview gate that fails closed, Sentry reporting through a tunnel route, and three GitHub workflows: CI, the assessment worker and a production configuration check.
Quality
Tested, typed and accessible
244 Vitest files, with a coverage gate and a Postgres persistence integration suite
Playwright end-to-end specs behind a gated harness that is never enabled on customer deployments
Strict TypeScript, ESLint layer rules and a single verify command that runs lint, typecheck, tests, build and a bundle check
Coverage tests that fail when a check is missing an engine, a catalog row or guidance
Want to see it live?
The store is live: browse the catalog, switch language and add to cart. The source code is private, so I am happy to walk through it on a call.