verdikt
v1.0.2
Published
Production-grade ADR & Technical Debt Tracker — manage architecture decisions and track technical debt with CQRS, event-driven workflows, and pluggable adapters
Maintainers
Readme
Verdikt
A production-grade, hexagonal modular monolith for managing Architecture Decision Records (ADRs) and Technical Debt across engineering organizations. Built with CQRS, event-driven architecture, and a pluggable adapter system that scales from a single-developer CLI to an enterprise-wide platform.
npx verdikt adr new "Use PostgreSQL for persistence"Key Features
- ADR Lifecycle Management -- Create, propose, accept, deprecate, and supersede architecture decisions with full revision history, relationship graphs, comments, and Git sync.
- Technical Debt Tracking -- Identify, triage, score, and remediate technical debt with three-point estimation, interest modeling, SLA policies, and budget tracking.
- Analytics & Forecasting -- Debt trends, velocity metrics, anomaly detection, cost-of-delay analysis, ADR staleness reports, and scheduled report generation.
- Workflow Automation -- Event-driven automation rules and approval flows triggered by domain events (e.g., auto-notify on critical debt, auto-assign reviewers).
- Multi-Tenancy & RBAC -- Organizations, projects, teams, and role-based access control (SuperAdmin, OrgAdmin, ProjectAdmin, Editor, Viewer).
- Integrations -- GitHub, GitLab, Bitbucket, Jira, Linear, Asana, Slack, Microsoft Teams, email, and inbound webhooks.
- Plugin SDK -- Extend the system with custom scanners, actions, routes, and lifecycle hooks via a sandboxed plugin API.
- Multiple API Surfaces -- REST (Fastify + OpenAPI), GraphQL (Apollo Server), gRPC, and a full-featured CLI.
- Deployment Profiles -- Run as a CLI tool, a standalone server, a team server, or an enterprise platform with a single configuration change.
Architecture
Verdikt follows a hexagonal (ports & adapters) architecture organized as a modular monolith with five bounded contexts:
+-----------------------+
| API Layer |
| REST | GraphQL | gRPC |
| CLI |
+----------+------------+
|
+----------v------------+
| Application Layer |
| CommandBus | QueryBus |
| Event Handlers |
+----------+------------+
|
+--------------------+--------------------+
| Core Domain Layer |
| ADR | Debt | Identity | Workflow | Analytics |
| (Aggregates, Value Objects, Events) |
+--------------------+--------------------+
|
+----------v------------+
| Ports (Interfaces) |
+----------+------------+
|
+--------------------+--------------------+
| Adapters Layer |
| Storage | Cache | EventBus | Search |
| Git | Scanner | Auth | Metrics |
| Notifier | Scheduler | Template | ... |
+--------------------------------------------+- CQRS: Commands and queries are dispatched through separate buses with middleware support.
- Event-Driven: Domain events propagate through the EventBus, triggering projections, notifications, integrations, and workflow rules.
- Deployment Profiles: The same codebase adapts to four deployment targets by swapping adapters.
| Feature | CLI | Standalone | Team | Enterprise | |---|---|---|---|---| | Storage | SQLite | SQLite | PostgreSQL | PostgreSQL | | Search | In-Memory | In-Memory | In-Memory | Elasticsearch | | Cache | In-Memory | In-Memory | In-Memory | Redis | | Event Bus | In-Process | In-Process | In-Process | Redis / NATS | | Scheduler | In-Process | In-Process | In-Process | BullMQ (Redis) | | Auth | None | Local | Local + JWT | Local + JWT + OAuth/SAML | | Notifiers | None | None | Slack | Slack + Email + Teams | | API Surfaces | CLI | REST + CLI | REST + GraphQL + CLI | REST + GraphQL + gRPC + CLI | | Metrics | None | In-Memory | In-Memory | Prometheus / OpenTelemetry |
For a deep dive, see docs/architecture.md.
Quick Start
Prerequisites
- Node.js >= 20
- Docker and Docker Compose (for the full stack)
Docker Compose (recommended)
cd docker && docker compose up -dThis starts the application server, PostgreSQL, Redis, Elasticsearch, and NATS. Once all containers are healthy:
curl http://localhost:3000/api/v1/healthExpected response:
{
"status": "healthy",
"timestamp": "2026-03-21T12:00:00.000Z",
"version": "1.0.0",
"uptime": 5.123
}Local Development (without Docker)
# Install dependencies
npm install
# Start in development mode with hot-reload
npm run dev
# Run tests
npm test
# Type-check
npm run typecheckCLI Usage
Installation
# Global install
npm install -g verdikt
# Or use directly with npx
npx verdikt <command>
# Or via the project scripts
npm run cli -- <command>ADR Commands
# Initialize ADR tracking in current directory
verdikt adr init --dir docs/adr
# Create a new ADR
verdikt adr new "Use PostgreSQL for Primary Storage" \
--category Architecture \
--impact High \
--tags "database,storage"
# List ADRs with filtering
verdikt adr list --status Accepted --format table
# Show a specific ADR
verdikt adr show <adr-id>
# Transition ADR status
verdikt adr status <adr-id> Accepted --reason "Approved in arch review"
# Supersede an ADR
verdikt adr supersede <old-id> "Use CockroachDB Instead"
# View relationship graph
verdikt adr graph <adr-id>
# Export ADRs
verdikt adr export --format markdown --output ./export/Debt Commands
# Add a new debt item
verdikt debt add "Migrate legacy auth module" \
--category ArchitectureDebt \
--severity High \
--source CodeReview
# List debt items
verdikt debt list --severity Critical --format table
# Trigger a scan
verdikt debt scan --scanners todo-scanner,dependency-scanner
# View debt score for a project
verdikt debt score --project <project-id>Analytics Commands
# Show high-level overview
verdikt analytics overview
# View debt trends
verdikt analytics debt-trends --format json
# Get cost-of-delay analysis
verdikt analytics cost-of-delayOther Commands
# Start the server
verdikt server start --port 3000
# Manage configuration
verdikt config show
verdikt config set deployment.profile team
# Plugin management
verdikt plugin list
verdikt plugin install ./my-pluginAPI
REST API
The REST API is served at http://localhost:3000/api/v1/ with OpenAPI documentation available at /api/v1/openapi.json and Swagger UI at /docs.
Key resource groups:
| Resource | Base Path | Endpoints |
|---|---|---|
| System | /health, /info, /openapi.json | 5 |
| ADRs | /adrs | 19 |
| Debt | /debt | 16 |
| Analytics | /analytics | 12 |
| Reports | /reports | 4 |
| Auth & Users | /auth, /users | 14 |
| Organizations | /orgs | 13 |
| Projects | /projects | 17 |
| Workflows | /workflows, /automation | 10 |
| Integrations | /integrations, /webhooks | 10 |
| Plugins | /plugins | 10 |
GraphQL
The GraphQL endpoint is available at /graphql with the GraphQL Playground enabled in development mode. The schema covers all five bounded contexts with queries, mutations, and subscriptions.
gRPC
gRPC services are available on port 50051 with the following .proto definitions:
proto/adr.proto-- AdrService (19 RPCs)proto/debt.proto-- DebtService (14 RPCs)proto/scan.proto-- ScanServiceproto/events.proto-- EventStreamService (server-side streaming)
For the full endpoint reference, see docs/api-reference.md.
Configuration
Configuration is managed via verdikt.config.yaml at the project root:
deployment:
profile: standalone # cli | standalone | team | enterprise
server:
port: 3000
host: 0.0.0.0
adapters:
storage: postgres # sqlite | postgres | in-memory
search: postgres-fulltext # in-memory | postgres-fulltext | elasticsearch | meilisearch
git: node-git # node-git
gitHost: github # github | gitlab | bitbucket
cache: in-memory # in-memory | redis | null
eventBus: in-process # in-process | redis | nats | rabbitmq
scheduler: node-cron # node-cron | bullmq
metrics: "null" # null | in-memory | prometheus | opentelemetry | statsd
auth:
- local # local | api-key | oauth2 | oidc | ldap | saml
notifiers:
- console # console | in-app | slack | teams | email | webhook
scanners:
- todo-scanner
- dependency-scanner
issueTrackers: [] # jira | linear | asana | github-issues
fileExport:
- csv
- json
- markdown # csv | json | markdown | pdf
sync:
conflictStrategy: git-wins # git-wins | database-wins | manual | latest-wins
logging:
level: info # trace | debug | info | warn | error | fatal
pretty: trueEnvironment variables override config file values:
| Variable | Description | Default |
|---|---|---|
| DEPLOYMENT_PROFILE | Deployment profile | standalone |
| DATABASE_URL | PostgreSQL connection string | -- |
| REDIS_URL | Redis connection string | -- |
| ELASTICSEARCH_URL | Elasticsearch connection string | -- |
| NATS_URL | NATS connection string | -- |
| JWT_SECRET | JWT signing secret | dev default |
| JWT_REFRESH_SECRET | JWT refresh token secret | dev default |
| LOG_LEVEL | Logging level | info |
| NODE_ENV | Node environment | development |
Deployment Profiles
| Profile | Use Case | Infrastructure Required | |---|---|---| | CLI | Individual developer, local ADR management | None (embedded SQLite) | | Standalone | Single server, small team | None (embedded SQLite + in-process) | | Team | Team collaboration with persistence and notifications | PostgreSQL | | Enterprise | Organization-wide deployment with full observability | PostgreSQL, Redis, Elasticsearch, NATS |
Set the profile in verdikt.config.yaml or via the DEPLOYMENT_PROFILE environment variable.
For detailed deployment instructions, see docs/deployment.md.
Plugin Development
Verdikt ships with a Plugin SDK that allows you to extend the system with custom scanners, actions, routes, and lifecycle hooks.
// my-plugin/index.ts
import type { PluginInstance, PluginApi } from 'verdikt/plugins/sdk';
export default function createPlugin(api: PluginApi): PluginInstance {
return {
async onStartup() {
api.logger.info('My plugin started');
api.registerScanner({
name: 'my-custom-scanner',
async scan(context) {
// Scan logic here
return { items: [], metadata: {} };
},
});
},
async onShutdown() {
api.logger.info('My plugin shutting down');
},
};
}Plugins are discovered from a plugins/ directory and must include a manifest.json describing their capabilities.
For the full Plugin SDK guide, see docs/plugin-sdk.md.
Tech Stack
| Layer | Technology | |---|---| | Runtime | Node.js 20, TypeScript 5.7 | | HTTP Framework | Fastify 5 | | GraphQL | Apollo Server 5, graphql-tools | | gRPC | @grpc/grpc-js, @grpc/proto-loader | | CLI | Commander.js, Chalk, Inquirer | | Database | PostgreSQL 16 (Kysely ORM), SQLite (better-sqlite3) | | Cache | Redis (ioredis) | | Search | Elasticsearch 8, PostgreSQL full-text search, Meilisearch | | Event Bus | In-process, Redis Streams, NATS JetStream, RabbitMQ | | Job Queue | BullMQ, node-cron | | Auth | JWT (jose), bcrypt, OAuth2, OIDC, SAML, LDAP | | Validation | Zod 4 | | DI Container | tsyringe | | Logging | pino | | Metrics | Prometheus (prom-client), OpenTelemetry | | Templating | Handlebars | | Notifications | Slack, Microsoft Teams, Nodemailer, Webhooks | | Git | isomorphic-git | | Build | tsup | | Testing | Vitest, Supertest | | Containerization | Docker (multi-stage), Docker Compose | | CI/CD | GitHub Actions |
Project Structure
verdikt/
+-- src/
| +-- core/ # Domain layer (pure business logic)
| | +-- adr/ # ADR bounded context (aggregate, events, value objects)
| | +-- debt/ # Debt bounded context (aggregate, scoring, events)
| | +-- identity/ # Identity context (users, orgs, RBAC)
| | +-- workflow/ # Workflow context (rules, actions, conditions)
| | +-- analytics/ # Analytics context (projections, models)
| | +-- shared/ # Shared kernel (AggregateRoot, Entity, DomainEvent)
| +-- ports/ # Port interfaces (technology-agnostic contracts)
| +-- adapters/ # Adapter implementations
| | +-- storage/ # PostgreSQL, SQLite, in-memory
| | +-- cache/ # Redis, in-memory, null
| | +-- event-bus/ # In-process, Redis Streams, NATS, RabbitMQ
| | +-- search/ # Elasticsearch, PostgreSQL FTS, in-memory
| | +-- auth/ # Local, JWT, OAuth2, OIDC, SAML, LDAP, API Key
| | +-- notifier/ # Slack, Teams, email, webhook, console, in-app
| | +-- scanner/ # TODO scanner, dependency scanner
| | +-- git/ # isomorphic-git adapter
| | +-- git-host/ # GitHub, GitLab, Bitbucket
| | +-- issue-tracker/ # Jira, Linear, Asana, GitHub Issues
| | +-- scheduler/ # node-cron, BullMQ
| | +-- metrics/ # Prometheus, OpenTelemetry, StatsD, null
| | +-- file-export/ # CSV, JSON, Markdown, PDF
| | +-- template/ # Handlebars
| | +-- config/ # YAML, env, in-memory
| +-- application/ # Application layer (CQRS handlers)
| | +-- commands/ # Command handlers
| | +-- queries/ # Query handlers
| | +-- event-handlers/ # Cross-context event handlers
| | +-- middleware/ # CommandBus, QueryBus
| +-- api/ # API layer (presentation)
| | +-- rest/ # Fastify routes, middleware, schemas, OpenAPI
| | +-- graphql/ # Apollo Server, type defs, resolvers, subscriptions
| | +-- grpc/ # gRPC server, services, proto loader
| | +-- cli/ # Commander.js commands, formatters
| +-- plugins/ # Plugin system
| | +-- sdk/ # Plugin SDK (manifest, loader, lifecycle, API)
| | +-- built-in/ # Built-in plugins
| +-- infrastructure/ # Cross-cutting infrastructure
| | +-- config/ # Config loader, schema, deployment profiles
| | +-- di/ # Dependency injection container, tokens
| | +-- errors/ # AppError, error codes, HTTP status mapping
| | +-- health/ # Health checker
| | +-- logger/ # Structured logging (pino)
| | +-- security/ # JWT, password hashing
| +-- main.ts # Server entry point
| +-- cli.ts # CLI entry point
+-- proto/ # gRPC protocol buffer definitions
+-- docker/ # Dockerfiles and Compose configurations
+-- tests/ # Test suites
+-- docs/ # Documentation
+-- verdikt.config.yaml # Default configuration
+-- tsconfig.json # TypeScript configuration
+-- vitest.config.ts # Test configurationContributing
- Fork the repository and create a feature branch from
main. - Install dependencies:
npm install - Make your changes, ensuring all tests pass:
npm test - Run type checking:
npm run typecheck - Run linting:
npm run lint - Submit a pull request with a clear description of the change.
Development Scripts
| Script | Purpose |
|---|---|
| npm run dev | Start dev server with hot-reload |
| npm run build | Build for production |
| npm start | Start production server |
| npm run cli | Run the CLI |
| npm test | Run unit tests |
| npm run test:watch | Run tests in watch mode |
| npm run test:coverage | Run tests with coverage |
| npm run lint | Lint source and tests |
| npm run format | Format code with Prettier |
| npm run typecheck | TypeScript type checking |
| npm run release:preview | Preview next version (bumpcraft) |
| npm run release | Bump version, changelog, tag, GitHub release |
Performance
Benchmarked with k6 against Docker Compose stack (PostgreSQL 16 + Redis 7 + Node 20):
| Metric | Result | |--------|--------| | Throughput | 590 req/s | | Checks passed | 100% (127,874 / 127,874) | | Failures | 0.00% | | p95 latency | 12.94ms | | p99 latency | 17.77ms |
Full CRUD lifecycle tested: create, list, get, update, transition, comment, history, graph, delete.
Documentation
| Doc | Description | |-----|-------------| | CLI Reference | All 50+ commands with options and examples | | API Reference | REST, GraphQL, gRPC endpoints | | Architecture | Hexagonal design, CQRS, event flows | | Deployment | All 4 profiles, Docker, production checklist | | Migration Guide | Import from adr-tools, MADR, Log4brains, CSV | | Scoring Model | Debt scoring formula and examples | | Workflow Automation | Event-driven rules and recipes | | Integrations | Jira, Slack, GitHub, Teams, Email setup | | Plugin SDK | Build custom scanners, actions, routes | | Examples | 9 real-world usage examples |
License
Apache License 2.0. See LICENSE.
