A draggable floating panel for logging bugs, features, and notes — without leaving the browser. Zero database, zero config. Issues save to a JSON file.
Install directly from GitHub — no npm publish required during beta.
Pin to a specific release tag:
npm install github:Jgequipaje/qa-center#v0.1.0-beta
Drop <QACenter /> anywhere in your React tree. It renders a floating button that won't affect your layout.
import { QACenter } from '@purr/qa-center'
export default function App() {
return (
<>
<YourApp />
<QACenter port={3333} />
</>
)
}
The Express server handles reads and writes to qa-issues.json. Run it in a separate terminal.
npx qa-center --port 3333
That's it. Click the floating button in the corner of your app to open the drawer.
QA Center runs alongside your existing dev server. Two terminals, that's all.
# Terminal 1 — your app (as usual)
npm run dev
# Terminal 2 — QA Center backend
npx qa-center --port 3333
Issues are saved to qa-issues.json in the directory where you run the command. Human-readable and git-friendly.
Commit qa-issues.json to share issue state, or add it to .gitignore to keep it personal.
# Share issues via git
git add qa-issues.json
git commit -m "chore: update qa issues"
# Or keep it local
echo "qa-issues.json" >> .gitignore
Built for QA engineers and developers who want a lightweight tracker that lives in the browser.
Log bugs with title, description, severity, area, repro steps, expected vs actual, and notes.
Track feature ideas and enhancements separately from bugs in their own tab.
Capture QA notes, checklists, and observations that don't fit as issues.
Live search across title, area, and description. Filter by status and severity.
Link a Playwright test to any issue. Run it directly from the detail panel and see pass/fail.
Issue lists paginate at 10 per page so large backlogs stay manageable.
Toggle between dark and light mode. Preference is persisted to localStorage.
The floating button snaps to the left or right edge. Position saved per browser.
An animated cat sits on the floating button. Enable with the neko prop. Sprite based on oneko.js by adryd325, originally from Neko (1989) by Naoshi Watanabe.
Issues follow a structured workflow with valid transitions enforced in the UI.
Closed issues can always be re-opened back to open.
Features use a simplified workflow: open → in progress → verified (done) → closed.
Notes use: open → closed (archived).
All props are optional. The component works out of the box with just <QACenter />.
| Prop | Type | Default | Description |
|---|---|---|---|
| port | number | 3333 | Port the Express backend is running on |
| apiBaseUrl | string | — | Full base URL if not using localhost — overrides port |
| name | string | "QA Center" | Label shown in the drawer header |
| buttonColor | string | { dark, light } | #7c3aed | Floating button color. Pass an object for per-theme values |
| buttonSize | number | 52 | Button diameter in px |
| shape | "circle" | "rounded" | "square" | "circle" | Shape of the floating button |
| logo | ReactNode | — | Custom icon rendered inside the button |
| ownTheme | boolean | true | Set to false if your app already has a ThemeProvider |
| neko | boolean | false | Show an animated cat sitting on the button |
// Custom color per theme
<QACenter
buttonColor={{ dark: "#7c3aed", light: "#6d28d9" }}
name="Bug Tracker"
shape="rounded"
/>
// Already have a ThemeProvider?
<QACenter ownTheme={false} port={4000} />
// With the neko cat
<QACenter neko />
QA Center uses window, localStorage, and requestAnimationFrame which don't exist on the server. The component handles this with a built-in SSR guard, but placement matters.
Place it in your root layout inside <body>. The SSR guard handles the rest.
// app/root.tsx
import { QACenter } from "@purr/qa-center";
export function Layout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<head>...</head>
<body>
{children}
<QACenter port={3333} />
<ScrollRestoration />
<Scripts />
</body>
</html>
);
}
Wrap it in a client component first.
// components/QACenterWrapper.tsx
"use client";
import { QACenter } from "@purr/qa-center";
export default function QACenterWrapper() {
return <QACenter port={3333} />;
}
// app/layout.tsx
import QACenterWrapper from "@/components/QACenterWrapper";
export default function RootLayout({ children }) {
return (
<html><body>
{children}
<QACenterWrapper />
</body></html>
);
}
The CLI starts the Express server that handles all reads and writes to qa-issues.json.
npx qa-center # default port 3333, opens browser
npx qa-center --port 4000 # custom port
npx qa-center --no-open # skip auto-opening browser
npx qa-center --data-dir ./qa-data # store data outside Vite watch scope
All endpoints are served at http://localhost:3333 (or your configured port).
Issues
| Method | Route | Description |
|---|---|---|
| GET | /api/qa-issues | Return all issues, newest first |
| POST | /api/qa-issues | Create a new issue |
| PATCH | /api/qa-issues/:id | Update issue fields or status |
| DELETE | /api/qa-issues/:id | Delete an issue |
| POST | /api/qa-issues/:id/run-test | Run the linked Playwright test |
Tests
| Method | Route | Description |
|---|---|---|
| GET | /api/qa-tests | Return cached Playwright test list |
| POST | /api/qa-tests | Force rescan of test directories |
Status
| Method | Route | Description |
|---|---|---|
| GET | /api/status | Server health, issue summary, test cache info |
{
"title": "Bug title", // required
"origin": "manual", // manual | feature | note | imported_markdown
"status": "open", // open | in_progress | ready_for_qa | verified | closed
"severity": "high", // critical | high | medium | low | info
"area": "Auth",
"description": "What is the bug?",
"reproSteps": "1. Go to...",
"expected": "Should work",
"actual": "Doesn't work",
"notes": "Additional notes"
}
{
"status": "in_progress",
"notes": "Updated notes"
}