Universal work item management with configurable types, statuses, maturity levels, dependency tracking, and hierarchical relationships
npm install @bernierllc/work-item-coreA comprehensive TypeScript library for managing work items with hierarchical relationships, dependency tracking, maturity progression, and status management.
``bash`
npm install @bernierllc/work-item-core
- Complete CRUD Operations - Create, read, update, delete work items
- Hierarchical Relationships - Parent/child relationships with tree traversal
- Dependency Management - Track dependencies with circular detection (DFS algorithm)
- Blocking Detection - Identify blocking items using BFS-style traversal
- Maturity Progression - State machine for work item maturity levels
- Status Management - Track work item status through lifecycle
- Assignment Management - Assign work items to team members or agents
- Readiness Checks - Determine if work items are ready to start
- Query & Filtering - Powerful filtering, sorting, and pagination
- Batch Operations - Efficient bulk create and update operations
- Statistics & Reporting - Comprehensive project analytics
- Storage Abstraction - Pluggable storage backend (memory included for testing)
`typescript
import { WorkItemManager, MemoryWorkItemStorage } from '@bernierllc/work-item-core';
// Initialize with in-memory storage
const storage = new MemoryWorkItemStorage();
const manager = new WorkItemManager(storage);
// Create a work item
const result = await manager.create({
project_id: 'proj_123',
title: 'Implement user authentication',
work_type_id: 'type_feature',
maturity_level_id: 'maturity_planned',
status_id: 'status_open',
priority: 8
});
if (result.success) {
console.log('Created work item:', result.data);
}
`
A work item represents a unit of work in a project. Each work item has:
- Identity: id, project_id, title, descriptionwork_type_id
- Classification: (feature, bug, refactor, documentation, chore)maturity_level_id
- Maturity: (idea → discovery → planned → ready → active → complete)status_id
- Status: (open, blocked, in-progress, in-review, done, cancelled)priority
- Priority: (1-10, higher = more important)parent_work_item_id
- Relationships: , depends_on_work_item_idsassigned_to
- Assignment: (team member or agent identifier)created_at
- Metadata: , updated_at, created_from_session_id
Work items progress through maturity levels:
1. idea - Initial concept
2. discovery - Research and investigation
3. planned - Defined and estimated
4. ready - Ready to start work
5. active - Work in progress
6. complete - Finished and verified
- feature - New functionality
- bug - Defect or issue
- refactor - Code improvement
- documentation - Documentation work
- chore - Maintenance tasks
- open - Not yet started
- blocked - Cannot proceed (waiting on dependencies)
- in-progress - Actively being worked on
- in-review - Under review
- done - Completed successfully
- cancelled - Work abandoned
`typescript
// Create a simple work item
const result = await manager.create({
project_id: 'proj_123',
title: 'Add login form',
work_type_id: 'type_feature',
maturity_level_id: 'maturity_planned',
status_id: 'status_open',
priority: 5
});
// Create with dependencies
const dependent = await manager.create({
project_id: 'proj_123',
title: 'Add logout button',
depends_on_work_item_ids: [result.data!.id],
priority: 3
});
// Create batch
const batch = await manager.createBatch([
{ project_id: 'proj_123', title: 'Task 1', priority: 5 },
{ project_id: 'proj_123', title: 'Task 2', priority: 4 },
{ project_id: 'proj_123', title: 'Task 3', priority: 3 }
]);
`
`typescript
// Create parent work item
const epic = await manager.create({
project_id: 'proj_123',
title: 'User Management Epic',
work_type_id: 'type_feature',
priority: 10
});
// Create child work items
const story1 = await manager.create({
project_id: 'proj_123',
title: 'User login',
parent_work_item_id: epic.data!.id,
priority: 8
});
const story2 = await manager.create({
project_id: 'proj_123',
title: 'User registration',
parent_work_item_id: epic.data!.id,
priority: 7
});
// Get all children
const children = await manager.getChildren(epic.data!.id, false); // Direct children only
const allDescendants = await manager.getChildren(epic.data!.id, true); // Recursive
// Get ancestors
const ancestors = await manager.getAncestors(story1.data!.id);
// Move work item to different parent
await manager.move(story1.data!.id, 'other_epic_id');
`
`typescript
// Add dependency
await manager.addDependency('work_item_1', 'work_item_2'); // 1 depends on 2
// Remove dependency
await manager.removeDependency('work_item_1', 'work_item_2');
// Get dependencies
const deps = await manager.getDependencies('work_item_1', false); // Direct only
const allDeps = await manager.getDependencies('work_item_1', true); // Transitive
// Get blocked items (items waiting for this one)
const blockedItems = await manager.getBlockedItems('work_item_1');
// Check for circular dependencies
const circularCheck = await manager.checkCircularDependencies(
'work_item_1',
'work_item_2'
);
if (!circularCheck.valid) {
console.log('Circular dependency detected:', circularCheck.cycle);
}
// Validate all dependencies
const validation = await manager.validateDependencies('work_item_1');
if (!validation.valid) {
console.log('Invalid dependencies:', validation.missing_dependencies);
}
`
`typescript
// Update status
await manager.updateStatus('work_item_1', 'status_in_progress');
// Status transitions are validated
const result = await manager.updateStatus('work_item_1', 'status_done');
if (!result.success) {
console.log('Status update failed:', result.error);
}
`
`typescript
// Promote to next maturity level
const promoted = await manager.promoteMaturity('work_item_1');
if (!promoted.success) {
console.log('Cannot promote:', promoted.error);
}
// Promote to specific level
await manager.promoteMaturity('work_item_1', 'maturity_ready');
// Check if promotion is allowed
const canPromote = await manager.canPromote('work_item_1', 'maturity_active');
if (!canPromote.valid) {
console.log('Cannot promote:', canPromote.reason);
}
`
`typescript
// Assign to team member
await manager.assign('work_item_1', 'user:john@example.com');
// Assign to agent
await manager.assign('work_item_1', 'agent:claude');
// Unassign
await manager.unassign('work_item_1');
// Get all assigned items for a person
const assigned = await manager.getAssignedItems('user:john@example.com', {
status_ids: ['status_in_progress']
});
`
`typescript
// Check if work item is ready to start
const readiness = await manager.isReadyToStart('work_item_1');
if (readiness.ready) {
console.log('Ready to start!');
} else {
console.log('Blocking reasons:', readiness.blocking_reasons);
}
`
`typescript
// Query with filters
const results = await manager.query(
{
project_id: 'proj_123',
work_type_ids: ['type_feature', 'type_bug'],
maturity_level_ids: ['maturity_ready', 'maturity_active'],
status_ids: ['status_open', 'status_in_progress'],
priority_min: 5,
priority_max: 10,
blocks_project: true,
assigned_to: 'user:john@example.com',
has_dependencies: false,
is_blocked: false
},
{
sort_by: 'priority',
sort_order: 'desc',
limit: 20,
offset: 0
}
);
// Get unassigned high-priority items
const unassigned = await manager.query({
project_id: 'proj_123',
assigned_to: null,
priority_min: 8
});
// Get root items (no parent)
const rootItems = await manager.query({
project_id: 'proj_123',
parent_work_item_id: null
});
`
`typescript
// Get project statistics
const stats = await manager.getStatistics('proj_123');
console.log('Total items:', stats.total_count);
console.log('By work type:', stats.by_work_type);
console.log('By maturity:', stats.by_maturity_level);
console.log('By status:', stats.by_status);
console.log('By priority:', stats.by_priority);
console.log('Assigned:', stats.assigned_count);
console.log('Unassigned:', stats.unassigned_count);
console.log('Ready to start:', stats.ready_count);
console.log('Blocked:', stats.blocked_count);
// Get dependency graph
const graph = await manager.getDependencyGraph({
project_id: 'proj_123'
});
console.log('Nodes:', graph.nodes.length);
console.log('Edges:', graph.edges.length);
`
`typescript
// Create multiple items efficiently
const created = await manager.createBatch([
{
project_id: 'proj_123',
title: 'Feature 1',
priority: 8
},
{
project_id: 'proj_123',
title: 'Feature 2',
priority: 7
}
]);
// Update multiple items
const updated = await manager.updateBatch([
{
id: 'item_1',
updates: { priority: 10, assigned_to: 'user:jane@example.com' }
},
{
id: 'item_2',
updates: { status_id: 'status_in_progress' }
}
]);
console.log(Created ${created.successful.length} items);Updated ${updated.successful.length} items
console.log();`
if (created.failed.length > 0) {
console.log('Failures:', created.failed);
}
Implement the WorkItemStorage interface for your database:
`typescript
import { WorkItemStorage, WorkItem } from '@bernierllc/work-item-core';
class PostgresWorkItemStorage implements WorkItemStorage {
async saveWorkItem(workItem: WorkItem): Promise
// Save to PostgreSQL
}
async getWorkItem(id: string): Promise
// Retrieve from PostgreSQL
}
async deleteWorkItem(id: string): Promise
// Delete from PostgreSQL
}
async queryWorkItems(
filters: WorkItemFilters,
options?: WorkItemQueryOptions
): Promise
// Query PostgreSQL with filters
}
// Implement remaining methods...
}
// Use custom storage
const storage = new PostgresWorkItemStorage();
const manager = new WorkItemManager(storage);
`
#### Constructor
`typescript`
constructor(
storage: WorkItemStorage,
config?: {
maturityLevels?: MaturityLevel[];
statuses?: WorkItemStatus[];
workTypes?: WorkType[];
}
)
#### CRUD Operations
- create(input: CreateWorkItemInput): Promiseget(workItemId: string, include_details?: boolean): Promise
- update(workItemId: string, updates: UpdateWorkItemInput): Promise
- delete(workItemId: string): Promise
- exists(workItemId: string): Promise
- query(filters: WorkItemFilters, options?: WorkItemQueryOptions): Promise
-
#### Hierarchy Management
- getChildren(workItemId: string, recursive?: boolean): PromisegetAncestors(workItemId: string): Promise
- move(workItemId: string, newParentId: string | null): Promise
-
#### Dependency Management
- addDependency(workItemId: string, dependsOnId: string): PromiseremoveDependency(workItemId: string, dependsOnId: string): Promise
- getDependencies(workItemId: string, recursive?: boolean): Promise
- getBlockedItems(workItemId: string): Promise
- checkCircularDependencies(workItemId: string, dependsOnId: string): Promise
- validateDependencies(workItemId: string): Promise
-
#### Status & Maturity
- updateStatus(workItemId: string, statusId: string): PromisepromoteMaturity(workItemId: string, maturityId?: string): Promise
- canPromote(workItemId: string, maturityId: string): Promise
-
#### Assignment
- assign(workItemId: string, assignee: string): Promiseunassign(workItemId: string): Promise
- getAssignedItems(assignee: string, filters?: WorkItemFilters): Promise
-
#### Readiness & Validation
- isReadyToStart(workItemId: string): Promisevalidate(workItem: WorkItem | CreateWorkItemInput): Promise
-
#### Batch Operations
- createBatch(inputs: CreateWorkItemInput[]): PromiseupdateBatch(updates: Array<{ id: string; updates: UpdateWorkItemInput }>): Promise
-
#### Statistics & Reporting
- getStatistics(projectId: string): PromisegetDependencyGraph(filters: WorkItemFilters): Promise
-
`typescript
const customMaturityLevels = [
{ id: 'backlog', name: 'Backlog', order: 1 },
{ id: 'sprint', name: 'In Sprint', order: 2 },
{ id: 'done', name: 'Done', order: 3 }
];
const manager = new WorkItemManager(storage, {
maturityLevels: customMaturityLevels
});
`
`typescript
const customStatuses = [
{ id: 'todo', name: 'To Do', category: 'not_started' },
{ id: 'doing', name: 'Doing', category: 'in_progress' },
{ id: 'testing', name: 'Testing', category: 'in_progress' },
{ id: 'finished', name: 'Finished', category: 'completed' }
];
const manager = new WorkItemManager(storage, {
statuses: customStatuses
});
`
`typescript
const customWorkTypes = [
{ id: 'story', name: 'User Story', icon: '📖' },
{ id: 'spike', name: 'Spike', icon: '🔬' },
{ id: 'epic', name: 'Epic', icon: '🎯' }
];
const manager = new WorkItemManager(storage, {
workTypes: customWorkTypes
});
`
- Logger: not-applicable - Core package with no logging requirements
- Docs-Suite: ready - Complete TypeDoc API documentation
- NeverHub: not-applicable - Core package with no service discovery needs
This package is written in TypeScript with strict mode enabled and includes complete type definitions.
`typescript`
import type {
WorkItem,
CreateWorkItemInput,
UpdateWorkItemInput,
WorkItemFilters,
WorkItemResult,
ValidationResult,
ReadinessResult,
WorkItemStatistics
} from '@bernierllc/work-item-core';
This package implements sophisticated graph algorithms for dependency management:
Uses Depth-First Search (DFS) to detect circular dependencies:
- Maintains visited set and stack for path tracking
- Detects cycles when revisiting a node in current path
- Returns all circular dependency chains found
- Time complexity: O(V + E) where V = work items, E = dependencies
Uses Breadth-First Search (BFS) traversal for blocking analysis:
- Identifies incomplete dependencies blocking work item start
- Computes readiness by checking all dependency statuses
- Returns blocking items with reasons for blocking
- Time complexity: O(V + E) for full traversal
Recursive algorithm for finding all transitive dependencies:
- Depth-limited to prevent infinite recursion (default max depth: 10)
- Uses visited set to prevent duplicate processing
- Returns flattened list of all direct and transitive dependencies
- Time complexity: O(V + E) with early termination on visited nodes
The package includes comprehensive tests with 90%+ coverage:
`bash``
npm test # Run tests in watch mode
npm run test:run # Run tests once
npm run test:coverage # Generate coverage report
- Branches: 90.13%
- Functions: 93.61%
- Lines: 91.15%
- Statements: 91.15%
Includes tests for:
- CRUD operations with validation
- Hierarchical relationships
- Dependency management and circular detection
- Status and maturity progression
- Assignment workflows
- Readiness checks
- Batch operations
- Edge cases and error conditions
Copyright (c) 2025 Bernier LLC
This file is licensed to the client under a limited-use license.
The client may use and modify this code only within the scope of the project it was delivered for.
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
- @bernierllc/retry-policy - Exponential backoff for retries
- @bernierllc/message-queue - Message queuing with priorities