req-planner
A standalone requirements management tool with interactive graph visualization, hierarchical decomposition, quality gates, and code traceability. Designed as a general-purpose planning tool that can connect to any repository.
What It Does
req-planner lets you decompose high-level project goals into traceable, testable requirements organized as a directed acyclic graph (DAG). Each requirement is a card that can be drilled down from abstract pillars to code-level leaf nodes, with quality validation at every level.
Core Concepts
- Pillars — Top-level project goals (e.g., "MIDI Signal Path")
- Requirements — Functional requirements under a pillar
- Sub-requirements — Decomposed pieces of a requirement
- Leaves — Code-level items with test specs and implementation
- Planning — Planning-phase nodes (larger green-tinted cards)
Each node carries:
- Acceptance criteria (what it must do)
- Test specification (GIVEN/WHEN/THEN format)
- Test and implementation code snippets
- Target file paths for code export
- Quality gate status
- Gitea issue integration fields
Quality Gates (TMCS)
Every requirement is validated against four gates:
| Gate | Type | Rule |
|---|---|---|
| Traceable | Auto | Has a parent requirement and description |
| Measurable | Toggle | Forced false without test specification; user can toggle when test spec exists |
| Consistent | Toggle | User asserts no contradictions with sibling requirements |
| Single-purpose | Toggle | User asserts requirement serves exactly one concern |
T is auto-calculated from the requirement's structure. M, C, and S are user-set toggles — click the badge in the detail panel to flip them. M is enforced: if a node has no test specification, measurable is always false regardless of the toggle.
Visual indicators on graph nodes:
- Red dot — Fewer than 2 quality gates pass
- Orange dot — 2 of 3 gates pass
- Green dot — All quality gates pass
Requirement Status Flow
Requirements follow a lifecycle: idea → draft → todo → in_progress → done
- idea (purple) — ideas backlog; things you're thinking about but haven't committed to building
- draft (gray) — being defined, not yet ready for work
- todo (blue) — defined and ready to implement
- in_progress (yellow) — actively being worked on
- done (green) — completed
Satisfaction Links
Requirements can declare they "also satisfy" other requirements beyond their parent. This creates cross-cutting traceability:
- Also Satisfies — outgoing links: "this requirement also contributes to requirement X"
- Satisfied By — incoming links: "requirement Y also contributes to this one"
These appear as purple dashed edges in the graph.
Features
Interactive Graph View (/graph)
The main view renders the requirement tree as a Cytoscape.js DAG with dagre layout.
Semantic zoom — node detail changes continuously with zoom level:
| Zoom Range | What You See |
|---|---|
| 0 - 0.3 | Dots with ID only |
| 0.3 - 0.6 | Cards with ID, title, child count |
| 0.6 - 1.0 | Cards with TMCS quality badges |
| 1.0+ | Expanded cards with AC count and status |
Mouse interactions:
| Action | Behavior |
|---|---|
| Click node | Select node, open detail panel, highlight paths to root (parent-child + satisfaction links) |
| Shift+Click | Highlight parent-child path to root only (no satisfaction links) |
| Alt+Click (Win) / Option+Click (Mac) | Highlight only "also satisfies" links for a node |
| Ctrl+Click (Win) / Cmd+Click (Mac) | Focus mode: show node, direct children, and paths to roots |
| Ctrl+Shift+Click (Win) / Cmd+Shift+Click (Mac) | Deep focus: show node, all descendants to leaves, and paths to roots |
| Right-click | Highlight entire subtree downward |
| Click background | Exit focus mode or close detail panel |
| Drag node | Reposition (saved across sessions) |
Keyboard shortcuts:
| Key | Action |
|---|---|
+ / = |
Zoom in |
- |
Zoom out |
0 |
Fit graph to screen |
| Ctrl+Z (Win) / Cmd+Z (Mac) | Undo last canvas action |
| Esc | Exit focus mode |
Canvas undo tracks all interactions: node clicks, focus/exit, right-click highlights, and node drags. Up to 20 states are kept in the undo stack.
Persistence:
- Node positions saved to localStorage — drag nodes to rearrange and they stay put across reloads
- Viewport (zoom + pan) persisted across sessions
- Selected node and panel state restored on reload
- Re-layout button resets to auto-calculated dagre positions
Named layouts:
- Save the current graph layout (node positions + viewport) with a name and description
- Load any saved layout from the toolbar dropdown
- Set a default layout that auto-loads on startup
- Manage layouts: load, set default, or delete
Edge rendering:
- Parent-child edges: solid gray lines, width scales up when zoomed out
- Satisfaction links: purple dashed lines with directional arrows
- Path highlight: blue for parent-child, purple for satisfaction links
Detail Panel
A 420px side panel for viewing and editing a requirement:
- Inline editing for title, description, priority, status, phase, node type
- Acceptance criteria and test spec (GIVEN/WHEN/THEN) editors
- Test code and implementation code blocks (monospace)
- Quality gate badges — click M/C/S to toggle, T is auto-calculated
- Quality validation with error/warning display
- Child requirements list with add-child form (auto-generates IDs)
- Parent card link — click to navigate to parent
- Also Satisfies section — manage outgoing satisfaction links with typeahead search
- Satisfied By section — view incoming links, click to navigate
- Edit history — collapsible section showing all versions with timestamps and change summaries
- Click a version to see field-level diffs (changed fields highlighted)
- Restore any previous version (creates a new version with "Restored from version N" note)
- Gitea issue badge with link (when issue number is set)
- Delete with cascade confirmation
Dashboard (/dashboard)
Statistics overview with:
- Node counts by type (pillars, requirements, sub-requirements, leaves, planning)
- Test coverage percentage
- Breakdown by status and priority
- Quality gates pass/fail ratio
Authentication
- Password-based login with JWT tokens (24-hour expiry)
- Protected routes with auth guard
- Token auto-injected into API requests via HTTP interceptor
- Configurable password via
REQ_PLANNER_PASSWORDenvironment variable
Architecture
req-planner/
├── backend/ FastAPI + SQLAlchemy + SQLite
│ └── app/
│ ├── main.py App entry, CORS config, router registration
│ ├── auth.py JWT authentication
│ ├── database.py SQLite connection (data/planner.db)
│ ├── models.py ORM models (RequirementNode, CrossPillarLink,
│ │ Project, RequirementHistory, GraphLayout)
│ ├── schemas.py Pydantic request/response schemas
│ ├── quality.py TMCS validation logic
│ └── routers/
│ ├── requirements.py CRUD + tree + validation + history endpoints
│ ├── links.py Cross-pillar link management
│ ├── projects.py Project CRUD
│ ├── stats.py Aggregated statistics
│ └── layouts.py Named graph layout CRUD
├── frontend/ Angular 17 + Cytoscape.js
│ └── src/app/
│ ├── core/
│ │ ├── guards/ Auth route guard
│ │ ├── interceptors/ JWT token interceptor
│ │ ├── models/ TypeScript interfaces
│ │ └── services/ HTTP API client (requirements, auth)
│ └── features/
│ ├── graph/ Interactive DAG visualization
│ ├── detail/ Side panel editor with history
│ ├── dashboard/ Statistics overview
│ └── login/ Password login
├── data/
│ └── planner.db SQLite database (auto-created)
└── docs/
└── MARKET-RESEARCH.md Competitive analysis
API Endpoints
Requirements
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/requirements |
List requirements (filter by project_id, parent_id) |
| GET | /api/requirements/tree |
Tree structure for graph rendering |
| GET | /api/requirements/{id} |
Single requirement with children |
| POST | /api/requirements |
Create requirement |
| PUT | /api/requirements/{id} |
Update requirement |
| DELETE | /api/requirements/{id} |
Delete requirement (cascades to children) |
| PATCH | /api/requirements/{id}/status |
Update status only |
| POST | /api/requirements/{id}/validate |
Run TMCS quality gates |
| GET | /api/requirements/{id}/children |
List direct children |
Edit History
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/requirements/{id}/history |
List all versions (newest first) |
| GET | /api/requirements/{id}/history/{version} |
Get specific version snapshot |
| POST | /api/requirements/{id}/history/{version}/restore |
Restore to previous version |
Satisfaction Links
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/links |
List links (optional node_id filter) |
| POST | /api/links |
Create satisfaction link |
| DELETE | /api/links/{source_id}/{target_id} |
Delete link |
Graph Layouts
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/layouts |
List saved layouts (optional project_id filter) |
| GET | /api/layouts/{id} |
Get layout with positions and viewport |
| POST | /api/layouts |
Save current layout |
| PUT | /api/layouts/{id} |
Update layout |
| DELETE | /api/layouts/{id} |
Delete layout |
Other
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/health |
Health check |
| POST | /api/auth/login |
Login, returns JWT token |
| GET/POST/DELETE | /api/projects |
Project management |
| GET | /api/stats |
Aggregated statistics |
Interactive API docs available at http://localhost:8100/docs (Swagger UI).
Tech Stack
Backend:
- Python 3.12+, FastAPI, SQLAlchemy 2.0, SQLite
- Pydantic 2.10+ for validation
- python-jose for JWT tokens
- Uvicorn ASGI server
Frontend:
- Angular 17 (standalone components, new control flow syntax)
- Cytoscape.js + cytoscape-dagre for graph rendering
- RxJS for reactive data flow
- SCSS with dark theme (GitHub-inspired palette)
- OnPush change detection, lazy-loaded routes
Running Locally
Backend
cd backend
uv sync # or: pip install -e ".[dev]"
uvicorn app.main:app --reload --port 8100
Frontend
cd frontend
npm install
ng serve # runs on http://localhost:4200
The frontend proxies API requests to http://localhost:8100/api via proxy.conf.json.
Database
SQLite database at data/planner.db, auto-created on first backend startup. Five tables:
- requirement_nodes — hierarchical requirements with quality flags, code metadata, and timestamps
- cross_pillar_links — many-to-many satisfaction links between requirements
- projects — project containers with optional repo path/URL
- requirement_history — versioned snapshots of requirement edits
- graph_layouts — named layout snapshots with node positions and viewport state