docs(projects): add German workflow guidance
Module Package Release / publish-packages (push) Successful in 10s

This commit is contained in:
2026-08-23 01:54:20 +02:00
parent de8ec81c47
commit f0a28dd8ec
6 changed files with 179 additions and 28 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@govoplan/projects",
"version": "0.1.18",
"version": "0.1.19",
"private": true,
"description": "GovOPlaN Projects domain module.",
"type": "module",
+2 -2
View File
@@ -4,14 +4,14 @@ build-backend = "setuptools.build_meta"
[project]
name = "govoplan-projects"
version = "0.1.18"
version = "0.1.19"
description = "GovOPlaN Projects domain module."
readme = "README.md"
requires-python = ">=3.12"
license = { file = "LICENSE" }
authors = [{ name = "GovOPlaN" }]
dependencies = [
"govoplan-core>=0.1.18",
"govoplan-core>=0.1.37",
"govoplan-access>=0.1.18",
]
+139 -24
View File
@@ -14,6 +14,7 @@ from govoplan_core.core.module_guards import (
)
from govoplan_core.core.modules import (
CapabilityDocumentation,
DocumentationCondition,
DocumentationLink,
DocumentationTopic,
FrontendModule,
@@ -50,7 +51,7 @@ from govoplan_projects.backend.service import (
MODULE_ID = "projects"
MODULE_NAME = "Projects"
MODULE_VERSION = "0.1.18"
MODULE_VERSION = "0.1.19"
READ_SCOPE = "projects:project:read"
WRITE_SCOPE = "projects:project:write"
ADMIN_SCOPE = "projects:project:admin"
@@ -209,21 +210,23 @@ ROLE_TEMPLATES = (
DOCUMENTATION = (
DocumentationTopic(
id="projects.module-boundary",
title="Projects module boundary",
title="Plan and coordinate projects",
summary=(
"Portfolios, projects, versioned goals and outcomes, milestones, "
"dependencies, capacity, benefits, participants, status, and references."
"Coordinate portfolios, projects, milestones, participants, dependencies, "
"capacity assumptions, outcomes, and benefit reviews without absorbing work-item ownership."
),
body=(
"Projects owns native project context. Tasks and Tickets own "
"actionable work, Cases owns formal procedures, and Connectors "
"owns OpenProject synchronization. Reporting owns measured indicators; "
"Risk Compliance owns risks and controls; Projects links those facts to "
"planning, change impact, and benefit review."
"Projects owns native portfolio and project context, immutable revisions of goals and intended outcomes, "
"milestones, participants, status, dependencies, capacity assumptions, benefit reviews, and governed resource references. "
"Create or revise the planning context, review its impact, and link provider-owned work and evidence without copying it. "
"Tasks and Tickets retain actionable work, Cases retains formal procedures, and Connectors retains OpenProject transport. "
"Reporting owns measured indicators and Risk Compliance owns risks and controls; Projects links those facts to planning, "
"change impact, and benefit review."
),
layer="available",
documentation_types=("admin", "user"),
audience=("user", "operator", "module_admin", "product_owner"),
conditions=(DocumentationCondition(required_scopes=(READ_SCOPE,)),),
related_modules=OPTIONAL_DEPENDENCIES,
links=(
DocumentationLink(
@@ -238,23 +241,105 @@ DOCUMENTATION = (
),
),
metadata={
"seed": True,
"domain_objects": [
"portfolio",
"project",
"milestone",
"versioned goal and intended outcome",
"dependency and capacity assumption",
"benefit review",
"project participant",
"project resource link",
"external project reference",
"kind": "workflow",
"help_contexts": [
"projects.workspace",
"projects.project",
"projects.milestone",
],
"first_slice": (
"Implement project and portfolio identity, status, milestones, "
"participants, outcome/benefit intent, dependency/resource links, "
"and OpenProject reference mapping."
"purpose": (
"Maintain a revisioned planning context and connect provider-owned work, evidence, and measurements to it."
),
"prerequisites": [
"The actor can read the project; revisions require project write access.",
"Referenced work, cases, files, risks, reports, and external systems remain authorized by their owner providers.",
],
"steps": [
"Select a portfolio or create the project identity, status, participants, and planning horizon.",
"Record versioned goals, intended outcomes, milestones, dependencies, and capacity assumptions.",
"Link Tasks, Tickets, Cases, files, risks, controls, reports, or external project references without copying owner data.",
"Review status, change impact, milestone progress, and benefit evidence before appending a revision.",
"Use owner-module links to manage actionable work or formal procedures in their authoritative surface.",
],
"fields": {
"portfolio": "Groups projects for planning and oversight without changing project authority.",
"project": "The native revisioned context for outcome, status, participation, and resource links.",
"milestone": "A dated project checkpoint, not an actionable Task or formal Case state.",
"participant": "An explicit project access grant and role, independent of object ownership elsewhere.",
"external_reference": "A governed link to a provider-owned project or resource, including OpenProject mappings.",
},
"limitations": [
"Projects does not own Tasks, Tickets, Cases, source measurements, risks, controls, files, or external synchronization transport.",
"A linked object remains unavailable when its owner provider denies current access.",
],
"operational_consequences": {
"revise_plan": "Appends a new planning revision while preserving prior goals, status, and evidence links.",
"change_participation": "Changes project access only and does not grant access to linked provider-owned objects.",
"link_external_resource": "Stores a governed reference; synchronization remains a Connector responsibility.",
},
"verification": [
"The project revision names its portfolio, status, participants, milestones, and intended outcomes.",
"Every linked resource identifies its owner module or external provider and remains independently authorized.",
"Benefit and change-impact review preserves the revision and evidence references used for the decision.",
],
},
translations={
"de": {
"title": "Projekte planen und koordinieren",
"summary": (
"Portfolios, Projekte, Meilensteine, Beteiligte, Abhängigkeiten, Kapazitätsannahmen, "
"Ergebnisse und Nutzenprüfungen koordinieren, ohne die Eigentümerschaft an Arbeitselementen zu übernehmen."
),
"body": (
"Projects führt den nativen Portfolio- und Projektkontext, unveränderliche Revisionen von Zielen und "
"beabsichtigten Ergebnissen, Meilensteine, Beteiligte, Status, Abhängigkeiten, Kapazitätsannahmen, "
"Nutzenprüfungen und gesteuerte Ressourcenreferenzen. Planungskontext wird angelegt oder revidiert, "
"seine Auswirkung geprüft und anbietergeführte Arbeit und Nachweise werden verknüpft, ohne sie zu kopieren. "
"Tasks und Tickets behalten ausführbare Arbeit, Cases formelle Verfahren und Connectors den OpenProject-Transport. "
"Reporting führt gemessene Kennzahlen und Risk Compliance Risiken und Kontrollen; Projects verknüpft diese Fakten "
"mit Planung, Änderungsfolgen und Nutzenprüfung."
),
}
},
structured_translation_version="1",
structured_translations={
"de": {
"purpose": (
"Einen revisionierten Planungskontext pflegen und anbietergeführte Arbeit, Nachweise und Messwerte damit verknüpfen."
),
"prerequisites": [
"Die handelnde Person darf das Projekt lesen; Revisionen erfordern Projektschreibberechtigung.",
"Verknüpfte Arbeit, Verfahren, Dateien, Risiken, Berichte und externe Systeme bleiben durch ihre Eigentümeranbieter autorisiert.",
],
"steps": [
"Ein Portfolio auswählen oder Projektidentität, Status, Beteiligte und Planungshorizont anlegen.",
"Revisionierte Ziele, beabsichtigte Ergebnisse, Meilensteine, Abhängigkeiten und Kapazitätsannahmen erfassen.",
"Tasks, Tickets, Cases, Dateien, Risiken, Kontrollen, Berichte oder externe Projektreferenzen verknüpfen, ohne Eigentümerdaten zu kopieren.",
"Status, Änderungsfolgen, Meilensteinfortschritt und Nutzennachweise prüfen, bevor eine Revision angefügt wird.",
"Verknüpfungen zu Eigentümermodulen verwenden, um ausführbare Arbeit oder formelle Verfahren in deren führender Oberfläche zu verwalten.",
],
"fields": {
"portfolio": "Gruppiert Projekte für Planung und Aufsicht, ohne die Projektzuständigkeit zu verändern.",
"project": "Der native revisionierte Kontext für Ergebnis, Status, Beteiligung und Ressourcenverknüpfungen.",
"milestone": "Ein datierter Projektprüfpunkt, kein ausführbarer Task und kein formeller Case-Status.",
"participant": "Eine ausdrückliche Projektzugriffsfreigabe und Rolle, unabhängig von Eigentümerschaft in anderen Modulen.",
"external_reference": "Eine gesteuerte Verknüpfung zu einem anbietergeführten Projekt oder einer Ressource, einschließlich OpenProject-Zuordnungen.",
},
"limitations": [
"Projects führt weder Tasks, Tickets, Cases, Quellmesswerte, Risiken, Kontrollen, Dateien noch externen Synchronisationstransport.",
"Ein verknüpftes Objekt bleibt unverfügbar, wenn sein Eigentümeranbieter den aktuellen Zugriff verweigert.",
],
"operational_consequences": {
"revise_plan": "Fügt eine neue Planungsrevision an und bewahrt frühere Ziele, Status und Nachweisverknüpfungen.",
"change_participation": "Ändert nur den Projektzugriff und gewährt keinen Zugriff auf verknüpfte anbietergeführte Objekte.",
"link_external_resource": "Speichert eine gesteuerte Referenz; Synchronisation bleibt Aufgabe eines Connectors.",
},
"verification": [
"Die Projektrevision nennt Portfolio, Status, Beteiligte, Meilensteine und beabsichtigte Ergebnisse.",
"Jede verknüpfte Ressource nennt Eigentümermodul oder externen Anbieter und bleibt unabhängig autorisiert.",
"Nutzen- und Änderungsfolgenprüfung bewahrt die für die Entscheidung verwendete Revision und Nachweisreferenzen.",
],
}
},
),
)
@@ -434,6 +519,7 @@ manifest = ModuleManifest(
related_modules=("core", "access", "tasks", "audit"),
order=90,
metadata={
"kind": "reference",
"help_contexts": [
"projects.workspace",
"privacy.data-subject-requests",
@@ -444,6 +530,35 @@ manifest = ModuleManifest(
"retain_project_attribution": "Preserves immutable lifecycle accountability.",
},
},
translations={
"de": {
"title": "Datenschutzanfragen zu Projekten",
"summary": (
"Projektbeteiligung und verantwortbare Aktivitäten ohne Projektinhalte exportieren."
),
"body": (
"Projects gleicht exakte Konto- und Identitätsfreigaben sowie eine ausdrücklich angegebene "
"Funktionszuweisungsreferenz ab. Exakte Konto-, Identitäts- und Mitgliedschaftskennungen für "
"Anlage- und Lebenszykluszuschreibung werden getrennt ermittelt. Suchen können auf ein Projekt, "
"Portfolio oder einen Meilenstein eingegrenzt werden; eine Objektkennung allein begründet niemals "
"eine betroffene Person. Beteiligungsexporte enthalten Rolle, Berechtigungen, Aktivstatus und "
"Quellrevision. Titel, Suchtext, Planungs- und Ereignisinhalte, Anforderungsprüfsummen, "
"Idempotenzschlüssel und unbeteiligte Mitglieder bleiben ausgeschlossen. Die Entfernung einer "
"Beteiligung erfordert eine manuelle Prüfung von Zugriff und Eigentumsfortbestand; unveränderliche "
"Zuschreibungen zu Anlage, Revision und Ereignissen bleiben als Steuerungsnachweise erhalten."
),
}
},
structured_translation_version="1",
structured_translations={
"de": {
"consequence_classes": {
"export_project_membership": "Gibt exakte Betroffenenfreigaben ohne unbeteiligte Mitglieder zurück.",
"review_membership_removal": "Erfordert eine Prüfung von Eigentümerschaft und Zugriffskontinuität.",
"retain_project_attribution": "Bewahrt unveränderliche Lebenszyklusverantwortung auf.",
}
}
},
),
*DOCUMENTATION,
),
+31
View File
@@ -0,0 +1,31 @@
from __future__ import annotations
import unittest
from govoplan_core.core.modules import (
documentation_structured_translation_issues,
user_workflow_scope_condition_issues,
)
from govoplan_projects.backend.manifest import manifest
class ProjectsDocumentationTests(unittest.TestCase):
def test_public_topics_have_complete_german_reference_content(self) -> None:
self.assertEqual(2, len(manifest.documentation))
for topic in manifest.documentation:
translation = topic.translations.get("de", {})
self.assertTrue(
all(translation.get(key) for key in ("title", "summary", "body"))
)
self.assertEqual((), documentation_structured_translation_issues(topic))
def test_documentation_has_scope_conditioned_workflow_and_reference(self) -> None:
kinds = {topic.metadata.get("kind") for topic in manifest.documentation}
self.assertIn("workflow", kinds)
self.assertIn("reference", kinds)
for topic in manifest.documentation:
self.assertEqual((), user_workflow_scope_condition_issues(topic))
if __name__ == "__main__":
unittest.main()
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@govoplan/projects-webui",
"version": "0.1.18",
"version": "0.1.19",
"private": true,
"type": "module",
"main": "src/index.ts",
+5
View File
@@ -4,6 +4,11 @@
overflow: hidden;
}
.projects-page :where(button, input, select, textarea, a[href]):focus-visible {
outline: var(--focus-outline);
outline-offset: 2px;
}
.projects-search {
flex: 1 1 560px;
}