Prepare GovOPlaN self-hosted release workflow
This commit is contained in:
@@ -80,6 +80,7 @@ The following contracts are the baseline API that modules can rely on:
|
||||
|
||||
- `ModuleManifest`
|
||||
- `ModuleCompatibility`
|
||||
- named interface contract provider/requirement metadata
|
||||
- module uninstall guard provider contract
|
||||
- `MigrationSpec`
|
||||
- route factory contract
|
||||
@@ -125,6 +126,50 @@ Feature modules should prefer these capabilities over direct reads of
|
||||
access/tenant ORM models when they need labels, group membership, default
|
||||
access provisioning, counts, audit actor labels, or tenant metadata.
|
||||
|
||||
### 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.
|
||||
|
||||
Current named interfaces:
|
||||
|
||||
- `files.campaign_attachments`
|
||||
- `mail.campaign_delivery`
|
||||
- `campaigns.access`
|
||||
- `campaigns.delivery_tasks`
|
||||
- `campaigns.mail_policy_context`
|
||||
- `campaigns.policy_context`
|
||||
- `campaigns.retention`
|
||||
|
||||
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
|
||||
@@ -450,6 +495,8 @@ Modules should provide:
|
||||
|
||||
- pinned backend and WebUI package refs for official catalog entries
|
||||
- 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
|
||||
work
|
||||
- uninstall guards for persistent data, active workers, schedulers, or external
|
||||
@@ -621,6 +668,10 @@ The repository includes `scripts/check_dependency_boundaries.py`. It enforces th
|
||||
- access source may not import files/mail/campaign internals
|
||||
- feature modules may not import access implementation internals
|
||||
- feature modules may not add new direct imports of sibling feature modules
|
||||
- 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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user