The issue tracker that gets out of your way. A board, a backlog, sprints, releases, and a query language instead of a search form. One instance, one team, no per-seat license.
- Board — drag issues between columns, drop into empty ones
- Backlog — plan into sprints, filter by epic, watch the points
- Sprints & releases — start one, end one, ship one
- Issue panel — every field editable inline, no round-trip
- TQ — search is a query, not a form (
assignee = me,GAME-1) - Keyboard first —
Ctrl+K,Ctrl+N,o,?for the cheat sheet - Per-project — labels, epics and members live on the project
- History — every change recorded: who, what, from what, to what
Prereqs: Node 20+, .NET 10 SDK, Postgres 15+ on localhost:5432 with
a trazer user and db.
Install:
- Windows:
winget install Microsoft.NodeJS Microsoft.DotNet.SDK.10 PostgreSQL.PostgreSQL.16 - macOS:
brew install node postgresql@16 && brew install --cask dotnet-sdk - Linux:
sudo apt install -y nodejs postgresql(.NET 10 from Microsoft docs)
Then create the role + db (one-time):
- macOS / Linux:
sudo -u postgres createuser trazer && sudo -u postgres createdb -O trazer trazer - Windows (psql as postgres user):
CREATE USER trazer WITH PASSWORD 'trazer'; CREATE DATABASE trazer OWNER trazer;
- Clone the repo:
git clone https://github.com/abba-dev/trazer.git && cd trazer
- Run the dev script — it installs
apps/web/node_modulesif missing, spawns the API on:8080and vite on:5173, waits for both to respond, and prints the URL:node scripts/trazer.mjs dev
- Open the URL the script prints (default
http://localhost:5173).
To stop: node scripts/trazer.mjs dev stop.
Prereqs: Docker.
- Clone the repo:
git clone https://github.com/abba-dev/trazer.git && cd trazer
- Run compose:
docker compose up -d
- Open
http://localhost:3000.
Two fresh-install paths, curated by what the API reports via
GET /api/config:
- Empty database (
setupRequired: true) — the dev script (node scripts/trazer.mjs dev) bootstraps the first admin for you and prints one-timeemail+passwordon the console. Log in with those (change the password after your first login). The web UI also shows a two-step setup wizard (create admin → create first project) if you'd rather type it yourself. - Demo mode (
Demo__Enabled=true) — demo data is seeded and the demo login is available (demo@trazer.dev). With the flag off, no demo of anything ships.
- Sign in with the credentials the first-run flow printed.
- Create a project with a short key — it shows up in every issue
(
GAME-1,GAME-2). - Add an issue with
Ctrl+N. Title, type, priority. Done. - Drag it across the board — ToDo → InProgress → InReview → QA → Done. The position saves automatically.
- Find it with TQ:
Ctrl+K, thenassignee = meorGAME-1. - Script it with the CLI:
npx trazer issue create GAME "Fix the bug"from your terminal or CI.
Link a project to GitHub or GitLab and Trazer keeps up with pull requests without leaving your workflow:
- Set the secret in Project settings → Git — Trazer stores it per-project, never returns it after save.
- Add the webhook to your repo:
- GitHub:
POST https://your-host/api/git/webhook/GAME→ Content typeapplication/json, secret = the one above. - GitLab: same URL, X-Gitlab-Token = the secret.
- GitHub:
- What happens: PRs mentioning
GAME-42in title/body link that issue to the PR (shown in the issue panel, with open/merged state). Commit messages likefixes GAME-42auto-close the issue on push.
Unauthenticated by design — verified by HMAC-SHA256 (GitHub) or the shared token (GitLab). No secret, no link, no state change.
A local GUI (no browser, no server) for day-to-day user administration:
python trazer-admin.py # run from source
build-admin.bat # or build a standalone trazer-admin.exe (PyInstaller)It locks itself with local credentials (created on first run, stored beside the script — never sent anywhere) and talks to the Trazer API with your admin account. Create/list users, reset passwords, disable accounts; every action is written to an audit log.
GET /api/docs renders the endpoint list straight from the generated
OpenAPI 3.1 spec at /api/openapi.json — no Swagger UI, no CDN, works
behind the strict CSP.
TQ is the search. No form to fill, no filters to click:
assignee = me my issues
status in (Done, QA) finished or in QA
epic = "UI / UX" quoted values with spaces
label ~ bug case-insensitive substring
priority = High and sprint = "Sprint 1" compound queries
GAME-1 by key
Fields: assignee, reporter, status, priority, project, label, epic,
sprint, release, type, title, description, text, estimate.
Operators: =, !=, ~, in (...). Parser + compiler live in
apps/api/Trazer.Query.
| Web | React, TypeScript, Vite, Tailwind, shadcn/ui, TanStack Query, dnd-kit |
| API | ASP.NET Core minimal API (.NET 10), EF Core, JWT + bcrypt |
| DB | PostgreSQL |
From the root, the same flows are wrapped as npm scripts:
npm test # 60 dotnet tests + tsc + vite build
npm run build # dotnet publish + tsc + vite build
npm run clean # remove build artifactsA small CLI for scripting against the API:
npx trazer issue list GAME
npx trazer issue create GAME "Fix the bug"
npx trazer issue update GAME-1 --status=Done
npx trazer issue comment GAME-1 "looks good"
npx trazer user me
npx trazer config showSet TRAZER_TOKEN (a JWT or API token) and TRAZER_API (default
http://localhost:8080). Run npx trazer for the full help. Long-
running commands (dev:*) belong in a sub-agent per
AGENTS.md.
git pull and restart:
- Native:
node scripts/trazer.mjs dev stop && node scripts/trazer.mjs dev - Docker:
docker compose pull && docker compose up -d
The dev defaults work for local. For a real server:
- Set
Jwt__Keyto a 32+ char random string (openssl rand -base64 48) — otherwise anyone can forge tokens. - Set
Demo__Enabled=false(default) so no demo data or demo-login endpoint ship.
Trazer stores no secrets of its own — passwords are bcrypt hashes, tokens are JWTs. The data itself (issues, comments, attachments) is protected at the filesystem level, so encryption is an operator concern, not an app feature. The supported posture is AES-256 full-disk/volume encryption:
| OS | Mechanism |
|---|---|
| Linux | LUKS on the volume holding the Postgres data dir (/var/lib/postgresql) and any attachment mount |
| macOS | FileVault (full-disk) on the boot volume |
| Windows | BitLocker on the system and data volumes |
Trazer itself never implements per-field encryption — it would break
search (title, description, text are indexed and queried) and the
strict schema. If the volume is encrypted, the whole database and all
attachments are at rest; nothing to configure per-project.
Verify after setup that the volume is truly encrypted
(lsblk -o NAME,TYPE,FSTYPE,MOUNTPOINT on Linux, System Settings →
Privacy & Security → FileVault on macOS) before relying on it.
Because the alternatives are either too thin (sticky notes don't survive a sprint) or too heavy (a week of configuration before your first issue). Trazer is the middle: a real tracker, up and running in a minute.
Multi-tenant? No — one team per instance, run more instances for more teams. Why "Trazer"? It's the verb form of "track" in old Galician-Portuguese. Short, pronounceable, doesn't collide with Jira, Linear, Trello, Asana, Notion, ClickUp, Height, Plane, Leantime, OpenProject, or any of the other 200 trackers named this decade.
MIT.
