Sync Repo-docs-MODULE-ARCHITECTURE from project files
+538
-34
@@ -1,4 +1,4 @@
|
|||||||
<!-- codex-wiki-sync:ef8e3029a6f4d806786e3d2a -->
|
<!-- codex-wiki-sync:cfc41e352b119bd8d96e1266 -->
|
||||||
|
|
||||||
> Mirrored from `/mnt/DATA/git/govoplan-core/docs/MODULE_ARCHITECTURE.md`.
|
> Mirrored from `/mnt/DATA/git/govoplan-core/docs/MODULE_ARCHITECTURE.md`.
|
||||||
> Origin: `repository`.
|
> Origin: `repository`.
|
||||||
@@ -20,6 +20,10 @@ Policy decision, source provenance, and explain-response contracts are tracked
|
|||||||
in [`POLICY_CONTRACTS.md`](POLICY_CONTRACTS.md).
|
in [`POLICY_CONTRACTS.md`](POLICY_CONTRACTS.md).
|
||||||
The experimental remote WebUI bundle loading design is tracked in
|
The experimental remote WebUI bundle loading design is tracked in
|
||||||
[`REMOTE_WEBUI_BUNDLES.md`](REMOTE_WEBUI_BUNDLES.md).
|
[`REMOTE_WEBUI_BUNDLES.md`](REMOTE_WEBUI_BUNDLES.md).
|
||||||
|
The cross-product semantic layers, source-authority modes, and candidate
|
||||||
|
Mandates, Services, Parties, and Decisions boundaries are canonical in the
|
||||||
|
meta repository's
|
||||||
|
[`INSTITUTIONAL_GOVERNANCE_TARGET_ARCHITECTURE.md`](../../govoplan/docs/INSTITUTIONAL_GOVERNANCE_TARGET_ARCHITECTURE.md).
|
||||||
|
|
||||||
## Layer Model
|
## Layer Model
|
||||||
|
|
||||||
@@ -31,6 +35,36 @@ The experimental remote WebUI bundle loading design is tracked in
|
|||||||
| Business modules | Public-sector workflows | campaigns, cases, forms, approvals, appointments |
|
| Business modules | Public-sector workflows | campaigns, cases, forms, approvals, appointments |
|
||||||
| Connector modules | External system integration | FIT-Connect, XÖV/XTA, DMS/eAkte, ERP, IDM |
|
| Connector modules | External system integration | FIT-Connect, XÖV/XTA, DMS/eAkte, ERP, IDM |
|
||||||
|
|
||||||
|
This table is the technical composition model. The product portfolio uses a
|
||||||
|
more detailed institutional layer model, but it does not change dependency
|
||||||
|
direction: Core provides contracts and composition; modules own semantics;
|
||||||
|
packages compose modules.
|
||||||
|
|
||||||
|
## Institutional Semantic Boundaries
|
||||||
|
|
||||||
|
Cross-module references must keep these answers distinct:
|
||||||
|
|
||||||
|
- Organizations owns where structures, units, and functions exist.
|
||||||
|
- Identity owns who a subject is; Access owns accounts, roles, permissions,
|
||||||
|
and authorization decisions; IDM owns effective function assignments.
|
||||||
|
- A Mandates capability will answer why a unit or function is competent for a
|
||||||
|
task, jurisdiction, subject, or period. It must not become another RBAC
|
||||||
|
system.
|
||||||
|
- A Services capability will own versioned institutional service definitions;
|
||||||
|
Portal presents and starts them.
|
||||||
|
- A Parties capability will own procedure-local participant roles,
|
||||||
|
representation, and delivery authority; it must reference rather than copy
|
||||||
|
Identity, Organizations, and Addresses subjects.
|
||||||
|
- A Decisions capability will own formal institutional outcomes and their
|
||||||
|
authority, facts, rules, reasoning, effects, correction, and review.
|
||||||
|
Approvals owns review gates, Committee owns deliberation/votes, and Workflow
|
||||||
|
Engine owns coordination.
|
||||||
|
|
||||||
|
Start each missing concept as a versioned DTO/provider contract used by a
|
||||||
|
bounded journey. A repository is justified only when the concept gains
|
||||||
|
independent persistence, lifecycle, security/operations behavior, release
|
||||||
|
reason, and reuse. Core must not store these domain objects.
|
||||||
|
|
||||||
## Kernel Responsibilities
|
## Kernel Responsibilities
|
||||||
|
|
||||||
The kernel target owns:
|
The kernel target owns:
|
||||||
@@ -54,8 +88,8 @@ helpers, and secret helpers. The extracted access implementation lives in
|
|||||||
`govoplan-access`; live ORM table definitions have been split across their
|
`govoplan-access`; live ORM table definitions have been split across their
|
||||||
platform owners using module-prefixed table names. The old core route,
|
platform owners using module-prefixed table names. The old core route,
|
||||||
admin-service, and access-security re-export modules have been removed.
|
admin-service, and access-security re-export modules have been removed.
|
||||||
Callers must use module-owned imports, the public `govoplan_access.auth` request
|
Callers must use module-owned imports, the public `govoplan_core.auth` request
|
||||||
dependency API, or kernel capabilities.
|
dependency facade, or kernel capabilities.
|
||||||
The remaining platform compatibility surfaces are temporary until the matching
|
The remaining platform compatibility surfaces are temporary until the matching
|
||||||
platform modules are fully self-contained:
|
platform modules are fully self-contained:
|
||||||
|
|
||||||
@@ -81,32 +115,76 @@ The compatibility/deprecation plan for the current split line is:
|
|||||||
- reject new cross-module imports that bypass manifests, capabilities, events,
|
- reject new cross-module imports that bypass manifests, capabilities, events,
|
||||||
or public module APIs
|
or public module APIs
|
||||||
|
|
||||||
|
The retention windows and removal checklist for database bridges,
|
||||||
|
configuration/export schemas, and runtime/API aliases are defined in
|
||||||
|
`COMPATIBILITY_POLICY.md`.
|
||||||
|
|
||||||
## Stable Kernel Contracts
|
## Stable Kernel Contracts
|
||||||
|
|
||||||
The following contracts are the baseline API that modules can rely on:
|
The following contracts are the baseline API that modules can rely on:
|
||||||
|
|
||||||
- `ModuleManifest`
|
- `ModuleManifest`
|
||||||
- `ModuleCompatibility`
|
- `ModuleCompatibility`
|
||||||
|
- named interface contract provider/requirement metadata
|
||||||
- module uninstall guard provider contract
|
- module uninstall guard provider contract
|
||||||
- `MigrationSpec`
|
- `MigrationSpec`
|
||||||
- route factory contract
|
- route factory contract
|
||||||
- capability factory contract
|
- capability factory contract
|
||||||
- access DTO/protocol contracts in `govoplan_core.core.access`
|
- access DTO/protocol contracts in `govoplan_core.core.access`
|
||||||
- resource ACL provider contract
|
- resource ACL provider contract
|
||||||
- tenant summary provider contract
|
- bounded reference-option search provider contract
|
||||||
|
- single-tenant and optional batched tenant summary provider contracts
|
||||||
- tenant delete-veto provider contract
|
- tenant delete-veto provider contract
|
||||||
- WebUI module contribution contract
|
- WebUI module contribution contract
|
||||||
- navigation metadata contract
|
- navigation metadata contract
|
||||||
- command/event envelope contract
|
- command/event envelope contract
|
||||||
- policy decision and source provenance contract in `govoplan_core.core.policy`
|
- policy decision and source provenance contract in `govoplan_core.core.policy`
|
||||||
|
- external object reference and integration-maturity contract in
|
||||||
|
`govoplan_core.core.external_references`
|
||||||
|
- action/effect preview and execution contract in
|
||||||
|
`govoplan_core.core.automation`
|
||||||
|
- workflow definition contribution and runtime-worker contracts
|
||||||
|
|
||||||
Changes to these contracts must be versioned or accompanied by compatibility shims.
|
Changes to these contracts must be versioned or accompanied by compatibility shims.
|
||||||
|
|
||||||
|
Tenant list pages prefer `tenant_summary_batch_providers`. A batch provider
|
||||||
|
receives the unique tenant IDs on the current page and returns count mappings
|
||||||
|
keyed by tenant ID. Missing tenant keys mean that the provider has no counts for
|
||||||
|
that tenant; provider errors remain visible. Modules that expose only the
|
||||||
|
single-tenant contract remain compatible through a per-tenant fallback.
|
||||||
|
Destructive tenant lifecycle planning deliberately continues to use the
|
||||||
|
single-tenant path so it invokes every registered provider for the target
|
||||||
|
tenant, independent of ordinary list-page projections.
|
||||||
|
|
||||||
This list is the Milestone A kernel-contract freeze baseline. New module work
|
This list is the Milestone A kernel-contract freeze baseline. New module work
|
||||||
may extend the kernel by adding explicit contracts, but existing contracts must
|
may extend the kernel by adding explicit contracts, but existing contracts must
|
||||||
remain source-compatible through the 0.1.x split line unless a migration shim
|
remain source-compatible through the 0.1.x split line unless a migration shim
|
||||||
and deprecation note are provided.
|
and deprecation note are provided.
|
||||||
|
|
||||||
|
### Architecture Metadata
|
||||||
|
|
||||||
|
`ModuleManifest.architecture` is the backward-compatible, versioned product-
|
||||||
|
portfolio declaration for:
|
||||||
|
|
||||||
|
- module kind and institutional architecture layer;
|
||||||
|
- evidence-backed maturity claim (`concept`, `scaffold`, `vertical_slice`,
|
||||||
|
`reference_ready`, `supported`, or `lts`);
|
||||||
|
- owned and explicitly non-owned concepts;
|
||||||
|
- supported source-authority modes;
|
||||||
|
- reference packages, tested providers, and known limits;
|
||||||
|
- migration, upgrade, recovery, security, operations, and documentation
|
||||||
|
evidence references.
|
||||||
|
|
||||||
|
Core validates the claim and all provider references during registry startup.
|
||||||
|
`reference_ready`, `supported`, and `lts` claims require a named reference
|
||||||
|
package and the cumulative evidence set; target-tested providers additionally
|
||||||
|
require provider evidence. A supported module with migrations must include
|
||||||
|
migration evidence. Signed release catalogs retain and revalidate the
|
||||||
|
declaration. The meta manifest check validates repository evidence paths and
|
||||||
|
provides an opt-in `--require-architecture` rollout gate. Platform metadata,
|
||||||
|
Docs, and Ops project the same declaration. A module cannot make itself
|
||||||
|
supported solely by changing its maturity string.
|
||||||
|
|
||||||
Known access-related capability names are defined in
|
Known access-related capability names are defined in
|
||||||
`govoplan_core.core.access`, including:
|
`govoplan_core.core.access`, including:
|
||||||
|
|
||||||
@@ -121,25 +199,139 @@ Known access-related capability names are defined in
|
|||||||
- `security.secretProvider`
|
- `security.secretProvider`
|
||||||
- `audit.sink`
|
- `audit.sink`
|
||||||
|
|
||||||
`govoplan-access` currently registers `access.principalResolver`,
|
`govoplan-access` currently registers `auth.principalResolver`,
|
||||||
|
`auth.permissionEvaluator`, `access.principalResolver`,
|
||||||
`access.permissionEvaluator`, `access.directory`, `access.tenantProvisioner`,
|
`access.permissionEvaluator`, `access.directory`, `access.tenantProvisioner`,
|
||||||
`access.administration`, and `access.governanceMaterializer`.
|
`access.administration`, and `access.governanceMaterializer`.
|
||||||
`govoplan-tenancy` registers `tenancy.tenantResolver`. The minimal
|
`govoplan-tenancy` registers `tenancy.tenantResolver`. The minimal
|
||||||
authenticated platform set is now `tenancy` plus `access`; the registry
|
authenticated platform set is now `access`; tenancy is optional and adds tenant
|
||||||
inserts `tenancy` before `access` when only feature modules are requested.
|
administration plus tenant resolver behavior when installed.
|
||||||
Feature modules should prefer these capabilities over direct reads of
|
Feature modules should prefer these capabilities over direct reads of
|
||||||
access/tenant ORM models when they need labels, group membership, default
|
access/tenant ORM models when they need labels, group membership, default
|
||||||
access provisioning, counts, audit actor labels, or tenant metadata.
|
access provisioning, counts, audit actor labels, or tenant metadata.
|
||||||
|
|
||||||
FastAPI route dependencies for authenticated endpoints are access-owned and
|
Other stable runtime capabilities currently include:
|
||||||
published from `govoplan_access.auth`. Routers may import that public API for
|
|
||||||
|
- `identity.directory` and `identity.search`
|
||||||
|
- `organizations.directory`
|
||||||
|
- `idm.directory`
|
||||||
|
- `calendar.outbox` and `calendar.scheduling`
|
||||||
|
- `poll.scheduling`
|
||||||
|
- `notifications.dispatch`
|
||||||
|
- `workflow.definitionContributions` and `workflow.runtimeWorker`
|
||||||
|
|
||||||
|
Modules contribute reusable process baselines through
|
||||||
|
`ModuleManifest.workflow_definitions`. Each contribution pins its origin module
|
||||||
|
and version, stable key, schema and content hash, native graph/BPMN content,
|
||||||
|
governance ceilings, execution mode, and required capabilities/interfaces.
|
||||||
|
`govoplan-workflow-engine` reconciles these declarations idempotently. A module
|
||||||
|
upgrade appends a baseline revision without replacing the active revision or
|
||||||
|
mutating a local override; the optional `govoplan-workflow` package supplies
|
||||||
|
the comparison, derivation, and reset UI.
|
||||||
|
|
||||||
|
### Named Interface Contracts
|
||||||
|
|
||||||
|
Capabilities are runtime objects. Named interface contracts are compatibility
|
||||||
|
metadata. A module uses them when it depends on a versioned cross-module API
|
||||||
|
shape but should not hard-code a package or repository release line.
|
||||||
|
|
||||||
|
Manifest fields:
|
||||||
|
|
||||||
|
- `provides_interfaces`: contracts this module provides, each with `name` and
|
||||||
|
`version`
|
||||||
|
- `requires_interfaces`: contracts this module needs, each with `name`,
|
||||||
|
optional `version_min`, optional `version_max_exclusive`, and optional
|
||||||
|
`optional: true`
|
||||||
|
|
||||||
|
Interface names use dot-separated lower-case identifiers such as
|
||||||
|
`files.spaces` or `mail.delivery`. A requirement range is interpreted as
|
||||||
|
`>= version_min` and `< version_max_exclusive`; the exclusive upper bound is
|
||||||
|
intended for SemVer major-version lines. Missing optional interfaces are
|
||||||
|
allowed, but an installed provider with an incompatible version blocks
|
||||||
|
activation because the integration would otherwise bind to an unsafe API.
|
||||||
|
|
||||||
|
### Source Authority And Provider Operations
|
||||||
|
|
||||||
|
Integration maturity and configured authority are independent. The existing
|
||||||
|
external-reference maturity ladder describes whether an adapter can discover,
|
||||||
|
link, search, read, publish, synchronize, migrate, or replace. A binding must
|
||||||
|
also state whether GovOPlaN is native authoritative, the external system is
|
||||||
|
authoritative, GovOPlaN keeps a mirror, both sides use governed sync, GovOPlaN
|
||||||
|
adds only a governance overlay, or the object is link-only.
|
||||||
|
|
||||||
|
`ModuleManifest.external_providers` composes existing contracts rather than
|
||||||
|
replacing them. Each declaration describes owned object/field groups, authority modes,
|
||||||
|
operations, revisions, freshness, health, limits, idempotency, conflicts,
|
||||||
|
outcome-unknown handling, evidence, correction/compensation, reconciliation,
|
||||||
|
outage behavior, classification, purpose, retention, and secret requirements.
|
||||||
|
Core owns the typed declaration and validation. Connectors and domain modules
|
||||||
|
own the actual protocol and domain behavior; configuration packages select the
|
||||||
|
effective mode and block missing/incompatible/unhealthy providers; Docs and Ops
|
||||||
|
explain the result. Effect-capable declarations fail validation unless their
|
||||||
|
retry, concurrency, outcome-unknown, correction, reconciliation, evidence,
|
||||||
|
audit, timeout, outage, classification, purpose, retention, and secret behavior
|
||||||
|
is explicit.
|
||||||
|
|
||||||
|
Declarations are release-time capability claims. Configured state is projected
|
||||||
|
separately through `ModuleManifest.external_provider_state_providers`. A state
|
||||||
|
provider receives a bounded tenant context and returns one sanitized observation
|
||||||
|
per configured binding: stable binding reference, effective authority mode,
|
||||||
|
active/configured state, health, freshness, conflict, recovery readiness,
|
||||||
|
observation/last-success time, and scalar metrics. Core validates and aggregates
|
||||||
|
those observations, isolates provider failures, and never accepts URLs,
|
||||||
|
credentials, or arbitrary nested metadata as runtime-state fields. Docs removes
|
||||||
|
binding-level detail from ordinary-user projections; Ops may show the full
|
||||||
|
sanitized operator projection.
|
||||||
|
|
||||||
|
Configuration-package preflight selects the exact requested binding from this
|
||||||
|
runtime state before evaluating authority, health, freshness, and recovery. A
|
||||||
|
healthy sibling binding therefore cannot mask an unhealthy required binding.
|
||||||
|
Providers with multiple configurations must use non-secret, stable references
|
||||||
|
such as `calendar:sync-source:<id>`.
|
||||||
|
|
||||||
|
Current named interfaces, generated from the source manifests by the workspace
|
||||||
|
contract checks, are:
|
||||||
|
|
||||||
|
- `addresses.contact_writer`, `addresses.lookup`, `addresses.recipient_source`
|
||||||
|
- `calendar.outbox`, `calendar.scheduling`
|
||||||
|
- `campaigns.access`, `campaigns.delivery_tasks`,
|
||||||
|
`campaigns.mail_policy_context`, `campaigns.policy_context`,
|
||||||
|
`campaigns.retention`
|
||||||
|
- `dist_lists.expand`, `dist_lists.source`, `dist_lists.writer`
|
||||||
|
- `evaluation.feedback`, `evaluation.result_aggregation`, `evaluation.scoring`
|
||||||
|
- `files.access`, `files.campaign_attachments`
|
||||||
|
- `mail.campaign_delivery`
|
||||||
|
- `notifications.dispatch`
|
||||||
|
- `poll.availability_matrix`, `poll.option_selection`,
|
||||||
|
`poll.response_collection`, `poll.signed_participation`,
|
||||||
|
`poll.workflow_context`
|
||||||
|
- `rest.function_publication`
|
||||||
|
- `scheduling.candidate_slots`, `scheduling.decision_handoff`
|
||||||
|
- `soap.operation_publication`
|
||||||
|
|
||||||
|
Core validates named interface contracts in three places:
|
||||||
|
|
||||||
|
- registry activation rejects missing required interfaces and incompatible
|
||||||
|
providers
|
||||||
|
- installer preflight reports the same failures before a module set is
|
||||||
|
activated
|
||||||
|
- signed catalog validation normalizes the metadata and warns when catalog
|
||||||
|
entries cannot satisfy each other's ranges
|
||||||
|
|
||||||
|
Module-id dependencies still decide startup ordering and mandatory package
|
||||||
|
presence. Named interfaces decide whether the versions in the active module
|
||||||
|
set are compatible.
|
||||||
|
|
||||||
|
FastAPI route dependencies for authenticated endpoints are imported from the
|
||||||
|
core `govoplan_core.auth` facade. Routers may import that public API for
|
||||||
`ApiPrincipal`, `get_api_principal`, `has_scope`, `require_scope`, and
|
`ApiPrincipal`, `get_api_principal`, `has_scope`, `require_scope`, and
|
||||||
`require_any_scope`; they must not import access ORM models or
|
`require_any_scope`; they must not import access ORM models or
|
||||||
`govoplan_access.backend.*` implementation internals.
|
`govoplan_access.backend.*` implementation internals.
|
||||||
|
|
||||||
Current live table ownership:
|
Current live table ownership:
|
||||||
|
|
||||||
- `govoplan-tenancy`: `tenancy_tenants`
|
- core scope table: `core_scopes` (used by access/core baseline; managed by
|
||||||
|
`govoplan-tenancy` behavior when the tenancy module is installed)
|
||||||
- `govoplan-access`: `access_accounts`, `access_users`, `access_groups`,
|
- `govoplan-access`: `access_accounts`, `access_users`, `access_groups`,
|
||||||
`access_roles`, `access_system_role_assignments`,
|
`access_roles`, `access_system_role_assignments`,
|
||||||
`access_user_group_memberships`, `access_user_role_assignments`,
|
`access_user_group_memberships`, `access_user_role_assignments`,
|
||||||
@@ -204,6 +396,23 @@ unsafe methods.
|
|||||||
This avoids retransmitting unchanged snapshots. It does not identify which row
|
This avoids retransmitting unchanged snapshots. It does not identify which row
|
||||||
changed inside a collection.
|
changed inside a collection.
|
||||||
|
|
||||||
|
### Mutation Preconditions
|
||||||
|
|
||||||
|
Weak response ETags are cache validators only. Mutable aggregates expose a
|
||||||
|
separate positive, monotonic revision and an opaque strong ETag generated by
|
||||||
|
`govoplan_core.core.concurrency.strong_resource_etag`. HTTP mutations send that
|
||||||
|
strong ETag in `If-Match`; capability and worker calls carry the equivalent
|
||||||
|
typed `expected_revision`.
|
||||||
|
|
||||||
|
Core's compare-and-set primitive advances the revision in the same transaction
|
||||||
|
as the domain mutation. A missing HTTP precondition is `428 Precondition
|
||||||
|
Required`, a stale HTTP precondition is `412 Precondition Failed`, and a
|
||||||
|
domain/reconciliation conflict is `409 Conflict`. Conflict responses contain
|
||||||
|
bounded resource and revision metadata rather than the complete current
|
||||||
|
object. Modules may opt into the conservative three-way merge helper, but must
|
||||||
|
declare protected workflow, delivery, ownership, lock, evidence, signature,
|
||||||
|
and cryptographic paths that can never be merged automatically.
|
||||||
|
|
||||||
### Delta Collections
|
### Delta Collections
|
||||||
|
|
||||||
Collection endpoints that can expose row-level changes should use the shared
|
Collection endpoints that can expose row-level changes should use the shared
|
||||||
@@ -237,12 +446,22 @@ Fields:
|
|||||||
- `full`: true when the response is a full snapshot rather than an incremental
|
- `full`: true when the response is a full snapshot rather than an incremental
|
||||||
delta.
|
delta.
|
||||||
|
|
||||||
|
Section-level settings endpoints use the same contract but replace `items`
|
||||||
|
with:
|
||||||
|
|
||||||
|
- `item`: the full settings object when `full: true`.
|
||||||
|
- `sections`: a map of changed settings sections when `full: false`.
|
||||||
|
- `changed_sections`: ordered section identifiers the client can merge into its
|
||||||
|
local settings object.
|
||||||
|
|
||||||
Recommended query parameters:
|
Recommended query parameters:
|
||||||
|
|
||||||
- `since`: opaque previous watermark. If omitted or expired, return a full
|
- `since`: opaque previous watermark. If omitted or expired, return a full
|
||||||
snapshot with `full: true`.
|
snapshot with `full: true`.
|
||||||
- `limit`: maximum number of changed items plus deleted markers.
|
- `limit`: maximum number of changed items plus deleted markers.
|
||||||
- `include_deleted`: whether deleted markers should be returned.
|
- `include_deleted`: whether deleted markers should be returned.
|
||||||
|
- `cursor`: opaque keyset cursor for table pages where offset shifts would make
|
||||||
|
row-level merging unsafe.
|
||||||
|
|
||||||
Modules should record changes with:
|
Modules should record changes with:
|
||||||
|
|
||||||
@@ -255,10 +474,61 @@ Modules should record changes with:
|
|||||||
- `payload`: small, non-secret routing metadata that helps determine whether a
|
- `payload`: small, non-secret routing metadata that helps determine whether a
|
||||||
tombstone belongs to the requested view.
|
tombstone belongs to the requested view.
|
||||||
|
|
||||||
If a retained sequence window is introduced, endpoints must compare the
|
Sequence retention is explicit. Cleanup jobs must call
|
||||||
incoming watermark with the oldest retained sequence entry for their module and
|
`prune_sequence_entries(...)` rather than deleting `core_change_sequence` rows
|
||||||
collections. A watermark older than that window is not safe for incremental
|
directly. Pruning records a retention floor per module, collection, and tenant
|
||||||
replay, so the endpoint must return a full snapshot with `full: true`.
|
scope. Endpoints compare incoming watermarks with that floor; a watermark older
|
||||||
|
than the floor is not safe for incremental replay, so the endpoint must return a
|
||||||
|
full snapshot with `full: true`. A first-use `seq:0` watermark remains valid
|
||||||
|
until such a floor exists, even if unrelated collections have advanced the
|
||||||
|
global sequence.
|
||||||
|
|
||||||
|
### Bounded Reference Selectors
|
||||||
|
|
||||||
|
Cross-module selectors use the module-neutral contract in
|
||||||
|
`govoplan_core.core.references`; consumers must not load an optional module's
|
||||||
|
complete directory and filter it in memory.
|
||||||
|
|
||||||
|
- Providers receive a normalized `ReferenceSearchRequest` with `kind`,
|
||||||
|
`tenant_id`, `query`, `selected_values`, `limit`, optional opaque `cursor`,
|
||||||
|
and policy context.
|
||||||
|
- Providers apply visibility and text filtering before materializing rows and
|
||||||
|
return `ReferenceSearchPage(options, next_cursor, has_more)`.
|
||||||
|
- A page contains at most the requested bounded search results. Already-selected
|
||||||
|
references are retained in addition to that bound so historical values remain
|
||||||
|
readable and removable even when they are inactive, deleted, or outside the
|
||||||
|
current search page.
|
||||||
|
- API consumers expose `next_cursor` and `has_more`. The current searchable
|
||||||
|
selector requests the first bounded page for each query; later load-more UI
|
||||||
|
can use the same cursor without changing the provider contract.
|
||||||
|
- `access.reference_options` supplies SQL-backed account, membership, and group
|
||||||
|
searches. When it is absent, Core degrades to the legacy Access directory or
|
||||||
|
to principal-only/unavailable references without importing Access.
|
||||||
|
- The shared WebUI `apiReferenceOptionProvider` resolves selected values in
|
||||||
|
chunks of at most 200, preventing a large existing selection from turning
|
||||||
|
into an unbounded request.
|
||||||
|
|
||||||
|
### Cursor/Keyset Pages
|
||||||
|
|
||||||
|
Offset pagination remains supported for compatibility and for first page loads,
|
||||||
|
but it is not safe as the merge anchor for row-level deltas on page 2 and later.
|
||||||
|
When a delta-capable table can be paged beyond the first page, the endpoint
|
||||||
|
should expose keyset cursors:
|
||||||
|
|
||||||
|
- Core provides `encode_keyset_cursor`, `decode_keyset_cursor`, and
|
||||||
|
`keyset_query_fingerprint` in `govoplan_core.core.pagination`.
|
||||||
|
- Cursors are opaque to clients and contain the endpoint scope, query
|
||||||
|
fingerprint, and last-row keyset values.
|
||||||
|
- The fingerprint must include every query input that changes membership or
|
||||||
|
order: scope, tenant, page size, sort column, sort direction, and filters.
|
||||||
|
- Reusing a cursor with different sort or filter parameters must fail with a
|
||||||
|
client error rather than returning a mismatched slice.
|
||||||
|
- Responses may still include `page`, `page_size`, `pages`, and `total` for
|
||||||
|
existing UI components, but `cursor` identifies the current slice and
|
||||||
|
`next_cursor` is the safe anchor for the next slice.
|
||||||
|
- The first visit to an arbitrary page can use offset compatibility. The
|
||||||
|
response should include the start cursor for that page so later reloads and
|
||||||
|
delta requests use keyset semantics.
|
||||||
|
|
||||||
Concrete consumers:
|
Concrete consumers:
|
||||||
|
|
||||||
@@ -274,9 +544,49 @@ Concrete consumers:
|
|||||||
refreshes when version, job, issue, or delivery-attempt changes invalidate the
|
refreshes when version, job, issue, or delivery-attempt changes invalidate the
|
||||||
workspace view.
|
workspace view.
|
||||||
- `GET /api/v1/campaigns/{campaign_id}/jobs/delta`: returns a paginated job
|
- `GET /api/v1/campaigns/{campaign_id}/jobs/delta`: returns a paginated job
|
||||||
table snapshot first, then stable row deltas for unfiltered job status
|
table snapshot first, then stable row deltas for cursor-backed job pages.
|
||||||
updates. Filtered, created, deleted, or stale-watermark requests fall back to
|
The job list also supports offset compatibility for first visits to a page and
|
||||||
a full page snapshot so pagination remains correct.
|
returns `cursor`/`next_cursor` for stable reloads. Filtered, created, deleted,
|
||||||
|
or stale-watermark requests fall back to a full page snapshot when pagination
|
||||||
|
membership can shift.
|
||||||
|
- `GET /api/v1/admin/users/delta`, `/groups/delta`, `/roles/delta`,
|
||||||
|
`/system/roles/delta`, `/system/accounts/delta`, and `/api-keys/delta`:
|
||||||
|
return access administration row deltas with tombstones where rows leave the
|
||||||
|
visible view.
|
||||||
|
- `GET /api/v1/admin/system/settings/delta`: returns section deltas for system
|
||||||
|
defaults, tenant capability flags, language packages, privacy retention
|
||||||
|
policy, maintenance mode, and raw settings.
|
||||||
|
- `GET /api/v1/admin/tenant/settings/delta`: returns tenant-local setting
|
||||||
|
sections and also reports language-section changes when system language
|
||||||
|
packages or enabled language codes change.
|
||||||
|
- `GET /api/v1/admin/configuration-changes/delta`: returns changed
|
||||||
|
configuration requests and history records.
|
||||||
|
- `GET /api/v1/admin/audit` and `/api/v1/admin/audit/delta`: return append-only
|
||||||
|
audit events using the same scope, sort, and filter query parameters. The list
|
||||||
|
supports offset compatibility plus `cursor`/`next_cursor` keyset paging; the
|
||||||
|
delta endpoint can replay changes against a cursor-backed slice.
|
||||||
|
- `GET /api/v1/mail/settings/delta`: returns mail profile row deltas plus the
|
||||||
|
current scoped mail profile policy when profile-policy dependencies changed.
|
||||||
|
The WebUI consumes this for system, tenant, user, group, and campaign mail
|
||||||
|
settings panels.
|
||||||
|
- `GET /api/v1/files/connectors/settings/delta`: returns file connector
|
||||||
|
profile, credential, connector-space, and scoped connector-policy deltas.
|
||||||
|
Credential changes also include referencing profiles because profile rows
|
||||||
|
display credential-derived state.
|
||||||
|
|
||||||
|
Open retrofit scope:
|
||||||
|
|
||||||
|
- Additional module-specific settings pages should expose section deltas as
|
||||||
|
their settings APIs stabilize. Remaining likely candidates are future
|
||||||
|
booking/resource configuration pages and settings pages introduced by new
|
||||||
|
modules.
|
||||||
|
- Remaining high-volume tables should adopt the cursor/keyset contract before
|
||||||
|
enabling arbitrary-page row deltas. Current rollout follow-ups:
|
||||||
|
`govoplan-files#22` for large file-space server windows,
|
||||||
|
`govoplan-mail#9` for provider-aware mailbox message cursors,
|
||||||
|
`govoplan-calendar#7` for event-window deltas,
|
||||||
|
`govoplan-tenancy#1` for tenant administration row deltas, and
|
||||||
|
`govoplan-admin#2` for governance/module-operation list deltas.
|
||||||
|
|
||||||
## Module Responsibilities
|
## Module Responsibilities
|
||||||
|
|
||||||
@@ -318,6 +628,18 @@ The manifest should declare:
|
|||||||
- navigation metadata using serializable icon names
|
- navigation metadata using serializable icon names
|
||||||
- uninstall guard providers for data, migration, worker, or scheduler vetoes
|
- uninstall guard providers for data, migration, worker, or scheduler vetoes
|
||||||
|
|
||||||
|
A tenant-level managed `RoleTemplate` may set `default_authenticated=True`
|
||||||
|
only when every authenticated tenant member must receive that narrow baseline
|
||||||
|
while the contributing module is installed. Access derives the explicit grant
|
||||||
|
from the active manifest set during authorization without mutating the request
|
||||||
|
transaction. It may materialize a non-assignable role row for administration,
|
||||||
|
but no per-user assignment is required and role edits cannot remove the
|
||||||
|
baseline.
|
||||||
|
This is not a shortcut for feature authorization: keep the template narrow and
|
||||||
|
continue to enforce each domain action's own permission and resource policy.
|
||||||
|
System-level, unmanaged, wildcard-bearing, or slug-colliding automatic
|
||||||
|
templates are rejected by registry validation.
|
||||||
|
|
||||||
Backend nav metadata must use icon-name strings, not frontend components:
|
Backend nav metadata must use icon-name strings, not frontend components:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@@ -330,6 +652,29 @@ NavItem(
|
|||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Core validates manifest shape when the platform registry is built. The current
|
||||||
|
supported manifest contract version is `1`, and frontend asset manifests use
|
||||||
|
contract version `1`. Registry validation rejects unsupported contract versions,
|
||||||
|
invalid module ids, duplicate dependency declarations, self-dependencies,
|
||||||
|
mismatched migration/frontend metadata, invalid frontend package names, and
|
||||||
|
frontend/nav routes that do not declare usable paths and labels.
|
||||||
|
|
||||||
|
Backend route contributions are also validated before they are mounted. Startup
|
||||||
|
routers and live module activation fail fast if two routers register the same
|
||||||
|
HTTP method and path. That keeps OpenAPI output and FastAPI route order from
|
||||||
|
silently masking a module collision.
|
||||||
|
|
||||||
|
Tenant deletion and cleanup use the registry-owned delete-veto contract. A
|
||||||
|
module that owns tenant-bound data may declare `delete_veto_providers` on its
|
||||||
|
manifest for resource types such as `tenant` or `group`. Providers receive
|
||||||
|
`(session, tenant_id, resource_id)` and should return `DeleteVetoIssue`, an
|
||||||
|
iterable of `DeleteVetoIssue`, or `None`; older exception-based providers are
|
||||||
|
still treated as blocking vetoes. Core attributes each issue to the provider
|
||||||
|
module and adds resource context before the tenancy module exposes the issues
|
||||||
|
through the deletion plan. `blocker` issues prevent destructive or retire
|
||||||
|
operations, `warning` issues explain retained data, and `info` issues document
|
||||||
|
non-blocking lifecycle facts.
|
||||||
|
|
||||||
## Database And Migrations
|
## Database And Migrations
|
||||||
|
|
||||||
Core owns the database/session lifecycle. Modules access the database through core session dependencies and register their models/migrations through their manifest.
|
Core owns the database/session lifecycle. Modules access the database through core session dependencies and register their models/migrations through their manifest.
|
||||||
@@ -342,12 +687,53 @@ Rules:
|
|||||||
- Keep cross-module foreign-key assumptions explicit and conservative.
|
- Keep cross-module foreign-key assumptions explicit and conservative.
|
||||||
- Register module metadata in `MigrationSpec` so core can discover it.
|
- Register module metadata in `MigrationSpec` so core can discover it.
|
||||||
- Optional module migrations may create multiple Alembic heads. Verification
|
- Optional module migrations may create multiple Alembic heads. Verification
|
||||||
should compare the database heads to the configured script heads instead of
|
should compare database heads to Alembic's resolved `heads` target instead
|
||||||
assuming one linear revision when multiple modules are enabled.
|
of assuming one linear revision when multiple modules are enabled. Owner
|
||||||
|
heads can be dependency parents and therefore may not all appear in
|
||||||
|
`alembic_version` after a full-graph upgrade.
|
||||||
- Treat migrations as release artifacts. Unreleased migrations may be squashed
|
- Treat migrations as release artifacts. Unreleased migrations may be squashed
|
||||||
or rewritten before a stable release; released revision IDs are immutable
|
or rewritten before a stable release; released revision IDs are immutable
|
||||||
once an installation may have recorded them. Each stable release records its
|
once an installation may have recorded them. Each stable release records its
|
||||||
public migration heads in `docs/migration-release-baselines.json`.
|
public migration heads in `docs/migration-release-baselines.json`.
|
||||||
|
- GovOPlaN keeps two Alembic tracks. The default `release` track loads
|
||||||
|
`versions` directories with reviewed release baselines and release-to-release
|
||||||
|
step-up migrations. The explicit `dev` track loads `dev_versions`
|
||||||
|
directories with the detailed development chain. Do not load both tracks for
|
||||||
|
one migration run, and do not switch a database between tracks unless it is a
|
||||||
|
disposable development database.
|
||||||
|
|
||||||
|
### Shared State And Runtime Ordering
|
||||||
|
|
||||||
|
Multi-host application roles use the `shared` state profile. In that profile,
|
||||||
|
PostgreSQL, Redis, a stable installation identifier, and S3-compatible object
|
||||||
|
storage are mandatory. Module durable artifacts must use Core's object-storage
|
||||||
|
contract and module-owned opaque key namespaces; node-local paths are limited
|
||||||
|
to temporary materialization. Same-host replicas may use the `host-shared`
|
||||||
|
profile and one shared volume.
|
||||||
|
|
||||||
|
Only the migration command mutates schema. PostgreSQL migration runs acquire a
|
||||||
|
deployment-wide advisory lock before module pre-tasks, Alembic, and post-tasks.
|
||||||
|
API, worker, and scheduler roles wait for exact configured migration heads and
|
||||||
|
fail closed instead of applying migrations during startup.
|
||||||
|
|
||||||
|
Runtime roles register identity, software/module composition, queues, heartbeat,
|
||||||
|
and drain state in PostgreSQL. Singleton work must use a distributed lease and
|
||||||
|
validate its monotonically increasing fencing token at the consequential
|
||||||
|
commit. See `STATE_AND_RECOVERY_CONTRACT.md` for the complete contract.
|
||||||
|
|
||||||
|
### Recovery Evidence
|
||||||
|
|
||||||
|
Operations spanning transactions, object storage, queues, or external systems
|
||||||
|
must choose an explicit Core recovery mode: atomic, compensation,
|
||||||
|
snapshot-restore, forward-recovery, or irreversible. Plans require verification
|
||||||
|
steps and mode-specific recovery material. Use idempotency keys, append-only
|
||||||
|
evidence checkpoints, and a runtime fence where work may race across nodes.
|
||||||
|
|
||||||
|
The recovery ledger is a shared primitive, not automatic coverage. A module may
|
||||||
|
claim its guarantees only after its operation records preconditions before side
|
||||||
|
effects, transitions partial/unknown outcomes honestly, and records verified
|
||||||
|
completion or recovery. Plaintext secrets must never enter recovery metadata or
|
||||||
|
evidence.
|
||||||
|
|
||||||
## Install, Uninstall, And Catalogs
|
## Install, Uninstall, And Catalogs
|
||||||
|
|
||||||
@@ -356,17 +742,45 @@ check, maintenance-mode guard, replay state, and installer request queue.
|
|||||||
Package mutation is performed by `govoplan-module-installer` outside the
|
Package mutation is performed by `govoplan-module-installer` outside the
|
||||||
FastAPI request process.
|
FastAPI request process.
|
||||||
|
|
||||||
Official catalogs can be served as static JSON from `govoplan-web`, but core
|
Official catalogs can be served as static JSON from `addideas-govoplan-website`, but core
|
||||||
does not trust the website by location alone. A catalog must pass the configured
|
does not trust the website by location alone. A catalog must pass the configured
|
||||||
signature, channel, freshness, and replay rules before a catalog entry can be
|
signature, channel, freshness, and replay rules before a catalog entry can be
|
||||||
planned. Catalog entries may declare `license_features`; core checks those
|
planned. Catalog entries may declare `license_features`; core checks those
|
||||||
against the configured offline license before adding the entry to the install
|
against the configured offline license before adding the entry to the install
|
||||||
plan.
|
plan. Catalog entries may also declare `migration_safety` as `automatic`,
|
||||||
|
`requires_review`, `forward_only`, or `destructive`; forward-only and
|
||||||
|
destructive entries require explicit operator acknowledgement in the install
|
||||||
|
plan before installer preflight allows activation. Forward-only and destructive
|
||||||
|
catalog entries must also declare a tested recovery path. Catalog update entries
|
||||||
|
can define direct-update windows with `current_version_min` and
|
||||||
|
`current_version_max_exclusive`, mark intermediate `bridge_release` targets, and
|
||||||
|
explicitly opt into reviewed downgrade or same-version package-refresh plans.
|
||||||
|
Module migration order can be declared with `migration_after` and
|
||||||
|
`migration_before` in manifests or release catalogs; installer preflight turns
|
||||||
|
that metadata, module dependencies, and named interface relationships into an
|
||||||
|
ordered migration plan.
|
||||||
|
|
||||||
|
Modules that need live-data work outside Alembic schema revisions may declare
|
||||||
|
`migration_tasks` on `MigrationSpec`. This is deliberately narrower than a
|
||||||
|
general lifecycle hook system. Each task has a stable `task_id`, one of four
|
||||||
|
phases (`pre_migration_check`, `pre_migration_prepare`,
|
||||||
|
`post_migration_backfill`, `post_migration_verify`), a short operator-facing
|
||||||
|
summary, a task version, safety metadata, and an idempotent executor. Installer
|
||||||
|
preflight blocks non-idempotent tasks, forward-only/destructive tasks without
|
||||||
|
operator acknowledgement, and installed manifest tasks that have no executor.
|
||||||
|
Catalog task metadata is surfaced before activation as pending because the
|
||||||
|
executor can only be verified after the package is installed.
|
||||||
|
|
||||||
Modules should provide:
|
Modules should provide:
|
||||||
|
|
||||||
- pinned backend and WebUI package refs for official catalog entries
|
- pinned backend and WebUI package refs for official catalog entries
|
||||||
|
- module dependency metadata for catalog target-state planning
|
||||||
|
- migration-safety metadata for catalog update planning
|
||||||
|
- migration task metadata when live-data checks, preparation, backfills, or
|
||||||
|
verification must run around Alembic
|
||||||
- compatibility metadata in the module manifest
|
- compatibility metadata in the module manifest
|
||||||
|
- named interface contracts in the manifest and catalog entry when the module
|
||||||
|
provides or consumes cross-module APIs
|
||||||
- lifecycle hooks when a runtime enable/disable action needs module-specific
|
- lifecycle hooks when a runtime enable/disable action needs module-specific
|
||||||
work
|
work
|
||||||
- uninstall guards for persistent data, active workers, schedulers, or external
|
- uninstall guards for persistent data, active workers, schedulers, or external
|
||||||
@@ -379,11 +793,18 @@ Uninstall remains non-destructive unless the operator explicitly requests
|
|||||||
|
|
||||||
## WebUI Contract
|
## WebUI Contract
|
||||||
|
|
||||||
A WebUI module exports a `PlatformWebModule` from its package. The object contributes local/fallback metadata and route render functions.
|
A WebUI module exports a `PlatformWebModule` from its package. The object
|
||||||
|
contributes local/fallback metadata and route render functions. The package
|
||||||
|
must ship `src/module.ts` with the default contribution export: Core's Vite
|
||||||
|
host imports that descriptor directly after the backend reports the module as
|
||||||
|
enabled. This keeps package-root re-exports from pulling page implementations
|
||||||
|
into the initial shell.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
|
const FilesPage = lazy(() => import("./features/files/FilesPage"));
|
||||||
|
|
||||||
export const filesModule: PlatformWebModule = {
|
export const filesModule: PlatformWebModule = {
|
||||||
id: "files",
|
id: "files",
|
||||||
label: "Files",
|
label: "Files",
|
||||||
@@ -398,6 +819,11 @@ export const filesModule: PlatformWebModule = {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Route pages and substantial panels must use stable lazy imports. Core supplies
|
||||||
|
the shared loading and retryable error state around route rendering. The
|
||||||
|
initial static import closure and largest asynchronous chunk are enforced by
|
||||||
|
the budgets documented in [WEBUI_BUNDLE_BUDGETS.md](WEBUI_BUNDLE_BUDGETS.md).
|
||||||
|
|
||||||
WebUI modules receive only the core route context:
|
WebUI modules receive only the core route context:
|
||||||
|
|
||||||
- `settings`
|
- `settings`
|
||||||
@@ -429,6 +855,31 @@ capabilities with `usePlatformUiCapabilities("admin.sections")`, filters them
|
|||||||
by `anyOf`/`allOf`, and renders them without importing the contributing module's
|
by `anyOf`/`allOf`, and renders them without importing the contributing module's
|
||||||
components directly.
|
components directly.
|
||||||
|
|
||||||
|
The configurable dashboard follows the same pattern. Core contributes only a
|
||||||
|
minimal `/dashboard` fallback when no `dashboard` WebUI module is active. The
|
||||||
|
`govoplan-dashboard` module owns the real `/dashboard` route and collects
|
||||||
|
widgets exposed through the `dashboard.widgets` capability:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const dashboardWidgets: DashboardWidgetsUiCapability = {
|
||||||
|
widgets: [
|
||||||
|
{
|
||||||
|
id: "ops.health",
|
||||||
|
title: "Operations health",
|
||||||
|
moduleId: "ops",
|
||||||
|
defaultSize: "wide",
|
||||||
|
anyOf: ["ops:operations:read"],
|
||||||
|
render: ({ settings, refreshKey }) => createElement(OpsHealthWidget, { settings, refreshKey })
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Dashboard widgets are module contributions, not cross-module imports. A widget
|
||||||
|
may render components from its own module and core components only. The
|
||||||
|
dashboard module is responsible for layout, visibility, refresh context, and
|
||||||
|
future server-side layout persistence.
|
||||||
|
|
||||||
## Icon Rules
|
## Icon Rules
|
||||||
|
|
||||||
Icons are resolved centrally by core.
|
Icons are resolved centrally by core.
|
||||||
@@ -474,7 +925,27 @@ Examples:
|
|||||||
|
|
||||||
## Cross-Module Integration
|
## Cross-Module Integration
|
||||||
|
|
||||||
A module can declare required dependencies and optional dependencies. Optional behavior should be enabled by module presence and permissions, not by importing another module's WebUI internals.
|
A module can declare required module dependencies, optional module
|
||||||
|
dependencies, required capabilities, and optional capabilities. Required module
|
||||||
|
dependencies are reserved for unavoidable startup ownership, such as a module
|
||||||
|
that cannot import or mount without another module package. Most runtime
|
||||||
|
relationships should be expressed as capabilities instead.
|
||||||
|
|
||||||
|
Auth/principal access is a capability contract, not a reason to hard-depend on
|
||||||
|
the `govoplan-access` repository. Current routers import `govoplan_core.auth`;
|
||||||
|
that facade delegates to access today and is the migration point for a future
|
||||||
|
provider-neutral auth kernel. Feature manifests should require
|
||||||
|
`auth.principalResolver` and `auth.permissionEvaluator`, while access remains
|
||||||
|
the default installed provider.
|
||||||
|
|
||||||
|
Tenancy is optional. Existing scoped data still uses `tenant_id` as a scope
|
||||||
|
identifier, backed by the core-owned `core_scopes` table. Access and
|
||||||
|
organizations must not import the tenancy package or declare a hard dependency
|
||||||
|
on it. Tenancy-specific administration and tenant resolver behavior live behind
|
||||||
|
the tenancy module and its capabilities.
|
||||||
|
|
||||||
|
Optional behavior should be enabled by module presence, capabilities, and
|
||||||
|
permissions, not by importing another module's WebUI internals.
|
||||||
|
|
||||||
Rules:
|
Rules:
|
||||||
|
|
||||||
@@ -487,13 +958,17 @@ Rules:
|
|||||||
|
|
||||||
### Dependency Boundary Enforcement
|
### Dependency Boundary Enforcement
|
||||||
|
|
||||||
The repository includes `scripts/check_dependency_boundaries.py`. It enforces the current baseline:
|
The meta repository includes `tools/checks/check_dependency_boundaries.py`. It enforces the current baseline:
|
||||||
|
|
||||||
- kernel/core source may not add new direct imports of files/mail/campaign internals
|
- kernel/core source may not add new direct imports of files/mail/campaign internals
|
||||||
- access source may not import files/mail/campaign internals
|
- access source may not import files/mail/campaign internals
|
||||||
- feature modules may not import access implementation internals
|
- feature modules may not import access implementation internals
|
||||||
- feature modules may not add new direct imports of sibling feature modules
|
- feature modules may not add new direct imports of sibling feature modules
|
||||||
- FastAPI routers may import the published `govoplan_access.auth` dependency API
|
- feature WebUI packages may not depend on or import sibling feature WebUI packages
|
||||||
|
- core WebUI may list module packages as host dependencies, but core WebUI source
|
||||||
|
may not import feature WebUI internals directly; module loading stays
|
||||||
|
declarative through the module contribution contract
|
||||||
|
- FastAPI routers import the core `govoplan_core.auth` dependency facade
|
||||||
- the transitional allowlist is expected to stay empty
|
- the transitional allowlist is expected to stay empty
|
||||||
|
|
||||||
Any future exception is extraction debt and must be temporary, documented in the
|
Any future exception is extraction debt and must be temporary, documented in the
|
||||||
@@ -566,7 +1041,7 @@ First slice:
|
|||||||
- `govoplan-files` owns file-backed governed locations and uploaded/stored file
|
- `govoplan-files` owns file-backed governed locations and uploaded/stored file
|
||||||
evidence.
|
evidence.
|
||||||
- `govoplan-reporting` owns report/data views and scheduled outputs.
|
- `govoplan-reporting` owns report/data views and scheduled outputs.
|
||||||
- `govoplan-workflow` owns process state, approvals, scheduling of process
|
- `govoplan-workflow-engine` owns process state, approvals, scheduling of process
|
||||||
steps, and human review.
|
steps, and human review.
|
||||||
|
|
||||||
Future `govoplan-datasources` is justified when GovOPlaN needs a broad source
|
Future `govoplan-datasources` is justified when GovOPlaN needs a broad source
|
||||||
@@ -629,7 +1104,7 @@ from workflow semantics.
|
|||||||
- form definitions, schemas, validation rules, field visibility rules,
|
- form definitions, schemas, validation rules, field visibility rules,
|
||||||
localization, versioning, admin editing, and reusable form package fragments
|
localization, versioning, admin editing, and reusable form package fragments
|
||||||
|
|
||||||
`govoplan-forms-runtime` owns, when implemented:
|
`govoplan-forms-runtime` owns:
|
||||||
|
|
||||||
- public/internal submissions, drafts, submitted values, validation evidence,
|
- public/internal submissions, drafts, submitted values, validation evidence,
|
||||||
attachment references, submission receipts, and handoff events
|
attachment references, submission receipts, and handoff events
|
||||||
@@ -642,6 +1117,16 @@ Boundary:
|
|||||||
- Reporting/dataflow may consume submitted data through governed DTOs or
|
- Reporting/dataflow may consume submitted data through governed DTOs or
|
||||||
source lifecycle contracts.
|
source lifecycle contracts.
|
||||||
|
|
||||||
|
Implemented contract:
|
||||||
|
|
||||||
|
- Core owns the provider-neutral `FormDefinition`/`FormFieldDefinition` DTOs.
|
||||||
|
- Forms persists immutable exact definitions and provides `forms.definitions`.
|
||||||
|
- Forms Runtime resolves that capability, persists revisioned instances and
|
||||||
|
events, validates draft/final values, and provides
|
||||||
|
`forms_runtime.service_launcher`.
|
||||||
|
- Portal delegates exact `<form-id>/<revision>` bindings and never writes either
|
||||||
|
owner's tables.
|
||||||
|
|
||||||
### OpenDesk Integration Profile
|
### OpenDesk Integration Profile
|
||||||
|
|
||||||
Tracking: `govoplan-core#195`, `govoplan-connectors#5`,
|
Tracking: `govoplan-core#195`, `govoplan-connectors#5`,
|
||||||
@@ -798,8 +1283,21 @@ The package install-plan API records operator intent only:
|
|||||||
also reports catalog validity, channel, signature, trust state, and the
|
also reports catalog validity, channel, signature, trust state, and the
|
||||||
configured path.
|
configured path.
|
||||||
- `POST /api/v1/admin/system/modules/install-plan/catalog/{module_id}` saves
|
- `POST /api/v1/admin/system/modules/install-plan/catalog/{module_id}` saves
|
||||||
a planned install row from a validated catalog entry. Catalog signature and
|
a planned install or update row from a validated catalog entry. Installed
|
||||||
approved-channel policy are enforced before the row is saved.
|
modules are planned as updates. Catalog signature and approved-channel policy
|
||||||
|
are enforced before the row is saved. When the selected catalog row requires
|
||||||
|
companion dependency or interface-provider updates, the endpoint adds those
|
||||||
|
rows to the plan automatically. The saved plan row can also carry a
|
||||||
|
data-safety acknowledgement used by preflight for forward-only or destructive
|
||||||
|
catalog entries.
|
||||||
|
- Install-plan preflight returns a structured `target_plan` summary so the
|
||||||
|
admin UI can show current version, target version, package refs,
|
||||||
|
migration-safety level, update-window and bridge metadata, recovery metadata,
|
||||||
|
and acknowledgement state without requiring JSON editing.
|
||||||
|
- Install-plan preflight also returns a structured `migration_plan` summary with
|
||||||
|
target enabled modules and ordered module migration steps. When the installer
|
||||||
|
runs with migration enabled, the database migration command receives that
|
||||||
|
target module set and ordered module list.
|
||||||
- `POST /api/v1/admin/system/modules/{module_id}/uninstall-plan` saves a
|
- `POST /api/v1/admin/system/modules/{module_id}/uninstall-plan` saves a
|
||||||
planned non-destructive uninstall row for an installed module after it has
|
planned non-destructive uninstall row for an installed module after it has
|
||||||
been disabled. The Python distribution name is resolved from the installed
|
been disabled. The Python distribution name is resolved from the installed
|
||||||
@@ -873,6 +1371,9 @@ the same restart/health set after restoring package and database snapshots.
|
|||||||
The installer preflight is intentionally conservative:
|
The installer preflight is intentionally conservative:
|
||||||
|
|
||||||
- maintenance mode must be active;
|
- maintenance mode must be active;
|
||||||
|
- the `shared` state profile blocks in-place package mutation; clustered
|
||||||
|
installations must roll one verified immutable module composition across all
|
||||||
|
replicas;
|
||||||
- installed module manifests must be compatible with the supported manifest
|
- installed module manifests must be compatible with the supported manifest
|
||||||
contract and current core version;
|
contract and current core version;
|
||||||
- uninstalling `tenancy`, `access`, or `admin` is blocked;
|
- uninstalling `tenancy`, `access`, or `admin` is blocked;
|
||||||
@@ -979,15 +1480,18 @@ Backend verification from core:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /mnt/DATA/git/govoplan-core
|
cd /mnt/DATA/git/govoplan-core
|
||||||
./.venv/bin/python -m compileall src/govoplan_core ../govoplan-access/src/govoplan_access ../govoplan-admin/src/govoplan_admin ../govoplan-tenancy/src/govoplan_tenancy ../govoplan-policy/src/govoplan_policy ../govoplan-audit/src/govoplan_audit ../govoplan-files/src/govoplan_files ../govoplan-mail/src/govoplan_mail ../govoplan-campaign/src/govoplan_campaign
|
/mnt/DATA/git/govoplan/.venv/bin/python -m compileall src/govoplan_core ../govoplan-access/src/govoplan_access ../govoplan-admin/src/govoplan_admin ../govoplan-tenancy/src/govoplan_tenancy ../govoplan-policy/src/govoplan_policy ../govoplan-audit/src/govoplan_audit ../govoplan-dashboard/src/govoplan_dashboard ../govoplan-files/src/govoplan_files ../govoplan-mail/src/govoplan_mail ../govoplan-campaign/src/govoplan_campaign
|
||||||
./.venv/bin/python scripts/check_dependency_boundaries.py
|
/mnt/DATA/git/govoplan/tools/checks/check_dependency_boundaries.py
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`govoplan/tools/checks/check-focused.sh` runs npm with an isolated temporary npm user config
|
||||||
|
so developer-local npm settings do not create release-check warning noise.
|
||||||
|
|
||||||
Focused module contract and permutation verification:
|
Focused module contract and permutation verification:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /mnt/DATA/git/govoplan-core
|
cd /mnt/DATA/git/govoplan
|
||||||
bash scripts/check-module-matrix.sh
|
GOVOPLAN_CORE_ROOT=/mnt/DATA/git/govoplan-core bash tools/checks/check-module-matrix.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
Core WebUI host verification:
|
Core WebUI host verification:
|
||||||
@@ -1001,7 +1505,7 @@ Clean generated `dist`, `.vite`, and source-tree `__pycache__` artifacts after v
|
|||||||
|
|
||||||
## Release Dependency Rules
|
## Release Dependency Rules
|
||||||
|
|
||||||
Local development may use editable Python installs and local WebUI `file:` dependencies so sibling module changes reload quickly. Release builds must use tagged git refs or published packages instead. Core provides:
|
Local development may use editable Python installs and local WebUI `file:` dependencies so sibling module changes reload quickly. Release builds must use tagged git refs or published packages instead. The meta repository provides:
|
||||||
|
|
||||||
- `requirements-dev.txt` for local editable backend installs
|
- `requirements-dev.txt` for local editable backend installs
|
||||||
- `requirements-release.txt` for tagged backend module installs
|
- `requirements-release.txt` for tagged backend module installs
|
||||||
|
|||||||
Reference in New Issue
Block a user