Internal QA workspace for the QA Backend team. Testers can paste plain-English scenarios or Jira tickets, run them through the local backend, and review a structured verdict, recommendations, and execution history.
This repo is a small full-stack app:
- React + Vite frontend in
src/ - Express backend in server.js
- File-backed local account store in
data/accounts.jsonat runtime - Optional integrations for OpenAI, QA Backend, Jira, Slack, Zoho Cliq, and Customer.io
The app gives QA a single internal workspace for:
- turning plain-English requests into a test brief
- optionally expanding Jira tickets into structured test context
- executing QA Backend-backed QA when credentials exist
- summarizing results for faster triage
- saving history, templates, suites, and exports per user
Without credentials, it still works in demo mode for local UI and workflow development.
At runtime, the backend chooses the best available pipeline based on environment configuration:
- User enters a plain-English scenario, Jira key, or Jira URL.
- The frontend detects Jira-like input and can fetch ticket details through the backend.
POST /run-testresolves the input into a test brief.- If OpenAI is configured, the backend uses it to interpret the request and summarize outcomes.
- If QA Backend is configured, the backend executes the QA run.
- The UI stores user-owned history, templates, suites, and settings in browser
localStorage.
Runtime behavior by config:
- OpenAI + QA Backend: full interpret -> execute -> summarize path
- OpenAI only: QA plan and analysis, no live execution
- QA Backend only: direct execution without LLM planning
- No external credentials: demo/mock behavior
- Sign in with a backend-issued
HttpOnlysession cookie - Bootstrap the first account as admin
- Admin invites users or creates them directly
- Invited users accept a one-time link and set their own password
- Users request password-reset links
- Testers run scenarios, save templates, group tests into suites, and export results
The current design gets several important basics right:
- credentials stay server-side in
.envor.env.production - frontend calls the backend with cookie auth; it does not talk directly to Jira or OpenAI
- passwords are hashed server-side before storage
- session cookies are signed and
HttpOnly - invite and reset tokens are hashed at rest and time-limited
- auth, test execution, Jira, and notification paths are rate-limited
- production readiness checks fail closed on unsafe config
Relevant files:
- server/security.mjs
- server/tokens.mjs
- scripts/check-production-readiness.mjs
- tests/security.test.mjs
- tests/auth-flow.test.mjs
This project is still best treated as a single-instance internal tool.
- Accounts are stored in a local JSON file, not a database.
- Rate limits are in-memory per Node process.
- Concurrent writes to
data/accounts.jsonare not coordinated across processes. - History/templates/suites/settings are stored client-side per user in
localStorage.
That means this is fine for local development and a small internal deployment, but not yet a horizontally scaled or highly concurrent production system.
QATool/
├── src/
│ ├── App.jsx # App composition root and public auth routes
│ ├── components/ # Login, invite/reset flows, shell, tabs
│ ├── hooks/ # Auth, tests, suites, accounts, export state
│ └── lib/ # API client, storage, export helpers, constants
├── server.js # Express API, auth, orchestration, runtime modes
├── server/
│ ├── security.mjs # Cookie auth, hashing, validation, rate limiting
│ ├── tokens.mjs # Invite/reset token generation and verification
│ ├── email.mjs # Customer.io-backed invite/reset delivery
│ ├── integrations.mjs # QA Backend, Jira, Slack, Zoho Cliq calls
│ ├── openai.mjs # LLM-guided QA flows
│ ├── jiraKey.mjs # Jira URL/key parsing helpers
│ └── loadEnv.mjs # Dev/prod env loading
├── tests/ # Node test coverage for security and auth flows
├── scripts/
│ ├── start-prod.mjs # Safe local production launcher
│ ├── check-production-readiness.mjs
│ ├── internal-publish-checklist.mjs
│ └── migrate-accounts-to-email.mjs
├── QUICKSTART.md # Fastest path for other devs
├── .env.example
└── .env.production.example
Core backend routes:
GET /healthGET /health/integrationsPOST /loginPOST /registerPOST /logoutGET /sessionGET /accountsPOST /inviteGET /invite/:tokenPOST /accept-invitePOST /forgot-passwordGET /reset/:tokenPOST /reset-passwordPOST /run-testGET /jira/issue/:keyPOST /notifications/slackPOST /notifications/zoho-cliq
Use QUICKSTART.md for day-one setup.
Short version:
npm install
cp .env.example .env
npm run start:dev
npm run devThen open http://localhost:5173.
The backend intentionally separates dev and production config:
.env: local development defaults.env.production: production-only overrides
Do not set NODE_ENV inside either file. The production launcher sets it for the child process when needed.
Important variables:
PORTSESSION_SECRETCORS_ALLOWED_ORIGINSALLOW_DEMO_MODEAPP_PUBLIC_URLOPENAI_API_KEYQA_BACKEND_API_BASE_URLQA_BACKEND_API_KEYJIRA_BASE_URLJIRA_EMAILJIRA_API_TOKENCUSTOMERIO_APP_API_KEYCUSTOMERIO_INVITE_TEMPLATE_IDCUSTOMERIO_RESET_TEMPLATE_ID
See .env.example and .env.production.example.
npm run devstarts the Vite frontendnpm run start:devstarts the backend in dev modenpm run start:prodruns fail-closed prod checks, then starts the backend in prod modenpm testruns the Node test suitenpm run buildbuilds the frontendnpm run check:prodvalidates production-critical confignpm run checklistprints an internal publish checklist
Two important engineering limits are still present:
- server.js and server.js use plain file reads and writes for account state. Concurrent requests or multiple app instances can overwrite each other's changes because there is no file lock, transactional write, or database coordination.
- server/security.mjs keeps rate-limit counters in process memory. That is acceptable for local/internal use, but limits reset on restart and do not protect across multiple instances.
Those are not reasons to stop using the app locally. They are reasons to document the current deployment envelope honestly and avoid over-claiming production readiness.