// case study
Live: public demo
QA Automation Test
A cross-stack QA automation test-health dashboard aggregating results from seven independent test repos, Playwright, Selenium, Cypress, Cucumber BDD, and API testing, across Python and TypeScript. Each repo posts its own results to a small authenticated webhook right after CI runs, and the dashboard renders whatever is on disk, no rebuild, no redeploy, no polling.
01 / Problem
Seven independent QA automation repos across five frameworks and two languages produce seven different places to check whether anything is actually passing. There was no single view of cross-stack health, and CI logs are not something anyone, including me, checks regularly. A pass/fail regression in one stack could sit unnoticed for days.
02 / Approach
A standardized results.json schema (stack, platform, pass/fail/skip counts, per-test detail) is shared across all seven repos. Each repo's CI workflow posts its results to a small authenticated webhook (POST /api/results/[stack]) right after every run, one bearer token per stack, compared with a timing-safe hash so a leaked token can only overwrite that one stack's file, never the git repo or any other stack. The dashboard itself is a Next.js app that reads results/*.json fresh on every request instead of baking data in at build time, groups cards by platform (web, API, with a mobile section ready for Appium/Maestro), color-codes by pass rate, and shows a per-test detail modal on demand. Adding a new stack later is just a new JSON file and a webhook call, no dashboard code changes.
03 / Engineering decisions
A scoped webhook token, not a git-push PAT.
Each source repo gets its own per-stack token that can only write one results file. A leaked token cannot touch the dashboard repo, other stacks, or anything else on the VPS, a narrower blast radius than the git-PAT-with-repo-write-access alternative.
Dynamic rendering, not a static export.
The homepage reads results/*.json on every request (export const dynamic = "force-dynamic") instead of freezing the data at build time. A webhook POST shows up on the next page load, with zero rebuild, redeploy, or restart.
Rate-limited and schema-validated at the edge.
Stack slugs are regex-locked to [a-z0-9-]+ (no path traversal), each stack is capped at 10 writes/minute, and every payload is checked against the same schema the dashboard renders, so a malformed or hostile request never reaches disk.
04 / Architecture
$ ci_run_(7_independent_repos)
↓
post_/api/results/[stack]_(per-stack_bearer_token)
├─ playwright-python
Playwright + pytest, Page Object Model
├─ playwright-js
Playwright + TypeScript, network mocking, parallel-safe
├─ selenium-python
Selenium 4 + pytest, Page Object Model
├─ cypress-js
Cypress + TypeScript, Page Object Model
├─ bdd-cucumber-playwright
Cucumber + Playwright, Gherkin feature files
├─ api-testing-python
pytest + requests + pydantic, schema validation
└─ api-testing-js
Jest + TypeScript, mirrors the Python suite
↓
results/*.json → dashboard renders on next request