from __future__ import annotations from pathlib import Path from govoplan_core.core.access import ( CAPABILITY_AUTH_PERMISSION_EVALUATOR, CAPABILITY_AUTH_PRINCIPAL_RESOLVER, ) from govoplan_core.core.modules import ( CapabilityDocumentation, DocumentationCondition, DocumentationLink, DocumentationSourceDefinition, DocumentationTopic, FrontendModule, FrontendRoute, MigrationSpec, ModuleContext, ModuleManifest, ModuleInterfaceProvider, NavItem, PermissionDefinition, RoleTemplate, ) from govoplan_core.core.module_guards import ( drop_table_retirement_provider, persistent_table_uninstall_guard, ) from govoplan_core.core.provider_governance import ( ModuleArchitectureDeclaration, ModuleArchitectureDocumentation, ModuleMaturityEvidence, ) from govoplan_core.db.base import Base from govoplan_core.core.search import SearchSourceProviderRegistration from govoplan_docs.backend.db import models as docs_models from govoplan_docs.backend.dsar_provider import DOCS_DSAR_CAPABILITY, DocsDsarProvider from govoplan_docs.backend.search_source import ( create_semantic_documentation_search_source, ) DOCS_READ_SCOPE = "docs:documentation:read" DOCS_ADMIN_READ_SCOPE = "docs:documentation:admin" DOCS_SEMANTIC_CREATE_SCOPE = "docs:semantic:create" DOCS_SEMANTIC_EDIT_SCOPE = "docs:semantic:edit" DOCS_SEMANTIC_PUBLISH_SCOPE = "docs:semantic:publish" DOCS_SEMANTIC_SUPERSEDE_SCOPE = "docs:semantic:supersede" DOCS_SEMANTIC_RETIRE_SCOPE = "docs:semantic:retire" DOCS_SEMANTIC_EXPORT_SCOPE = "docs:semantic:export" DOCS_SEMANTIC_POLICY_SCOPE = "docs:semantic:policy" DOCS_ADMIN_READ_SCOPES = ( DOCS_ADMIN_READ_SCOPE, "system:settings:read", "admin:settings:read", ) DOCS_READ_SCOPES = (DOCS_READ_SCOPE, *DOCS_ADMIN_READ_SCOPES) ARCHITECTURE = ModuleArchitectureDeclaration( layer="governance_accountability", kind="presentation", maturity="vertical_slice", evidence=( ModuleMaturityEvidence( kind="test", reference="tests/test_docs_context.py", summary="Tests audience-safe configured documentation and architecture projections.", ), ModuleMaturityEvidence( kind="test", reference="tests/test_semantic_documentation.py", summary="Tests tenant isolation, immutable revision lifecycle, publication policy, subject reauthorization, search, localization, and DSAR projection.", ), ModuleMaturityEvidence( kind="documentation", reference="docs/DOCUMENTATION_LAYER_CONCEPT.md", summary="Defines the manifest-driven documentation boundary.", ), ModuleMaturityEvidence( kind="documentation", reference="docs/INTERFACE_PATTERN_MIGRATION.md", summary="Records the Core-owned Docs workspace and page-layout boundary.", ), ModuleMaturityEvidence( kind="documentation", reference="docs/SEMANTIC_DOCUMENTATION.md", summary="Defines semantic authoring, authorization, lifecycle, export, and recovery behavior.", ), ), known_limits=( "Architecture declarations are in staged adoption, so undeclared modules remain visible as pending.", ), owned_concepts=( "configured documentation projection", "documentation audience filtering", "tenant semantic documentation revisions", "semantic documentation publication lifecycle", ), non_owned_concepts=("module feature behavior", "module evidence generation"), documentation=ModuleArchitectureDocumentation( security=("docs/DOCUMENTATION_LAYER_CONCEPT.md",), operations=("docs/DOCUMENTATION_LAYER_CONCEPT.md",), ), ) def _permission(scope: str, label: str, description: str) -> PermissionDefinition: module_id, resource, action = scope.split(":", 2) return PermissionDefinition( scope=scope, label=label, description=description, category="Documentation", level="tenant", module_id=module_id, resource=resource, action=action, ) def _route_factory(context: ModuleContext): del context from govoplan_docs.backend.api.v1.routes import router return router def _dsar_provider(_context: ModuleContext) -> DocsDsarProvider: return DocsDsarProvider() manifest = ModuleManifest( id="docs", name="Docs", version="0.1.23", required_capabilities=( CAPABILITY_AUTH_PRINCIPAL_RESOLVER, CAPABILITY_AUTH_PERMISSION_EVALUATOR, ), provides_interfaces=( ModuleInterfaceProvider(name=DOCS_DSAR_CAPABILITY, version="0.1.0"), ), capability_factories={DOCS_DSAR_CAPABILITY: _dsar_provider}, capability_documentation={ DOCS_DSAR_CAPABILITY: CapabilityDocumentation( label="Docs data-subject request provider", summary=( "Exports minimized tenant semantic-documentation authorship, " "review, ownership, and stewardship references while retaining " "published configuration-governance evidence." ), contract_version="0.1.0", ), }, optional_dependencies=( "policy", "audit", "ops", "workflow", "forms", "search", ), permissions=( _permission( DOCS_READ_SCOPE, "View configured documentation", "Read user documentation generated for the current actor from installed modules and effective configuration.", ), _permission( DOCS_SEMANTIC_CREATE_SCOPE, "Create semantic documentation", "Create tenant-owned semantic documentation for configured subjects.", ), _permission( DOCS_SEMANTIC_EDIT_SCOPE, "Edit semantic documentation", "Edit drafts using immutable revisions and optimistic concurrency.", ), _permission( DOCS_SEMANTIC_PUBLISH_SCOPE, "Publish semantic documentation", "Review and publish semantic documentation under tenant policy.", ), _permission( DOCS_SEMANTIC_SUPERSEDE_SCOPE, "Supersede semantic documentation", "Replace semantic documentation with another published entry.", ), _permission( DOCS_SEMANTIC_RETIRE_SCOPE, "Retire semantic documentation", "Retire semantic documentation while retaining its revision history.", ), _permission( DOCS_SEMANTIC_EXPORT_SCOPE, "Export tenant semantic documentation", "Export tenant-owned semantic entries and immutable history.", ), _permission( DOCS_SEMANTIC_POLICY_SCOPE, "Configure semantic publication policy", "Choose direct publication or independent reviewer publication.", ), _permission( DOCS_ADMIN_READ_SCOPE, "View administrative documentation", "Read technical module, route, permission, configuration, and evidence documentation.", ), ), role_templates=( RoleTemplate( slug="docs_reader", name="Documentation reader", description="Read the configured-system documentation browser. This role is granted automatically to every authenticated tenant member while Docs is installed.", permissions=(DOCS_READ_SCOPE,), default_authenticated=True, ), RoleTemplate( slug="semantic_documentation_author", name="Semantic documentation author", description="Discover configured subjects and create or revise their semantic documentation.", permissions=( DOCS_READ_SCOPE, DOCS_SEMANTIC_CREATE_SCOPE, DOCS_SEMANTIC_EDIT_SCOPE, ), ), RoleTemplate( slug="semantic_documentation_reviewer", name="Semantic documentation reviewer", description="Review, publish, supersede, and retire semantic documentation.", permissions=( DOCS_READ_SCOPE, DOCS_SEMANTIC_PUBLISH_SCOPE, DOCS_SEMANTIC_SUPERSEDE_SCOPE, DOCS_SEMANTIC_RETIRE_SCOPE, ), ), RoleTemplate( slug="semantic_documentation_manager", name="Semantic documentation manager", description="Administer semantic authoring, review, lifecycle, policy, and tenant export.", permissions=( DOCS_READ_SCOPE, DOCS_ADMIN_READ_SCOPE, DOCS_SEMANTIC_CREATE_SCOPE, DOCS_SEMANTIC_EDIT_SCOPE, DOCS_SEMANTIC_PUBLISH_SCOPE, DOCS_SEMANTIC_SUPERSEDE_SCOPE, DOCS_SEMANTIC_RETIRE_SCOPE, DOCS_SEMANTIC_EXPORT_SCOPE, DOCS_SEMANTIC_POLICY_SCOPE, ), ), RoleTemplate( slug="docs_admin", name="Documentation administrator", description="Read user guidance and the technical configured-system documentation projection.", permissions=(DOCS_READ_SCOPE, DOCS_ADMIN_READ_SCOPE), ), ), route_factory=_route_factory, nav_items=( NavItem( path="/docs", label="Docs", icon="reports", required_any=DOCS_READ_SCOPES, order=880, ), ), frontend=FrontendModule( module_id="docs", package_name="@govoplan/docs-webui", routes=( FrontendRoute( path="/docs", component="DocsPage", required_any=DOCS_READ_SCOPES, order=880, ), FrontendRoute( path="/docs/semantic", component="SemanticDocumentationPage", required_any=( DOCS_SEMANTIC_CREATE_SCOPE, DOCS_SEMANTIC_EDIT_SCOPE, DOCS_SEMANTIC_PUBLISH_SCOPE, DOCS_SEMANTIC_SUPERSEDE_SCOPE, DOCS_SEMANTIC_RETIRE_SCOPE, ), order=881, ), ), nav_items=( NavItem( path="/docs", label="Docs", icon="reports", required_any=DOCS_READ_SCOPES, order=880, ), ), ), documentation=( DocumentationTopic( id="docs.workflow.find-help", title="Find help by area and keyword", summary="Search visible help topics and use area and keyword tags to narrow the results.", body=( "Enter words from your question in Search help topics. Titles, summaries, topic text, area names, and contributed tags are searched together. " "Areas and tags is a multi-selection dropdown: selected tags match any of those tags; Select all removes the restriction and Clear all selects no topics. " "Topics by area includes all visible guidance associated with an area, including guidance contributed by another module. " "A topic can appear in several branches; only the occurrence you select is highlighted, and expanding it does not expand its other occurrences. " "Search results show each topic once. Choosing a result clears the filters and opens the topic. Search and tags only narrow the documentation already authorized for your role. " "Administrators and module authors contribute public keywords in DocumentationTopic metadata.tags and optional module-area IDs in metadata.areas; the source module and authorized related_modules also supply area tags. " "Use stable module IDs for areas and readable keywords for tags; do not put credentials, private configuration, or hidden capability names in public search tags. " "User area facets omit related modules without a visible route; administrative documentation still requires its separate permission." ), layer="always", documentation_types=("admin", "user"), order=9, conditions=(DocumentationCondition(required_scopes=(DOCS_READ_SCOPE,)),), translations={ "de": { "title": "Hilfe nach Bereich und Stichwort finden", "summary": "Sichtbare Hilfethemen durchsuchen und Ergebnisse mit Bereichen und Schlagwörtern eingrenzen.", "body": ( "Geben Sie unter Hilfethemen suchen Wörter aus Ihrer Frage ein. Titel, Zusammenfassungen, Thementexte, Bereichsnamen und beigetragene Schlagwörter werden gemeinsam durchsucht. " "Bereiche und Schlagwörter ist eine Auswahlliste mit Mehrfachauswahl: Ein ausgewähltes Schlagwort genügt für einen Treffer. Alle auswählen entfernt die Einschränkung, Auswahl aufheben wählt keine Themen. " "Themen nach Bereich enthält sämtliche sichtbaren Hinweise eines Bereichs, auch Beiträge anderer Module. " "Ein Thema kann in mehreren Zweigen erscheinen; nur die angeklickte Stelle wird hervorgehoben, und das Aufklappen öffnet nicht zugleich die anderen Vorkommen. " "Suchergebnisse zeigen jedes Thema einmal. Die Auswahl eines Ergebnisses setzt die Filter zurück und öffnet das Thema. Suche und Schlagwörter grenzen ausschließlich die bereits für Ihre Rolle freigegebene Dokumentation ein. " "Administratoren und Modulautoren hinterlegen öffentliche Stichwörter in DocumentationTopic metadata.tags und optionale Modul-Bereichskennungen in metadata.areas; das Quellmodul und berechtigte related_modules liefern ebenfalls Bereichsschlagwörter. " "Verwenden Sie stabile Modulkennungen für Bereiche und lesbare Stichwörter für Schlagwörter. Zugangsdaten, private Konfiguration und Namen verborgener Fähigkeiten gehören nicht in öffentliche Suchschlagwörter. " "Bereichsfilter der Benutzerdokumentation zeigen keine zugeordneten Module ohne sichtbare Route. Administrative Dokumentation benötigt weiterhin ihre gesonderte Berechtigung." ), }, }, metadata={ "kind": "workflow", "tags": ["Help", "Hilfe", "Search", "Suche", "Tags", "Schlagwörter"], "help_contexts": ["docs.help-center.search"], }, ), DocumentationTopic( id="docs.semantic-documentation", title="Tenant semantic documentation", summary="Explain what configured forms, fields, workflows, steps, and other stable subjects mean in this tenant.", body=( "Authors select an authorized subject supplied by its owning module and create locale-specific plain-text guidance. " "Every save creates an immutable revision. Tenant policy chooses direct publication or an independent reviewer. " "Published content remains subject to the subject's current authorization, the documentation audience and classification, tenant isolation, and locale selection. " "Changed, missing, superseded, or temporarily unavailable subjects are shown explicitly; direct links, contextual help, search, caches, and tenant exports apply the same read-time authorization. " "Retirement and supersession preserve history. Generic public documentation exports never include tenant semantic entries; administrators use the separately authorized tenant export. " "Collection, configured-context, and search-authorization reads batch the required revisions in request-local groups of at most 400 identifiers instead of fetching revisions once per entry. Read-only views load published content, not pending draft bodies. Each revision must belong to the same tenant and entry, and a published pointer must reference a published revision; inconsistent references fail closed. Audience denial avoids unnecessary subject-provider work, while allowed results still require the owning subject's current authorization. No cross-request permission cache is introduced; complete tenant exports and full history remain separately authorized operations." ), layer="always", documentation_types=("admin", "user"), audience=("tenant_admin", "module_admin", "documentation_author"), order=11, conditions=( DocumentationCondition( any_scopes=( DOCS_SEMANTIC_CREATE_SCOPE, DOCS_SEMANTIC_EDIT_SCOPE, DOCS_SEMANTIC_PUBLISH_SCOPE, DOCS_SEMANTIC_POLICY_SCOPE, ), ), ), links=( DocumentationLink( label="Semantic documentation administration", href="/docs/semantic", kind="runtime", ), DocumentationLink( label="Semantic documentation operations", href="govoplan-docs/docs/SEMANTIC_DOCUMENTATION.md", kind="repository", ), ), translations={ "de": { "title": "Semantische Dokumentation des Mandanten", "summary": "Erläutern, was konfigurierte Formulare, Felder, Workflows, Schritte und andere stabile Fachobjekte in diesem Mandanten bedeuten.", "body": ( "Autorinnen und Autoren wählen ein berechtigtes Fachobjekt aus, das sein besitzendes Modul bereitstellt, " "und verfassen sprachspezifische Hinweise als Klartext. Jeder Speichervorgang erzeugt eine unveränderliche Revision. " "Die Mandantenrichtlinie legt direkte Veröffentlichung oder eine unabhängige Prüfung fest. Veröffentlichte Inhalte " "unterliegen weiterhin der aktuellen Berechtigung für das Fachobjekt, der Zielgruppe und Klassifizierung der Dokumentation, " "der Mandantentrennung und der Sprachauswahl. Geänderte, fehlende, abgelöste oder vorübergehend nicht verfügbare Fachobjekte " "werden ausdrücklich gekennzeichnet; Direktlinks, Kontexthilfe, Suche, Zwischenspeicher und Mandantenexporte wenden dieselbe " "Berechtigungsprüfung beim Lesen an. Stilllegung und Ablösung bewahren die Historie. Allgemeine öffentliche Dokumentationsexporte " "enthalten niemals semantische Mandanteneinträge; für diese steht der getrennt berechtigte Mandantenexport bereit. " "Listen, Konfigurationskontext und Suchberechtigungsprüfung laden benötigte Revisionen anfragebezogen in Gruppen von höchstens 400 Kennungen statt einzeln je Eintrag. " "Nur lesbare Ansichten laden veröffentlichte Inhalte und keine offenen Entwurfstexte. Jede Revision muss zum selben Mandanten und Eintrag gehören; " "ein Veröffentlichungsverweis muss auf eine veröffentlichte Revision zeigen. Widersprüchliche Verweise werden abgewiesen. " "Bei einer nicht berechtigten Zielgruppe entfällt unnötige Arbeit des Fachobjekt-Providers; zulässige Ergebnisse erfordern weiterhin dessen aktuelle Berechtigungsprüfung. " "Es entsteht kein anfrageübergreifender Berechtigungszwischenspeicher. Vollständiger Mandantenexport und Historie bleiben getrennt berechtigte Vorgänge." ), } }, metadata={ "kind": "workflow", "help_contexts": ["docs.semantic-documentation.publish"], }, ), DocumentationTopic( id="docs.data-subject-requests", title="Review Docs semantic attribution in a data-subject request", summary="Export minimized author, reviewer, owner, and steward references without disclosing unrelated tenant-authored guidance.", body=( "Docs matches exact account and namespaced semantic-entry references within the active tenant. " "The projection identifies the entry, revision, subject, locale, lifecycle state, and fields that matched, but excludes authored body content. " "Published, superseded, and retired attribution is immutable configuration-governance evidence and is retained with a reason. " "Draft attribution requires manual governance review so ownership or stewardship can be reassigned before any anonymization; Docs performs no automatic erasure." ), layer="configured", documentation_types=("admin",), audience=("privacy_officer", "documentation_administrator", "operator"), order=12, conditions=( DocumentationCondition( required_modules=("docs", "access"), any_scopes=( "access:privacy:read", "access:privacy:manage", "access:privacy:erase", ), ), ), links=( DocumentationLink( label="Data-subject requests", href="/admin?section=tenant-data-subject-requests", kind="runtime", ), DocumentationLink( label="Semantic documentation operations", href="govoplan-docs/docs/SEMANTIC_DOCUMENTATION.md", kind="repository", ), ), related_modules=("access", "audit", "policy"), translations={ "de": { "title": "Semantische Docs-Zuordnungen in einer Betroffenenanfrage prüfen", "summary": "Minimierte Verweise auf Autorenschaft, Prüfung, Eigentümerschaft und fachliche Zuständigkeit exportieren, ohne unbeteiligte mandanteneigene Hinweise offenzulegen.", "body": ( "Docs gleicht exakte Konto- und namensraumgebundene Verweise auf semantische Einträge innerhalb des aktiven Mandanten ab. " "Die Projektion nennt Eintrag, Revision, Fachobjekt, Sprache, Lebenszyklusstatus und die übereinstimmenden Felder, schließt den " "verfassten Inhalt jedoch aus. Zuordnungen veröffentlichter, abgelöster und stillgelegter Inhalte sind unveränderliche Nachweise " "der Konfigurationssteuerung und werden mit Begründung aufbewahrt. Zuordnungen aus Entwürfen erfordern eine manuelle fachliche " "Prüfung, damit Eigentümerschaft oder Zuständigkeit vor einer möglichen Anonymisierung neu zugewiesen werden können; Docs führt " "keine automatische Löschung aus." ), } }, metadata={ "kind": "workflow", "route": "/admin?section=tenant-data-subject-requests", "help_contexts": ["admin.privacy.data-subject-requests"], }, ), DocumentationTopic( id="docs.configured-system-documentation", title="Configured system documentation", summary="This documentation page starts with installed modules, active configuration, visible routes, and permissions for the current actor.", body="Module manifests can contribute durable documentation topics. Modules can also register runtime documentation providers when content depends on tenant policy, installed integrations, or operational settings.", layer="always", documentation_types=("admin", "user"), audience=("tenant_admin", "operator", "module_admin"), order=10, i18n_key="docs.topic.configured_system_documentation", translations={ "de": { "title": "Dokumentation dieses Systems", "summary": "Diese Dokumentation beginnt mit den installierten Modulen, der aktiven Konfiguration und den Funktionen, die für diese Rolle sichtbar sind.", "body": "Module können feste Dokumentationsabschnitte beitragen. Wenn Inhalte von Mandantenregeln, installierten Integrationen oder Betriebsoptionen abhängen, kann ein Modul laufzeitbasierte Dokumentation registrieren.", }, }, links=( DocumentationLink( label="Public GovOPlaN documentation", href="https://govoplan.add-ideas.de/docs", kind="public", ), DocumentationLink( label="Documentation layer concept", href="govoplan-docs/docs/DOCUMENTATION_LAYER_CONCEPT.md", kind="repository", ), DocumentationLink( label="Instance-aware documentation contract", href="govoplan-docs/docs/INSTANCE_AWARE_DOCUMENTATION.md", kind="repository", ), ), metadata={"kind": "system"}, ), DocumentationTopic( id="docs.public-manifest-export", title="Public documentation from module manifests", summary="Publish the static documentation baseline from every module without maintaining a second content source.", body=( "The public exporter reads DocumentationTopic contributions from all installed packages or sibling module checkouts, " "projects German and English content, and records documentation coverage. Runtime providers remain in the authenticated " "Docs surface because their output can depend on the current actor, policy, configuration, and live service state. " "Rendered steps, fields, limitations, consequences, and verification use Core's versioned same-shape structured-translation contract. " "Publication CI runs both the source-digest check and a reviewed monotonic coverage baseline, so regenerating the catalog cannot conceal a regression." ), layer="always", documentation_types=("admin", "user"), audience=("user", "tenant_admin", "operator", "module_admin", "publisher"), order=12, translations={ "de": { "title": "Öffentliche Dokumentation aus Modulmanifesten", "summary": "Die statische Dokumentationsbasis aller Module veröffentlichen, ohne eine zweite Inhaltsquelle zu pflegen.", "body": ( "Der öffentliche Export liest die DocumentationTopic-Beiträge aus allen installierten Paketen oder benachbarten Modulquellen, " "projiziert deutsche und englische Inhalte und weist Dokumentationslücken aus. Laufzeit-Provider verbleiben in der authentifizierten " "Dokumentationsoberfläche, da ihre Ausgabe von Rolle, Richtlinie, Konfiguration und Dienstzustand abhängen kann. " "Gerenderte Schritte, Felder, Einschränkungen, Folgen und Prüfhinweise verwenden den versionierten, formgleichen Vertrag für strukturierte Übersetzungen in Core. " "Die Veröffentlichungs-CI prüft sowohl den Quelldigest als auch einen freigegebenen monotonen Abdeckungsstand, damit das Neuerzeugen des Katalogs keine Verschlechterung verdecken kann." ), } }, links=( DocumentationLink( label="Public documentation", href="https://govoplan.add-ideas.de/docs", kind="public", ), ), metadata={"kind": "system"}, ), DocumentationTopic( id="docs.reference.institutional-governance-architecture", title="Institutional governance architecture", summary="GovOPlaN models institutional responsibility, governed work, formal outcomes, evidence, and external-system authority without turning every concept into Core or one monolithic application.", body=( "Organizations, Identity, IDM, Access, and Policy answer different parts of who may act. " "Mandate, service, procedure-party, and formal-decision semantics are being introduced as shared contracts and become modules only after independent lifecycle and reuse are proven. " "External integrations separately declare technical maturity and whether GovOPlaN is authoritative, mirrors an external source, synchronizes under governance, adds an overlay, or retains only a link." ), layer="always", documentation_types=("admin",), audience=("tenant_admin", "operator", "module_admin", "product_owner"), order=15, translations={ "de": { "title": "Architektur der institutionellen Steuerung", "summary": "GovOPlaN modelliert institutionelle Verantwortung, gesteuerte Arbeit, formale Ergebnisse, Nachweise und die Datenhoheit externer Systeme, ohne alle Begriffe in den Kern oder eine monolithische Anwendung zu ziehen.", "body": "Organisationen, Identitäten, IDM, Zugriff und Richtlinien beantworten unterschiedliche Teile der Frage, wer handeln darf. Mandate, Leistungen, Verfahrensbeteiligte und formale Entscheidungen beginnen als gemeinsame Verträge und werden erst bei nachgewiesenem eigenständigem Lebenszyklus zu Modulen. Integrationen erklären technische Reife und Datenhoheit getrennt.", }, }, links=( DocumentationLink( label="Institutional governance target architecture", href="govoplan/docs/architecture/INSTITUTIONAL_GOVERNANCE_TARGET_ARCHITECTURE.md", kind="repository", ), DocumentationLink( label="Core module architecture", href="govoplan-core/docs/MODULE_ARCHITECTURE.md", kind="repository", ), ), metadata={ "kind": "reference", "architecture_topics": [ "institutional context", "module ownership", "source authority", "integration maturity", "product packages", ], }, ), DocumentationTopic( id="docs.pattern.field-help", title="Field help marker", summary="A small help marker next to a label gives local context without turning dense forms into manuals.", body="Use the marker for short explanations of a field, option, or compact term. Link to a workflow or reference topic when the reader needs steps, API mapping, policy provenance, or operational detail.", layer="always", documentation_types=("admin", "user"), audience=("user", "tenant_admin", "operator", "module_admin"), order=20, i18n_key="docs.topic.pattern.field_help", translations={ "de": { "title": "Hinweis am Feld", "summary": "Eine kleine Hilfemarkierung neben einer Beschriftung gibt lokalen Kontext, ohne dichte Formulare in Handbücher zu verwandeln.", "body": ( "Verwenden Sie die Markierung für kurze Erläuterungen zu einem Feld, einer Option oder einem kompakten Begriff. " "Verweisen Sie auf ein Ablauf- oder Referenzthema, wenn Schritte, API-Zuordnung, Richtlinienherkunft oder betriebliche " "Einzelheiten benötigt werden." ), } }, links=( DocumentationLink( label="Documentation experience concept", href="govoplan-docs/docs/DOCUMENTATION_EXPERIENCE_CONCEPT.md", kind="repository", ), ), metadata={ "kind": "pattern", "pattern_id": "field-help-marker", "purpose": "Keep labels scannable while making short explanations available on demand.", "when_used": "Form labels, toggle labels, effective-value rows, and compact admin terms.", "user_explanation": "Open the marker when a label is unclear. It should explain the local choice in one or two sentences.", "admin_explanation": "Field help stays local. Longer procedural, API, or policy explanations belong in linked workflow or reference topics.", "component_refs": [ "govoplan-core/webui/src/components/help/FieldLabel.tsx", "govoplan-core/webui/src/components/help/InlineHelp.tsx", "govoplan-core/webui/src/utils/fieldHelp.ts", ], "related_topic_ids": [ "access.reference.admin-access-fields", "access.workflow.grant-user-access", ], }, structured_translation_version="1", structured_translations={ "de": { "purpose": ( "Beschriftungen bleiben schnell erfassbar, während kurze Erläuterungen bei Bedarf verfügbar sind." ), "when_used": ( "Formular- und Umschalterbeschriftungen, Zeilen mit wirksamen Werten und kompakte Verwaltungsbegriffe." ), "user_explanation": ( "Öffnen Sie die Markierung, wenn eine Beschriftung unklar ist. Sie erläutert die lokale Auswahl in ein oder zwei Sätzen." ), "admin_explanation": ( "Feldhilfe bleibt am Feld. Längere Verfahrens-, API- oder Richtlinienerläuterungen gehören in verknüpfte Ablauf- oder Referenzthemen." ), } }, ), DocumentationTopic( id="docs.pattern.contextual-help", title="Context-sensitive help", summary="Press F1 on a page, field, action, or dialog to open help for the current interface context.", body=( "GovOPlaN first resolves help for the focused field or action, then its dialog or section, " "the current page, and the owning module. Exact documentation is shown when available; " "otherwise the page or module documentation is used. The titlebar help button opens the " "current page context. Documentation remains filtered by the current account's audience, " "permissions, and configured modules." ), layer="always", documentation_types=("admin", "user"), audience=("user", "tenant_admin", "operator", "module_admin"), order=21, i18n_key="docs.topic.pattern.contextual_help", translations={ "de": { "title": "Kontextsensitive Hilfe", "summary": "Mit F1 Hilfe zum aktuellen Seiten-, Feld-, Aktions- oder Dialogkontext öffnen.", "body": ( "GovOPlaN löst Hilfe zuerst für das fokussierte Feld oder die fokussierte Aktion auf, danach für den Dialog oder Abschnitt, " "die aktuelle Seite und schließlich das besitzende Modul. Ist eine genaue Dokumentation vorhanden, wird sie angezeigt; andernfalls " "dient die Seiten- oder Moduldokumentation als Rückfall. Die Hilfe-Schaltfläche in der Titelleiste öffnet den aktuellen Seitenkontext. " "Die Dokumentation bleibt nach Zielgruppe, Berechtigungen und konfigurierten Modulen des aktuellen Kontos gefiltert." ), } }, links=( DocumentationLink( label="Contextual help contract", href="govoplan-core/docs/CONTEXTUAL_HELP_CONTRACT.md", kind="repository", ), ), metadata={ "kind": "pattern", "pattern_id": "contextual-f1-help", "help_contexts": [ "core.contextual-help", "core.titlebar.language", ], "component_refs": [ "govoplan-core/webui/src/layout/HelpMenu.tsx", "govoplan-core/webui/src/utils/helpContext.ts", ], }, ), DocumentationTopic( id="docs.reference.temporal-data-context", title="Temporal data context", summary="Choose whether pages show currently valid records, records valid at a selected time, or all valid-time states.", body=( "The titlebar calendar controls valid time across participating modules. Current is the neutral " "default. At time selects records valid at the chosen instant, while All includes historical and " "future valid-time states. Recorded time remains separate: it describes when the platform learned " "or stored a fact. Permissions are evaluated now, so temporal selection never restores historical access." ), layer="always", documentation_types=("admin", "user"), audience=("user", "tenant_admin", "operator", "module_admin"), order=22, i18n_key="docs.topic.reference.temporal_data_context", translations={ "de": { "title": "Zeitlicher Datenkontext", "summary": "Festlegen, ob Seiten aktuell gültige Datensätze, zu einem gewählten Zeitpunkt gültige Datensätze oder alle Gültigkeitszustände zeigen.", "body": ( "Die Kalendersteuerung in der Titelleiste setzt die Gültigkeitszeit für beteiligte Module. Aktuell ist die neutrale " "Voreinstellung. Zeitpunkt zeigt Datensätze, die zum gewählten Moment gültig sind; Alle umfasst historische und zukünftige " "Gültigkeitszustände. Die Aufzeichnungszeit bleibt davon getrennt und beschreibt, wann die Plattform eine Tatsache erfahren " "oder gespeichert hat. Berechtigungen werden stets gegenwärtig ausgewertet; eine Zeitauswahl stellt daher niemals frühere " "Zugriffsrechte wieder her." ), } }, links=( DocumentationLink( label="Temporal data read contract", href="govoplan-core/docs/TEMPORAL_DATA_CONTEXT.md", kind="repository", ), ), metadata={ "kind": "reference", "help_contexts": ["core.temporal-data-context"], }, ), DocumentationTopic( id="docs.reference.organization-identity-idm-access-boundary", title="Organization, identity, IDM, and access boundary", summary="Organizations defines structures and functions. Identity defines people and accounts. IDM links identities to functions. Access turns accepted facts into roles and rights.", body=( "Use Organizations to model units, structures, relations, and function definitions. " "Use Identity to maintain normalized identities and account links. " "Use IDM to link an identity or account to a function in an organization unit, including delegated or acting-for cases. " "Use Access to map accepted function facts to roles and permissions. " "This split keeps organization modeling separate from identity lifecycle and keeps authorization decisions explicit." ), layer="configured", documentation_types=("admin", "user"), audience=("tenant_admin", "access_admin", "operator", "user"), related_modules=("organizations", "identity", "idm", "access"), order=23, conditions=( DocumentationCondition( required_modules=("organizations", "identity", "idm", "access"), ), ), translations={ "de": { "title": "Abgrenzung von Organisationen, Identität, IDM und Zugriff", "summary": "Organizations definiert Strukturen und Funktionen, Identity Personen und Konten, IDM die Zuordnung von Identitäten zu Funktionen und Access die daraus entstehenden Rollen und Rechte.", "body": ( "Verwenden Sie Organizations für Einheitstypen, Strukturen, Beziehungen, Organisationseinheiten und Funktionsdefinitionen. " "Identity verwaltet normalisierte Identitäten und Kontoverknüpfungen. IDM ordnet eine Identität oder ein Konto einer Funktion " "in einer Organisationseinheit zu und bildet dabei auch Delegation oder Handeln für andere ab. Access überführt anerkannte " "Funktionsmerkmale in Rollen und Berechtigungen. Diese Aufteilung trennt das Organisationsmodell vom Identitätslebenszyklus " "und hält Autorisierungsentscheidungen ausdrücklich nachvollziehbar." ), } }, links=( DocumentationLink( label="Organizations", href="/organizations", kind="runtime" ), DocumentationLink(label="IDM assignments", href="/idm", kind="runtime"), DocumentationLink( label="Access administration", href="/admin", kind="runtime" ), ), metadata={ "kind": "reference", "admin_explanation": "Function-to-role effects are owned by Access. IDM assignment changes can be governed independently from organization model changes.", "user_explanation": "A person can hold a function because IDM links their identity to the organization function. Access decides which application permissions that function gives.", "module_boundaries": [ { "module": "organizations", "owns": "unit types, structures, relations, units, and function definitions", }, {"module": "identity", "owns": "identities and account links"}, { "module": "idm", "owns": "identity-to-function assignments, delegation, acting-for links, and synchronization mapping", }, { "module": "access", "owns": "roles, permissions, and accepted function-to-role mappings", }, ], }, structured_translation_version="1", structured_translations={ "de": { "admin_explanation": ( "Auswirkungen von Funktionen auf Rollen gehören Access. Änderungen an IDM-Zuordnungen können unabhängig von Änderungen am Organisationsmodell gesteuert werden." ), "user_explanation": ( "Eine Person kann eine Funktion innehaben, weil IDM ihre Identität mit der Organisationsfunktion verknüpft. Access entscheidet, welche Anwendungsberechtigungen diese Funktion gewährt." ), } }, ), ), documentation_sources=( DocumentationSourceDefinition( id="docs.project.wiki", kind="wiki", label="GovOPlaN Docs wiki", provenance={"source": "gitea_wiki"}, link=DocumentationLink( label="GovOPlaN Docs wiki", href="https://git.add-ideas.de/GovOPlaN/govoplan-docs/wiki", kind="wiki", ), inspection={ "href": "https://git.add-ideas.de/GovOPlaN/govoplan-docs/wiki", }, ), ), migration_spec=MigrationSpec( module_id="docs", metadata=Base.metadata, script_location=str(Path(__file__).with_name("migrations") / "versions"), retirement_supported=True, retirement_provider=drop_table_retirement_provider( docs_models.SemanticDocumentationRevision, docs_models.SemanticDocumentationEntry, label="Docs semantic documentation", ), retirement_notes=( "Destructive retirement removes tenant semantic entries and immutable " "revision history after the installer captures a database snapshot." ), ), uninstall_guard_providers=( persistent_table_uninstall_guard( docs_models.SemanticDocumentationEntry, docs_models.SemanticDocumentationRevision, label="Docs semantic documentation", ), ), search_sources=( SearchSourceProviderRegistration( id="docs.semantic_documentation", factory=create_semantic_documentation_search_source, ), ), architecture=ARCHITECTURE, ) def get_manifest() -> ModuleManifest: return manifest