Changelog
All notable changes to this project are documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Unreleased
Added
- Phase 13 - production hardening (no version bump):
- Deterministic concurrency and idempotency:
engine.versioningensure_workflow_versionnow retries on concurrent version creation withtransaction.atomic()+IntegrityErrorfallback, so parallel first use collapses to a single v1 (tests/test_phase13_concurrency.py, 16 tests). - Database performance:
api.views.get_querysetnow usesselect_related("content_type", "workflow_version"), removing an N+1 for versioned execution lists; new query-count regression tests (tests/test_phase13_queries.py, 5 tests) cap queries for list, detail + actions, history/timeline and analytics metrics. - Row-level access: justified indexes on
WorkflowExecutionforcurrent_stateand-started_atordering (migration 0006). - Security audit (§17–§23 of PHASE13):
AttachmentErrorexception added and exported; attachment uploads enforce an optional size cap (ATTACHMENT_MAX_SIZE) and content-type allow-list (ATTACHMENT_ALLOWED_CONTENT_TYPES); stored file names are sanitized against absolute/path-traversal uploads; attachmenturlin the REST API is only exposed whenATTACHMENT_PUBLIC_URLSisTrue;tests/test_phase13_security.py(15 tests) covering the authorization boundary across GET/POST/PUT/PATCH/DELETE, tenant/object isolation, sensitive-data logging hygiene, webhook payloads, admin read-only across all registered models, and published-version immutability. -
Workflow Dashboard (
workflow_kit.dashboard): a server-rendered Django app (templates + static CSS, no frontend framework) with an Overview (metrics + per-workflow health), My Work (assignable pending approvals + active delegations), searchable/filterable/paginated executions, execution detail (state, version, approvals, timeline, comments, attachments, audit) and analytics screens. It consumes the existing engine, analytics and service layers — never a second source of truth — and applies the same permission rule as the REST analytics API (staff orworkflow_kit.view_analytics). Responsive, keyboard-accessible with a consistent design system. Mounted in the Invoice Approval demo and the package test project;tests/test_dashboard.py(15 tests) plus 6 demo dashboard tests. -
Phase 12 - observability and analytics (package version bumped to 0.4.0):
analytics.base:AnalyticsError, aware-date parsing (parse_datetime), the sharedexecution_querysetscope helper andDurationStatssummary statistics (count/average/median/min/max/P95/P99).analytics.metrics:execution_metricsaggregate counts — started, active, completed, rejected, cancelled, failed, escalated, SLA-breached — computed with database aggregations andExistssubqueries (constant query cost regardless of execution volume), plusVersionAnalytics/version_analyticsper-version breakdowns.analytics.duration:completion_metrics(completion times),state_durations(per-state turnaround reconstructed from the audit trail) andbottlenecks(states flagged when their average far exceeds the rest).analytics.approvals:approval_metricsandapproval_totalswith decision-time statistics and grouping by workflow/version/step/approver/ status.analytics.sla:sla_metrics(compliance rate, breaches, pending-overdue, average overdue, average completion) andescalation_analytics(distribution by workflow/state/reason plus average escalation delay).analytics.prometheus: dependency-freeprometheus_metrics_textexposition andcollect_metricsdict form - noprometheus_clientdependency.observability:correlation_idcontextvars API andStructuredEventLoggerthat subscribes to the existing event dispatcher (installed automatically byAppConfig.ready()unlessWORKFLOW_KIT["STRUCTURED_LOGGING"]isFalse).- REST analytics endpoints under
/api/analytics/(metrics, completion, state durations, bottlenecks, approvals, approval totals, SLA, escalations, versions) gated byIsAnalyticsViewer(staff or theworkflow_kit.view_analyticspermission);AnalyticsErrormaps to HTTP 400 with codeinvalid_analytics_arguments. - Read-only admin analytics summary page at
/admin/workflow_kit/ workflowexecution/summary/. -
Docs:
docs/analytics.md,docs/observability.md,docs/phase12-report.md; README,docs/index.md,docs/api.mdanddocs/admin.mdupdated. -
Phase 11 - developer experience (package version bumped to 0.3.0):
engine.validation:ValidationIssue/ValidationReportwith severities, stable codes and locations;validate_definition/validate_manystatic analysis (unreachable states, ambiguous routing, self-loops, conditional routing, approvals on terminal states);ValidationReport.raise_if_invalid()raisingWorkflowValidationErrorwith a JSON-safepayload["issues"].engine.parse:parse_workflow_defbuilds aWorkflowfrom a dict, JSON string, file path or file-like object — one shared validation path with version snapshots, noeval/exec.engine.introspection:workflow_to_dict(JSON-safe dump with reachability/terminal metrics),reachable_states,simple_paths,path_states,condition_variants.engine.simulation:simulate,simulate_all,verify_always_completes— pure-Python dry-runs with no database writes;SimStep/SimulationResult, optional conditiongateandmax_steps;NoPathFoundErrorfor definitions that cannot always complete.engine.explain:explain/why_notreturnActionExplanationwith per-factorBlockReasonentries (terminal,no_action,permission,condition,ambiguous,no_satisfying_transition).graph:to_dot(Graphviz) andto_mermaid(Mermaid) rendering plusrender(fmt)dispatch.cli:python -m workflow_kit.cliwithdeploy,validate,view-workflow,simulate,explain,why-notandgraphsubcommands; refuses to deploy invalid definitions; structured exit codes.testing:WorkflowValidationMixin,ExecutionAssertions,assert_valid,workflow_factory,SimpleWorkflow,workflow_module,unregister_all.- Structured exceptions: every
WorkflowErrorcarries optionalworkflow,state,actionand a JSON-safepayload; addedWorkflowValidationError,SimulationError,NoPathFoundError. -
Docs: new
docs/tooling.mdanddocs/phase11-report.md;docs/index.md,README.md,CHANGELOG.mdupdated; demo smoke now covers the CLI-facing tools (21 checks); 94 new tests (package suite 393 passed). -
Phase 10 - comments and attachments:
WorkflowCommentmodel: free-form discussion scoped to one execution, with the author (user),text,metadataandcreated_at. TheWorkflowComment.author_labelproperty exposes a stable author name that falls back toanonymous.WorkflowAttachmentmodel: file attachments stored through Django's storage abstraction (FileField+ default storage) with the originalname,content_type,sizeandextensioncaptured at upload time. No third-party storage backend is required.- Service layer (
workflow_kit.commentsandworkflow_kit.attachments):add_comment/execution_comments,add_attachment/execution_attachments. Adding a comment or uploading a file appends acomment_added/attachment_addedaudit event and emits aworkflow.comment_added/workflow.attachment_addeddomain event, so discussion appears in the timeline and event stream like any state change. - Execution convenience methods:
execution.add_comment(user, text)andexecution.add_attachment(upload, name=..., user=...). - Timeline labels
Comment added/Attachment addedderived from the new audit event codes (WorkflowEventType.COMMENT_ADDED,WorkflowEventType.ATTACHMENT_ADDED). - Read-only
WorkflowCommentAdminandWorkflowAttachmentAdmin. - DRF API:
GET/POST /executions/{id}/comments/andGET/POST /executions/{id}/attachments/(multipart uploads) on the execution viewset, withCommentSerializer,CommentCreateSerializer,AttachmentSerializerandAttachmentCreateSerializer. - Migration
0005adds both models plus indexes. - Invoice Approval demo: comment and attachment widgets on the invoice
detail page (
/invoices/{id}/comment/and.../attach/), media served in DEBUG, and view tests for adding/listing comments and uploading files. - New
tests/test_comments.pyandtests/test_attachments.py(22 tests: convenience methods, audit + domain events, timeline integration, REST endpoints, authentication and input validation). - Docs:
docs/comments.mdanddocs/attachments.mdguides linked from the docs index; README features and timeline/API docs updated. - Phase 9 - workflow versioning:
WorkflowVersionmodel with per-workflow sequential numbering, aDRAFT/PUBLISHED/RETIREDlifecycle, a JSON definition snapshot, changelog and created/published/retired timestamps. Only declarative, JSON-safe definitions are snapshottable (built-in conditions, string permissions, string approvers) — everything else raisesWorkflowVersionError.workflow_kit.engine.versioning:ensure_workflow_version,create_workflow_version,update_version,publish_version,retire_version,active_version,resolve_start_version,serialize_workflow,deserialize_workflowandget_version_workflow(cached per version byupdated_at).- Version-bound executions:
WorkflowExecutive.start(...)pins each execution to the workflow's active version (or an explicitversion=), and the engine resolves the pinned definition for every transition — an execution never silently switches to a newer definition. Audit events and the timeline carry the workflow version in their metadata. - Safe upgrade path:
ensure_workflow_versionsnapshots the registered definition as version 1 and pins pre-existing unversioned executions to it; the shipped data migration (0004) does the same for production databases and refuses to invent history for non-serializable workflows. - Concurrency-hardened version lifecycle: strictly increasing numbers and row-locked publish/retire so simultaneous publishes cannot collide.
- Convenience methods on
Workflow:active_version,create_version,publish_version,retire_version,update_version,versions,version. - Read-only
WorkflowVersionAdmin;WorkflowExecutionAdminshows the pinned version.WorkflowVersionErroradded to the public exception surface. - Invoice Approval demo end-to-end: definitions built through a
build_invoice_workflow(executive_threshold=...)factory; the first invoice publishes version 1,services.publish_invoice_v2publishes a higher-threshold revision, and tests prove running executions stay on v1 while new ones bind to v2. - New
tests/test_versioning.py(40 tests: lifecycle, immutability, serialization, introspection, admin, upgrade binding, concurrent publish/start). Package version bumped to0.2.0. - Docs:
docs/versioning.mdguide linked from the docs index. - Phase 9 - advanced workflows:
- Step approval requirements (
ApprovalRequirement,ApprovalMode) with all-of, any-of and quorum voting modes. A step may declare one pendingApprovalper approver slot; approvers are resolved at step entry from group names, usernames, user instances,ApproverResolversubclasses or callables (workflow_kit.approvals.requirements).Workflow(...)accepts anapproval_requirementsmapping keyed by state name. - Delegation: an approver can forward a step's slot to another user via
execution.delegate(...). Decisions made through a delegation are authorized against the granter's rights. Delegations are scoped to an execution/step, optional expiry, revocable (delegation.revoke()), recorded in the newWorkflowDelegationmodel and traced asapproval_delegated/delegation_revokedevents. - Escalation:
execution.escalate(approver, user=..., reason=...)cancels a step's pending approvals and replaces them with a single any-of approval the escalation approver alone decides (approval_escalated). - SLA tracking: each requirement can set an
sla; deadlines are stored onApproval.due_atand surfaced through theoverdue_approvals()query helper and theApproval.is_overdueproperty. - Self-approval control (
allow_self) compared against the initiating user (WorkflowExecution.initiated_by, set viaWorkflow.start(..., user=...)). - Concurrency hardening: approval decisions re-read the execution and the
target approval with
select_for_updateinside one transaction so simultaneous votes cannot double-advance a step; sibling approvals are cancelled transactionally on advance. - DRF API:
delegate/escalateendpoints onExecutionViewSetand extendedApprovalSerializer; approvals carrymode,order,assignmentandis_overdue. - Admin: read-only
Approval/WorkflowDelegationadmins; execution admin shows the initiating user. - Invoice Approval demo:
executive_reviewis now a parallel all-of step (Executive + Finance), anExecutivedemo account was added, and the demo exercises delegation and escalation end-to-end. - Phase 6 - optional DRF REST API:
workflow_kit.apipackage that loads only when Django REST Framework is installed; the core remains DRF-free (installed via thedrfextra).WorkflowExecutionViewSetexposing list (filterable byworkflow/current_state/completed, paginated) and detail (including the caller'savailable_actions), plusactions,transition,history,timelineandapprovalssub-actions.- Business objects are rendered only as
{type, id}— arbitrary model fields and stack traces are never exposed over HTTP; every endpoint requires an authenticated user. - Engine exceptions mapped to structured JSON errors (
invalid_transition,permission_denied,condition_failed,workflow_completed,approval_not_pending) viaworkflow_kit.api.exceptions.workflow_error_handler;approve/rejectroute through the approval decision service, other actions through the generic transition API. - Optional
WorkflowKitPagination(page size 20,page_sizequery param). - Invoice Approval demo mounts the API at
/api/with an end-to-end REST test suite; docs: REST API guide. - Phase 5 - domain events and notifications:
EventTypevocabulary (workflow.started/transitioned/completed/ cancelled/rejected,approval.created/approved/rejected) and an immutableDomainEventpayload (type, workflow, execution id,ObjectRef, actor, timestamp, source/target states, action, metadata and unique id).- Explicit in-process
EventDispatcherwithsubscribe/dispatch/clear,"*"wildcard subscriptions and fault-isolated handlers; a module-leveldefault_dispatcherwithsubscribe/dispatchaliases. - Transaction-aware
capture/emit/flush: events buffered incaptureare dispatched in order on success and discarded on failure, so a rolled-back transition never delivers events; events emitted outsidecapturedispatch immediately. - Engine integration:
startemitsworkflow.started, non-terminal transitions emitworkflow.transitioned+approval.created, and terminal transitions emitworkflow.completed/workflow.cancelled/workflow.rejected; approval decisions emitapproval.approved/approval.rejected. NotificationProviderabstraction,NotificationRouter(register/install/uninstall/clear),EmailProviderbuilt on Django's mail system, andWebhookProviderposting signed HMAC-SHA256 JSON payloads (X-Domain-Signature,-Event,-Event-Id,-Timestampheaders). Webhooks disabled by default.- New
WORKFLOW_KITsettings:NOTIFICATIONS_ENABLED,EMAIL_NOTIFICATIONS_ENABLED,EMAIL_FROM,EMAIL_SUBJECT_PREFIX,WEBHOOK_NOTIFICATIONS_ENABLED,WEBHOOK_URL,WEBHOOK_SECRET. - Invoice Approval demo subscribes an
[EVENT]console logger and an email notification on completion via Django's console email backend. - Tests for events, transaction semantics, dispatch isolation and the notification providers; docs: events and notifications guides.
- Phase 4 - conditions, conditional routing and Django admin:
Conditioninterface and a frozenConditionContext(user/workflow/execution/object) evaluated by every built-in; conditions neverevaluser code.- Built-in conditions:
FieldEquals,FieldNotEquals,GreaterThan,GreaterThanOrEqual,LessThan,LessThanOrEqual,IsTrueandIsFalse, supporting dotted paths (customer.is_verified); a missing attribute raisesConditionEvaluationError. - Logical operators
All,AnyandNotinworkflow_kit.conditions. Transition(..., conditions=...)accepts a condition or a list; the engine evaluates them oncan_transition()/available_actions()and re-evaluates against a freshly-persisted business object at execution time.- Conditional routing: multiple transitions may share an action name and
branch to different targets. Resolution requires exactly one passing
candidate; none raises
ConditionFailedErrorand is hidden from introspection, more than one raisesWorkflowConfigurationError. - Invoice Approval demo routes invoices above
10 000through anExecutive Reviewstep; new engine-level and demo tests. - Read-only Django admin for
WorkflowExecution,ApprovalandWorkflowEvent(no add / change / delete, so the admin can never bypass workflow authorization). - Docs: conditions and admin guides implemented; quickstart/transitions updated.
- Phase 3 - approval engine, audit trail and timeline:
Approvalmodel: one pending approval per non-terminal step, decided (APPROVED/REJECTED) throughexecution.approve()/execution.reject()with persisted approver, action and reason.- Approval decisions run atomically with the state transition, re-read and
lock the execution row (
select_for_update), and delegate authorization to the Phase 2 permission system. - Sequential approvals handled naturally: the next pending approval is created as the execution moves into each review state.
- Append-only
WorkflowEventaudit model recording start, transitions, approval requirements/decisions and completion;WorkflowEvent.save()rejects updates to existing rows (AuditError). execution.history()(ordered audit trail) andexecution.timeline()(structuredTimelineEventdataclasses exported from the package top level); the timeline derives from the audit trail only.- Invoice Approval demo now drives approve/reject through the approval API, passes rejection reasons and renders the timeline and pending approvals.
- New tests for approvals, audit, timeline and demo integration; package coverage remains 96%.
- Docs: approvals, audit and timeline pages implemented.
- Phase 1 core workflow engine:
Workflow,StateandTransitiondefinitions with eager validation (unknown states, duplicate names, invalid transitions raiseWorkflowConfigurationError).- Global workflow registry (
get_workflow,all_workflows,registry.unregister). WorkflowExecutionORM model (generic foreign key to any business object) withcurrent_state,is_completed,state_label, andavailable_actions/can_transition/transitionconveniences.- Atomic, row-locked transition execution
(
execute_transition), withInvalidTransitionErrorandWorkflowAlreadyCompletedError. - Read-only
WorkflowExecutionDjango admin registration. - Invoice Approval demo now runs its full lifecycle through the public
API (submit / approve / reject), replacing the old
statusfield. - Unit, integration and demo tests; coverage 96% on the package.
- Project bootstrap: packaging, CI, test infrastructure and documentation skeleton.
1.0.0 - 2026-08-12
First stable 1.0 release.
Added
- 1.0 release-readiness preparation:
- Added migration
0007to provision the documentedworkflow_kit.view_analyticspermission onWorkflowExecution. - Added PyPI project URLs, the Django 6.2 classifier, package data for admin
templates and a minimal
mkdocs.ymlfor the documenteddocsextra. - Removed placeholder Celery and Redis extras from package metadata because no integrations are shipped yet.
- Corrected README and documentation drift for quickstart API usage, compatibility, analytics permissions, repository URLs and security support policy.
- Public API frozen and verified (
workflow_kit.__all__), coverage ≥ 90%, full packaging and clean-room verification passed.
0.1.0 - 2026-08-08
Added
- Initial repository structure
pyproject.tomlpackaging fordjango-workflow-kit- Django application skeleton (
workflow_kit) - Exception hierarchy (
WorkflowErrorand subclasses) - Configuration proxy (
WORKFLOW_KITDjango settings) - Test project with an
Invoicedemo model - Pytest + pytest-django test suite
- GitHub Actions CI (lint, typecheck, matrix tests, build)
- Documentation skeleton, README, LICENSE, CONTRIBUTING and SECURITY