diff --git a/.env.example b/.env.example index f7ea799..93fff73 100644 --- a/.env.example +++ b/.env.example @@ -15,7 +15,7 @@ GOVOPLAN_DB_MAX_OVERFLOW=10 GOVOPLAN_DB_POOL_TIMEOUT_SECONDS=30 GOVOPLAN_DB_POOL_RECYCLE_SECONDS=1800 -ENABLED_MODULES=tenancy,organizations,identity,idm,access,admin,dashboard,policy,audit,files,templates,mail,campaigns,calendar,poll,scheduling,connectors,datasources,dataflow,dist_lists,workflow_engine,workflow,views,search,risk_compliance,postbox,notifications,services,parties,mandates,decisions,portal,cases,committee,docs,ops +ENABLED_MODULES=tenancy,organizations,identity,idm,access,admin,dashboard,policy,audit,files,templates,mail,campaigns,calendar,poll,scheduling,connectors,datasources,dataflow,dist_lists,workflow_engine,workflow,tasks,views,search,risk_compliance,postbox,notifications,services,parties,mandates,decisions,portal,cases,committee,docs,ops CELERY_ENABLED=true REDIS_URL=redis://127.0.0.1:6379/0 diff --git a/docs/PLATFORM_CORE_IDEAS.md b/docs/PLATFORM_CORE_IDEAS.md index b51ef2c..0db951b 100644 --- a/docs/PLATFORM_CORE_IDEAS.md +++ b/docs/PLATFORM_CORE_IDEAS.md @@ -61,6 +61,12 @@ next responsible action, reason, deadline, consequence, and completion evidence. Workflow Engine coordinates machine and human transitions; focused views guide people through the relevant platform surfaces. +Tasks owns explicit work items and the unified work inbox. Workflow Engine owns +process execution and resumable handoffs. Notifications attract attention, and +domain modules retain their business objects. These boundaries prevent an +inbox, workflow, or notification from becoming a second copy of institutional +state. + ### 7. Views reduce complexity without changing authority The interface is a task- and role-sensitive projection of installed @@ -84,6 +90,11 @@ records who entered information, for whom, from which source, with which attestation, and how the affected person receives a usable receipt and correction path. +Responsive, mobile, desktop, and embedded launch surfaces are additional ways +to enter the same governed context, not separate products with weaker authority +or evidence. Common task-local actions may open in bounded overlays while their +owning modules retain validation, policy, and persistence. + ### 10. Successful configurations are portable products Modules are ingredients. A usable product is a signed configuration package @@ -106,6 +117,10 @@ deployment tiers. | Data and integration | Connectors, datasources, dataflow, search, external references, provider health, and reconciliation | | Runtime and assurance | Module composition, operations, deployment, recovery, security evidence, and signed packages | +Collected product ideas and normalized actor outcomes are preserved in the +[Product Input Register](PRODUCT_INPUT_REGISTER.md). They enter implementation +only through a named journey, package, or explicit discovery issue. + ## Canonical Distinctions The platform must not collapse these pairs: @@ -170,4 +185,3 @@ institutional journey and can answer: 6. How can it operate with an external owner without losing autonomy? 7. How will a person discover and complete it without learning the module graph? - diff --git a/docs/PRODUCT_INPUT_REGISTER.md b/docs/PRODUCT_INPUT_REGISTER.md new file mode 100644 index 0000000..9ee34f9 --- /dev/null +++ b/docs/PRODUCT_INPUT_REGISTER.md @@ -0,0 +1,195 @@ +# GovOPlaN Product Input Register + +## Purpose + +This document preserves and normalizes product ideas and user-story notes that +inform GovOPlaN without turning a private note file into a second backlog. +Gitea issues remain the source of live work state; the stable platform direction +remains in [Platform Core Ideas](PLATFORM_CORE_IDEAS.md), the +[Connected Governance Platform Roadmap](CONNECTED_GOVERNANCE_PLATFORM_ROADMAP.md), +and the [Reference Journey Program](REFERENCE_JOURNEY_PROGRAM.md). + +The register was reconciled on 2026-08-06 from: + +- `/mnt/DATA/Nextcloud/ADD ideas UG/Products/govoplan/ideas.md`; +- `/mnt/DATA/Nextcloud/ADD ideas UG/Products/govoplan/user_stories.txt`. + +The source notes remain useful as the original capture. This maintained version +uses consistent terminology, makes ownership explicit, and records where an +idea enters the product program. + +## Product Themes + +### Operable and scalable installation + +An operator should be able to install, update, reconfigure, scale, back up, +restore, pause, and retire GovOPlaN through one explainable control plane. +Existing infrastructure may be reused or managed components may be provisioned. +The WebUI and CLI must invoke the same governed operations, show the planned and +completed effects, preserve recovery evidence, and never claim rollback for an +external effect that cannot actually be reversed. + +This theme is owned by Core, Admin, Ops, Policy, Files, and the signed product +package. It is tracked primarily by GovOPlaN #13 and the production evidence +issues. It advances in parallel with, but does not replace, actor-facing +reference journeys. + +### Focused, consistent work + +People should see the work and tools relevant to the current task, not the +installed module graph. Views may be defined by administrators, groups, or +users within policy. Workflow instances may pin a governed View. Contextual +help, predictable action placement, consistent central components, visible +intermediate results, and plain institutional terminology are product +requirements. + +Small task-local actions such as writing a Mail or Postbox message, completing +a Template, or manipulating Files should be launchable without abandoning the +current context. These actions remain owned by their modules and use bounded +overlays or workspaces; the shell supplies discovery and return context rather +than reimplementing them. + +This theme is owned by Core experience contracts, Views, Dashboard, Tasks, +Workflow Engine, Docs, and the contributing feature modules. The first proof is +the resumable service-to-decision/eAkte journey in GovOPlaN #42. + +### Governed human work + +An intake or event becomes owned work with a responsible actor or function, +priority, deadline, current action, consequence, source context, and completion +evidence. Tasks owns explicit work items and the unified work inbox. Workflow +Engine owns process execution, waits, retries, and handoffs. Domain modules own +the business objects and commands. Notifications attract attention but do not +replace durable work state. + +This distinction applies to service requests, technical support, approvals, +data reconciliation, campaigns, meetings, decisions, records, and failed +automation. It is the immediate shared implementation priority because users +must be able to leave work and resume it safely. + +### Institutional responsibility and workforce context + +Organization units, functions, mandates, assignments, delegations, and acting +context determine institutional responsibility. Presence, absence, illness, +availability, and similar status are effective-dated operational facts used to +route work, suppress or redirect notifications, explain planning, and trigger +policy. They are not merely profile decorations and they do not replace the IDM +lifecycle status of an identity or account. + +Time recording, absence management, sickness reporting, return-to-work +management, and applicant management form a possible workforce package. The +first implementation must be driven by a real journey and legal/privacy +profile; no new module boundary is implied solely by this register. + +### Integration-first and provider-neutral operation + +GovOPlaN should integrate tightly with software already used by an institution +and offer native alternatives only where that produces a better governed +outcome. Core-mediated provider contracts expose stable, vendor-neutral +capabilities; adapters encapsulate specific products. Authority, synchronized +fields, conflict behavior, health, credential custody, provenance, and +retirement must be explicit. + +The LBV Baden-Wuerttemberg idea is retained as a candidate workforce/payroll +integration profile and as a test of provider-neutral contracts. Desktop and +groupware integration for Microsoft Office, Outlook, LibreOffice, Thunderbird, +file managers, Windows, Unix, and macOS should use standards, deep links, +protocol handlers, synchronization, and governed connectors before custom +desktop software is introduced. + +### Inclusive channels and device surfaces + +Portal, Postbox, Mail, telephone, paper, in-person assistance, API, desktop, +and mobile are channels around the same governed work. A responsive or native +mobile surface must not create a second authority or data model. Assisted work +records representation, source, attestation, receipt, correction, and delivery +choice. People may opt into permitted distribution channels while policy keeps +mandatory channels and legal delivery requirements explicit. + +Video meetings, chat, instant messaging, and forums are retained as governed +collaboration-channel candidates. The default direction is integration with an +established provider through typed message, meeting, participant, evidence, and +retention contracts before building another communications stack. + +### Meetings, deliberation, decisions, and voting + +An institutional meeting spans scheduling, participants and mandates, +documents, agenda, discussion, formal motions, votes, decisions, minutes, +follow-up work, publication, and eligible expense settlement. Committee owns +the meeting and deliberation semantics while Calendar, Scheduling, Files, +Templates, Decisions, Tasks, Reporting, Ledger, and Voting contribute optional +capabilities. + +Voting requiring certified assurance remains a provider program. POLYAS is the +first external profile; a native provider may progress only through the +controlled assurance and certification program already tracked in Voting. + +### Controlled data work and understandable reporting + +People should manipulate data through immutable inputs, previewed operations, +intermediate materializations, reversible definition changes, durable review +decisions, quality rules, and complete lineage. Reports expose their definitions +and source revisions so controllers can understand and change how a result is +produced. Technical support may package controlled workflows that let +non-technical users safely operate otherwise hidden data. + +The monthly-data journey is the first proof. Sanctions screening follows on the +same source, snapshot, transformation, review, reporting, workflow, and +delivery contracts. + +### Institutional memory and consequence + +Decisions should be prepared, discussed, made, communicated, implemented, and +filed with their authority and consequences visible. A record/eAkte provides +the familiar administrative context across exact source revisions without +copying ownership from Cases, Decisions, Files, Forms, Campaign, Postbox, or +other modules. The institutional digital twin may later use governed +projections to model and simulate organizational change, but simulation output +never becomes authority without an explicit adoption decision. + +## Normalized Story Catalogue + +The following catalogue preserves the intent of the collected notes. It is an +orientation index, not a completion checklist. + +| Actor and desired outcome | Product owner or composition | First proof | +| --- | --- | --- | +| Operator installs, updates, scales, backs up, restores, and rolls back through one explainable workflow | Core, Admin, Ops, signed package | GovOPlaN #13 and target-evidence lane | +| System and tenant module administrators govern module availability and lifecycle | Core, Admin, Policy, Tenancy | Module entitlement and lifecycle composition | +| User works in a decluttered, consistent and task-sensitive interface | Views, Core, Dashboard, Workflow, Docs | Service-to-decision workspace | +| Policy maker defines inherited, explainable and enforced rules | Policy plus every consequential owner | Information-governance adoption gate | +| Controller and auditor reconstruct results, rules, evidence and correction paths | Audit, Reporting, Records, Dataflow | Monthly-data and eAkte journeys | +| User sees institutional terminology, current progress, intermediate results and consequences | Domain owner, Tasks, Workflow, Views | All reference journey acceptance tests | +| Voting body and voter obtain independently assured democratic voting | Voting, Committee, Identity Trust, Encryption | POLYAS profile and controlled native-provider program | +| Support staff packages safe guided manipulation of hidden data | Workflow, Dataflow, Tasks, Views | Monthly reconciliation workflow | +| Data worker performs controlled, understandable and recoverable transformations | Datasources, Connectors, Dataflow, Reporting | GovOPlaN #8 | +| Decision maker prepares, deliberates, decides, records and follows consequences | Committee, Decisions, Tasks, Records, Reporting | Service-to-decision journey | +| Management delegates responsibility and receives governed activity reports | Organizations, IDM, Access, Policy, Reporting | Function-bound Postbox and work inbox | +| Institution models and simulates organizational change | Organizations, Policy, Dataflow, Reporting, Digital Twin | Later governed digital-twin package | +| Sender distributes generated files to functions without knowing incumbents | Campaign, Distribution Lists, Postbox, Organizations, IDM | Governed communication package | +| Function holder receives current and policy-selected historical work and information | IDM, Access, Postbox, Tasks, Records | Postbox reassignment/history tests | +| Administrative worker accesses one familiar eAkte context across exact owned objects | Records and record-source providers | GovOPlaN #42 and Records #8 | +| User invokes common message, template and file actions without leaving the current task | Core shell, Views, Workflow and contributing modules | Task-local action contract and service workspace | + +## Idea Preservation Map + +| Original idea cluster | Preserved direction | +| --- | --- | +| Time recording, absence, sickness, reintegration, applicant management | Governed workforce-context journey; effective-dated status and privacy profile before module expansion | +| LBV BW interface | Candidate provider-neutral workforce/payroll connector profile | +| Abstract interfaces | Versioned Core contracts with product adapters and explicit source authority | +| Desktop and groupware integration | Standards, connectors, deep launch and synchronization before custom clients | +| GovOPlaN app/mobile-first pages | Responsive shared semantics; native shell only when a proven journey needs device capabilities | +| Video, chat, instant messaging and forum | Optional governed collaboration providers with retention/evidence contracts | +| Somacos Session-style meeting management | Committee-led meeting composition across Calendar, Files, Decisions, Templates, Tasks, Reporting and Ledger | +| Stronger software integration | Integration-first roadmap rule and first full external product connectors | + +## Maintenance + +When a source idea becomes actionable: + +1. link it to a named reference journey or explicit discovery issue; +2. identify the owning module and external authority; +3. create or update the Gitea issue with acceptance criteria; +4. keep live status out of this document; +5. update this register only when the durable interpretation changes. diff --git a/docs/README.md b/docs/README.md index 3f0c615..e9abee8 100644 --- a/docs/README.md +++ b/docs/README.md @@ -14,6 +14,7 @@ volatile repository, issue, release, or maturity counts as current facts. | Which institutional concepts and owners form the target architecture? | [Institutional Governance Target Architecture](INSTITUTIONAL_GOVERNANCE_TARGET_ARCHITECTURE.md) | | Which end-to-end proofs should guide implementation? | [Reference Journey Program](REFERENCE_JOURNEY_PROGRAM.md) | | What is the reconciled state now? | [Strategy Status](STRATEGY_STATUS.md) | +| Which collected ideas and user stories inform the product direction? | [Product Input Register](PRODUCT_INPUT_REGISTER.md) | The dated [Strategic Review](STRATEGIC_REVIEW_2026-08-05.md) explains why the current reset and sequencing were chosen. It is an assessment record, not a @@ -74,3 +75,5 @@ be edited manually. repository. Meta documentation defines cross-module outcomes and contracts. 6. A new strategy document must replace, narrow, or link an existing source; it must not introduce a parallel roadmap. +7. The Product Input Register preserves external idea and story notes, but only + Gitea issues carry live priority, ownership, and implementation state. diff --git a/docs/REFERENCE_JOURNEY_PROGRAM.md b/docs/REFERENCE_JOURNEY_PROGRAM.md index 5f686dd..f1e3eb5 100644 --- a/docs/REFERENCE_JOURNEY_PROGRAM.md +++ b/docs/REFERENCE_JOURNEY_PROGRAM.md @@ -46,9 +46,11 @@ and archive-neutral package simulation. Forms Runtime, Cases, and Decisions expose exact, permission-rechecked source revisions for explicit filing, and all three contribute metadata-only native Search projections that can be rebuilt from authoritative state. The executable fixtures prove those native -transitions without claiming archival custody. The journey still needs -resumable user handoffs, pinned-composition reconstruction evidence, and one -target-tested archive profile. +transitions without claiming archival custody. A persisted Workflow Engine +handoff is now reloaded through the Tasks aggregation surface and remains +visible until the authoritative Workflow transition completes. The journey +still needs pinned-composition reconstruction evidence and one target-tested +archive profile. ## Why this sequence @@ -124,6 +126,14 @@ journey needs and supplies contracts shared by all five stages. Module manifests state `contract_only`, `partial`, `enforced`, or `not_applicable` adoption with evidence; supported maturity is blocked until every applicable dimension is enforced. +11. **Durable human work.** Tasks aggregates explicit work and module-owned + attention items; Workflow Engine persists process state and handoffs; + Notifications attracts attention; Views focuses the relevant surfaces. + Leaving or refreshing the browser never becomes the only record that work + remains unfinished. +12. **Task-local tools.** Mail, Postbox, Templates, Files, and other common + actions may contribute bounded launch surfaces with return context. The + shell and Workflow compose them without copying their data or validation. ## Documentation contract for every reference stage diff --git a/docs/STRATEGY_STATUS.md b/docs/STRATEGY_STATUS.md index c7d0fa4..3e4a2f7 100644 --- a/docs/STRATEGY_STATUS.md +++ b/docs/STRATEGY_STATUS.md @@ -7,6 +7,7 @@ | Reconciled on | 2026-08-06 | | Source scope | Local workspace manifests, source inventory, focused journey checks, signed release evidence, and live Gitea issue state | | Stable direction | [Platform Core Ideas](PLATFORM_CORE_IDEAS.md) and [Connected Governance Platform Roadmap](CONNECTED_GOVERNANCE_PLATFORM_ROADMAP.md) | +| Collected product input | [Product Input Register](PRODUCT_INPUT_REGISTER.md) | | Delivery source | Gitea issues | This is the only prose source for current cross-product status. It is a @@ -15,8 +16,8 @@ evidence remain authoritative for specific maturity claims. ## Portfolio Snapshot -- 65 source module manifests were loadable and architecture-declared. -- 47 modules declared `vertical_slice`; 18 declared `scaffold`. +- 66 source module manifests were loadable and architecture-declared. +- 48 modules declared `vertical_slice`; 18 declared `scaffold`. - No module declared `reference_ready`, `supported`, or `lts`. - The live portfolio had 133 open issues, including 39 priority-P1 items. - 117 open issues had no milestone, so issue labels do not yet express a @@ -30,19 +31,20 @@ document. ## Interface And Contract Evidence -The 2026-08-05 source inventory found: +The 2026-08-06 source inventory found: -- 1,247 UI fields and 1,220 UI actions; -- 7,929 stable interface declarations with no duplicate IDs; -- 39 frontend routes and 872 backend endpoints; +- 1,307 UI fields and 1,291 UI actions; +- 8,157 stable interface declarations with no duplicate IDs; +- 43 frontend routes and 920 backend endpoints; - no public WebUI surfaces missing runtime declarations; - no stale runtime route declarations; - no unclassified endpoint without a static UI reference; -- all 1,247 fields with a resolvable F1 context; 1,087 remain candidates for +- all 1,307 fields with a resolvable F1 context; 1,143 remain candidates for richer field-specific content beyond page/module fallback; - German (`de`) as the complete reference locale and no used key missing from the required German or English catalogs; -- 260 module information-governance dimensions classified as `contract_only`. +- 3 module information-governance dimensions classified as `enforced`, 1 as + `partial`, and 260 as `contract_only`. This is an honest platform-wide baseline, not a claim that temporal, purpose, retention, and institutional-context adoption is complete. @@ -70,24 +72,28 @@ Voting, Decisions, Portal, Postbox, and Audit have an executable service-to- decision fixture. Public and invitation intake can retain Files-backed evidence; Forms submissions, Cases, and formal Decisions can be explicitly filed as exact eAkte source revisions and reconstructed through permission- -rechecked native Search projections. Browser-complete assisted intake, -resumable work guidance, production identity and delivery, a named archive -profile, and target evidence remain. +rechecked native Search projections. A durable Workflow Engine handoff now +survives session restart and appears through the Tasks work inbox until the +authoritative transition completes. Browser-complete assisted intake, broader +work projections and escalation, production identity and delivery, a named +archive profile, and target evidence remain. ### Governed data and assurance Connectors, Datasources, Dataflow, Reporting, Search, Policy, Risk Compliance, and Workflow provide source governance, immutable snapshots, transformation, quality, semantic reporting, and provenance foundations. The monthly-data and -sanctions journeys still need real connectors, complete interactive -reconciliation, publication/export, and guided handoff evidence. +sanctions compositions now prove immutable connector snapshots, pinned +Dataflow publication, Risk Compliance review, and rescreening in process. The +journeys still need target connector profiles, complete interactive +reconciliation, governed export/delivery, and browser-level handoff evidence. ## Material Gaps | Gap | Consequence | Next proof | | --- | --- | --- | | No reference-ready product package | The platform cannot yet make a bounded supported-product claim | Complete one named target composition and evidence bundle | -| Human-work spine incomplete | Users still navigate modules and remember unfinished work | Task/work inbox, resumable guided journey, deadlines and handoffs | +| Human-work spine is only an MVP | Tasks aggregates explicit work plus Workflow, Approval, and unread Postbox projections, but broad domain coverage, deadline escalation, assignment lifecycle, and focused product UX remain | Extend source providers through the three reference journeys and prove overdue/reassignment behavior in browser tests | | Records/eAkte target integration incomplete | Native lifecycle, retention, holds, approval, recovery, and transfer simulation are implemented, but real custody is not proved | Target-test one archive/xdomea profile and complete the assisted reference journey | | Cross-cutting governance adoption uneven | Historical and purpose-sensitive behavior varies by module | Enforced adoption declarations and route/query/effect migration | | Explicit help/accessibility depth incomplete | German/reference and F1 association gates now pass, but generic fallback remains too common | High-risk German help content and browser/a11y matrix | @@ -103,9 +109,11 @@ reconciliation, publication/export, and guided handoff evidence. sanctions screening. 4. Complete the browser and resumable-work proof for the digital and assisted service-to-decision journey with its existing exact eAkte filing contracts. -5. Extend native PostgreSQL search coverage from the implemented service-to- - decision objects to the communication and monthly-data journeys; keep - OpenSearch optional. +5. Complete native PostgreSQL search coverage for remaining journey-owned + objects and prove reauthorization and reindex operations at target volume; + keep OpenSearch optional. Communication, Records, service-to-decision, + Dataflow, Reporting, Risk Compliance, and Datasource catalogue sources now + exist. 6. Prove one external product connector and one GovOPlaN federation exchange. 7. Finish multi-host, restore, provider, accessibility, and independent signed target evidence before increasing maturity claims. diff --git a/packages/govoplan-meta/pyproject.toml b/packages/govoplan-meta/pyproject.toml index 199a422..d1748af 100644 --- a/packages/govoplan-meta/pyproject.toml +++ b/packages/govoplan-meta/pyproject.toml @@ -72,6 +72,7 @@ full = [ "govoplan-search==0.1.18", "govoplan-services==0.1.18", "govoplan-soap==0.1.18", + "govoplan-tasks==0.1.18", "govoplan-templates==0.1.18", "govoplan-tickets==0.1.18", "govoplan-transparency==0.1.18", diff --git a/packages/product/governed-communication/README.md b/packages/product/governed-communication/README.md index 37b7718..d3690a6 100644 --- a/packages/product/governed-communication/README.md +++ b/packages/product/governed-communication/README.md @@ -28,5 +28,7 @@ The artifact remains a `product` package. Promotion to `reference` requires: access; and - version-pinned user and administrator documentation. -Optional Notifications, Portal, Reporting, and Workflow Engine integrations do -not change the package boundary when absent. +Optional Notifications, Portal, Reporting, Tasks, and Workflow Engine +integrations do not change the package boundary when absent. When Tasks is +present, acknowledgement, reconciliation, and operator intervention remain +owned by their source modules and are projected into the common work inbox. diff --git a/packages/product/governed-communication/package.json b/packages/product/governed-communication/package.json index c2e875e..e1885ab 100644 --- a/packages/product/governed-communication/package.json +++ b/packages/product/governed-communication/package.json @@ -21,6 +21,7 @@ {"module_id": "notifications"}, {"module_id": "portal"}, {"module_id": "reporting"}, + {"module_id": "tasks"}, {"module_id": "workflow_engine"} ], "evidence": [ diff --git a/packages/product/governed-data-assurance/README.md b/packages/product/governed-data-assurance/README.md index d122ce4..9b3459f 100644 --- a/packages/product/governed-data-assurance/README.md +++ b/packages/product/governed-data-assurance/README.md @@ -37,8 +37,10 @@ The artifact remains a `product` package. Promotion to `reference` requires: aggregate disclosure; and - version-pinned user and administrator documentation. -Optional Connectors, Files, Notifications, and Workflow Engine integrations -must remain capability-based and absence-safe. +Optional Connectors, Files, Notifications, Tasks, and Workflow Engine +integrations must remain capability-based and absence-safe. Tasks may present +review and recovery handoffs, but Dataflow and Risk Compliance remain the +authoritative owners of run and screening state. ## Executable evidence diff --git a/packages/product/governed-data-assurance/package.json b/packages/product/governed-data-assurance/package.json index e81d095..a694288 100644 --- a/packages/product/governed-data-assurance/package.json +++ b/packages/product/governed-data-assurance/package.json @@ -21,6 +21,7 @@ {"module_id": "connectors"}, {"module_id": "files"}, {"module_id": "notifications"}, + {"module_id": "tasks"}, {"module_id": "workflow_engine"} ], "evidence": [ diff --git a/packages/product/service-to-decision/README.md b/packages/product/service-to-decision/README.md index 2956aec..536d6ba 100644 --- a/packages/product/service-to-decision/README.md +++ b/packages/product/service-to-decision/README.md @@ -33,6 +33,11 @@ values, evidence payloads, Decision reasoning, operative results, and conditions are excluded; every candidate is authorized again before it is shown. +When Tasks is present, explicit work and source-owned Workflow handoffs appear +in one resumable inbox with typed account, group, role, function, or assignment +responsibility. Workflow Engine retains process state and completion commands; +Tasks retains only explicit tasks and the aggregation surface. + ## Security And Recovery Every provider is tenant-bound. Missing or conflicting authority fails closed. @@ -46,9 +51,11 @@ The executable fixture in `tests/test_institutional_governance_journey.py` proves SQL-backed Service, Case, Party, Mandate, Committee meeting/agendum/vote/minute, and Decision state. `tests/test_institutional_service_journey.py` separately proves exact Portal -Form launch, persisted submission provenance, and idempotent replay. +Form launch, persisted submission provenance, idempotent replay, and a durable +Workflow handoff that remains visible through Tasks after the database session +is reopened and disappears only after the Workflow Engine records completion. Module-level Records source tests prove exact Form submission, Case revision, and Decision revision filing. Target-environment browser accessibility, -resumable work guidance, production identity and delivery, a named archive -profile, and recovery evidence are still required before this product package -may claim `reference_ready` maturity. +production identity and delivery, a named archive profile, and recovery evidence +are still required before this product package may claim `reference_ready` +maturity. diff --git a/requirements-dev.txt b/requirements-dev.txt index d3a4155..bb58909 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -35,6 +35,7 @@ -e ../govoplan-dataflow -e ../govoplan-workflow-engine -e ../govoplan-workflow +-e ../govoplan-tasks -e ../govoplan-views -e ../govoplan-voting -e ../govoplan-search diff --git a/tests/test_institutional_service_journey.py b/tests/test_institutional_service_journey.py index f225b66..3e99d81 100644 --- a/tests/test_institutional_service_journey.py +++ b/tests/test_institutional_service_journey.py @@ -2,11 +2,14 @@ from __future__ import annotations from dataclasses import dataclass from datetime import UTC, datetime, timedelta +from types import SimpleNamespace import unittest from sqlalchemy import create_engine -from sqlalchemy.orm import Session +from sqlalchemy.orm import Session, sessionmaker +from govoplan_core.auth import ApiPrincipal +from govoplan_core.core.access import PrincipalRef from govoplan_core.core.institutional import ( CAPABILITY_FORM_DEFINITIONS, CAPABILITY_SERVICE_DEFINITIONS, @@ -18,6 +21,17 @@ from govoplan_core.core.institutional import ( TemporalRevision, service_launch_capability, ) +from govoplan_core.core.runtime_coordination import ( + DistributedLease, + RuntimeIdentity, + bind_process_runtime_identity, +) +from govoplan_core.core.tasks import ( + RegisteredWorkItemProvider, + WorkItemProviderRegistration, + WorkItemQuery, +) +from govoplan_core.core.recovery import RecoveryCheckpoint, RecoveryOperation from govoplan_cases.backend.service_intake import ( CAPABILITY_CASES_SERVICE_INTAKE, CaseServiceIntake, @@ -37,6 +51,34 @@ from govoplan_forms_runtime.backend.service import ( FormsServiceLauncher, ) from govoplan_portal.backend.service_directory import PortalServiceDirectory +from govoplan_tasks.backend.aggregation import aggregate_work_items +from govoplan_workflow_engine.backend.db.models import ( + WorkflowDefinition, + WorkflowDefinitionRevision, + WorkflowInstance, + WorkflowInstanceEvent, + WorkflowInstanceStep, + WorkflowTrigger, + WorkflowTriggerDelivery, + WorkflowWaitState, +) +from govoplan_workflow_engine.backend.instance_service import ( + resolve_step, + start_instance, +) +from govoplan_workflow_engine.backend.schemas import ( + WorkflowDefinitionCreateRequest, + WorkflowEdge, + WorkflowGraph, + WorkflowInstanceStartRequest, + WorkflowNode, + WorkflowStepActionRequest, +) +from govoplan_workflow_engine.backend.service import ( + activate_definition, + create_definition, +) +from govoplan_workflow_engine.backend.work_items import WorkflowWorkItemProvider NOW = datetime(2026, 8, 1, 10, 0, tzinfo=UTC) @@ -74,10 +116,14 @@ class _Provider: def __init__(self, definition: ServiceDefinition) -> None: self.definition = definition - def get_service_definition(self, session, principal, *, reference, effective_at=None): + def get_service_definition( + self, session, principal, *, reference, effective_at=None + ): return self.definition - def list_service_definitions(self, session, principal, *, tenant_id, query="", limit=100): + def list_service_definitions( + self, session, principal, *, tenant_id, query="", limit=100 + ): return (self.definition,) @@ -111,17 +157,58 @@ class _Principal: class _FormRegistry(_Registry): def __init__(self, definition: ServiceDefinition) -> None: super().__init__(definition) - self.capabilities[CAPABILITY_FORM_DEFINITIONS] = ( - SqlFormDefinitionProvider() - ) - self.capabilities[service_launch_capability("form")] = ( - FormsServiceLauncher(self) + self.capabilities[CAPABILITY_FORM_DEFINITIONS] = SqlFormDefinitionProvider() + self.capabilities[service_launch_capability("form")] = FormsServiceLauncher( + self ) def has(self, module_id: str) -> bool: return module_id in {"portal", "forms", "forms_runtime"} +class _WorkflowTaskRegistry: + def __init__(self) -> None: + self.provider = WorkflowWorkItemProvider(registry=self) + self.registered = RegisteredWorkItemProvider( + module_id="workflow_engine", + registration=WorkItemProviderRegistration( + id="workflow_engine.handoffs", + factory=lambda _context: self.provider, + order=20, + ), + ) + + def has_capability(self, _name: str) -> bool: + return False + + def capability(self, name: str) -> object: + raise KeyError(name) + + def work_item_providers(self): + return ((self.registered, self.provider),) + + +def _workflow_principal() -> ApiPrincipal: + return ApiPrincipal( + principal=PrincipalRef( + account_id="account-1", + membership_id="membership-1", + tenant_id="tenant-1", + scopes=frozenset( + { + "tasks:item:read", + "workflow:definition:read", + "workflow:instance:read", + "workflow:instance:start", + "workflow:instance:transition", + } + ), + ), + account=SimpleNamespace(id="account-1"), + user=SimpleNamespace(id="membership-1"), + ) + + class InstitutionalServiceJourneyTests(unittest.TestCase): def test_one_service_version_drives_portal_and_case_intake(self) -> None: definition = _service() @@ -266,6 +353,149 @@ class InstitutionalServiceJourneyTests(unittest.TestCase): session.close() engine.dispose() + def test_workflow_handoff_survives_session_reopen_and_projects_into_tasks( + self, + ) -> None: + engine = create_engine("sqlite+pysqlite:///:memory:") + tables = ( + DistributedLease.__table__, + RecoveryOperation.__table__, + RecoveryCheckpoint.__table__, + WorkflowDefinition.__table__, + WorkflowDefinitionRevision.__table__, + WorkflowInstance.__table__, + WorkflowInstanceStep.__table__, + WorkflowInstanceEvent.__table__, + WorkflowTrigger.__table__, + WorkflowTriggerDelivery.__table__, + WorkflowWaitState.__table__, + ) + for table in tables: + table.create(engine) + sessions = sessionmaker(bind=engine) + registry = _WorkflowTaskRegistry() + principal = _workflow_principal() + bind_process_runtime_identity( + RuntimeIdentity( + installation_id="service-journey", + node_id="journey-node", + incarnation="journey-run", + role="web", + software_version="test", + composition_hash="c" * 64, + ) + ) + try: + with sessions() as session: + definition = create_definition( + session, + tenant_id="tenant-1", + actor_id="account-1", + payload=WorkflowDefinitionCreateRequest( + name="Permit decision", + graph=WorkflowGraph( + nodes=[ + WorkflowNode( + id="start", + type="workflow.start.manual", + ), + WorkflowNode( + id="review", + type="workflow.activity", + config={ + "title": "Decide the permit application", + "instructions": "Review the filed evidence and record the decision.", + "assignee": "account:account-1", + "due_after": "2d", + }, + ), + WorkflowNode( + id="done", + type="workflow.end.completed", + ), + ], + edges=[ + WorkflowEdge( + id="start-review", + source="start", + target="review", + ), + WorkflowEdge( + id="review-done", + source="review", + target="done", + ), + ], + ), + execution_mode="guided", + ), + ) + activate_definition( + session, + tenant_id="tenant-1", + definition_id=definition.id, + actor_id="account-1", + ) + instance, replayed = start_instance( + session, + tenant_id="tenant-1", + definition_id=definition.id, + actor_id="account-1", + principal=principal, + registry=registry, + payload=WorkflowInstanceStartRequest( + idempotency_key="permit-decision-1", + input={"case_id": "case-1"}, + correlation_id="case-1", + ), + ) + self.assertFalse(replayed) + session.commit() + instance_id = instance.id + step_id = instance.current_step_id + + with sessions() as reopened: + work = aggregate_work_items( + registry, + reopened, + principal, + query=WorkItemQuery(tenant_id="tenant-1"), + ) + self.assertEqual(1, work.total) + self.assertEqual(step_id, work.items[0].id) + self.assertEqual( + "Decide the permit application", + work.items[0].title, + ) + self.assertTrue(work.items[0].action_url.startswith("/workflow?")) + self.assertIn(f"run={instance_id}", work.items[0].action_url) + + resolve_step( + reopened, + tenant_id="tenant-1", + instance_id=instance_id, + step_id=step_id, + actor_id="account-1", + principal=principal, + registry=registry, + payload=WorkflowStepActionRequest(action="complete"), + ) + reopened.commit() + + with sessions() as verified: + self.assertEqual( + 0, + aggregate_work_items( + registry, + verified, + principal, + query=WorkItemQuery(tenant_id="tenant-1"), + ).total, + ) + finally: + bind_process_runtime_identity(None) + engine.dispose() + if __name__ == "__main__": unittest.main() diff --git a/tools/deployment/govoplan_deploy/model.py b/tools/deployment/govoplan_deploy/model.py index 2b4c271..c5653c4 100644 --- a/tools/deployment/govoplan_deploy/model.py +++ b/tools/deployment/govoplan_deploy/model.py @@ -54,6 +54,7 @@ FULL_MODULES = ( "dataflow", "workflow_engine", "workflow", + "tasks", "views", "search", "risk_compliance", diff --git a/tools/inventory/endpoint-surface-declarations.json b/tools/inventory/endpoint-surface-declarations.json index d922b95..ad4dc7d 100644 --- a/tools/inventory/endpoint-surface-declarations.json +++ b/tools/inventory/endpoint-surface-declarations.json @@ -1819,6 +1819,13 @@ "rationale": "IDM lacks the typed-group membership explanation surface for this existing API.", "repository": "govoplan-idm", "tracking_issue": "https://git.add-ideas.de/GovOPlaN/govoplan-idm/issues/11" + }, + { + "category": "intentionally_headless", + "method": "GET", + "path": "/tasks/{}", + "rationale": "Task command clients retrieve one explicit task and its strong revision token; the Work UI already receives the same projection through the aggregated list.", + "repository": "govoplan-tasks" } ], "schema_version": 1 diff --git a/tools/launch/launch-production-like-dev.sh b/tools/launch/launch-production-like-dev.sh index 6fd3227..540605b 100644 --- a/tools/launch/launch-production-like-dev.sh +++ b/tools/launch/launch-production-like-dev.sh @@ -51,7 +51,7 @@ set +a export APP_ENV="${APP_ENV:-staging}" export GOVOPLAN_INSTALL_PROFILE="${GOVOPLAN_INSTALL_PROFILE:-production-like}" -export ENABLED_MODULES="${ENABLED_MODULES:-tenancy,organizations,identity,idm,access,admin,dashboard,policy,audit,campaigns,files,mail,calendar,poll,scheduling,connectors,datasources,dataflow,dist_lists,templates,workflow_engine,workflow,views,search,risk_compliance,notifications,docs,ops}" +export ENABLED_MODULES="${ENABLED_MODULES:-tenancy,organizations,identity,idm,access,admin,dashboard,policy,audit,campaigns,files,mail,calendar,poll,scheduling,connectors,datasources,dataflow,dist_lists,templates,workflow_engine,workflow,tasks,views,search,risk_compliance,notifications,docs,ops}" export DATABASE_URL="${DATABASE_URL:-${GOVOPLAN_PRODUCTION_LIKE_DATABASE_URL:-postgresql+psycopg://govoplan:govoplan-dev@127.0.0.1:55433/govoplan}}" export GOVOPLAN_DATABASE_URL_PGTOOLS="${GOVOPLAN_DATABASE_URL_PGTOOLS:-${GOVOPLAN_PRODUCTION_LIKE_DATABASE_URL_PGTOOLS:-postgresql://govoplan:govoplan-dev@127.0.0.1:55433/govoplan}}" export REDIS_URL="${REDIS_URL:-${GOVOPLAN_PRODUCTION_LIKE_REDIS_URL:-redis://127.0.0.1:56379/0}}" diff --git a/tools/launch/production-like-dev.sh b/tools/launch/production-like-dev.sh index 858cb7c..25901a5 100644 --- a/tools/launch/production-like-dev.sh +++ b/tools/launch/production-like-dev.sh @@ -66,7 +66,7 @@ export DATABASE_URL="${DATABASE_URL:-${GOVOPLAN_PRODUCTION_LIKE_DATABASE_URL:-po export GOVOPLAN_DATABASE_URL_PGTOOLS="${GOVOPLAN_DATABASE_URL_PGTOOLS:-${GOVOPLAN_PRODUCTION_LIKE_DATABASE_URL_PGTOOLS:-postgresql://govoplan:govoplan-dev@127.0.0.1:55433/govoplan}}" export REDIS_URL="${REDIS_URL:-${GOVOPLAN_PRODUCTION_LIKE_REDIS_URL:-redis://127.0.0.1:56379/0}}" export CELERY_ENABLED="${CELERY_ENABLED:-true}" -export ENABLED_MODULES="${ENABLED_MODULES:-tenancy,organizations,identity,idm,access,admin,dashboard,policy,audit,campaigns,files,mail,calendar,poll,scheduling,connectors,datasources,dataflow,dist_lists,templates,workflow_engine,workflow,views,search,risk_compliance,notifications,docs,ops}" +export ENABLED_MODULES="${ENABLED_MODULES:-tenancy,organizations,identity,idm,access,admin,dashboard,policy,audit,campaigns,files,mail,calendar,poll,scheduling,connectors,datasources,dataflow,dist_lists,templates,workflow_engine,workflow,tasks,views,search,risk_compliance,notifications,docs,ops}" export FILE_STORAGE_BACKEND="${FILE_STORAGE_BACKEND:-local}" export FILE_STORAGE_LOCAL_ROOT="${FILE_STORAGE_LOCAL_ROOT:-$META_ROOT/runtime/production-like/files}" export DEV_AUTO_MIGRATE_ENABLED="${DEV_AUTO_MIGRATE_ENABLED:-false}"