chore: consolidate platform split checks
This commit is contained in:
@@ -1,456 +0,0 @@
|
||||
# GovOPlaN Access Extraction Plan
|
||||
|
||||
> Backlog state migrated to Gitea issues on 2026-07-06. Keep this document as
|
||||
> durable extraction context and architecture notes. Track active tasks,
|
||||
> decisions, blockers, and implementation state in `add-ideas/govoplan-core`
|
||||
> issues with `module/access` and `source/backlog-import`.
|
||||
|
||||
This plan describes how to extract access, authentication, RBAC, and related
|
||||
administration behavior from the current compatibility core into a dedicated
|
||||
`govoplan-access` platform module.
|
||||
|
||||
The goal is not to make access optional in every real deployment. The goal is to
|
||||
make ownership explicit: the kernel composes modules and exposes contracts;
|
||||
`govoplan-access` owns identity, sessions, API keys, roles, groups, and access
|
||||
administration.
|
||||
|
||||
## Current Inventory
|
||||
|
||||
### Existing Access Module Seed
|
||||
|
||||
`govoplan-access` contains the extracted module-shaped seed package under
|
||||
`src/govoplan_access/backend`. `govoplan-core` keeps compatibility import shims
|
||||
under `src/govoplan_core/access`:
|
||||
|
||||
- `manifest.py` declares `ModuleManifest(id="access")`.
|
||||
- `db/models.py` defines access-owned model candidates.
|
||||
- `auth/principals.py`, `auth/roles.py`, and `auth/tokens.py` contain auth
|
||||
helper concepts.
|
||||
- `permissions/definitions.py`, `permissions/evaluator.py`, and
|
||||
`permissions/registry.py` contain permission catalogue/evaluation concepts.
|
||||
- `tenancy/datastore.py` contains early tenancy access helpers.
|
||||
|
||||
This seed package is now the starting point for the access module, but it is
|
||||
not yet the full live source of truth for the running product.
|
||||
|
||||
### Live Compatibility Ownership In Core
|
||||
|
||||
The active implementation still uses core-owned models and services:
|
||||
|
||||
- `src/govoplan_core/db/models.py`
|
||||
- `Account`
|
||||
- `Tenant`
|
||||
- `User`
|
||||
- `Group`
|
||||
- `Role`
|
||||
- `SystemSettings`
|
||||
- `GovernanceTemplate`
|
||||
- `GovernanceTemplateAssignment`
|
||||
- `SystemRoleAssignment`
|
||||
- `UserGroupMembership`
|
||||
- `UserRoleAssignment`
|
||||
- `GroupRoleAssignment`
|
||||
- `ApiKey`
|
||||
- `AuthSession`
|
||||
- `AuditLog`
|
||||
- `src/govoplan_core/auth/dependencies.py`
|
||||
- `src/govoplan_core/security/api_keys.py`
|
||||
- `src/govoplan_core/security/permissions.py`
|
||||
- `src/govoplan_core/security/sessions.py`
|
||||
- `src/govoplan_core/security/passwords.py`
|
||||
- `src/govoplan_core/security/secrets.py`
|
||||
- `src/govoplan_core/security/module_permissions.py`
|
||||
- `src/govoplan_core/admin/service.py`
|
||||
- `src/govoplan_core/admin/governance.py`
|
||||
- `src/govoplan_core/api/v1/auth.py`
|
||||
- `src/govoplan_core/api/v1/admin.py`
|
||||
- `src/govoplan_core/api/v1/admin_schemas.py`
|
||||
- `src/govoplan_core/api/v1/audit.py`
|
||||
- `src/govoplan_core/db/bootstrap.py`
|
||||
|
||||
Core still hosts the generic login/settings shell and shared WebUI primitives.
|
||||
The legacy administration page has moved to the `govoplan-access` WebUI package
|
||||
and is contributed as the `/admin` route by the access module. Individual admin
|
||||
panels can now be split further into access, admin, tenancy, policy, and audit
|
||||
WebUI contributions without changing the core shell route wiring again.
|
||||
|
||||
### Current Module Consumers
|
||||
|
||||
Feature modules no longer import core auth dependency wrappers or access-owned
|
||||
ORM models. Backend routers import the access-published FastAPI dependency API
|
||||
from `govoplan_access.backend.auth.dependencies`; runtime cooperation uses
|
||||
kernel capabilities such as `access.directory`, `campaigns.access`,
|
||||
`campaigns.mailPolicyContext`, and `campaigns.deliveryTasks`.
|
||||
|
||||
## Target Ownership
|
||||
|
||||
### Kernel
|
||||
|
||||
The kernel keeps only platform composition and stable contracts:
|
||||
|
||||
- module discovery and registry validation
|
||||
- route aggregation
|
||||
- migration orchestration
|
||||
- database engine/session lifecycle
|
||||
- permission catalogue aggregation
|
||||
- capability registry
|
||||
- event/command envelopes
|
||||
- dependency injection hooks
|
||||
- health and diagnostics
|
||||
- compatibility facades while modules migrate
|
||||
|
||||
The kernel should not own account, tenant, role, group, session, or API-key
|
||||
semantics.
|
||||
|
||||
### `govoplan-access`
|
||||
|
||||
`govoplan-access` owns:
|
||||
|
||||
- accounts
|
||||
- authentication routes
|
||||
- session lifecycle
|
||||
- API keys
|
||||
- users
|
||||
- groups and memberships
|
||||
- roles and assignments
|
||||
- principal resolution
|
||||
- permission evaluation
|
||||
- access administration routes
|
||||
- access administration WebUI contributions
|
||||
- access-related migrations
|
||||
- access permissions and role templates
|
||||
|
||||
### Later Platform Modules
|
||||
|
||||
Some current access-adjacent behavior can remain in access initially, but should
|
||||
have clean seams for later extraction:
|
||||
|
||||
- `govoplan-tenancy`: tenants, tenant lifecycle, tenant switching, tenant
|
||||
metadata, tenant settings boundaries.
|
||||
- `govoplan-policy`: hierarchical policy/effective policy resolution and
|
||||
provenance display contracts.
|
||||
- `govoplan-audit`: audit log storage, audit routes, retention hooks, evidence
|
||||
exports.
|
||||
- `govoplan-admin`: generic administration shell contributions if they are not
|
||||
owned by access/tenancy/policy/audit directly.
|
||||
|
||||
## Kernel Contracts To Stabilize First
|
||||
|
||||
Before moving live code, define contracts that feature modules can depend on
|
||||
without importing access ORM models:
|
||||
|
||||
- `PrincipalResolver`
|
||||
- resolves the current actor from a request/session/API key.
|
||||
- returns a stable DTO, not an ORM model.
|
||||
- `AccessDirectory`
|
||||
- resolves users, groups, memberships, and display labels by stable IDs.
|
||||
- supports batch lookups for grids and policy screens.
|
||||
- `TenantResolver`
|
||||
- resolves current tenant context and tenant metadata by stable ID.
|
||||
- `PermissionEvaluator`
|
||||
- evaluates required scopes for a principal and resource.
|
||||
- `ResourceAccessProvider`
|
||||
- lets modules register resource ACL behavior without importing each other.
|
||||
- `SecretProvider`
|
||||
- encrypts/decrypts named secrets without tying consumers to access models.
|
||||
- `AuditSink`
|
||||
- records audit events without importing audit storage models.
|
||||
|
||||
DTOs should be small and serializable:
|
||||
|
||||
- `PrincipalRef`
|
||||
- `AccountRef`
|
||||
- `TenantRef`
|
||||
- `UserRef`
|
||||
- `GroupRef`
|
||||
- `RoleRef`
|
||||
|
||||
## Extraction Stages
|
||||
|
||||
### Stage 0: Baseline Safeguards
|
||||
|
||||
Status: started.
|
||||
|
||||
- Document the kernel/platform module model.
|
||||
- Add dependency-boundary checks.
|
||||
- Add backend module permutation startup tests.
|
||||
- Inventory access/auth/RBAC imports.
|
||||
- Draft this extraction plan.
|
||||
|
||||
Acceptance criteria:
|
||||
|
||||
- `scripts/check_dependency_boundaries.py` passes.
|
||||
- backend module permutation tests start every supported module combination.
|
||||
- current direct imports are tracked as explicit transitional debt.
|
||||
|
||||
### Stage 1: Contract Definitions
|
||||
|
||||
Add kernel-owned protocols and DTOs for access-related interaction.
|
||||
|
||||
Tasks:
|
||||
|
||||
- Add protocol definitions under a kernel contract package.
|
||||
- Add registry/capability names for access services.
|
||||
- Keep existing core dependency functions as compatibility wrappers.
|
||||
- Make wrappers resolve through capabilities when `govoplan-access` is present.
|
||||
- Add tests for missing-capability behavior and clear error messages.
|
||||
|
||||
Acceptance criteria:
|
||||
|
||||
- Feature modules can receive principal/tenant/group/user references without
|
||||
importing access ORM models.
|
||||
- Existing routes continue to work through compatibility wrappers.
|
||||
|
||||
### Stage 2: Create `govoplan-access`
|
||||
|
||||
Create the new repository/package and move the access seed package into it.
|
||||
|
||||
Tasks:
|
||||
|
||||
- Create package metadata and entry points for `govoplan-access`.
|
||||
- Move `govoplan_core/access` implementation into the new package.
|
||||
- Publish `ModuleManifest(id="access")`.
|
||||
- Register access permissions, role templates, routers, and migrations.
|
||||
- Add compatibility imports in core where needed.
|
||||
- Add release/dev dependency entries in core.
|
||||
|
||||
Acceptance criteria:
|
||||
|
||||
- `govoplan-core + govoplan-access` starts through normal module discovery.
|
||||
- `govoplan-core` compatibility imports still work during transition.
|
||||
- access manifest, migrations, and route contributions are discovered by core.
|
||||
|
||||
### Stage 3: Move Live Models And Migrations
|
||||
|
||||
Move active identity/access models out of `govoplan_core.db.models`.
|
||||
|
||||
Current state: the stable table naming strategy is to keep legacy table names
|
||||
and move SQLAlchemy class definitions under their platform owners. The old
|
||||
`govoplan_core.db.models` compatibility re-export has been removed; callers
|
||||
must import module-owned models or use kernel capabilities. The earlier
|
||||
`access_*` candidate tables are not active metadata.
|
||||
|
||||
Current table ownership:
|
||||
|
||||
- `govoplan-tenancy`: `tenants`
|
||||
- `govoplan-access`: `accounts`, tenant memberships in `users`, `groups`,
|
||||
`roles`, role/group assignment tables, `api_keys`, and `auth_sessions`
|
||||
- `govoplan-admin`: governance templates and assignments
|
||||
- `govoplan-audit`: audit log
|
||||
- `govoplan-core`: system settings
|
||||
|
||||
Tasks:
|
||||
|
||||
- [x] Decide the stable table naming strategy.
|
||||
- [x] Map legacy model names to access-owned model classes.
|
||||
- [x] Keep database table names where possible to avoid data migration churn.
|
||||
- [x] Add Alembic migration metadata owned by the platform module owners.
|
||||
- [x] Remove core model compatibility aliases after callers moved to
|
||||
module-owned imports.
|
||||
- [x] Update bootstrap/create-all compatibility paths.
|
||||
|
||||
Acceptance criteria:
|
||||
|
||||
- Existing development databases migrate without data loss.
|
||||
- New databases initialize with module-owned metadata.
|
||||
- Core no longer owns or re-exports live account/user/group/role/session/API-key
|
||||
model definitions.
|
||||
|
||||
### Stage 4: Move Auth Routes And Dependencies
|
||||
|
||||
Move authentication, sessions, API keys, and principal dependencies.
|
||||
|
||||
Tasks:
|
||||
|
||||
- Move `/api/v1/auth/*` implementation to access.
|
||||
- Move session/API-key services to access.
|
||||
- Keep core route compatibility only if required by clients.
|
||||
- Replace feature-module imports of core auth dependencies with the
|
||||
access-published FastAPI dependency API.
|
||||
- Add tests for login, session refresh, tenant selection, API-key auth, and
|
||||
missing access capability failures.
|
||||
|
||||
Acceptance criteria:
|
||||
|
||||
- Auth behavior works through the access module.
|
||||
- Feature modules do not import access internals except the published
|
||||
`govoplan_access.backend.auth.dependencies` dependency API used by FastAPI
|
||||
routers.
|
||||
- Core can explain startup failure clearly if auth-required routes are enabled
|
||||
without the access capability.
|
||||
|
||||
### Stage 5: Move Admin And WebUI Contributions
|
||||
|
||||
Move access administration UI/API ownership into modules.
|
||||
|
||||
Tasks:
|
||||
|
||||
- [x] Move users, groups, roles, API keys, and access settings pages into
|
||||
`govoplan-access`.
|
||||
- [ ] Move tenant-specific pages to `govoplan-tenancy` when that module exists, or
|
||||
keep them temporarily in access with clear boundaries.
|
||||
- [x] Move overview, system settings, and governance-template panels into
|
||||
`govoplan-admin`.
|
||||
- [x] Register admin navigation and admin sections through module
|
||||
contributions.
|
||||
- [x] Keep core shell, layout, route rendering, and generic components only.
|
||||
|
||||
Acceptance criteria:
|
||||
|
||||
- Core WebUI shell renders admin/access pages from module contributions.
|
||||
- Core does not import access page components directly.
|
||||
- Module nav and route metadata remain serializable.
|
||||
- The access admin shell consumes module-owned `admin.sections` capability
|
||||
contributions without importing sibling module panels.
|
||||
|
||||
### Stage 6: Decouple Feature Modules
|
||||
|
||||
Remove direct ORM/model imports from files, mail, and campaign.
|
||||
|
||||
Tasks:
|
||||
|
||||
- Replace `Group`, `Tenant`, `User`, and `UserGroupMembership` imports with
|
||||
directory/capability lookups.
|
||||
- Replace direct cross-module cleanup/count queries with registered providers,
|
||||
events, or module-owned API contracts.
|
||||
- Replace mail-profile ownership resolution with stable owner references.
|
||||
- Replace campaign/file access checks with resource ACL provider contracts.
|
||||
|
||||
Acceptance criteria:
|
||||
|
||||
- `govoplan-files`, `govoplan-mail`, and `govoplan-campaign` do not import
|
||||
access implementation modules or sibling feature modules.
|
||||
- Dependency-boundary allowlist stays empty after each replacement.
|
||||
|
||||
### Stage 7: Remove Compatibility Debt
|
||||
|
||||
Finalize the split.
|
||||
|
||||
Tasks:
|
||||
|
||||
- Remove obsolete core compatibility aliases.
|
||||
- Keep the dependency-boundary checker allowlist empty.
|
||||
- Update release dependency docs.
|
||||
- Update operator migration notes.
|
||||
- Add full module permutation tests including access-present and access-absent
|
||||
behavior.
|
||||
|
||||
Acceptance criteria:
|
||||
|
||||
- Core is a composition kernel.
|
||||
- Access behavior is owned by `govoplan-access`.
|
||||
- Feature modules communicate through kernel contracts, capabilities, events,
|
||||
and their own APIs.
|
||||
|
||||
## Immediate Backlog
|
||||
|
||||
- [x] Document kernel/platform module model.
|
||||
- [x] Add dependency-boundary check.
|
||||
- [x] Add backend permutation startup smoke checks.
|
||||
- [x] Inventory access/auth/RBAC import debt.
|
||||
- [x] Draft access extraction plan.
|
||||
- [x] Define kernel access DTOs and protocols.
|
||||
- [x] Add access capability registry names.
|
||||
- [x] Register live access directory and tenant resolver capability
|
||||
implementations backed by the current compatibility tables.
|
||||
- [x] Register an access tenant-provisioner capability so tenancy can seed
|
||||
access-owned default roles without importing access service internals.
|
||||
- [x] Replace `govoplan-files` direct user/group/tenant model imports with the
|
||||
`access.directory` capability for group membership and share-target checks.
|
||||
- [x] Replace `govoplan-files` direct campaign model imports with the
|
||||
`campaigns.access` capability for campaign share/existence checks.
|
||||
- [x] Replace `govoplan-mail` direct user/group/tenant model imports with
|
||||
mail-owned policy storage plus access-directory validation and legacy-read
|
||||
fallback.
|
||||
- [x] Replace `govoplan-mail` direct campaign model imports with the
|
||||
`campaigns.mailPolicyContext` capability for campaign-scoped mail policy and
|
||||
owner context.
|
||||
- [x] Replace `govoplan-campaign` runtime user/group/tenant model imports with
|
||||
access-directory lookups and string-based ORM relationships.
|
||||
- [x] Create `govoplan-access` repository workspace and issue workflow scaffold.
|
||||
- [x] Create `govoplan-access` repository/package skeleton.
|
||||
- [x] Move `govoplan_core/access` seed package into `govoplan-access`.
|
||||
- [x] Add compatibility wrappers in core for old import paths.
|
||||
- [x] Route existing auth dependency wrappers through access principal/evaluator capabilities.
|
||||
- [x] Move FastAPI auth dependency wrappers out of core and into
|
||||
`govoplan-access`.
|
||||
- [x] Move session, API-key, and password helper services into `govoplan-access`.
|
||||
- [x] Move interactive auth/session routes behind access module manifest.
|
||||
- [x] Move legacy admin/API-key routes behind access module manifest.
|
||||
- [x] Move access-owned legacy admin service helpers into `govoplan-access`.
|
||||
- [x] Move governance-template CRUD helpers and routes into `govoplan-admin`.
|
||||
- [x] Move governance-template materialization of access-owned groups and roles
|
||||
behind the `access.governanceMaterializer` capability.
|
||||
- [x] Replace legacy access-to-files/campaign admin lookups with module
|
||||
tenant-summary and group-delete veto providers.
|
||||
- [x] Split legacy admin route contribution across `govoplan-admin`,
|
||||
`govoplan-tenancy`, `govoplan-policy`, `govoplan-audit`, and
|
||||
`govoplan-access` route slices.
|
||||
- [x] Move legacy admin route-handler ownership out of the access compatibility
|
||||
router into access, admin, tenancy, policy, and audit module routers.
|
||||
- [x] Move shared system-settings, tenant-governance, slug/error, and
|
||||
tenant-count helpers out of access internals into core settings/tenancy
|
||||
helpers used by the split platform route modules.
|
||||
- [x] Move campaign schema routes into the campaign route contribution.
|
||||
- [x] Move development mailbox routes into the mail route contribution.
|
||||
- [x] Replace core Celery direct campaign/mail imports with the
|
||||
`campaigns.deliveryTasks` capability.
|
||||
- [x] Replace core retention direct campaign queries with
|
||||
`campaigns.policyContext` and `campaigns.retention` capabilities.
|
||||
- [x] Replace core `create_all` feature-model imports with module registry
|
||||
metadata discovery.
|
||||
- [x] Remove transitional boundary checker allowlist entries.
|
||||
- [x] Move live legacy model definitions out of core and into
|
||||
`govoplan-access` while preserving existing table names.
|
||||
- [x] Split the transitional access-owned legacy model graph further into
|
||||
tenancy, audit, admin, access, and core settings ownership.
|
||||
- [x] Reverse the tenancy/access dependency direction so `govoplan-access`
|
||||
depends on `govoplan-tenancy`, and the registry inserts tenancy before access.
|
||||
- [x] Replace tenancy-to-access default role seeding with an access
|
||||
tenant-provisioner capability.
|
||||
- [x] Replace tenancy-to-access owner candidate and owner membership handling
|
||||
with the access tenant-provisioner capability.
|
||||
- [x] Replace admin overview counts and audit actor lookup/filtering with the
|
||||
`access.administration` capability.
|
||||
- [x] Replace feature-module direct user/group/tenant model imports.
|
||||
- [x] `govoplan-files`
|
||||
- [x] `govoplan-mail`
|
||||
- [x] `govoplan-campaign`
|
||||
- [x] Replace files/mail/campaign direct cross-module SQL lookups with
|
||||
provider/capability contracts.
|
||||
- [x] Move access admin WebUI pages to module route contributions.
|
||||
- [x] Move generic admin-owned WebUI panels into `govoplan-admin` and register
|
||||
them through the `admin.sections` UI capability.
|
||||
- [x] Remove transitional boundary checker allowlist entries as each contract
|
||||
lands.
|
||||
- [x] Remove old core import shims for access models, access routes, admin
|
||||
service helpers, and access-owned security services.
|
||||
- [ ] Move campaign-scoped mail policy ownership fully behind an API/event
|
||||
workflow if direct synchronous capability calls become too tight for later
|
||||
deployment boundaries.
|
||||
|
||||
## Open Decisions
|
||||
|
||||
- Is `govoplan-access` required for any authenticated deployment, while
|
||||
core-only remains a diagnostics/settings shell?
|
||||
- Tenant models live in `govoplan-tenancy`; `govoplan-access` depends on
|
||||
tenancy for authenticated platform composition.
|
||||
- Historical table names remain stable for painless migrations.
|
||||
- Should secret encryption remain a kernel primitive or become an access-owned
|
||||
capability?
|
||||
- Audit log storage lives in `govoplan-audit`; policy provenance can build on
|
||||
that module boundary.
|
||||
- How long should core keep compatibility route paths for existing clients?
|
||||
|
||||
## Verification
|
||||
|
||||
Use the following checks while extracting access:
|
||||
|
||||
```bash
|
||||
cd /mnt/DATA/git/govoplan-core
|
||||
./.venv/bin/python scripts/check_dependency_boundaries.py
|
||||
./.venv/bin/python -m unittest tests.test_module_system
|
||||
```
|
||||
|
||||
For each removed dependency-boundary exception, add or update a focused test
|
||||
that proves the replacement contract starts without the old direct import.
|
||||
288
docs/ACCESS_RBAC_MODEL.md
Normal file
288
docs/ACCESS_RBAC_MODEL.md
Normal file
@@ -0,0 +1,288 @@
|
||||
# GovOPlaN RBAC And Resource-Access Model
|
||||
|
||||
**Updated:** 2026-07-09
|
||||
|
||||
## Authorization Equation
|
||||
|
||||
An operation is permitted only when every applicable layer allows it:
|
||||
|
||||
```text
|
||||
effective role/API-key capability
|
||||
AND resource ownership/share access
|
||||
AND workflow state
|
||||
AND active governance/policy constraints
|
||||
```
|
||||
|
||||
RBAC answers what an actor may do. ACLs answer which resource the actor may do
|
||||
it to. Workflow state and policy decide whether the operation is currently
|
||||
valid.
|
||||
|
||||
## Identity And Scope
|
||||
|
||||
```text
|
||||
Account global login identity
|
||||
+- User membership tenant-local identity
|
||||
+- direct tenant roles
|
||||
+- active group memberships
|
||||
| +- inherited tenant roles
|
||||
+- tenant-local API keys
|
||||
|
||||
Account
|
||||
+- direct system-role assignments
|
||||
```
|
||||
|
||||
A browser session has one active tenant membership. System privileges do not
|
||||
silently grant tenant data access. API keys remain tenant-local and receive the
|
||||
intersection of their configured scopes and their owner's live tenant scopes on
|
||||
every request.
|
||||
|
||||
## Wildcards
|
||||
|
||||
```text
|
||||
tenant:* every canonical tenant permission
|
||||
system:* every canonical system permission
|
||||
* legacy alias interpreted as tenant:* only
|
||||
```
|
||||
|
||||
Tenant wildcards never grant system permissions.
|
||||
|
||||
## Canonical Tenant Permissions
|
||||
|
||||
Campaigns:
|
||||
|
||||
```text
|
||||
campaign:read
|
||||
campaign:create
|
||||
campaign:update
|
||||
campaign:copy
|
||||
campaign:archive
|
||||
campaign:delete
|
||||
campaign:share
|
||||
campaign:validate
|
||||
campaign:build
|
||||
campaign:review
|
||||
campaign:send_test
|
||||
campaign:queue
|
||||
campaign:control
|
||||
campaign:send
|
||||
campaign:retry
|
||||
campaign:reconcile
|
||||
```
|
||||
|
||||
Recipients:
|
||||
|
||||
```text
|
||||
recipients:read
|
||||
recipients:write
|
||||
recipients:import
|
||||
recipients:export
|
||||
```
|
||||
|
||||
Files:
|
||||
|
||||
```text
|
||||
files:read
|
||||
files:download
|
||||
files:upload
|
||||
files:organize
|
||||
files:share
|
||||
files:delete
|
||||
files:admin
|
||||
```
|
||||
|
||||
Reports and audit:
|
||||
|
||||
```text
|
||||
reports:read
|
||||
reports:export
|
||||
reports:send
|
||||
audit:read
|
||||
```
|
||||
|
||||
Mail servers:
|
||||
|
||||
```text
|
||||
mail_servers:read
|
||||
mail_servers:use
|
||||
mail_servers:test
|
||||
mail_servers:write
|
||||
mail_servers:manage_credentials
|
||||
```
|
||||
|
||||
Tenant administration:
|
||||
|
||||
```text
|
||||
admin:users:read
|
||||
admin:users:create
|
||||
admin:users:update
|
||||
admin:users:suspend
|
||||
|
||||
admin:groups:read
|
||||
admin:groups:write
|
||||
admin:groups:manage_members
|
||||
|
||||
admin:roles:read
|
||||
admin:roles:write
|
||||
admin:roles:assign
|
||||
|
||||
admin:api_keys:read
|
||||
admin:api_keys:create
|
||||
admin:api_keys:revoke
|
||||
|
||||
admin:settings:read
|
||||
admin:settings:write
|
||||
admin:policies:read
|
||||
admin:policies:write
|
||||
```
|
||||
|
||||
## Canonical System Permissions
|
||||
|
||||
```text
|
||||
system:tenants:read
|
||||
system:tenants:create
|
||||
system:tenants:update
|
||||
system:tenants:suspend
|
||||
|
||||
system:accounts:read
|
||||
system:accounts:create
|
||||
system:accounts:update
|
||||
system:accounts:suspend
|
||||
|
||||
system:roles:read
|
||||
system:roles:write
|
||||
system:roles:assign
|
||||
|
||||
system:access:read
|
||||
system:access:assign
|
||||
|
||||
system:audit:read
|
||||
system:settings:read
|
||||
system:settings:write
|
||||
system:governance:read
|
||||
system:governance:write
|
||||
```
|
||||
|
||||
`system:access:*` remains a read/assignment boundary for cross-tenant and
|
||||
system access handling. It is not a separate primary UI area.
|
||||
|
||||
## Default Tenant Roles
|
||||
|
||||
- **Owner:** `tenant:*`. At least one active operational owner must remain.
|
||||
- **Tenant administrator:** settings, policies, users, groups, roles, API keys,
|
||||
and read access to campaigns/files/reports/audit. Real delivery remains
|
||||
separately delegable.
|
||||
- **Administrator:** all tenant permissions for upgraded installations.
|
||||
- **Access administrator:** membership and assignment management within
|
||||
delegation limits.
|
||||
- **Campaign manager:** prepare, validate, and build campaigns; no review
|
||||
approval or real delivery by default.
|
||||
- **Reviewer:** inspect and approve prepared campaign messages.
|
||||
- **Sender:** mock-test, queue, control, send, retry, and reconcile prepared
|
||||
campaigns; can use/test approved mail profiles.
|
||||
- **File manager:** managed file operations without campaign delivery rights.
|
||||
- **Viewer:** read campaigns, recipients, files, and reports.
|
||||
- **Auditor:** read campaigns, recipient evidence, reports, and audit records;
|
||||
export detailed evidence.
|
||||
|
||||
## Default System Roles
|
||||
|
||||
- **System owner:** `system:*`, protected. At least one active account must
|
||||
retain it.
|
||||
- **System administrator:** all specific system permissions, editable and not
|
||||
protected.
|
||||
- **System auditor:** read-only system registry/settings/governance/audit role,
|
||||
editable.
|
||||
|
||||
## Delegation Ceiling
|
||||
|
||||
For role definition, assignment, and API-key creation:
|
||||
|
||||
```text
|
||||
requested scopes subset of actor delegateable scopes
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
1. Tenant roles may contain tenant scopes only.
|
||||
2. System roles may contain system scopes only.
|
||||
3. Definition rights and assignment rights are separate.
|
||||
4. Group definition and group membership management are separate.
|
||||
5. API-key scopes are intersected with the owner's current effective scopes on
|
||||
every request.
|
||||
6. Suspended accounts, users, tenants, or groups stop contributing access
|
||||
immediately.
|
||||
7. Administrative updates are field-sensitive; a user with only status
|
||||
authority cannot change role assignments.
|
||||
|
||||
## Campaign Ownership And ACLs
|
||||
|
||||
A campaign has exactly one owner:
|
||||
|
||||
```text
|
||||
owner user OR owner group
|
||||
```
|
||||
|
||||
Additional active shares may target users or groups with `read` or `write`.
|
||||
|
||||
Resolution:
|
||||
|
||||
- owner user: read and write;
|
||||
- member of owner group: read and write;
|
||||
- explicit read share: read;
|
||||
- explicit write share: read and write;
|
||||
- `tenant:*`: tenant-wide ACL bypass;
|
||||
- ordinary campaign permission without ownership/share: no object access.
|
||||
|
||||
ACLs do not add capabilities. A write share still needs the specific permission
|
||||
for update, validation, review, send, report, retry, or reconciliation.
|
||||
|
||||
## Files
|
||||
|
||||
The current file access model distinguishes tenant-level file capabilities from
|
||||
space/folder/file ownership:
|
||||
|
||||
| Scope | Meaning |
|
||||
| --- | --- |
|
||||
| `files:read` | browse/read visible file spaces and metadata |
|
||||
| `files:download` | download file content when ACL permits |
|
||||
| `files:upload` | create files in writable spaces |
|
||||
| `files:organize` | create folders, move files, and update metadata where ACL permits |
|
||||
| `files:share` | share files/spaces according to owner and policy rules |
|
||||
| `files:delete` | delete or retire files where ACL permits |
|
||||
| `files:admin` | tenant-wide administration of user/group file spaces |
|
||||
|
||||
External file connections and spaces are additionally constrained by connector
|
||||
policy and owner/group assignment in the files module.
|
||||
|
||||
## Mail Servers
|
||||
|
||||
| Scope | Meaning |
|
||||
| --- | --- |
|
||||
| `mail_servers:read` | profile metadata and effective policy visibility |
|
||||
| `mail_servers:use` | use an allowed profile for a campaign or message flow |
|
||||
| `mail_servers:test` | run connectivity tests without revealing secrets |
|
||||
| `mail_servers:write` | create/update profile metadata where policy allows |
|
||||
| `mail_servers:manage_credentials` | create/replace SMTP/IMAP secrets or lower-level credentials where policy allows |
|
||||
|
||||
Reusable encrypted profiles exist. Effective usability is also constrained by
|
||||
hierarchical mail-profile policy, ownership, allowed/forced profile sets,
|
||||
credential inheritance mode, lower-level override switches, and allow/deny
|
||||
patterns.
|
||||
|
||||
## Compatibility Aliases
|
||||
|
||||
Compatibility aliases may exist in backend code for upgraded installations, but
|
||||
new UI and docs should use canonical scopes.
|
||||
|
||||
Current alias direction:
|
||||
|
||||
```text
|
||||
* -> tenant:*
|
||||
system:tenants:write -> create/update/suspend tenant scopes
|
||||
system:access:write -> system access assignment/write scopes
|
||||
```
|
||||
|
||||
A separate `retention:*` family is not currently canonical because retention is
|
||||
managed through system settings and tenant policy scopes. Add it only if
|
||||
retention operation duties need separation from general policy/settings
|
||||
administration.
|
||||
121
docs/ACTION_EFFECT_AUTOMATION_LAYER.md
Normal file
121
docs/ACTION_EFFECT_AUTOMATION_LAYER.md
Normal file
@@ -0,0 +1,121 @@
|
||||
# Action, Effect, And Automation Layer
|
||||
|
||||
GovOPlaN needs an automation layer because administrative processes will not be
|
||||
only linear screen flows. Workflows, schedules, imports, connectors, policies,
|
||||
and external events all need to request governed actions without bypassing the
|
||||
same safety rules that apply to human users.
|
||||
|
||||
The first implementation should live in `govoplan-workflow` and core contracts.
|
||||
Create a separate `govoplan-automation` module only if action planning,
|
||||
schedulers, rule execution, or cross-module automation become too broad for
|
||||
workflow ownership.
|
||||
|
||||
## Layer Purpose
|
||||
|
||||
The automation layer should provide:
|
||||
|
||||
- a typed action catalogue
|
||||
- a typed effect catalogue
|
||||
- consequence preview before execution
|
||||
- policy and permission checks
|
||||
- idempotent execution
|
||||
- audit and provenance records
|
||||
- retry, quarantine, and manual exception handling
|
||||
- system-actor execution without hiding responsibility
|
||||
|
||||
Automation is not a shortcut around module boundaries. It is a governed caller
|
||||
of module capabilities.
|
||||
|
||||
## Action Definition
|
||||
|
||||
An `ActionDefinition` describes something a human or system actor can request.
|
||||
|
||||
Recommended fields:
|
||||
|
||||
- `action_key`
|
||||
- owning module
|
||||
- input schema
|
||||
- actor requirements and required scopes
|
||||
- required capabilities
|
||||
- policy checks
|
||||
- risk level
|
||||
- reversibility class: reversible, compensatable, corrective-only, or
|
||||
irreversible
|
||||
- expected effects
|
||||
- idempotency key strategy
|
||||
- audit event names
|
||||
- preview provider
|
||||
|
||||
Examples:
|
||||
|
||||
- create a case from a form submission
|
||||
- assign a task
|
||||
- generate a document from a template
|
||||
- send a postbox message
|
||||
- send an email notification
|
||||
- append evidence to records
|
||||
- create a payment request
|
||||
- call an external connector
|
||||
|
||||
## Effect Definition
|
||||
|
||||
An `EffectDefinition` describes the expected and observed result of an action.
|
||||
|
||||
Recommended fields:
|
||||
|
||||
- `effect_key`
|
||||
- affected module and resource references
|
||||
- external system references where applicable
|
||||
- created, changed, deleted, sent, notified, locked, or retained markers
|
||||
- visibility and privacy classification
|
||||
- audit event references
|
||||
- rollback or compensation hints
|
||||
- operator-facing explanation
|
||||
|
||||
Effects should be recorded even when execution fails partially. This makes
|
||||
manual recovery and audit review possible.
|
||||
|
||||
## Execution Model
|
||||
|
||||
The runner should execute an action plan as follows:
|
||||
|
||||
1. Resolve actor context: human, delegated actor, or system actor.
|
||||
2. Validate input schema.
|
||||
3. Resolve required module capabilities.
|
||||
4. Run permission and policy checks.
|
||||
5. Generate a consequence preview.
|
||||
6. Reserve or verify the idempotency key.
|
||||
7. Execute the owning module capability.
|
||||
8. Record observed effects.
|
||||
9. Emit events and audit records.
|
||||
10. Mark the command complete, retryable, quarantined, or requiring manual
|
||||
intervention.
|
||||
|
||||
The runner must never advance workflow state past a required side effect unless
|
||||
the action definition explicitly allows asynchronous completion and the pending
|
||||
state is visible.
|
||||
|
||||
## Failure States
|
||||
|
||||
Automation should use explicit failure states:
|
||||
|
||||
- `blocked`: policy, permission, missing capability, or invalid input prevents
|
||||
execution.
|
||||
- `retryable`: transient transport, timeout, rate-limit, or lock conflict.
|
||||
- `quarantined`: unexpected response, schema mismatch, unsafe partial result,
|
||||
or unknown external state.
|
||||
- `manual_required`: human decision or correction is needed.
|
||||
- `compensation_required`: a later action must correct an already observed
|
||||
side effect.
|
||||
|
||||
These states should be visible in workflow, task, and admin diagnostics.
|
||||
|
||||
## Boundary
|
||||
|
||||
Core may own stable DTOs, registry contracts, and generic audit/event hooks.
|
||||
`govoplan-workflow` should own the first runner because workflow is the first
|
||||
module that coordinates cross-module process actions.
|
||||
|
||||
Domain modules own their own action providers. For example, templates own
|
||||
document generation actions, postbox owns postbox message actions, and
|
||||
connectors own external handoff actions.
|
||||
@@ -1,185 +0,0 @@
|
||||
# Module Catalog Trust And Licensing
|
||||
|
||||
GovOPlaN module install and uninstall must remain operator-controlled. The
|
||||
running server may plan and validate package changes, but package mutation is
|
||||
performed by the separate installer daemon or an operator shell during
|
||||
maintenance mode.
|
||||
|
||||
## Roles
|
||||
|
||||
`govoplan-web` is the public static distribution surface for official catalog
|
||||
resources:
|
||||
|
||||
- signed module package catalogs, grouped by release channel
|
||||
- public catalog keyrings
|
||||
- public license verification keyrings
|
||||
- examples and operator-facing download paths
|
||||
|
||||
`govoplan-core` is the verifier and orchestrator:
|
||||
|
||||
- fetches a local or remote module catalog
|
||||
- verifies catalog signatures against configured trusted keys
|
||||
- enforces approved release channels
|
||||
- rejects expired or not-yet-valid catalogs
|
||||
- records accepted catalog sequence numbers for replay protection
|
||||
- checks catalog entry license feature requirements before planning installs
|
||||
- writes installer plans and request records
|
||||
|
||||
Feature and platform modules own their package artifacts, manifests, migration
|
||||
metadata, retirement providers, and optional lifecycle behavior.
|
||||
|
||||
## Catalog Source
|
||||
|
||||
Core accepts either a local catalog file or a remote URL:
|
||||
|
||||
```bash
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG=/srv/govoplan/catalogs/stable.json
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_URL=https://govoplan.example/catalogs/v1/channels/stable.json
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_CACHE=/srv/govoplan/runtime/catalog-cache/stable.json
|
||||
```
|
||||
|
||||
If both file and URL are set, the URL wins. The cache is used when a remote
|
||||
fetch fails, so an operator can still inspect the last known catalog. A cached
|
||||
catalog must still pass signature, freshness, channel, and replay validation.
|
||||
|
||||
## Catalog Shape
|
||||
|
||||
An official catalog is a JSON object with:
|
||||
|
||||
- `catalog_version`
|
||||
- `channel`
|
||||
- `sequence`
|
||||
- `generated_at`
|
||||
- `not_before` when delayed activation is needed
|
||||
- `expires_at`
|
||||
- `modules`
|
||||
- `signatures`
|
||||
|
||||
Each module entry can declare:
|
||||
|
||||
- backend package name and pinned install reference
|
||||
- WebUI package name and pinned install reference
|
||||
- display metadata and tags
|
||||
- `license_features`, the feature entitlements required to plan that install
|
||||
|
||||
The signature is Ed25519 over canonical JSON with both `signature` and
|
||||
`signatures` removed. Core accepts the legacy single `signature` field and the
|
||||
new `signatures` array.
|
||||
|
||||
## Keyrings And Rotation
|
||||
|
||||
Trusted catalog keys are configured locally:
|
||||
|
||||
```bash
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_TRUSTED_KEYS_FILE=/srv/govoplan/trust/catalog-keyring.json
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_TRUSTED_KEYS='{"release-key-1":"<base64 public key>"}'
|
||||
```
|
||||
|
||||
For development or tightly controlled deployments, a keyring can be read from a
|
||||
URL and cached:
|
||||
|
||||
```bash
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_TRUSTED_KEYS_URL=https://govoplan.example/catalogs/v1/keyring.json
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_TRUSTED_KEYS_CACHE=/srv/govoplan/runtime/catalog-cache/keyring.json
|
||||
```
|
||||
|
||||
Production installations should pin the trusted keyring locally or ship it
|
||||
through deployment configuration. Fetching trusted keys from the same public
|
||||
origin as the catalog is convenient, but that origin must not become the only
|
||||
trust root.
|
||||
|
||||
Keyring entries support:
|
||||
|
||||
- `key_id`
|
||||
- `public_key` or `public_key_base64`
|
||||
- `status`: `active`, `next`, `retired`, `revoked`, or `disabled`
|
||||
- `not_before`
|
||||
- `not_after`
|
||||
|
||||
Rotation process:
|
||||
|
||||
1. Add the next public key to the local trusted keyring with status `next`.
|
||||
2. Publish catalogs signed by both current and next keys.
|
||||
3. Upgrade installations so the next key is locally trusted.
|
||||
4. Promote the next key to `active`.
|
||||
5. Retire the old key only after every supported installation trusts the new
|
||||
key.
|
||||
6. Mark a compromised key `revoked` and publish a higher sequence catalog
|
||||
signed by an uncompromised key.
|
||||
|
||||
## Replay And Freshness
|
||||
|
||||
Use replay state in production:
|
||||
|
||||
```bash
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_SEQUENCE_STATE=/srv/govoplan/runtime/catalog-sequences.json
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_ENFORCE_SEQUENCE=true
|
||||
```
|
||||
|
||||
Core records the accepted sequence per channel after a catalog entry is planned
|
||||
from the admin interface. With strict sequence enforcement, a previously
|
||||
accepted sequence is rejected; without strict enforcement, only older sequences
|
||||
are rejected.
|
||||
|
||||
Catalogs should always expire. Long-lived catalogs make rollback and key
|
||||
compromise harder to reason about.
|
||||
|
||||
## Release Channels
|
||||
|
||||
Approved channels are deployment policy:
|
||||
|
||||
```bash
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_APPROVED_CHANNELS=stable,lts
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_REQUIRE_SIGNATURE=true
|
||||
```
|
||||
|
||||
The admin UI can display other catalog metadata, but core rejects catalogs from
|
||||
unapproved channels when validation is configured.
|
||||
|
||||
## Licensing
|
||||
|
||||
Catalog entries can require license features:
|
||||
|
||||
```json
|
||||
"license_features": ["module.mail", "support.standard"]
|
||||
```
|
||||
|
||||
Core checks those requirements against an offline license file before allowing
|
||||
the entry into the install plan.
|
||||
|
||||
```bash
|
||||
GOVOPLAN_LICENSE_FILE=/srv/govoplan/license.json
|
||||
GOVOPLAN_LICENSE_ENFORCEMENT=true
|
||||
GOVOPLAN_LICENSE_TRUSTED_KEYS_FILE=/srv/govoplan/trust/license-keyring.json
|
||||
```
|
||||
|
||||
License files are JSON objects with:
|
||||
|
||||
- `license_id`
|
||||
- `subject`
|
||||
- `features`
|
||||
- `valid_from`
|
||||
- `valid_until`
|
||||
- `signature`
|
||||
|
||||
License enforcement can run in observe-only mode by leaving
|
||||
`GOVOPLAN_LICENSE_ENFORCEMENT` unset. In that mode, missing or invalid license
|
||||
data is surfaced as a warning but does not block planning.
|
||||
|
||||
Licensing is intentionally separate from open-source code licensing. The
|
||||
catalog/license mechanism can govern support channels, official release
|
||||
eligibility, hosted update access, professional support, or commercial
|
||||
entitlements without changing the source license of the repositories.
|
||||
|
||||
## Production Gaps
|
||||
|
||||
The current implementation validates signed catalog metadata and offline
|
||||
license entitlements. Production-grade distribution still needs:
|
||||
|
||||
- artifact digest verification for package archives or registry artifacts
|
||||
- SBOM/provenance fields and verification workflow
|
||||
- hardened catalog publishing pipeline in `govoplan-web`
|
||||
- automated key rotation runbook and emergency revocation procedure
|
||||
- license issuance and renewal tooling
|
||||
- tests for remote catalog cache fallback and replay-state upgrades
|
||||
|
||||
@@ -27,6 +27,12 @@ trust_level = "trusted"
|
||||
[projects."/mnt/DATA/git/govoplan-access"]
|
||||
trust_level = "trusted"
|
||||
|
||||
[projects."/mnt/DATA/git/govoplan-organizations"]
|
||||
trust_level = "trusted"
|
||||
|
||||
[projects."/mnt/DATA/git/govoplan-identity"]
|
||||
trust_level = "trusted"
|
||||
|
||||
[projects."/mnt/DATA/git/govoplan-mail"]
|
||||
trust_level = "trusted"
|
||||
|
||||
|
||||
@@ -9,6 +9,13 @@ Example: an application-handling package could configure a public portal form,
|
||||
a case workflow, task creation, a mail template, payment processing, access
|
||||
roles, audit evidence, and the interface bindings between those modules.
|
||||
|
||||
The guiding reference scenario is the government-operations permit journey in
|
||||
`docs/GOVOPLAN_MASTER_ROADMAP.md`: a person applies through the portal,
|
||||
uploads files, receives workflow-driven messages and appointment proposals, has
|
||||
a case opened, gets a permit generated from a template, and completes payment.
|
||||
Configuration packages are the mechanism that should make such processes
|
||||
reusable and safely importable.
|
||||
|
||||
This document is durable architecture context and should be mirrored to the
|
||||
Gitea wiki. Active implementation should be tracked in Gitea issues.
|
||||
|
||||
@@ -97,6 +104,33 @@ export(selection, context) -> fragment, data_placeholders, warnings
|
||||
health(import_result, context) -> diagnostics
|
||||
```
|
||||
|
||||
The initial core contract lives in
|
||||
`govoplan_core.core.configuration_packages`. Modules register providers through
|
||||
module-specific capability keys and implement the `ConfigurationProvider`
|
||||
protocol. The generic `configuration.provider` key names the contract and can be
|
||||
used in package requirements; concrete providers such as `access.configuration`
|
||||
are resolved by the admin package wizard. The first DTO surface includes package
|
||||
manifests, module/capability requirements, module-owned fragments, diagnostics,
|
||||
required operator data, dry-run plan items, apply results, export selections,
|
||||
and export results.
|
||||
|
||||
The initial implementation includes provider-neutral orchestration helpers:
|
||||
|
||||
- `dry_run_configuration_package(...)`
|
||||
- `apply_configuration_package(...)`
|
||||
- `export_configuration_package(...)`
|
||||
|
||||
The first concrete provider is `govoplan_access.backend.configuration_provider`.
|
||||
It supports access-owned `roles`, `groups`, and `group_role_assignments`
|
||||
fragments and applies them idempotently.
|
||||
|
||||
The admin wizard backend starts with these routes:
|
||||
|
||||
- `GET /api/v1/admin/configuration-packages/catalog`
|
||||
- `POST /api/v1/admin/configuration-packages/dry-run`
|
||||
- `POST /api/v1/admin/configuration-packages/apply`
|
||||
- `POST /api/v1/admin/configuration-packages/export`
|
||||
|
||||
## Import Flow
|
||||
|
||||
1. Select a package from a trusted catalog or upload a package file.
|
||||
@@ -168,6 +202,20 @@ Configuration catalogs should follow the existing module package catalog model:
|
||||
a file-backed or remotely fetched JSON catalog with Ed25519 signatures, channel
|
||||
gating, trusted key ids, and operator-controlled trust policy.
|
||||
|
||||
The initial catalog validator mirrors the module catalog environment model with
|
||||
configuration-specific names:
|
||||
|
||||
```bash
|
||||
GOVOPLAN_CONFIGURATION_PACKAGE_CATALOG=/srv/govoplan/configuration-catalogs/stable.json
|
||||
GOVOPLAN_CONFIGURATION_PACKAGE_CATALOG_URL=https://govoplan.example/configuration-catalogs/stable.json
|
||||
GOVOPLAN_CONFIGURATION_PACKAGE_CATALOG_CACHE=/srv/govoplan/runtime/configuration-catalog-cache/stable.json
|
||||
GOVOPLAN_CONFIGURATION_PACKAGE_CATALOG_REQUIRE_SIGNATURE=true
|
||||
GOVOPLAN_CONFIGURATION_PACKAGE_CATALOG_APPROVED_CHANNELS=stable,lts
|
||||
GOVOPLAN_CONFIGURATION_PACKAGE_CATALOG_TRUSTED_KEYS_FILE=/srv/govoplan/trust/configuration-catalog-keyring.json
|
||||
GOVOPLAN_CONFIGURATION_PACKAGE_CATALOG_SEQUENCE_STATE=/srv/govoplan/runtime/configuration-catalog-sequences.json
|
||||
GOVOPLAN_CONFIGURATION_PACKAGE_CATALOG_ENFORCE_SEQUENCE=true
|
||||
```
|
||||
|
||||
Catalog entries should include:
|
||||
|
||||
- package id, version, name, description, publisher, tags, and channel
|
||||
|
||||
67
docs/DEPENDENCY_AUDITS.md
Normal file
67
docs/DEPENDENCY_AUDITS.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# Dependency Audits
|
||||
|
||||
GovOPlaN keeps dependency vulnerability checks reproducible but separate from
|
||||
the fast local smoke suite, because both Python and npm audits need network
|
||||
metadata and can fail for newly disclosed advisories without a source change.
|
||||
|
||||
## Local Workflow
|
||||
|
||||
Install the development audit dependency once:
|
||||
|
||||
```bash
|
||||
cd /mnt/DATA/git/govoplan-core
|
||||
./.venv/bin/python -m pip install -r requirements-dev.txt
|
||||
```
|
||||
|
||||
Run both backend and WebUI production audits:
|
||||
|
||||
```bash
|
||||
cd /mnt/DATA/git/govoplan-core
|
||||
bash scripts/check-dependency-audits.sh
|
||||
```
|
||||
|
||||
The script runs:
|
||||
|
||||
- `scripts/check-dependency-hygiene.sh` for pip resolver consistency, stale
|
||||
legacy editable package metadata, deprecated framework constants, and the
|
||||
Starlette `TestClient` deprecation smoke when test dependencies are present
|
||||
- `python -m pip_audit --progress-spinner off`
|
||||
- `npm audit --omit=dev` in `webui`
|
||||
|
||||
For fast local checks without vulnerability metadata lookups, run:
|
||||
|
||||
```bash
|
||||
cd /mnt/DATA/git/govoplan-core
|
||||
CHECK_TESTCLIENT_DEPRECATIONS=1 bash scripts/check-dependency-hygiene.sh
|
||||
```
|
||||
|
||||
This is also part of `scripts/check-focused.sh`, so resolver drift and
|
||||
deprecation regressions fail close to the code change that introduced them.
|
||||
|
||||
Override tool paths when testing from a disposable environment:
|
||||
|
||||
```bash
|
||||
PYTHON=/tmp/govoplan-audit/bin/python \
|
||||
NPM=/home/zemion/.nvm/versions/node/v22.22.3/bin/npm \
|
||||
bash scripts/check-dependency-audits.sh
|
||||
```
|
||||
|
||||
## CI Workflow
|
||||
|
||||
`.gitea/workflows/dependency-audit.yml` installs release dependencies from
|
||||
tagged package refs, installs `pip-audit`, and runs the same script on pushes,
|
||||
pull requests, and a weekly schedule.
|
||||
|
||||
The workflow intentionally uses release dependency refs instead of local
|
||||
`file:` or editable sibling paths. Development lockfiles may keep local module
|
||||
links, but release audit results should represent the installable product.
|
||||
|
||||
## Recording Results
|
||||
|
||||
When closing or triaging dependency-audit issues, add a short dated note under
|
||||
`docs/audits/`. Record:
|
||||
|
||||
- the commands that were run
|
||||
- whether Python and npm passed
|
||||
- any advisories accepted as temporary risk
|
||||
- follow-up issue links for required upgrades
|
||||
390
docs/DEPLOYMENT_OPERATOR_GUIDE.md
Normal file
390
docs/DEPLOYMENT_OPERATOR_GUIDE.md
Normal file
@@ -0,0 +1,390 @@
|
||||
# GovOPlaN Deployment Operator Guide
|
||||
|
||||
This guide defines the current install/runtime configuration contract and the
|
||||
operator flow for a production-realistic self-hosted deployment. Keep secrets in
|
||||
the deployment environment or a secret manager; do not commit populated `.env`
|
||||
files.
|
||||
|
||||
## Runtime Configuration Contract
|
||||
|
||||
### Required Runtime Identity
|
||||
|
||||
| Setting | Required outside dev | Purpose |
|
||||
| --- | --- | --- |
|
||||
| `APP_ENV` | yes | Runtime profile. Use `prod`, `staging`, or a deployment-specific value outside local development. |
|
||||
| `MASTER_KEY_B64` | yes | Fernet key or base64 encoded 32-byte key used for encrypted module secrets. Rotate through an explicit operator plan. |
|
||||
| `DATABASE_URL` | yes | SQLAlchemy database URL for core and installed modules. SQLite is supported for dev/small installs; PostgreSQL is the preferred production target. |
|
||||
| `ENABLED_MODULES` | yes | Comma-separated startup module set. Keep `tenancy,access` enabled; keep `admin` enabled for operator UI. |
|
||||
|
||||
Generate a local key for a new non-production environment:
|
||||
|
||||
```bash
|
||||
python - <<'PY'
|
||||
from cryptography.fernet import Fernet
|
||||
print(Fernet.generate_key().decode())
|
||||
PY
|
||||
```
|
||||
|
||||
### Database And Migrations
|
||||
|
||||
| Setting | Default | Notes |
|
||||
| --- | --- | --- |
|
||||
| `DATABASE_URL` | `postgresql+psycopg://govoplan_dev@127.0.0.1:5432/govoplan_dev` | Local development and production-like profiles use PostgreSQL. Use `GOVOPLAN_DEV_DATABASE_BACKEND=sqlite` only for disposable SQLite runs. |
|
||||
| `DEV_AUTO_MIGRATE_ENABLED` | `true` | Dev convenience only. Production should run migration commands explicitly during deployment. |
|
||||
| `DEV_BOOTSTRAP_ENABLED` | `false` | Dev bootstrap only. `govoplan_core.devserver` and `scripts/launch-dev.sh` default it to `true`; use controlled first-admin creation outside dev. |
|
||||
|
||||
Operator rule: take a database backup before applying migrations or destructive
|
||||
module retirement. For non-SQLite databases, configure deployment-specific
|
||||
backup/restore hooks for the module installer.
|
||||
|
||||
### PostgreSQL Production Target
|
||||
|
||||
PostgreSQL is the primary development and production target. SQLite remains
|
||||
supported only for tiny disposable profiles and unit-test style smoke runs.
|
||||
Production/staging deployments should use a managed PostgreSQL database and
|
||||
explicit migration commands.
|
||||
|
||||
Install the server extra so the `psycopg` driver is available:
|
||||
|
||||
```bash
|
||||
cd /mnt/DATA/git/govoplan-core
|
||||
./.venv/bin/python -m pip install -r requirements-release.txt
|
||||
```
|
||||
|
||||
Example runtime database URLs:
|
||||
|
||||
```bash
|
||||
export DATABASE_URL='postgresql+psycopg://govoplan:change-me@db.example.internal:5432/govoplan'
|
||||
export GOVOPLAN_DATABASE_URL_PGTOOLS='postgresql://govoplan:change-me@db.example.internal:5432/govoplan'
|
||||
```
|
||||
|
||||
Use the SQLAlchemy URL for GovOPlaN. Use the pg-tools URL for `pg_dump`,
|
||||
`pg_restore`, and `psql`; these tools do not understand the
|
||||
`postgresql+psycopg://` driver marker.
|
||||
|
||||
Bootstrap or upgrade the schema explicitly during deployment:
|
||||
|
||||
```bash
|
||||
export APP_ENV=prod
|
||||
export ENABLED_MODULES=tenancy,access,admin,policy,audit,campaigns,files,mail,calendar,docs,ops
|
||||
./.venv/bin/python -m govoplan_core.commands.init_db \
|
||||
--database-url "$DATABASE_URL"
|
||||
```
|
||||
|
||||
Backup and restore-check before migration-bearing package changes:
|
||||
|
||||
```bash
|
||||
pg_dump --format=custom \
|
||||
--file "$PWD/runtime/govoplan-$(date +%Y%m%d%H%M%S).dump" \
|
||||
"$GOVOPLAN_DATABASE_URL_PGTOOLS"
|
||||
pg_restore --list "$PWD/runtime/govoplan-YYYYMMDDHHMMSS.dump" >/dev/null
|
||||
```
|
||||
|
||||
Restore a checked backup to the target database:
|
||||
|
||||
```bash
|
||||
pg_restore --clean --if-exists \
|
||||
--dbname "$GOVOPLAN_DATABASE_URL_PGTOOLS" \
|
||||
"$PWD/runtime/govoplan-YYYYMMDDHHMMSS.dump"
|
||||
```
|
||||
|
||||
For local development, create the host database described in
|
||||
`dev/postgres/README.md`, then run:
|
||||
|
||||
```bash
|
||||
cd /mnt/DATA/git/govoplan-core
|
||||
./.venv/bin/python -m govoplan_core.commands.init_db \
|
||||
--database-url postgresql+psycopg://govoplan_dev@127.0.0.1:5432/govoplan_dev \
|
||||
--with-dev-data
|
||||
./.venv/bin/python -m govoplan_core.devserver --smoke --no-reload
|
||||
scripts/launch-dev.sh
|
||||
```
|
||||
|
||||
For disposable local validation against a throwaway PostgreSQL instance, use
|
||||
the bundled PostgreSQL testbed:
|
||||
|
||||
```bash
|
||||
cd /mnt/DATA/git/govoplan-core/dev/postgres
|
||||
cp .env.example .env
|
||||
docker compose --env-file .env up -d
|
||||
|
||||
cd /mnt/DATA/git/govoplan-core
|
||||
set -a
|
||||
. dev/postgres/.env
|
||||
set +a
|
||||
./.venv/bin/python scripts/postgres-integration-check.py \
|
||||
--database-url "$GOVOPLAN_POSTGRES_DATABASE_URL" \
|
||||
--reset-schema
|
||||
```
|
||||
|
||||
The integration check runs migrations and startup smoke checks across the
|
||||
standard module permutations. `--reset-schema` is destructive and belongs only
|
||||
on throwaway databases.
|
||||
|
||||
### Broker And Workers
|
||||
|
||||
| Setting | Default | Notes |
|
||||
| --- | --- | --- |
|
||||
| `REDIS_URL` | `redis://redis:6379/0` | Celery broker/result backend when async workers are enabled. |
|
||||
| `CELERY_ENABLED` | `false` | Local/dev can send synchronously. Production campaign delivery should run workers and set this to `true`. |
|
||||
| `CELERY_QUEUES` | `send_email,append_sent,default` | Queue list expected by worker/process manager definitions. |
|
||||
|
||||
Worker command:
|
||||
|
||||
```bash
|
||||
python -m celery -A govoplan_core.celery_app:celery worker \
|
||||
--queues send_email,append_sent,default \
|
||||
--loglevel INFO
|
||||
```
|
||||
|
||||
### Storage
|
||||
|
||||
| Setting | Default | Notes |
|
||||
| --- | --- | --- |
|
||||
| `FILE_STORAGE_BACKEND` | `local` | Use `local` for dev/small deployments; use object storage when files must scale independently. |
|
||||
| `FILE_STORAGE_LOCAL_ROOT` | `runtime/files` | Must live on durable storage and be backed up when `FILE_STORAGE_BACKEND=local`. |
|
||||
| `FILE_STORAGE_LOCAL_FALLBACK_ROOTS` | empty | Read-only fallback roots for migrated local files. |
|
||||
| `FILE_STORAGE_S3_ENDPOINT_URL` | empty | Object-store endpoint for the files module. |
|
||||
| `FILE_STORAGE_S3_REGION` | empty | Object-store region. |
|
||||
| `FILE_STORAGE_S3_ACCESS_KEY_ID` | empty | Secret; inject through deployment environment. |
|
||||
| `FILE_STORAGE_S3_SECRET_ACCESS_KEY` | empty | Secret; inject through deployment environment. |
|
||||
| `FILE_STORAGE_S3_BUCKET` | `files` | Managed-file object bucket. |
|
||||
|
||||
Legacy `S3_*` settings remain for older storage paths but new deployments should
|
||||
prefer `FILE_STORAGE_*`.
|
||||
|
||||
### HTTP, Cookies, And Base URLs
|
||||
|
||||
| Setting | Default | Notes |
|
||||
| --- | --- | --- |
|
||||
| `CORS_ORIGINS` | local dev origins | Set to the exact WebUI origins in staging/production. |
|
||||
| `AUTH_SESSION_COOKIE_NAME` | configured default | Change only through a controlled rollout because it logs users out. |
|
||||
| `AUTH_CSRF_COOKIE_NAME` | configured default | Must match WebUI/API deployment. |
|
||||
| `AUTH_COOKIE_SECURE` | `false` | Set `true` behind HTTPS. |
|
||||
| `AUTH_COOKIE_SAMESITE` | `lax` | Use a stricter value only after testing login and CSRF flows. |
|
||||
| `AUTH_COOKIE_DOMAIN` | empty | Set only when the API and WebUI intentionally share a parent domain. |
|
||||
|
||||
Public URLs are currently supplied by deployment/reverse-proxy configuration and
|
||||
module settings. Do not hardcode them in core; configuration packages should ask
|
||||
for portal, WebUI, postbox, and notification URLs when they become relevant.
|
||||
|
||||
### Module Catalogs, Licenses, And Trust Roots
|
||||
|
||||
| Setting | Purpose |
|
||||
| --- | --- |
|
||||
| `GOVOPLAN_MODULE_PACKAGE_CATALOG_URL` or `GOVOPLAN_MODULE_PACKAGE_CATALOG` | Module package catalog source. |
|
||||
| `GOVOPLAN_MODULE_PACKAGE_CATALOG_TRUSTED_KEYS_FILE` | Preferred production keyring path. |
|
||||
| `GOVOPLAN_MODULE_PACKAGE_CATALOG_APPROVED_CHANNEL` | Approved catalog channel, for example `stable`. |
|
||||
| `GOVOPLAN_LICENSE_TRUSTED_KEYS_FILE` | Trusted license issuer keyring path. |
|
||||
| `GOVOPLAN_LICENSE_ENFORCEMENT` | Enables license enforcement when set to `true`. |
|
||||
|
||||
Trust roots are deployment-managed and should not be editable through the
|
||||
running WebUI.
|
||||
|
||||
### Mail Test Credentials
|
||||
|
||||
Dedicated SMTP/IMAP test credentials belong to the mail/campaign test-bed
|
||||
configuration, not the core runtime contract. Store them in a local ignored
|
||||
`.env` file for the test bed or in CI secrets. Required values are:
|
||||
|
||||
- SMTP host, port, TLS mode, username, password, and envelope/from address.
|
||||
- IMAP host, port, TLS mode, username, password, and append folder.
|
||||
- At least one recipient mailbox that is safe for automated send tests.
|
||||
|
||||
## First Deployment Flow
|
||||
|
||||
1. Create an environment file or secret set with the runtime contract above.
|
||||
2. Install the tagged core and module packages from `requirements-release.txt`.
|
||||
3. Build the WebUI from `webui/package.release.json` or deploy a prebuilt
|
||||
artifact from the same release tag.
|
||||
4. Run database migrations with the target `DATABASE_URL`.
|
||||
5. Create the first tenant and system owner through the controlled bootstrap or
|
||||
one-time admin command for the deployment.
|
||||
6. Start the API service with `govoplan_core.server.app:app`.
|
||||
7. Start workers when `CELERY_ENABLED=true`.
|
||||
8. Start the WebUI/reverse proxy and verify CORS/cookie settings.
|
||||
9. Open Admin > System > Modules, verify enabled modules, and save desired
|
||||
module state if it differs from `ENABLED_MODULES`.
|
||||
10. Run health checks:
|
||||
|
||||
```bash
|
||||
curl -fsS http://127.0.0.1:8000/health
|
||||
curl -fsS http://127.0.0.1:8000/api/v1/platform/modules
|
||||
```
|
||||
|
||||
Authenticated health details require `system:settings:read`:
|
||||
|
||||
```bash
|
||||
curl -fsS -H "X-API-Key: $GOVOPLAN_HEALTH_API_KEY" \
|
||||
http://127.0.0.1:8000/health/details
|
||||
```
|
||||
|
||||
## Production-Like Dev Profile
|
||||
|
||||
Use this profile to verify deployment behavior without publishing packages or
|
||||
using real production credentials. The canonical launcher keeps API, worker, and
|
||||
WebUI code in the editable repositories while Docker provides PostgreSQL and
|
||||
Redis:
|
||||
|
||||
```bash
|
||||
cd /mnt/DATA/git/govoplan-core
|
||||
scripts/launch-production-like-dev.sh
|
||||
```
|
||||
|
||||
The launcher uses `dev/production-like/.env` when present, otherwise the checked
|
||||
in `.env.example`. It runs:
|
||||
|
||||
- PostgreSQL on `127.0.0.1:55433`
|
||||
- Redis on `127.0.0.1:56379`
|
||||
- explicit `ENABLED_MODULES`
|
||||
- explicit migrations and `--with-dev-data` bootstrap
|
||||
- API via the module-aware devserver
|
||||
- a Celery worker for `send_email,append_sent,default`
|
||||
- WebUI through the Vite dev server
|
||||
- durable local files under `runtime/production-like/files`
|
||||
|
||||
This profile validates explicit migration execution, config loading, module
|
||||
discovery, route aggregation, local storage paths, Redis broker connectivity,
|
||||
worker heartbeats, and health/readiness startup without real production
|
||||
credentials. It does not replace a managed PostgreSQL/Redis/WebUI/worker
|
||||
deployment test.
|
||||
|
||||
To stop PostgreSQL and Redis when the launcher exits:
|
||||
|
||||
```bash
|
||||
GOVOPLAN_STOP_PROFILE_DEPENDENCIES_ON_EXIT=1 scripts/launch-production-like-dev.sh
|
||||
```
|
||||
|
||||
## Module Install/Uninstall Operations
|
||||
|
||||
Use Admin > System > Modules for planning. The running API server validates and
|
||||
queues install plans; it does not run pip/npm or restart itself from an HTTP
|
||||
request. Package mutation belongs to the trusted installer CLI/daemon in an
|
||||
operator shell while maintenance mode is active.
|
||||
|
||||
Preflight from the server shell:
|
||||
|
||||
```bash
|
||||
govoplan-module-installer --format shell
|
||||
```
|
||||
|
||||
Apply a prepared plan directly from a controlled shell:
|
||||
|
||||
```bash
|
||||
govoplan-module-installer --apply --build-webui
|
||||
```
|
||||
|
||||
For production-like runs, prefer supervised mode with migrations, database
|
||||
backup/restore hooks, restart commands, and health checks:
|
||||
|
||||
```bash
|
||||
govoplan-module-installer \
|
||||
--supervise \
|
||||
--migrate \
|
||||
--restart-command 'systemctl restart govoplan-api' \
|
||||
--restart-command 'systemctl restart govoplan-worker' \
|
||||
--health-url http://127.0.0.1:8000/health \
|
||||
--database-backup-command 'pg_dump --format=custom "$GOVOPLAN_DATABASE_URL_PGTOOLS" > "$GOVOPLAN_DATABASE_BACKUP_PATH"' \
|
||||
--database-restore-check-command 'pg_restore --list "$GOVOPLAN_DATABASE_BACKUP_PATH" >/dev/null' \
|
||||
--database-restore-command 'pg_restore --clean --if-exists --dbname "$GOVOPLAN_DATABASE_URL_PGTOOLS" "$GOVOPLAN_DATABASE_BACKUP_PATH"'
|
||||
```
|
||||
|
||||
To let the admin UI submit work without executing package managers inside the
|
||||
API process, run the daemon in a separate operator shell:
|
||||
|
||||
```bash
|
||||
govoplan-module-installer \
|
||||
--daemon \
|
||||
--migrate \
|
||||
--build-webui \
|
||||
--database-backup-command 'pg_dump --format=custom "$GOVOPLAN_DATABASE_URL_PGTOOLS" > "$GOVOPLAN_DATABASE_BACKUP_PATH"' \
|
||||
--database-restore-check-command 'pg_restore --list "$GOVOPLAN_DATABASE_BACKUP_PATH" >/dev/null' \
|
||||
--database-restore-command 'pg_restore --clean --if-exists --dbname "$GOVOPLAN_DATABASE_URL_PGTOOLS" "$GOVOPLAN_DATABASE_BACKUP_PATH"' \
|
||||
--health-url http://127.0.0.1:8000/health \
|
||||
--restart-command '<restart govoplan server>'
|
||||
```
|
||||
|
||||
The daemon claims one queued request at a time and writes request/run records
|
||||
below `runtime/module-installer`. For process-manager one-shot usage or tests,
|
||||
use `--daemon-once`. Check daemon status with:
|
||||
|
||||
```bash
|
||||
govoplan-module-installer --daemon-status --format json
|
||||
```
|
||||
|
||||
The installer uses a runtime lock, snapshots `pip freeze` plus WebUI package
|
||||
files, writes a run record, and marks planned rows as applied only after all
|
||||
commands succeed. With `--migrate`, SQLite databases are backed up through
|
||||
SQLite's backup API; non-SQLite databases require
|
||||
`--database-backup-command`, `--database-restore-check-command`, and
|
||||
`--database-restore-command`.
|
||||
|
||||
Database hook commands receive:
|
||||
|
||||
- `GOVOPLAN_INSTALLER_RUN_DIR`
|
||||
- `GOVOPLAN_DATABASE_URL`
|
||||
- `GOVOPLAN_DATABASE_URL_PGTOOLS` for PostgreSQL tools
|
||||
- `GOVOPLAN_DATABASE_BACKUP_PATH`
|
||||
- `GOVOPLAN_DATABASE_BACKUP_METADATA`
|
||||
|
||||
Avoid embedding secrets directly in commands; prefer environment variables,
|
||||
service credentials, or deployment-local secret injection.
|
||||
|
||||
Inspect installer history and lock state from the operator shell:
|
||||
|
||||
```bash
|
||||
govoplan-module-installer --list-runs --format json
|
||||
govoplan-module-installer --show-run <run-id> --format json
|
||||
govoplan-module-installer --lock-status --format json
|
||||
govoplan-module-installer --list-requests --format json
|
||||
govoplan-module-installer --show-request <request-id> --format json
|
||||
govoplan-module-installer --cancel-request <request-id> --format json
|
||||
govoplan-module-installer --retry-request <request-id> --format json
|
||||
```
|
||||
|
||||
Rollback uses the saved run snapshot:
|
||||
|
||||
```bash
|
||||
govoplan-module-installer --rollback <run-id>
|
||||
govoplan-module-installer --rollback <run-id> --database-restore-command '<override restore command>'
|
||||
```
|
||||
|
||||
Uninstall is non-destructive by default. A planned uninstall row can set
|
||||
`destroy_data: true` to request destructive module retirement. The module must
|
||||
provide an automated retirement provider, and the installer snapshots the
|
||||
database before dropping module-owned tables.
|
||||
|
||||
Run the rollback drill before relying on installer automation in a new
|
||||
environment:
|
||||
|
||||
```bash
|
||||
./.venv/bin/python scripts/module-installer-rollback-drill.py --format json
|
||||
```
|
||||
|
||||
The drill uses temporary SQLite databases and simulated package commands. It
|
||||
does not install or uninstall real packages. It exercises:
|
||||
|
||||
- package command failure followed by supervised rollback;
|
||||
- migration failure with a SQLite database snapshot;
|
||||
- restart-command failure;
|
||||
- health timeout after restart;
|
||||
- destructive retirement executor failure with database rollback;
|
||||
- PostgreSQL-style backup, restore-check, and restore hooks;
|
||||
- daemon heartbeat, request queue claim/update, retry/cancel, and stale lock
|
||||
detection/removal.
|
||||
|
||||
See `RELEASE_DEPENDENCIES.md` for release package refs, migration baseline
|
||||
checks, catalog trust, signing, keyring, replay, and license operation.
|
||||
|
||||
## Operator Checklist
|
||||
|
||||
- Runtime secrets are injected outside git.
|
||||
- `MASTER_KEY_B64` is set and backed up securely.
|
||||
- Database backup and restore commands are tested.
|
||||
- File/object storage is durable and backed up.
|
||||
- `CORS_ORIGINS` and cookie settings match the deployed WebUI origin.
|
||||
- Redis and workers are running before `CELERY_ENABLED=true`.
|
||||
- Module catalog and license keyrings are pinned locally.
|
||||
- Health endpoints are monitored.
|
||||
- Test SMTP/IMAP credentials are non-production and isolated.
|
||||
- Module installer rollback drill has passed in the deployment environment.
|
||||
51
docs/DOCUMENTATION_MAP.md
Normal file
51
docs/DOCUMENTATION_MAP.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# GovOPlaN Documentation Map
|
||||
|
||||
This map defines the source-of-truth documents for the current repository docs.
|
||||
Use it to avoid duplicating long procedures across architecture, release,
|
||||
operator, and roadmap pages.
|
||||
|
||||
## Core Platform
|
||||
|
||||
| Topic | Canonical document | Notes |
|
||||
| --- | --- | --- |
|
||||
| Module architecture and kernel contracts | `MODULE_ARCHITECTURE.md` | Stable module contracts, API efficiency contracts, durable boundary decisions, lifecycle, and WebUI contribution rules. |
|
||||
| RBAC and resource access | `ACCESS_RBAC_MODEL.md` | Current permission, role, API-key, and resource-access model. |
|
||||
| Governance hierarchy | `GOVERNANCE_MODEL.md` | System, tenant, user/group, campaign policy inheritance and admin UI structure. |
|
||||
| Policy decision DTOs and provenance | `POLICY_CONTRACTS.md` | Shared explain/provenance shape; module-specific policy docs should link here. |
|
||||
| Events and audit trace context | `EVENTS_AND_AUDIT.md` | Event dispatch semantics and audit payload conventions. |
|
||||
| Action/effect automation layer | `ACTION_EFFECT_AUTOMATION_LAYER.md` | Action/effect contracts, consequence preview, runner semantics, and module boundary for automation. |
|
||||
| Postbox E2EE target architecture | `POSTBOX_E2EE_ARCHITECTURE.md` | Strategic encrypted postbox/mailbox model, key ownership, role mailbox semantics, and retraction limits. |
|
||||
|
||||
## Release And Operations
|
||||
|
||||
| Topic | Canonical document | Notes |
|
||||
| --- | --- | --- |
|
||||
| Runtime configuration and operator flow | `DEPLOYMENT_OPERATOR_GUIDE.md` | Production/staging configuration, migrations, backups, installer operation, and rollback drill. |
|
||||
| Release dependencies and catalogs | `RELEASE_DEPENDENCIES.md` | Release package refs, migration baselines, release lockfiles, catalog trust/licensing, catalog publishing, and release checklist. |
|
||||
| Dependency vulnerability audits | `DEPENDENCY_AUDITS.md` | Local and CI audit commands plus dated audit result notes. |
|
||||
| Remote WebUI bundle design | `REMOTE_WEBUI_BUNDLES.md` | Experimental controlled-deployment design; normal releases still use package builds. |
|
||||
|
||||
## Product And Module Planning
|
||||
|
||||
| Topic | Canonical document | Notes |
|
||||
| --- | --- | --- |
|
||||
| Product roadmap and module routing | `GOVOPLAN_MASTER_ROADMAP.md` | Product-level sequencing, implementation gates, issue routing, and missing-module decisions. |
|
||||
| UI/UX decisions | `UI_UX_DECISION_LEDGER.md` | Binding guided-UI decisions, open decisions, impact index, and review checklist. |
|
||||
| Interface ethics and design doctrine | `INTERFACE_ETHICS_AND_DESIGN_DOCTRINE.md` | Product-level doctrine for context, decision, consequence, contestability, responsibility, and traceability. |
|
||||
| Public-sector integration posture | `PUBLIC_SECTOR_INTEGRATION_STRATEGY.md` | Strategy index; executable target inventory lives in `govoplan-connectors`. |
|
||||
| Configuration packages | `CONFIGURATION_PACKAGES.md` | Package model, provider contract, import/export flow, and tracking slices. |
|
||||
|
||||
## Workflow Docs
|
||||
|
||||
| Topic | Canonical document | Notes |
|
||||
| --- | --- | --- |
|
||||
| Gitea issues and wiki sync | `GITEA_ISSUES.md` | Issue labels, imports, wiki mirroring, and Codex state updates. |
|
||||
| Codex local workflow | `CODEX_WORKFLOW.md` | Local agent setup and focused verification commands. |
|
||||
|
||||
## Cross-Repo Rule
|
||||
|
||||
Core docs may keep strategy, kernel contracts, and routing decisions. Module
|
||||
repositories should own executable module behavior, concrete API/UI contracts,
|
||||
and operator notes for their own module. When content spans both, keep the
|
||||
durable decision in core and link to the module document for implementation
|
||||
details.
|
||||
180
docs/EVENTS_AND_AUDIT.md
Normal file
180
docs/EVENTS_AND_AUDIT.md
Normal file
@@ -0,0 +1,180 @@
|
||||
# Events And Audit
|
||||
|
||||
GovOPlaN uses a small kernel event contract first, not a broad command bus.
|
||||
Commands remain module-owned application-service methods or API endpoints until
|
||||
there is a concrete need for durable asynchronous command orchestration. Events
|
||||
are facts about completed work and are safe for audit, projections, optional
|
||||
module reactions, and operator diagnostics.
|
||||
|
||||
## Production Transport Decision
|
||||
|
||||
The first production target is a **database outbox plus in-process immediate
|
||||
dispatch**:
|
||||
|
||||
- Use `govoplan_core.core.events.PlatformEvent` for domain and platform events.
|
||||
- Use `EventBus` as the in-process dispatch contract for same-process module
|
||||
reactions that are safe to run inline.
|
||||
- Persist durable integration/workflow events through a database outbox before
|
||||
acknowledging the state change that produced them.
|
||||
- Drain the outbox through a small dispatcher process. The dispatcher may call
|
||||
in-process handlers in the same deployment first, but its storage contract is
|
||||
database-backed.
|
||||
- Treat Redis/Celery as worker/job infrastructure, not as the authoritative
|
||||
first event transport. A Celery dispatcher can consume the outbox later.
|
||||
- Keep the dispatch implementation pluggable behind the `PlatformEvent`
|
||||
envelope so a future message broker can be added without changing event
|
||||
producers.
|
||||
- Keep commands out of the kernel until workflows need retryable, durable,
|
||||
operator-visible command records.
|
||||
|
||||
This keeps the first contract small, PostgreSQL-friendly, auditable, and
|
||||
recoverable after process crashes. It also avoids making Redis a correctness
|
||||
dependency for deployments that only need synchronous mail/tests or light
|
||||
background work.
|
||||
|
||||
## Dispatch Semantics
|
||||
|
||||
Event producers should write their domain state and outbox event in the same
|
||||
database transaction wherever possible. Handlers must be idempotent because the
|
||||
outbox dispatcher can retry after a crash or timeout.
|
||||
|
||||
Recommended first outbox columns:
|
||||
|
||||
- `event_id`, `event_type`, `module_id`
|
||||
- `correlation_id`, `causation_id`
|
||||
- `payload`, `occurred_at`
|
||||
- `available_at`, `attempt_count`, `claimed_at`, `claim_token`
|
||||
- `processed_at`, `last_error`
|
||||
|
||||
Inline `EventBus` handlers are allowed only for non-critical local reactions.
|
||||
Anything that must survive process failure, restart, package update, or worker
|
||||
redeployment belongs in the outbox.
|
||||
|
||||
## Trace IDs
|
||||
|
||||
Every `PlatformEvent` has:
|
||||
|
||||
- `event_id`: unique ID for that event.
|
||||
- `correlation_id`: stable ID for the whole request, workflow, or job.
|
||||
- `causation_id`: the event ID or external operation ID that caused this
|
||||
event.
|
||||
|
||||
The FastAPI app factory creates an event context for every request. It accepts
|
||||
`X-Correlation-ID` or `X-Request-ID` when the value is a compact safe trace ID,
|
||||
otherwise it generates a new ID. Responses include `X-Correlation-ID`.
|
||||
|
||||
Audit logging reads the current event context and stores trace IDs in
|
||||
`details._trace`. Callers can also pass explicit `correlation_id` and
|
||||
`causation_id` to `audit_event` or `audit_from_principal`.
|
||||
|
||||
Admin and lifecycle code should use the compact operational detail shape
|
||||
documented in `govoplan-audit/docs/AUDIT_TRACE_CONTEXT.md`. The core
|
||||
`audit_operation_context` helper preserves `module_id`, `request_id`, `run_id`,
|
||||
`outcome`, and `_trace` while applying the shared audit redaction pass to
|
||||
additional detail values.
|
||||
|
||||
## Audit MVP Boundary
|
||||
|
||||
`govoplan-audit` owns:
|
||||
|
||||
- the `audit_log` table and audit API routes
|
||||
- audit route contribution through its module manifest
|
||||
- audit retention behavior in cooperation with policy/retention settings
|
||||
- future audit sink/export capability implementations
|
||||
|
||||
`govoplan-core` owns:
|
||||
|
||||
- `AuditEvent` and `AuditSink` protocol contracts
|
||||
- request and event trace context
|
||||
- the compatibility `audit_event` helper while routes are still migrating
|
||||
- retention orchestration that calls module capabilities
|
||||
|
||||
Feature modules should record audit facts through a small audit API or future
|
||||
`audit.sink` capability. They should not import audit storage internals.
|
||||
|
||||
## Initial Domain Event Inventory
|
||||
|
||||
Access:
|
||||
|
||||
- `access.account.created`
|
||||
- `access.account.updated`
|
||||
- `access.membership.created`
|
||||
- `access.membership.updated`
|
||||
- `access.group.created`
|
||||
- `access.group.updated`
|
||||
- `access.role.created`
|
||||
- `access.role.updated`
|
||||
- `access.role.deleted`
|
||||
- `access.api_key.created`
|
||||
- `access.api_key.revoked`
|
||||
- `access.session.created`
|
||||
- `access.session.revoked`
|
||||
|
||||
Tenancy:
|
||||
|
||||
- `tenancy.tenant.created`
|
||||
- `tenancy.tenant.updated`
|
||||
- `tenancy.tenant.suspended`
|
||||
- `tenancy.tenant.reactivated`
|
||||
- `tenancy.tenant.delete_requested`
|
||||
- `tenancy.tenant.delete_blocked`
|
||||
- `tenancy.tenant.deleted`
|
||||
|
||||
Policy:
|
||||
|
||||
- `policy.system.updated`
|
||||
- `policy.tenant.updated`
|
||||
- `policy.user.updated`
|
||||
- `policy.group.updated`
|
||||
- `policy.campaign.updated`
|
||||
- `policy.effective_policy.changed`
|
||||
|
||||
Files:
|
||||
|
||||
- `files.file.uploaded`
|
||||
- `files.file.renamed`
|
||||
- `files.file.deleted`
|
||||
- `files.file.frozen`
|
||||
- `files.share.created`
|
||||
- `files.share.revoked`
|
||||
- `files.connector.imported`
|
||||
- `files.connector.access_denied`
|
||||
|
||||
Mail:
|
||||
|
||||
- `mail.profile.created`
|
||||
- `mail.profile.updated`
|
||||
- `mail.profile.credentials_rotated`
|
||||
- `mail.profile.tested`
|
||||
- `mail.message.sent`
|
||||
- `mail.message.send_failed`
|
||||
- `mail.imap.appended`
|
||||
- `mail.imap.append_failed`
|
||||
- `mail.mailbox.message_seen`
|
||||
|
||||
Campaign:
|
||||
|
||||
- `campaign.created`
|
||||
- `campaign.version.created`
|
||||
- `campaign.validated`
|
||||
- `campaign.built`
|
||||
- `campaign.reviewed`
|
||||
- `campaign.queued`
|
||||
- `campaign.send_started`
|
||||
- `campaign.recipient_attempted`
|
||||
- `campaign.recipient_delivered`
|
||||
- `campaign.recipient_failed`
|
||||
- `campaign.paused`
|
||||
- `campaign.resumed`
|
||||
- `campaign.cancelled`
|
||||
- `campaign.report.exported`
|
||||
|
||||
## Event Payload Rules
|
||||
|
||||
- Payloads must be JSON-serializable.
|
||||
- Use stable IDs, not ORM objects.
|
||||
- Include tenant ID when tenant-scoped.
|
||||
- Include actor/principal references only as DTOs or primitive IDs.
|
||||
- Do not include secrets, raw message bodies, full recipient lists, or file
|
||||
content.
|
||||
- Put large evidence in owning module storage and reference it by ID.
|
||||
@@ -33,7 +33,15 @@ For a shared credentials file outside the target repository, pass `--env-file`:
|
||||
./scripts/gitea-sync-labels.py --env-file /path/to/private/gitea.env --apply
|
||||
```
|
||||
|
||||
Create a Gitea token with issue read/write access and label-management permission for the repository. On scoped-token instances, this usually means issue read/write and, if label writes are rejected, repository write permission too.
|
||||
Create a Gitea token with issue read/write access and label-management
|
||||
permission for the repository. On scoped-token instances, this usually means
|
||||
issue read/write and, if label writes are rejected, repository write permission
|
||||
too.
|
||||
|
||||
For GovOPlaN repositories, prefer organization labels for the shared taxonomy.
|
||||
Creating or updating organization labels requires a token with
|
||||
`write:organization`. Repository label management only needs repository label
|
||||
permission, but it duplicates the taxonomy into each repository.
|
||||
|
||||
Preview and apply labels:
|
||||
|
||||
@@ -43,6 +51,19 @@ cd /mnt/DATA/git/govoplan-core
|
||||
./scripts/gitea-sync-labels.py --apply
|
||||
```
|
||||
|
||||
Preview and apply the shared taxonomy as organization labels:
|
||||
|
||||
```bash
|
||||
cd /mnt/DATA/git/govoplan-core
|
||||
./scripts/gitea-sync-labels.py --scope organization --env-file /home/zemion/.config/gitea/gitea.env
|
||||
./scripts/gitea-sync-labels.py --scope organization --env-file /home/zemion/.config/gitea/gitea.env --apply
|
||||
```
|
||||
|
||||
The import helpers resolve repository labels and organization labels. Repository
|
||||
labels win when a repository defines the same name locally, but a repository does
|
||||
not need a local copy of every shared `type/*`, `status/*`, `priority/*`,
|
||||
`module/*`, `area/*`, `source/*`, or `codex/*` label.
|
||||
|
||||
After the `.gitea` files are pushed to the default branch, Gitea will show the issue template chooser. Blank issues are disabled by `.gitea/ISSUE_TEMPLATE/config.yaml`.
|
||||
|
||||
## Multiple Repositories And Workspaces
|
||||
@@ -167,7 +188,10 @@ For a broader project import across all local repositories hosted on `git.add-id
|
||||
./scripts/gitea-import-all-backlogs.py --env-file /home/zemion/.config/gitea/gitea.env --apply
|
||||
```
|
||||
|
||||
It scans repository and product-directory files with backlog-like names, creates the shared generic labels where needed, imports missing open work, and deduplicates reruns by hidden fingerprint and normalized title.
|
||||
It scans repository and product-directory files with backlog-like names, resolves
|
||||
shared labels from the organization label catalogue where available, creates only
|
||||
missing fallback repository labels when needed, imports missing open work, and
|
||||
deduplicates reruns by hidden fingerprint and normalized title.
|
||||
|
||||
## Mirroring Project Docs Into Gitea Wikis
|
||||
|
||||
@@ -184,6 +208,13 @@ Apply the wiki mirror:
|
||||
./scripts/gitea-sync-wiki.py --env-file /home/zemion/.config/gitea/gitea.env --apply
|
||||
```
|
||||
|
||||
After renaming or deleting repository docs, prune previously managed wiki pages
|
||||
that no longer have a source file:
|
||||
|
||||
```bash
|
||||
./scripts/gitea-sync-wiki.py --env-file /home/zemion/.config/gitea/gitea.env --repo govoplan-core --prune-managed --apply
|
||||
```
|
||||
|
||||
The default apply path uses the Gitea wiki git repository, not one REST API
|
||||
request per page. It keeps a local checkout cache below
|
||||
`/tmp/codex-gitea-wiki-sync`, commits changed pages once per repository, and
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# Multi Seal Mail - Current System and Tenant Governance Model
|
||||
# GovOPlaN Governance Model
|
||||
|
||||
**Updated:** 2026-06-16
|
||||
**Current migration head:** `f5a6b7c8d9e0`
|
||||
**Updated:** 2026-07-09
|
||||
|
||||
## Governance Rule
|
||||
|
||||
System policy is authoritative for tenants and all lower levels. Each lower level may only narrow what it inherits:
|
||||
System policy is authoritative for tenants and all lower levels. Each lower
|
||||
level may only narrow what it inherits:
|
||||
|
||||
```text
|
||||
system
|
||||
@@ -14,52 +14,65 @@ system
|
||||
-> campaign
|
||||
```
|
||||
|
||||
Lower levels do not widen privileges, allowed profiles, retention durations or credential rights granted by a higher level.
|
||||
Lower levels do not widen privileges, allowed profiles, retention durations, or
|
||||
credential rights granted by a higher level.
|
||||
|
||||
## Administration Structure
|
||||
|
||||
GovOPlaN separates system administration from scoped configuration:
|
||||
|
||||
```text
|
||||
SYSTEM
|
||||
- Settings
|
||||
- Retention
|
||||
- Mail servers
|
||||
ADMINISTRATION
|
||||
- Modules
|
||||
- Packages
|
||||
- Maintenance
|
||||
- Changes
|
||||
|
||||
GLOBAL
|
||||
- Tenants
|
||||
- Users
|
||||
- Groups
|
||||
- System roles
|
||||
- Tenant roles
|
||||
- Audit
|
||||
- Roles
|
||||
- Groups and users
|
||||
- File connectors
|
||||
- Mail servers
|
||||
- API keys
|
||||
- Retention
|
||||
|
||||
TENANT
|
||||
- Settings boundary
|
||||
- Users
|
||||
- Groups
|
||||
- Roles
|
||||
- API keys
|
||||
- Groups and users
|
||||
- File connectors
|
||||
- Mail servers
|
||||
- API keys
|
||||
- Retention
|
||||
- Audit
|
||||
|
||||
USER
|
||||
- User mail
|
||||
- User retention
|
||||
|
||||
GROUP
|
||||
- Group mail
|
||||
- Group retention
|
||||
- File connectors
|
||||
- Mail servers
|
||||
- API keys
|
||||
- Retention
|
||||
|
||||
USER
|
||||
- File connectors
|
||||
- Mail servers
|
||||
- API keys
|
||||
- Retention
|
||||
```
|
||||
|
||||
There is no separate System access page. Compatibility access scopes remain in the backend for assignment/read boundaries.
|
||||
System access scopes remain in the backend for assignment/read boundaries, but
|
||||
the UI should present the configuration hierarchy rather than a separate
|
||||
"system access" concept.
|
||||
|
||||
## Tenant Governance
|
||||
|
||||
System settings define tenant defaults and whether tenants may narrow selected options. Tenant overrides can only restrict:
|
||||
System settings define tenant defaults and whether tenants may narrow selected
|
||||
options. Tenant overrides can only restrict:
|
||||
|
||||
- custom groups;
|
||||
- custom roles;
|
||||
- tenant API keys.
|
||||
|
||||
The backend enforces that tenant governance cannot widen system-denied privileges.
|
||||
The backend enforces that tenant governance cannot widen system-denied
|
||||
privileges.
|
||||
|
||||
## Mail-Profile Governance
|
||||
|
||||
@@ -73,7 +86,10 @@ group
|
||||
campaign
|
||||
```
|
||||
|
||||
Effective campaign profile availability follows campaign ownership. A campaign owned by a user resolves through system, tenant, that user and campaign policy. A group-owned campaign resolves through system, tenant, that group and campaign policy.
|
||||
Effective campaign profile availability follows campaign ownership. A campaign
|
||||
owned by a user resolves through system, tenant, that user, and campaign
|
||||
policy. A group-owned campaign resolves through system, tenant, that group, and
|
||||
campaign policy.
|
||||
|
||||
Policy semantics:
|
||||
|
||||
@@ -81,12 +97,18 @@ Policy semantics:
|
||||
- lower levels can further restrict the set;
|
||||
- forced profiles mean the lower level must choose from the forced set;
|
||||
- a forced set with one profile effectively enforces that profile;
|
||||
- campaign-level profile creation is allowed only if the effective policy permits it;
|
||||
- SMTP/IMAP credentials use one inheritance decision per protocol: lower levels must inherit profile credentials, may inherit profile credentials, or must provide local credentials;
|
||||
- the lower-level override switch for `smtp_credentials.inherit` and `imap_credentials.inherit` controls whether descendants may change that inheritance decision;
|
||||
- campaign-level profile creation is allowed only if the effective policy
|
||||
permits it;
|
||||
- SMTP/IMAP credentials use one inheritance decision per protocol: lower levels
|
||||
must inherit profile credentials, may inherit profile credentials, or must
|
||||
provide local credentials;
|
||||
- the lower-level override switch for `smtp_credentials.inherit` and
|
||||
`imap_credentials.inherit` controls whether descendants may change that
|
||||
inheritance decision;
|
||||
- deny patterns always win over allow patterns;
|
||||
- empty or `*` allowlist means allow all except denied;
|
||||
- non-empty allowlist means at least one allow rule must match and no deny rule may match.
|
||||
- non-empty allowlist means at least one allow rule must match and no deny rule
|
||||
may match.
|
||||
|
||||
Pattern targets:
|
||||
|
||||
@@ -98,7 +120,23 @@ From header
|
||||
recipient domains
|
||||
```
|
||||
|
||||
Ownership transfer is intentionally deferred as a two-step workflow: original owner initiates, new owner accepts and reselects/repairs the mail profile if their effective policy requires it.
|
||||
Ownership transfer is intentionally deferred as a two-step workflow: original
|
||||
owner initiates, new owner accepts and reselects/repairs the mail profile if
|
||||
their effective policy requires it.
|
||||
|
||||
## File-Connector Governance
|
||||
|
||||
File connector profiles and credentials are separated. Profiles describe
|
||||
external endpoints; credentials bind authentication material and policy to a
|
||||
scope. Concrete linked folders appear as file spaces in the files module.
|
||||
|
||||
Governance follows the same inheritance shape as mail:
|
||||
|
||||
- system and tenant policy can permit, require, or forbid lower-level
|
||||
connections/credentials;
|
||||
- user or group ownership controls which spaces appear to principals;
|
||||
- spaces inherit endpoint and credential policy from their connector profile;
|
||||
- connector health and credential tests must not reveal plaintext secrets.
|
||||
|
||||
## Retention Governance
|
||||
|
||||
@@ -120,20 +158,27 @@ Rules:
|
||||
|
||||
- system may set concrete defaults or unlimited retention;
|
||||
- system exposes allow-limiting toggles per field;
|
||||
- tenants, users/groups and campaigns may only shorten inherited retention where the parent allows limiting;
|
||||
- tenants, users/groups, and campaigns may only shorten inherited retention
|
||||
where the parent allows limiting;
|
||||
- blank lower-level values inherit;
|
||||
- mock mailbox retention is currently system-level because mock mailbox records do not yet carry tenant/campaign ownership metadata;
|
||||
- dry-run/apply retention actions report affected classes before destructive cleanup.
|
||||
- mock mailbox retention is currently system-level because mock mailbox records
|
||||
do not yet carry tenant/campaign ownership metadata;
|
||||
- dry-run/apply retention actions report affected classes before destructive
|
||||
cleanup.
|
||||
|
||||
## Role Definitions and Assignments
|
||||
## Role Definitions And Assignments
|
||||
|
||||
### System roles
|
||||
### System Roles
|
||||
|
||||
System roles define instance-wide permissions. `system:*` is stored as one wildcard and displayed as granting the full system catalogue. System owner is protected.
|
||||
System roles define instance-wide permissions. `system:*` is stored as one
|
||||
wildcard and displayed as granting the full system catalogue. System owner is
|
||||
protected.
|
||||
|
||||
### Tenant roles
|
||||
### Tenant Roles
|
||||
|
||||
Tenant roles can be system-governed templates or tenant-local definitions, subject to system tenant-governance settings and actor delegation ceilings. Wildcard counts are expanded against the canonical tenant catalogue.
|
||||
Tenant roles can be system-governed templates or tenant-local definitions,
|
||||
subject to system tenant-governance settings and actor delegation ceilings.
|
||||
Wildcard counts are expanded against the canonical tenant catalogue.
|
||||
|
||||
## Audit Access
|
||||
|
||||
@@ -144,15 +189,17 @@ system audit -> system:audit:read
|
||||
tenant audit -> active tenant + audit:read
|
||||
```
|
||||
|
||||
Audit pages use server pagination, filtering and bounded grids.
|
||||
Audit pages use server pagination, filtering, and bounded grids.
|
||||
|
||||
## Tenant Switching
|
||||
|
||||
Tenant switching preserves the current URL when possible and falls back when a route/resource is not accessible in the new tenant context.
|
||||
Tenant switching preserves the current URL when possible and falls back when a
|
||||
route/resource is not accessible in the new tenant context.
|
||||
|
||||
The tenant selector is hidden for ordinary single-tenant accounts and visible for multi-tenant or system tenant-management contexts.
|
||||
The tenant selector is hidden for ordinary single-tenant accounts and visible
|
||||
for multi-tenant or system tenant-management contexts.
|
||||
|
||||
## DataGrid Contract in Administration
|
||||
## Administration DataGrid Contract
|
||||
|
||||
Admin lists use bounded container grids:
|
||||
|
||||
@@ -164,14 +211,12 @@ Admin lists use bounded container grids:
|
||||
- sticky headers where needed;
|
||||
- server pagination for audit.
|
||||
|
||||
## Still Deferred
|
||||
## Deferred Work
|
||||
|
||||
- real SMTP/IMAP test-bed verification and operator runbook;
|
||||
- recipient import with column mapping;
|
||||
- Seafile/external connector governance;
|
||||
- system/tenant/group/user file-space hierarchy and external storage hierarchy;
|
||||
- session/device revocation UI;
|
||||
- backup/restore, monitoring and update procedures;
|
||||
- backup/restore, monitoring, and update procedures;
|
||||
- DSAR workflows and evidence bundle verifier;
|
||||
- campaign ownership transfer workflow;
|
||||
- policy impact analysis before delete/disable/unshare/change;
|
||||
663
docs/GOVOPLAN_MASTER_ROADMAP.md
Normal file
663
docs/GOVOPLAN_MASTER_ROADMAP.md
Normal file
@@ -0,0 +1,663 @@
|
||||
# GovOPlaN Master Roadmap
|
||||
|
||||
This roadmap is the durable product north star and sequencing guide for
|
||||
GovOPlaN as a modular platform for administrative operations. It keeps the
|
||||
product moving without turning every possible public-sector need into an
|
||||
immediate implementation track.
|
||||
|
||||
Use this document for product direction, sequencing, and module routing. Issues
|
||||
are the active backlog; this document is durable planning context and should be
|
||||
mirrored to the Gitea wiki.
|
||||
|
||||
## Product Thesis
|
||||
|
||||
GovOPlaN should become a configurable operations platform for public
|
||||
institutions. It should help an institution model real administrative
|
||||
procedures, connect existing systems, keep durable evidence, and explain the
|
||||
configured system to users.
|
||||
|
||||
The goal is not to replace every existing system. GovOPlaN should connect
|
||||
existing systems, provide better workflows where the current landscape is weak,
|
||||
and make administrative processes configurable, auditable, and reusable.
|
||||
|
||||
The product should first provide a reliable administrative spine:
|
||||
|
||||
- identities, roles, tenants, policy, audit, and governance
|
||||
- forms, files, cases, workflow, tasks, templates, and records
|
||||
- postboxes, notifications, mail, portal, appointments, and booking
|
||||
- identity trust, role-bound postboxes, and eventually encrypted administrative
|
||||
communication
|
||||
- configuration packages that assemble modules into repeatable procedures
|
||||
- docs that explain the configured system, not the full theoretical product
|
||||
|
||||
Domain modules should come after the spine can run a reference procedure end to
|
||||
end.
|
||||
|
||||
The platform should be a governance-capable runtime for modules, connectors,
|
||||
configuration, and administrative decisions. The kernel must stay free of domain
|
||||
semantics while still providing the contracts needed for modules to explain what
|
||||
they do, what they require, which effects they create, and how operators can
|
||||
verify or reverse those effects.
|
||||
|
||||
## Design Principles
|
||||
|
||||
- Modules must stay independently installable, enableable, and disableable.
|
||||
- Cross-module behavior should use core-mediated capabilities, commands,
|
||||
events, DTOs, and UI contribution points rather than direct imports.
|
||||
- Configuration packages should turn installed modules into concrete, reusable
|
||||
administrative processes.
|
||||
- Operators should be able to configure the platform through the UI.
|
||||
- Every powerful configuration path needs preflight, preview, audit, rollback,
|
||||
RBAC, and policy checks.
|
||||
- Context, decision, consequence, and traceability must be visible together for
|
||||
consequential actions. The full doctrine lives in
|
||||
`INTERFACE_ETHICS_AND_DESIGN_DOCTRINE.md`.
|
||||
- Automation must use governed action/effect contracts, not hidden side
|
||||
effects. The first automation layer is defined in
|
||||
`ACTION_EFFECT_AUTOMATION_LAYER.md` and should start in `govoplan-workflow`
|
||||
unless a separate automation module becomes justified.
|
||||
- Encrypted postboxes are a strategic target. Early postbox, access, and
|
||||
identity-trust contracts should stay compatible with the E2EE architecture in
|
||||
`POSTBOX_E2EE_ARCHITECTURE.md`.
|
||||
- Integration should be a first-class product path: connect to existing
|
||||
systems, consume their data, and publish governed outputs back to them.
|
||||
- GovOPlaN should scale from a small local installation to a larger deployment
|
||||
with separately scalable web, API, worker, storage, and database components.
|
||||
|
||||
## User Experience Direction
|
||||
|
||||
GovOPlaN should expose the full power of the platform without forcing
|
||||
non-technical users to face every field, flag, and internal representation at
|
||||
once. The default experience should feel guided, explainable, and calm. Expert
|
||||
depth should remain available, but it should be layered behind deliberate
|
||||
interaction patterns.
|
||||
|
||||
Core UX rules:
|
||||
|
||||
- Use progressive disclosure. Common decisions stay visible; advanced,
|
||||
hazardous, or rarely used options live in collapsed panels, secondary steps,
|
||||
or explicit advanced areas.
|
||||
- Do not use raw JSON as the primary configuration UI. Every configurable value
|
||||
should have an appropriate control, validation, and plain-language help.
|
||||
Import/export and diagnostics may show JSON as a secondary artifact.
|
||||
- Prefer guided flows over option dumps. Connector setup, package import,
|
||||
module installation, policy changes, and destructive operations should use
|
||||
wizards that explain what is happening, why it matters, and what will happen
|
||||
next.
|
||||
- Discover values when the system can infer them. For example, a Nextcloud file
|
||||
connection should start with the base URL, discover the WebDAV endpoint, and
|
||||
fill technical fields for review instead of asking the user to know them
|
||||
upfront.
|
||||
- Make explanations always available without making every screen verbose.
|
||||
Inline helper text should be short; richer explanations should be reachable
|
||||
through expandable help, tooltips, side panels, or review steps.
|
||||
- Explain blocked actions in actionable language. A disabled control or failed
|
||||
step should say what is missing, who can fix it, and where to go, for example
|
||||
"A system administrator must allow this provider" or "Configure the provider
|
||||
in Settings > File Providers before linking a folder here."
|
||||
- Reuse visual language and placements consistently. Similar configuration,
|
||||
policy, connection, credential, review, and confirmation flows should share
|
||||
components, button placement, modal behavior, problem lists, and empty/error
|
||||
states.
|
||||
- Use modals and step flows for focused creation/editing where they reduce page
|
||||
clutter. Reserve large always-open pages for overview, comparison, and
|
||||
repeated administration work.
|
||||
- Treat diagnostics as product UX. Validation results, preflight blockers,
|
||||
policy explanations, permission denials, and missing capabilities should be
|
||||
understandable to a non-technical operator before exposing internal details.
|
||||
|
||||
This is a product quality gate. New admin/configuration surfaces should not be
|
||||
considered complete if they expose all options at once, require JSON editing,
|
||||
hide why an action is unavailable, or use a one-off layout where a shared
|
||||
pattern exists.
|
||||
|
||||
## Focus Rules
|
||||
|
||||
1. Build one reference journey per wave.
|
||||
2. Do not implement a module because the repository exists.
|
||||
3. Do not add module-to-module imports for optional behavior.
|
||||
4. Every new domain module must justify its own semantics beyond `cases`,
|
||||
`workflow`, `tasks`, `forms`, and `files`.
|
||||
5. Prefer connector first when an external specialist system is likely to remain
|
||||
the system of record.
|
||||
6. Keep active work in Gitea issues; keep durable context in docs and synced
|
||||
wiki pages.
|
||||
7. A module moves from scaffold to implementation only when it has an owner,
|
||||
reference journey, boundary notes, capability contracts, and testable MVP.
|
||||
|
||||
## Capability Map
|
||||
|
||||
| Capability | Likely owner |
|
||||
| --- | --- |
|
||||
| Public application entry point | `govoplan-portal` |
|
||||
| Structured forms and validation | `govoplan-forms` |
|
||||
| Uploaded files and managed storage | `govoplan-files` |
|
||||
| Case record and lifecycle | `govoplan-cases` |
|
||||
| Workflow transitions and automation | `govoplan-workflow` |
|
||||
| Action/effect catalogue and automation runner | first `govoplan-workflow`; possible future `govoplan-automation` if it outgrows workflow |
|
||||
| Internal work queues and tasks | `govoplan-tasks` |
|
||||
| Appointment proposals and booking | `govoplan-appointments`, `govoplan-calendar` |
|
||||
| Postbox, email, and notifications | `govoplan-postbox`, `govoplan-mail`, `govoplan-notifications` |
|
||||
| Identity trust, device keys, and encrypted postbox key contracts | `govoplan-identity-trust`, `govoplan-access`, `govoplan-postbox` |
|
||||
| Service directory/catalog | `govoplan-portal` |
|
||||
| Permit/document generation | `govoplan-templates`, `govoplan-dms` |
|
||||
| Payment capture and accounting handoff | `govoplan-payments`, `govoplan-ledger` |
|
||||
| Roles, permissions, tenants, policy, audit | `govoplan-access`, `govoplan-tenancy`, `govoplan-policy`, `govoplan-audit` |
|
||||
| External software integration | `govoplan-connectors` |
|
||||
| Recurring extraction and transformation | possible future `govoplan-datasources`, possible future `govoplan-dataflow` |
|
||||
| Reports, BI, and management visibility | `govoplan-reporting` |
|
||||
|
||||
## Configuration And Safety Target
|
||||
|
||||
The long-term target is that operators configure the platform through the UI
|
||||
instead of editing files for normal operation.
|
||||
|
||||
UI-managed configuration should include:
|
||||
|
||||
- module installation, enablement, lifecycle state, and health
|
||||
- tenants, users, groups, roles, policies, and permissions
|
||||
- connectors, credentials, secret references, and external service tests
|
||||
- workflows, forms, templates, task queues, schedules, and notifications
|
||||
- configuration package import/export and environment-specific data collection
|
||||
- retention, audit, privacy, maintenance mode, and safety controls
|
||||
- deployment-visible settings such as public URLs, mail senders, storage
|
||||
profiles, queues, and worker capabilities
|
||||
|
||||
Safety controls should include dry-run plans, field-level validation, policy
|
||||
explanations, two-person approval for destructive changes, versioned
|
||||
configuration history, rollback paths, audit events, and maintenance-mode
|
||||
guards.
|
||||
|
||||
The initial safety metadata contract lives in
|
||||
`govoplan_core.core.configuration_safety`. It classifies known configuration
|
||||
fields as UI-managed or deployment-managed, assigns risk levels, marks secret
|
||||
handling as reference-only or env-only, and declares dry-run, policy
|
||||
explanation, audit, approval, rollback-history, maintenance-mode, and RBAC
|
||||
requirements. Admin UI editors should consume this metadata before exposing
|
||||
powerful settings.
|
||||
|
||||
The initial executable guardrail path is `plan_configuration_change(...)`,
|
||||
exposed through:
|
||||
|
||||
- `GET /api/v1/admin/configuration-safety`
|
||||
- `POST /api/v1/admin/configuration-safety/plan`
|
||||
|
||||
The planner reports missing scopes, dry-run requirements, maintenance-mode
|
||||
requirements, two-person approval status, secret-reference violations,
|
||||
rollback-history requirements, policy explanations, and audit event names before
|
||||
an editor applies a high-impact configuration change.
|
||||
|
||||
## Reference Journeys
|
||||
|
||||
The roadmap should be driven by three journeys.
|
||||
|
||||
### Journey 1: Permit To Payment
|
||||
|
||||
This is the primary public-administration journey.
|
||||
|
||||
1. A person applies for a permit through the public portal.
|
||||
2. The applicant uploads required files and submits structured form data.
|
||||
3. Submission creates a case, a workflow instance, and an internal task.
|
||||
4. Completing the task creates a postbox message, a notification, and an email
|
||||
notification with an appointment proposal.
|
||||
5. The applicant accepts an appointment, which updates the calendar and the
|
||||
workflow state.
|
||||
6. During the appointment, the case is opened and the permit is generated from
|
||||
a governed template.
|
||||
7. The payment is processed and linked to the case and accounting handoff.
|
||||
8. The permit, payment evidence, communication history, audit trail, retention
|
||||
state, and records evidence remain available according to policy.
|
||||
|
||||
This journey proves the platform can coordinate modules without core knowing
|
||||
module internals.
|
||||
|
||||
### Journey 2: Training To Certificate
|
||||
|
||||
This is the best university-administration and internal-administration journey.
|
||||
|
||||
1. Course or training offer is planned.
|
||||
2. Room, trainer, resource, and capacity are booked.
|
||||
3. Participants register or are assigned.
|
||||
4. Attendance is tracked.
|
||||
5. Certificate or participation confirmation is issued.
|
||||
6. Evidence remains available through records, files, audit, and docs.
|
||||
|
||||
This journey keeps `booking`, `resources`, `learning`, and `certificates`
|
||||
focused instead of becoming broad ERP replacements.
|
||||
|
||||
### Journey 3: Report To Resolution
|
||||
|
||||
This is the internal operations and municipal issue-reporting journey.
|
||||
|
||||
1. A person reports an issue.
|
||||
2. The issue is triaged into helpdesk, facilities, assets, or a case.
|
||||
3. Work is assigned, tracked, and escalated.
|
||||
4. Evidence, communication, and status updates are preserved.
|
||||
5. Reports show workload, SLA, recurring problems, and completion.
|
||||
|
||||
This journey prevents `helpdesk`, `issue-reporting`, `facilities`, and `assets`
|
||||
from becoming disconnected ticket silos.
|
||||
|
||||
## Roadmap Waves
|
||||
|
||||
### Wave 0: Platform Spine
|
||||
|
||||
Goal: make the platform safe to configure and extend.
|
||||
|
||||
Refine:
|
||||
|
||||
- `govoplan-core`: module discovery, capabilities, events, migrations, release
|
||||
catalog, configuration package runtime, WebUI shell.
|
||||
- `govoplan-access`: identities, sessions, API keys, users, groups, roles,
|
||||
memberships, function assignments, delegation, RBAC decisions.
|
||||
- `govoplan-tenancy`: tenant and organizational-unit boundaries.
|
||||
- `govoplan-identity-trust`: initial trust contracts for device keys, public key
|
||||
directory, assurance, and later encrypted postbox key access.
|
||||
- `govoplan-policy`: policy sources, policy decisions, retention inputs.
|
||||
- `govoplan-audit`: audit sink, audit routes, trace context, retention
|
||||
cooperation.
|
||||
- `govoplan-admin`: UI-managed configuration with preflight, rollback, audit,
|
||||
and approval controls.
|
||||
- `govoplan-dashboard`: configurable user home assembled from module-provided
|
||||
widgets, with core providing only a minimal fallback when the module is absent.
|
||||
- `govoplan-docs`: configured-system documentation and evidence-aware help.
|
||||
- `govoplan-ops`: deployment profiles, health checks, worker split, sizing
|
||||
assumptions.
|
||||
|
||||
Do not expand domain scope in this wave. The output is a dependable platform
|
||||
surface for later modules.
|
||||
|
||||
Exit criteria:
|
||||
|
||||
- module enablement and capability lookup are stable
|
||||
- configuration package preflight works for at least one simple package
|
||||
- audit and policy decisions are visible in admin flows
|
||||
- access distinguishes identity, account, function, role, and right in durable
|
||||
contracts
|
||||
- action/effect automation contracts are specified before hidden side effects
|
||||
spread across modules
|
||||
- docs can show installed/enabled modules and configured routes
|
||||
|
||||
### Wave 1: Permit-To-Payment MVP
|
||||
|
||||
Goal: one complete public-administration process.
|
||||
|
||||
Create or refine in this order:
|
||||
|
||||
1. `govoplan-forms-runtime`: form submissions, drafts, validation, attachments,
|
||||
and submission evidence.
|
||||
2. `govoplan-portal`: public authenticated and unauthenticated entry points.
|
||||
3. `govoplan-files`: upload, evidence links, file spaces, and permissioned
|
||||
access.
|
||||
4. `govoplan-cases`: case record, status, assignments, deadlines, and case
|
||||
evidence.
|
||||
5. `govoplan-workflow`: state machine, transitions, commands, and module
|
||||
handoff.
|
||||
6. `govoplan-tasks`: work queues, assignments, due dates, and follow-ups.
|
||||
7. `govoplan-templates`: permit/decision document generation.
|
||||
8. `govoplan-postbox`, `govoplan-mail`, `govoplan-notifications`: applicant and
|
||||
internal communication, with the postbox model compatible with later E2EE
|
||||
and role-bound access.
|
||||
9. `govoplan-calendar`, `govoplan-appointments`, `govoplan-booking`: appointment
|
||||
or booking handoff for the reference process.
|
||||
10. `govoplan-payments`, `govoplan-ledger`, `govoplan-xrechnung`: payment
|
||||
capture, payment evidence, and accounting/e-invoice handoff.
|
||||
|
||||
Exit criteria:
|
||||
|
||||
- a permit-to-payment package can be installed in a local demo
|
||||
- every step has audit evidence
|
||||
- every module integration uses capabilities, events, or DTOs
|
||||
- user-facing documentation describes only the configured process
|
||||
|
||||
### Wave 2: Booking And Resource Operations
|
||||
|
||||
Goal: make time, capacity, and resource allocation a reusable product area.
|
||||
|
||||
Create or refine in this order:
|
||||
|
||||
1. `govoplan-booking`: booking rules, capacity, quotas, waitlists, cancellation,
|
||||
attendance, no-shows, and approvals.
|
||||
2. `govoplan-resources`: rooms, equipment, vehicles, counters, labs, capacity,
|
||||
availability, and maintenance blocks.
|
||||
3. `govoplan-calendar`: event and availability integration.
|
||||
4. `govoplan-appointments`: appointment-specific booking surfaces.
|
||||
5. `govoplan-facilities`: buildings, rooms, maintenance, access zones,
|
||||
inspections, and defects.
|
||||
6. `govoplan-assets`: inventory, assignment, lifecycle, maintenance, and handover
|
||||
evidence.
|
||||
|
||||
Reference journey: reserve a room/resource for a training or appointment and
|
||||
preserve all booking evidence.
|
||||
|
||||
Exit criteria:
|
||||
|
||||
- bookable resources are not hardcoded into appointments
|
||||
- booking decisions are explainable and auditable
|
||||
- resources can be blocked by maintenance or facility status
|
||||
|
||||
### Wave 3: Training And Certificates
|
||||
|
||||
Goal: support university-style and internal public-sector training without
|
||||
building a full learning-management system first.
|
||||
|
||||
Create or refine in this order:
|
||||
|
||||
1. `govoplan-learning`: course planning, course booking, participant lists,
|
||||
trainers, attendance, evaluations, and learning records.
|
||||
2. `govoplan-certificates`: participation confirmations, certificates,
|
||||
verification, revocation, and evidence links.
|
||||
3. `govoplan-booking`, `govoplan-resources`, `govoplan-calendar`: reuse booking
|
||||
and room/resource allocation.
|
||||
4. `govoplan-templates`, `govoplan-files`, `govoplan-records`: certificate
|
||||
generation and durable retention.
|
||||
|
||||
Reference journey: plan a course, book resources, register participants, track
|
||||
attendance, and issue a certificate.
|
||||
|
||||
Exit criteria:
|
||||
|
||||
- attendance can produce certificate eligibility
|
||||
- certificates can be verified later
|
||||
- course operations do not depend on university-specific assumptions
|
||||
|
||||
### Wave 4: Report-To-Resolution Operations
|
||||
|
||||
Goal: cover internal support and public issue reporting.
|
||||
|
||||
Create or refine in this order:
|
||||
|
||||
1. `govoplan-issue-reporting`: public/internal reports, categories, intake,
|
||||
location, evidence, and triage.
|
||||
2. `govoplan-helpdesk`: service desk tickets, queues, SLAs, assignments,
|
||||
escalation, and resolution evidence.
|
||||
3. `govoplan-facilities` and `govoplan-assets`: issue handoff to maintenance or
|
||||
asset lifecycle.
|
||||
4. `govoplan-cases`, `govoplan-workflow`, `govoplan-tasks`: escalation into
|
||||
formal administrative matters.
|
||||
5. `govoplan-reporting`: workload, SLA, recurring defects, and status reports.
|
||||
|
||||
Reference journey: report a facility issue, triage it, assign work, resolve it,
|
||||
and report recurring defects.
|
||||
|
||||
Exit criteria:
|
||||
|
||||
- issue reporting is not just a generic form inbox
|
||||
- helpdesk tickets can remain lightweight unless formal case handling is needed
|
||||
- operational metrics exist without custom SQL
|
||||
|
||||
### Wave 5: Records, DMS, Transparency
|
||||
|
||||
Goal: make evidence legally and organizationally durable.
|
||||
|
||||
Create or refine in this order:
|
||||
|
||||
1. `govoplan-dms`: document lifecycle, collaboration, versions, locks, approvals,
|
||||
and DMS connectors.
|
||||
2. `govoplan-records`: file plans, classification, retention schedules, disposal
|
||||
holds, archive handoff, and records evidence.
|
||||
3. `govoplan-policy` and `govoplan-audit`: retention policy, legal hold, audit
|
||||
traceability.
|
||||
4. `govoplan-search`: permissioned cross-module discovery.
|
||||
5. `govoplan-transparency`: FOI/public-records requests, redaction, publication,
|
||||
and disclosure evidence.
|
||||
|
||||
Reference journey: close a case, classify records, apply retention, and answer a
|
||||
transparency request.
|
||||
|
||||
Exit criteria:
|
||||
|
||||
- files, documents, and records are not treated as the same concept
|
||||
- transparency disclosure can redact and explain evidence
|
||||
- retention and archive handoff are policy-governed
|
||||
|
||||
### Wave 6: Finance, Procurement, Contracts, Grants
|
||||
|
||||
Goal: cover the back-office procedures around spending, obligations, funding,
|
||||
and revenue without replacing a finance system too early.
|
||||
|
||||
Create or refine in this order:
|
||||
|
||||
1. `govoplan-procurement`: purchase requests, approvals, vendor comparison,
|
||||
tender references, goods receipt, and handoff.
|
||||
2. `govoplan-contracts`: contract register, obligations, renewals, reminders,
|
||||
and responsible units.
|
||||
3. `govoplan-grants`: funding programs, applications, eligibility, awards,
|
||||
milestones, claims, and reporting duties.
|
||||
4. `govoplan-payments`, `govoplan-ledger`, `govoplan-xrechnung`: payment,
|
||||
accounting, and e-invoice handoff.
|
||||
5. `govoplan-erp`: integration with the actual system of record, not a full ERP
|
||||
replacement unless later justified.
|
||||
|
||||
Reference journey: purchase or grant approval through obligation tracking and
|
||||
financial handoff.
|
||||
|
||||
Exit criteria:
|
||||
|
||||
- ERP remains an integration point unless GovOPlaN must own semantics
|
||||
- contracts and grants produce obligations, deadlines, and reporting tasks
|
||||
- financial evidence links back to cases, files, and audit
|
||||
|
||||
### Wave 7: Institutional Governance And Participation
|
||||
|
||||
Goal: support public bodies, municipalities, ministries, and universities in
|
||||
formal coordination.
|
||||
|
||||
Create or refine in this order:
|
||||
|
||||
1. `govoplan-committee`: committees, boards, councils, agendas, minutes,
|
||||
decisions, voting, and follow-up tasks.
|
||||
2. `govoplan-consultation`: hearings, public consultations, stakeholder
|
||||
feedback, formal comments, response matrices, and publication workflows.
|
||||
3. `govoplan-campaign`: communication campaigns, recipients, templates, review,
|
||||
sending control, and reports.
|
||||
4. `govoplan-addresses`: persons, organizations, contacts, distribution lists,
|
||||
and recipient import/export.
|
||||
5. `govoplan-portal` and `govoplan-transparency`: public participation and
|
||||
publication surfaces.
|
||||
|
||||
Reference journey: prepare a committee decision, publish consultation material,
|
||||
collect feedback, document the decision, and assign follow-up tasks.
|
||||
|
||||
Exit criteria:
|
||||
|
||||
- decisions create durable tasks and records
|
||||
- consultations can publish evidence without exposing restricted material
|
||||
- campaign and address behavior stays optional and capability-based
|
||||
|
||||
### Wave 8: Integration, Data, And Reporting
|
||||
|
||||
Goal: connect the platform to real institutional landscapes.
|
||||
|
||||
Refine:
|
||||
|
||||
- `govoplan-connectors`: integration catalog, connector metadata, adapter
|
||||
lifecycle, test harnesses.
|
||||
- `govoplan-idm`, `govoplan-identity-trust`: identity provider, directory, and
|
||||
assurance integration.
|
||||
- `govoplan-fit-connect`, `govoplan-xoev`, `govoplan-xta-osci`: public-sector
|
||||
transport and standards integration.
|
||||
- `govoplan-reporting`: operational reporting, scheduled outputs, exports, and
|
||||
dashboard data.
|
||||
- `govoplan-search`: permissioned cross-module discovery.
|
||||
|
||||
Create only when justified:
|
||||
|
||||
- `govoplan-datasources`: source catalog, connection profiles, schema discovery,
|
||||
freshness, provenance.
|
||||
- `govoplan-dataflow`: transformations, validation, lineage, scheduled runs,
|
||||
publication outputs.
|
||||
- `govoplan-projects`: only if OpenProject connectors and existing cases/tasks
|
||||
cannot cover the required semantics.
|
||||
|
||||
Reference journey: monthly data extraction, transformation, validation, approval,
|
||||
publication, and reporting.
|
||||
|
||||
Recurring extraction/transformation should start as a configuration package
|
||||
across connectors, files, workflow, reporting, and templates. The package should
|
||||
register sources, declare schemas, define mapping/validation versions, schedule
|
||||
runs, produce previewable diffs, write governed outputs, and preserve lineage,
|
||||
hashes, operator actions, and audit evidence. Create `govoplan-datasources` or
|
||||
`govoplan-dataflow` only after this work exposes repeated contracts that do not
|
||||
belong to existing modules.
|
||||
|
||||
Exit criteria:
|
||||
|
||||
- connector catalog exists before building many adapters
|
||||
- dataflow is created only after recurring transformation becomes product
|
||||
behavior
|
||||
- reporting consumes governed sources with provenance
|
||||
|
||||
## Implementation Gates
|
||||
|
||||
Before a module receives implementation work, it needs:
|
||||
|
||||
- one reference journey step it owns
|
||||
- ownership and boundary notes
|
||||
- initial manifest and permission list
|
||||
- capability contracts or API DTOs
|
||||
- audit and policy expectations
|
||||
- Gitea issues for MVP tasks
|
||||
- docs page that can sync to the wiki
|
||||
- focused tests that can run from the core environment
|
||||
|
||||
Before a module becomes release-included, it needs:
|
||||
|
||||
- installable Python package metadata where applicable
|
||||
- WebUI package metadata where applicable
|
||||
- module manifest entry point
|
||||
- release catalog entry
|
||||
- smoke test or permutation test
|
||||
- no required imports from optional modules
|
||||
|
||||
## Priority Order Summary
|
||||
|
||||
1. Stabilize the platform spine.
|
||||
2. Deliver permit-to-payment MVP.
|
||||
3. Build booking and resource operations.
|
||||
4. Add learning and certificates.
|
||||
5. Add issue reporting and helpdesk.
|
||||
6. Add records, DMS, search, and transparency.
|
||||
7. Add procurement, contracts, grants, and finance handoff.
|
||||
8. Add committee and consultation workflows.
|
||||
9. Expand integration, dataflow, reporting, and operations.
|
||||
|
||||
## Deliberate Deferrals
|
||||
|
||||
Defer these until a reference journey proves the need:
|
||||
|
||||
- full ERP replacement
|
||||
- native project management beyond connector support
|
||||
- broad BI/dataflow platform
|
||||
- every possible public-sector protocol adapter
|
||||
- rich LMS behavior beyond training administration
|
||||
- full qualified digital signing/trust services beyond the identity-trust and
|
||||
encrypted-postbox contracts needed for early architecture safety
|
||||
- mobile apps
|
||||
- AI assistants embedded into workflows
|
||||
|
||||
These may become important, but they should not distract from the first complete
|
||||
administrative journeys.
|
||||
|
||||
## Module And Integration Routing
|
||||
|
||||
This table maps current module and integration ideas to existing GovOPlaN
|
||||
repositories or to explicit missing-module decisions.
|
||||
|
||||
| Idea | Owner | Tracking |
|
||||
| --- | --- | --- |
|
||||
| Government operations backbone reference model | `govoplan-core` | `add-ideas/govoplan-core#213` |
|
||||
| Permit-to-payment configuration package | `govoplan-core` plus participating modules | `add-ideas/govoplan-core#214` |
|
||||
| Fully UI-managed configuration with safety controls | `govoplan-admin`, `govoplan-core`, `govoplan-policy`, `govoplan-access`, `govoplan-audit` | `add-ideas/govoplan-core#218` |
|
||||
| Access as a module | `govoplan-access` | `add-ideas/govoplan-access#7` |
|
||||
| Interface ethics and decision-consequence doctrine | `govoplan-core` plus all UI-owning modules | `add-ideas/govoplan-core#227` |
|
||||
| Action/effect automation layer | first `govoplan-workflow`; possible future `govoplan-automation` | `add-ideas/govoplan-workflow#1` |
|
||||
| E2EE role/function postbox architecture | `govoplan-postbox`, `govoplan-identity-trust`, `govoplan-access`, `govoplan-policy`, `govoplan-audit` | `add-ideas/govoplan-postbox#15`, `add-ideas/govoplan-identity-trust#1` |
|
||||
| Identity, account, function, role, right semantic model | `govoplan-access` | `add-ideas/govoplan-access#9` |
|
||||
| Role-based service directory/catalog | `govoplan-portal` | `add-ideas/govoplan-portal#1` |
|
||||
| Unified inbox across tasks, postbox, notifications, and portal | `govoplan-core` coordination plus owning modules | `add-ideas/govoplan-tasks#1`, `add-ideas/govoplan-notifications#1` |
|
||||
| OpenProject API / project management connector | `govoplan-connectors` | `add-ideas/govoplan-connectors#1` |
|
||||
| Native project-management module decision | connector-first through `govoplan-connectors`; no native project module yet | `add-ideas/govoplan-core#196`, `add-ideas/govoplan-connectors#1` |
|
||||
| Datasources for databases, CSV, files, APIs | no repository yet; start with connectors/files/reporting and create `govoplan-datasources` only after the first package proves shared source-catalog ownership | `add-ideas/govoplan-core#197` |
|
||||
| Dataflow for pipelines, BI, publication | no repository yet; start with workflow/reporting/connectors and create `govoplan-dataflow` only after repeated pipeline/lineage contracts emerge | `add-ideas/govoplan-core#198` |
|
||||
| Monthly datasource and transformation workflows | first as configuration package across connectors, files, workflow, reporting, and templates | `add-ideas/govoplan-core#216` |
|
||||
| Templates for letters, emails, forms, reports | `govoplan-templates`, separate from reporting | `add-ideas/govoplan-core#190`, `add-ideas/govoplan-templates#1` |
|
||||
| Reporting and BI | `govoplan-reporting`, separate from templates | `add-ideas/govoplan-core#190`, `add-ideas/govoplan-reporting#1` |
|
||||
| File connectors: Nextcloud, Seafile, SMB, NFS | `govoplan-files` | `add-ideas/govoplan-files#15` |
|
||||
| Public-sector software integration catalogue | `govoplan-connectors` with core strategy index | `add-ideas/govoplan-core#191`, `add-ideas/govoplan-connectors#2` |
|
||||
| Public-sector integration landscape catalogue | `govoplan-connectors` with core tracking | `add-ideas/govoplan-core#215` |
|
||||
| Cases module concept | `govoplan-cases` | `add-ideas/govoplan-core#174` |
|
||||
| Workflow module concept | `govoplan-workflow` | `add-ideas/govoplan-core#175` |
|
||||
| Connectors module concept | `govoplan-connectors` | `add-ideas/govoplan-core#176` |
|
||||
| Adrema-style address and distribution-list management | `govoplan-addresses` | `add-ideas/govoplan-addresses#1` |
|
||||
| Consume sources and become a governed source | `govoplan-connectors` plus possible future `govoplan-dataflow` | `add-ideas/govoplan-connectors#3`, `add-ideas/govoplan-core#198` |
|
||||
| Governed connector configuration, dry-run, and simulation runtime | `govoplan-connectors` | `add-ideas/govoplan-connectors#6` |
|
||||
| Terminfindung and meeting scheduling polls | `govoplan-scheduling`; calendar primitives remain in calendar | `add-ideas/govoplan-core#193`, `add-ideas/govoplan-scheduling#1` |
|
||||
| Terminplaner and calendar primitives | `govoplan-calendar` | `add-ideas/govoplan-core#193`, `add-ideas/govoplan-calendar#1` |
|
||||
| Terminbuchung appointment booking | `govoplan-appointments` | `add-ideas/govoplan-core#193`, `add-ideas/govoplan-appointments#1` |
|
||||
| Collaborative documents | `govoplan-dms` | `add-ideas/govoplan-dms#1` |
|
||||
| Forms | `govoplan-forms` for definitions and `govoplan-forms-runtime` for submissions/runtime behavior | `add-ideas/govoplan-core#194`, `add-ideas/govoplan-forms#1` |
|
||||
| RSS consume and emit | `govoplan-connectors` | `add-ideas/govoplan-connectors#4` |
|
||||
| LDAP, Active Directory, OpenDesk identity | `govoplan-idm` | `add-ideas/govoplan-idm#1` |
|
||||
| OpenDesk stack integration map | integration profile across IDM/access, mail/calendar, files/DMS, and connectors; not a monolithic module | `add-ideas/govoplan-core#195`, `add-ideas/govoplan-connectors#5` |
|
||||
| Open-Xchange mail/groupware | `govoplan-mail` | `add-ideas/govoplan-mail#5` |
|
||||
| Open-Xchange calendar | `govoplan-calendar` | `add-ideas/govoplan-calendar#2` |
|
||||
| Scalability profiles and autoscaling readiness | `govoplan-ops`, `govoplan-core` | `add-ideas/govoplan-core#217` |
|
||||
| Hardware sizing matrix and requirements calculator | `govoplan-ops`, `govoplan-core` | `add-ideas/govoplan-core#219` |
|
||||
| Collaboration suite integration strategy | `govoplan-connectors`, `govoplan-dms`, `govoplan-workflow`, `govoplan-tasks`, `govoplan-appointments`, `govoplan-calendar` | `add-ideas/govoplan-core#220` |
|
||||
| Install/runtime configuration contract | `govoplan-core`, later `govoplan-ops` | `add-ideas/govoplan-core#19` |
|
||||
| Installer/deployment operator flow | `govoplan-core`, later `govoplan-ops` | `add-ideas/govoplan-core#26` |
|
||||
| Production-like deployment documentation | `govoplan-core`, later `govoplan-ops` | `add-ideas/govoplan-core#28` |
|
||||
|
||||
Boundary rationale lives in `MODULE_ARCHITECTURE.md`. Current decisions:
|
||||
|
||||
- templates and reporting are separate modules
|
||||
- RSS/source consume-publish starts in connectors; datasources/dataflow are not
|
||||
repositories yet
|
||||
- calendar, scheduling, and appointments are three separate modules
|
||||
- forms definitions and forms runtime are separate responsibilities
|
||||
- OpenDesk is an integration profile across modules, not a monolithic module
|
||||
- OpenProject is connector-first; no native projects module yet
|
||||
- public-sector integration strategy stays in core; executable catalogue work
|
||||
lives in connectors
|
||||
- encrypted postbox and identity-trust are strategic contracts, not mail-module
|
||||
behavior
|
||||
- automation starts as workflow-owned action/effect execution and may split into
|
||||
a dedicated module only after the runner becomes broader than workflow
|
||||
|
||||
The following modules are intentionally not created yet:
|
||||
|
||||
- `govoplan-datasources`
|
||||
- `govoplan-dataflow`
|
||||
- `govoplan-projects`
|
||||
|
||||
Create a repository only after a concrete implementation package proves that
|
||||
existing connector, files, reporting, workflow, or task ownership is too narrow.
|
||||
|
||||
Core keeps the strategy index in
|
||||
`PUBLIC_SECTOR_INTEGRATION_STRATEGY.md`: integration postures, default
|
||||
ownership, and prioritization rules. `govoplan-connectors` owns the detailed
|
||||
target inventory and connector entry shape in
|
||||
`govoplan-connectors/docs/PUBLIC_SECTOR_INTEGRATION_CATALOGUE.md`.
|
||||
|
||||
Release composition and tag-only repository handling are documented in
|
||||
`RELEASE_DEPENDENCIES.md`.
|
||||
|
||||
## Next Practical Work
|
||||
|
||||
The next planning step should create or update Gitea issues for Wave 0 and Wave
|
||||
1 only. Later waves should stay as roadmap context until the permit-to-payment
|
||||
MVP is demonstrable.
|
||||
|
||||
Recommended immediate issue buckets:
|
||||
|
||||
- platform spine hardening
|
||||
- configuration package preflight and rollback
|
||||
- forms-runtime MVP
|
||||
- portal submission MVP
|
||||
- cases/workflow/tasks integration MVP
|
||||
- template-generated decision document
|
||||
- postbox/notification handoff
|
||||
- appointment/booking handoff
|
||||
- payment evidence handoff
|
||||
- configured documentation for the reference process
|
||||
@@ -1,79 +0,0 @@
|
||||
# GovOPlaN Module And Integration Roadmap
|
||||
|
||||
This page maps current module and integration ideas to existing GovOPlaN repositories or to missing-module decisions. Issues are the active backlog. This document is durable routing context and should be mirrored to the Gitea wiki.
|
||||
|
||||
## Current Routing
|
||||
|
||||
| Idea | Owner | Tracking |
|
||||
| --- | --- | --- |
|
||||
| Access as a module | `govoplan-access` | `add-ideas/govoplan-access#7` |
|
||||
| OpenProject API / project management connector | `govoplan-connectors` | `add-ideas/govoplan-connectors#1` |
|
||||
| Native project-management module decision | `govoplan-core` | `add-ideas/govoplan-core#196` |
|
||||
| Datasources for databases, CSV, files, APIs | proposed `govoplan-datasources` | `add-ideas/govoplan-core#197` |
|
||||
| Dataflow for pipelines, BI, publication | proposed `govoplan-dataflow` | `add-ideas/govoplan-core#198` |
|
||||
| Templates for letters, emails, forms, reports | `govoplan-templates` | `add-ideas/govoplan-templates#1` |
|
||||
| Reporting and BI | `govoplan-reporting` | `add-ideas/govoplan-reporting#1` |
|
||||
| File connectors: Nextcloud, Seafile, SMB, NFS | `govoplan-files` | `add-ideas/govoplan-files#15` |
|
||||
| Public-sector software integration catalogue | `govoplan-connectors` | `add-ideas/govoplan-connectors#2` |
|
||||
| Adrema-style address and distribution-list management | `govoplan-addresses` | `add-ideas/govoplan-addresses#1` |
|
||||
| Consume sources and become a governed source | `govoplan-connectors` plus proposed `govoplan-dataflow` | `add-ideas/govoplan-connectors#3`, `add-ideas/govoplan-core#198` |
|
||||
| Terminfindung and meeting scheduling polls | `govoplan-scheduling` | local scaffold; remote creation tracked by `add-ideas/govoplan-core#199` |
|
||||
| Terminplaner and calendar primitives | `govoplan-calendar` | `add-ideas/govoplan-calendar#1` |
|
||||
| Terminbuchung appointment booking | `govoplan-appointments` | `add-ideas/govoplan-appointments#1` |
|
||||
| Collaborative documents | `govoplan-dms` | `add-ideas/govoplan-dms#1` |
|
||||
| Forms | `govoplan-forms` | `add-ideas/govoplan-forms#1` |
|
||||
| RSS consume and emit | `govoplan-connectors` | `add-ideas/govoplan-connectors#4` |
|
||||
| LDAP, Active Directory, OpenDesk identity | `govoplan-idm` | `add-ideas/govoplan-idm#1` |
|
||||
| OpenDesk stack integration map | `govoplan-connectors` | `add-ideas/govoplan-connectors#5` |
|
||||
| Open-Xchange mail/groupware | `govoplan-mail` | `add-ideas/govoplan-mail#5` |
|
||||
| Open-Xchange calendar | `govoplan-calendar` | `add-ideas/govoplan-calendar#2` |
|
||||
|
||||
## Proposed Missing Modules
|
||||
|
||||
`govoplan-datasources` should exist only if source catalog ownership becomes broad enough to justify a module separate from connectors and reporting. Candidate responsibilities:
|
||||
|
||||
- source catalogue for SQL databases, CSV/Excel files, uploaded files, APIs, RSS feeds, and governed file locations
|
||||
- credentials and connection profiles
|
||||
- schema discovery and refresh cadence
|
||||
- provenance, freshness, permission boundaries, and audit events
|
||||
|
||||
`govoplan-dataflow` should exist only if pipelines and publication become first-class product behavior. Candidate responsibilities:
|
||||
|
||||
- ingestion, transformation, validation, scheduling, and lineage
|
||||
- connecting datasources to reports, APIs, RSS, exports, and downstream systems
|
||||
- the "consume sources, become source" lifecycle
|
||||
- publication-state and audit integration
|
||||
|
||||
`govoplan-projects` is undecided. The default path should be an OpenProject connector first. A native module is justified only if GovOPlaN must own project semantics beyond cases, tasks, workflow, appointments, documents, and reporting.
|
||||
|
||||
## Boundary Notes
|
||||
|
||||
- `govoplan-connectors` owns protocol and external-system integration strategy. It should not own business semantics once a domain module exists.
|
||||
- `govoplan-files` owns file storage semantics and file-provider contracts. Remote provider implementations must stay optional.
|
||||
- `govoplan-dms` owns document lifecycle, collaboration, versions, approvals, locks, retention, and legal hold.
|
||||
- `govoplan-addresses` owns persons, organizations, postal/email addresses, distribution lists, and recipient import/export.
|
||||
- `govoplan-calendar` owns events, availability, resources, recurrence, and groupware calendar adapters.
|
||||
- `govoplan-scheduling` owns meeting scheduling polls, participant availability collection, candidate-slot ranking, and decision handoff.
|
||||
- `govoplan-appointments` owns public/internal appointment-booking workflows.
|
||||
- `govoplan-idm` owns directory, provisioning, and identity-provider integration; `govoplan-access` consumes resolved principals and permissions.
|
||||
- `govoplan-reporting` owns report definitions, BI views, scheduled outputs, and export targets.
|
||||
- `govoplan-templates` owns reusable renderable templates, not data selection or persistence.
|
||||
|
||||
## Release Tooling Note
|
||||
|
||||
`scripts/push-release-tag.sh` covers the released full-product package set:
|
||||
|
||||
- `govoplan-access`
|
||||
- `govoplan-admin`
|
||||
- `govoplan-tenancy`
|
||||
- `govoplan-policy`
|
||||
- `govoplan-audit`
|
||||
- `govoplan-files`
|
||||
- `govoplan-mail`
|
||||
- `govoplan-campaign`
|
||||
- `govoplan-calendar`
|
||||
- `govoplan-core`
|
||||
|
||||
It also includes existing roadmap/scaffold module repositories such as addresses, appointments, connectors, DMS, forms, IDM, reporting, scheduling, templates, workflow, XOE/V, and XRechnung as tag-only repositories. Tag-only repositories are committed, tagged, and pushed with the same release tag, but they are not added to `requirements-release.txt` or `webui/package.release.json` until they contain installable package metadata.
|
||||
|
||||
Proposed modules without repositories, such as `govoplan-datasources`, `govoplan-dataflow`, and possibly `govoplan-projects`, cannot be included until their repositories are created.
|
||||
102
docs/INTERFACE_ETHICS_AND_DESIGN_DOCTRINE.md
Normal file
102
docs/INTERFACE_ETHICS_AND_DESIGN_DOCTRINE.md
Normal file
@@ -0,0 +1,102 @@
|
||||
# GovOPlaN Interface Ethics And Design Doctrine
|
||||
|
||||
This document captures the product-level design doctrine for GovOPlaN. It is
|
||||
more durable than an individual screen design and should guide admin,
|
||||
configuration, workflow, policy, portal, and operational UI decisions.
|
||||
|
||||
GovOPlaN is meant to support administrative responsibility. The interface must
|
||||
therefore make context, decision, consequence, and traceability visible enough
|
||||
that users can act deliberately instead of being pushed through opaque
|
||||
automation.
|
||||
|
||||
## Core Doctrine
|
||||
|
||||
1. Context, decision, and consequence belong together.
|
||||
2. Decisions should not silently happen.
|
||||
3. Transparency comes before convenience when rights, duties, records, money,
|
||||
access, or legal effects are involved.
|
||||
4. Explicit state is preferable to implicit state.
|
||||
5. Navigation is not consent.
|
||||
6. Responsibility cannot be delegated to the system.
|
||||
7. Traceability is part of the action, not a later reporting feature.
|
||||
8. Context loss is a product defect.
|
||||
|
||||
These rules do not mean every screen should become verbose. They mean the
|
||||
interface must expose the right explanation at the moment of decision and keep
|
||||
technical detail available without making it the default surface.
|
||||
|
||||
## Decision Surface Contract
|
||||
|
||||
Any action that changes records, rights, policies, retention, communication,
|
||||
payments, external systems, or workflow state should answer these questions
|
||||
before execution:
|
||||
|
||||
- What object, person, organization, or process is affected?
|
||||
- Which authority or role allows the actor to do this?
|
||||
- What will change immediately?
|
||||
- What downstream effects may happen?
|
||||
- Can the action be undone, superseded, or only corrected later?
|
||||
- What evidence or audit entry will be created?
|
||||
- Which policy, configuration, or missing capability blocks the action?
|
||||
- Who can resolve a blocker?
|
||||
|
||||
The answer may be shown through inline labels, a review step, a side panel, a
|
||||
problem list, or a confirmation dialog. The important point is that consequence
|
||||
and responsibility are not hidden behind a generic submit button.
|
||||
|
||||
## Contestability
|
||||
|
||||
Administrative decisions are often contestable or reviewable. GovOPlaN should
|
||||
therefore preserve the path from input to decision:
|
||||
|
||||
- source data and attachments
|
||||
- workflow state and task assignment
|
||||
- policy decisions and source path
|
||||
- actor and delegation context
|
||||
- generated document/template version
|
||||
- external handoff result
|
||||
- notification or postbox delivery evidence
|
||||
- retention and record classification state
|
||||
|
||||
Where a user sees a decision, they should be able to reach the provenance that
|
||||
explains how the system got there. This is especially important for denials,
|
||||
locks, calculated defaults, generated documents, payment state, retention
|
||||
state, and access decisions.
|
||||
|
||||
## Anti-Patterns
|
||||
|
||||
Avoid these patterns in GovOPlaN interfaces:
|
||||
|
||||
- Magical buttons that execute multiple side effects without preview.
|
||||
- Process tunnels that hide where the user is in an administrative procedure.
|
||||
- Silent automation that changes external systems without an audit-visible
|
||||
command record.
|
||||
- Friendly hiding that removes complexity at the cost of obscuring authority,
|
||||
consequence, or accountability.
|
||||
- Disabled controls without actionable explanation.
|
||||
- Configuration screens that ask users to edit raw JSON as the normal path.
|
||||
|
||||
## Automation Rule
|
||||
|
||||
Automation must use the same governed action surface as a human actor. The
|
||||
system may execute actions as a system actor, but it must still run through
|
||||
policy checks, capability contracts, audit, idempotency, and failure handling.
|
||||
|
||||
When an automated decision is not clear, GovOPlaN should create a manual
|
||||
exception, task, or review item instead of guessing silently.
|
||||
|
||||
## Relationship To UI Components
|
||||
|
||||
Shared components should make this doctrine easy to follow:
|
||||
|
||||
- preflight and problem-list components for blockers
|
||||
- policy source path and effective decision displays
|
||||
- action review panels for consequence preview
|
||||
- audit/provenance links on decision outputs
|
||||
- guided dialogs for risky configuration
|
||||
- disabled-action explanations with actor and next step
|
||||
- confirmation dialogs that distinguish reversible, corrective, and destructive
|
||||
actions
|
||||
|
||||
The UI/UX decision ledger defines concrete implementation rules. This doctrine
|
||||
defines why those rules exist.
|
||||
@@ -2,10 +2,17 @@
|
||||
|
||||
GovOPlaN is structured as a platform kernel plus installable modules. The kernel starts and composes the platform. Modules own product behavior and contribute backend routes, database metadata, permissions, WebUI routes, navigation metadata, capabilities, and events.
|
||||
|
||||
The current package name is still `govoplan-core`, but the architecture target is a smaller kernel. Access, tenancy, policy, audit, and admin semantics are platform-module responsibilities and should be extracted in stages.
|
||||
The current package name is still `govoplan-core`, but the architecture target is a smaller kernel. Access, tenancy, policy, audit, and admin semantics are platform-module responsibilities.
|
||||
|
||||
The concrete access/auth/RBAC extraction path is tracked in
|
||||
[`ACCESS_EXTRACTION_PLAN.md`](ACCESS_EXTRACTION_PLAN.md).
|
||||
Access extraction is complete enough that current ownership is described here,
|
||||
in [`ACCESS_RBAC_MODEL.md`](ACCESS_RBAC_MODEL.md), and in the
|
||||
`govoplan-access` repository docs.
|
||||
The event and audit trace contract is tracked in
|
||||
[`EVENTS_AND_AUDIT.md`](EVENTS_AND_AUDIT.md).
|
||||
Policy decision, source provenance, and explain-response contracts are tracked
|
||||
in [`POLICY_CONTRACTS.md`](POLICY_CONTRACTS.md).
|
||||
The experimental remote WebUI bundle loading design is tracked in
|
||||
[`REMOTE_WEBUI_BUNDLES.md`](REMOTE_WEBUI_BUNDLES.md).
|
||||
|
||||
## Layer Model
|
||||
|
||||
@@ -35,14 +42,15 @@ The kernel must not own product semantics such as users, tenants, RBAC decisions
|
||||
## Current Compatibility Responsibilities
|
||||
|
||||
During the staged split, `govoplan-core` still contains compatibility surfaces
|
||||
for access, auth, tenancy, RBAC, governance, audit, CSRF/API helpers, and
|
||||
secret helpers. The extracted access implementation now lives in
|
||||
`govoplan-access`; live legacy ORM table definitions have been split across
|
||||
their platform owners while retaining historical table names. The old core
|
||||
model, route, admin-service, and access-security import shims have been
|
||||
removed; callers must use module-owned imports or kernel capabilities. The
|
||||
remaining compatibility surfaces are temporary until the matching platform
|
||||
modules are fully self-contained:
|
||||
for tenancy settings, governance/policy contracts, audit helpers, CSRF/API
|
||||
helpers, and secret helpers. The extracted access implementation lives in
|
||||
`govoplan-access`; live ORM table definitions have been split across their
|
||||
platform owners using module-prefixed table names. The old core route,
|
||||
admin-service, and access-security re-export modules have been removed.
|
||||
Callers must use module-owned imports, the public `govoplan_access.auth` request
|
||||
dependency API, or kernel capabilities.
|
||||
The remaining platform compatibility surfaces are temporary until the matching
|
||||
platform modules are fully self-contained:
|
||||
|
||||
- `govoplan-access`
|
||||
- `govoplan-tenancy`
|
||||
@@ -54,6 +62,18 @@ New code should avoid deepening these compatibility dependencies. Prefer explici
|
||||
|
||||
Core must not import module feature pages or module business logic directly. It should interact with modules through manifests, entry points, metadata, capabilities, events, and route contributions.
|
||||
|
||||
The compatibility/deprecation plan for the current split line is:
|
||||
|
||||
- keep documented public compatibility imports until the owning module exposes a
|
||||
stable replacement and all in-tree callers have migrated
|
||||
- remove deep implementation re-export modules once callers can use module-owned
|
||||
public APIs or kernel capabilities
|
||||
- preserve migration/table compatibility for already-created development and
|
||||
release databases
|
||||
- document remaining compatibility surfaces here and in the owning module README
|
||||
- reject new cross-module imports that bypass manifests, capabilities, events,
|
||||
or public module APIs
|
||||
|
||||
## Stable Kernel Contracts
|
||||
|
||||
The following contracts are the baseline API that modules can rely on:
|
||||
@@ -71,9 +91,15 @@ The following contracts are the baseline API that modules can rely on:
|
||||
- WebUI module contribution contract
|
||||
- navigation metadata contract
|
||||
- command/event envelope contract
|
||||
- policy decision and source provenance contract in `govoplan_core.core.policy`
|
||||
|
||||
Changes to these contracts must be versioned or accompanied by compatibility shims.
|
||||
|
||||
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
|
||||
remain source-compatible through the 0.1.x split line unless a migration shim
|
||||
and deprecation note are provided.
|
||||
|
||||
Known access-related capability names are defined in
|
||||
`govoplan_core.core.access`, including:
|
||||
|
||||
@@ -99,22 +125,23 @@ access/tenant ORM models when they need labels, group membership, default
|
||||
access provisioning, counts, audit actor labels, or tenant metadata.
|
||||
|
||||
FastAPI route dependencies for authenticated endpoints are access-owned and
|
||||
published from `govoplan_access.backend.auth.dependencies`. Routers may import
|
||||
that dependency module directly until a more generic request-principal adapter
|
||||
exists; they must not import access ORM models or other access implementation
|
||||
internals.
|
||||
published from `govoplan_access.auth`. Routers may import that public API for
|
||||
`ApiPrincipal`, `get_api_principal`, `has_scope`, `require_scope`, and
|
||||
`require_any_scope`; they must not import access ORM models or
|
||||
`govoplan_access.backend.*` implementation internals.
|
||||
|
||||
Current live table ownership:
|
||||
|
||||
- `govoplan-tenancy`: `tenants`
|
||||
- `govoplan-access`: `accounts`, `users`, `groups`, `roles`,
|
||||
`system_role_assignments`, `user_group_memberships`,
|
||||
`user_role_assignments`, `group_role_assignments`, `api_keys`,
|
||||
`auth_sessions`
|
||||
- `govoplan-admin`: `governance_templates`,
|
||||
`governance_template_assignments`
|
||||
- `govoplan-tenancy`: `tenancy_tenants`
|
||||
- `govoplan-access`: `access_accounts`, `access_users`, `access_groups`,
|
||||
`access_roles`, `access_system_role_assignments`,
|
||||
`access_user_group_memberships`, `access_user_role_assignments`,
|
||||
`access_group_role_assignments`, `access_api_keys`,
|
||||
`access_auth_sessions`
|
||||
- `govoplan-admin`: `admin_governance_templates`,
|
||||
`admin_governance_template_assignments`
|
||||
- `govoplan-audit`: `audit_log`
|
||||
- `govoplan-core`: `system_settings`
|
||||
- `govoplan-core`: `core_system_settings`
|
||||
|
||||
Current admin route ownership follows the same boundary: access contributes
|
||||
users, groups, roles, system accounts/roles, auth, sessions, and API-key
|
||||
@@ -143,6 +170,183 @@ campaign file-share access, and core retention can call campaign-owned cleanup
|
||||
logic without importing campaign ORM models. Keep these contracts small
|
||||
DTO/protocol surfaces and register concrete behavior from the owning module.
|
||||
|
||||
## API Efficiency Contracts
|
||||
|
||||
GovOPlaN uses conditional GET and delta collections to reduce reload cost
|
||||
without giving every module a custom synchronization format.
|
||||
|
||||
### Conditional GET
|
||||
|
||||
Core applies conditional GET handling centrally for successful JSON `GET`
|
||||
responses:
|
||||
|
||||
- Responses receive a weak `ETag` based on the serialized JSON body.
|
||||
- Responses are marked `Cache-Control: private, no-cache`.
|
||||
- Responses vary by `Authorization`, `Cookie`, `X-API-Key`, and
|
||||
`Accept-Language`.
|
||||
- Matching `If-None-Match` requests return `304 Not Modified` without a body.
|
||||
- Responses with `Set-Cookie`, `Content-Disposition`, `Content-Encoding`, a
|
||||
non-JSON content type, a non-200 status, or `Cache-Control: no-store` are not
|
||||
converted.
|
||||
|
||||
The WebUI `apiFetch` client keeps an in-memory conditional cache for reusable
|
||||
safe requests. It sends `If-None-Match` after an endpoint has returned an ETag,
|
||||
returns the cached payload on `304`, and clears the cache generation after
|
||||
unsafe methods.
|
||||
|
||||
This avoids retransmitting unchanged snapshots. It does not identify which row
|
||||
changed inside a collection.
|
||||
|
||||
### Delta Collections
|
||||
|
||||
Collection endpoints that can expose row-level changes should use the shared
|
||||
delta contract instead of inventing module-specific formats.
|
||||
|
||||
Core provides `core_change_sequence` as the shared monotonic change sequence.
|
||||
Modules record append-only entries in the same database transaction as the
|
||||
resource write. Watermarks are encoded as `seq:<number>` and should be treated
|
||||
as opaque by clients.
|
||||
|
||||
Backend shape:
|
||||
|
||||
```json
|
||||
{
|
||||
"items": [],
|
||||
"deleted": [],
|
||||
"watermark": "opaque-next-watermark",
|
||||
"has_more": false,
|
||||
"full": false
|
||||
}
|
||||
```
|
||||
|
||||
Fields:
|
||||
|
||||
- `items`: changed or current items since the requested watermark.
|
||||
- `deleted`: deleted item markers with at least `id`, and optionally
|
||||
`resource_type`, `revision`, and `deleted_at`.
|
||||
- `watermark`: opaque value the client sends as `since` on the next request.
|
||||
- `has_more`: true when the client should request the next page with the
|
||||
returned watermark.
|
||||
- `full`: true when the response is a full snapshot rather than an incremental
|
||||
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:
|
||||
|
||||
- `since`: opaque previous watermark. If omitted or expired, return a full
|
||||
snapshot with `full: true`.
|
||||
- `limit`: maximum number of changed items plus deleted markers.
|
||||
- `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:
|
||||
|
||||
- `module_id`: the owning module, for example `files`.
|
||||
- `collection`: the delta collection, for example `files.assets`.
|
||||
- `resource_type`: stable row kind, for example `file` or `folder`.
|
||||
- `resource_id`: stable resource identifier.
|
||||
- `operation`: `created`, `updated`, or `deleted`.
|
||||
- `tenant_id`: tenant scope when the change is tenant-owned.
|
||||
- `payload`: small, non-secret routing metadata that helps determine whether a
|
||||
tombstone belongs to the requested view.
|
||||
|
||||
Sequence retention is explicit. Cleanup jobs must call
|
||||
`prune_sequence_entries(...)` rather than deleting `core_change_sequence` rows
|
||||
directly. Pruning records a retention floor per module, collection, and tenant
|
||||
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.
|
||||
|
||||
### 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:
|
||||
|
||||
- `GET /api/v1/files/delta`: without `since`, returns the current files/folders
|
||||
snapshot for the requested owner/campaign scope. With `since=seq:<number>`,
|
||||
returns changed files, changed folders, and tombstones for resources that
|
||||
left the current view.
|
||||
- `GET /api/v1/campaigns/delta`: returns accessible campaign rows and campaign
|
||||
tombstones when ownership, sharing, or soft deletion removes a campaign from
|
||||
the current list.
|
||||
- `GET /api/v1/campaigns/{campaign_id}/workspace/delta`: returns a workspace
|
||||
snapshot first, then changed campaign/version metadata and optional summary
|
||||
refreshes when version, job, issue, or delivery-attempt changes invalidate the
|
||||
workspace view.
|
||||
- `GET /api/v1/campaigns/{campaign_id}/jobs/delta`: returns a paginated job
|
||||
table snapshot first, then stable row deltas for cursor-backed job pages.
|
||||
The job list also supports offset compatibility for first visits to a page and
|
||||
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
|
||||
|
||||
A module owns one bounded feature area. A module can include both backend and WebUI code in the same repository so feature behavior and frontend integration evolve together.
|
||||
@@ -195,6 +399,18 @@ 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.
|
||||
|
||||
## 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.
|
||||
@@ -209,6 +425,10 @@ Rules:
|
||||
- Optional module migrations may create multiple Alembic heads. Verification
|
||||
should compare the database heads to the configured script heads instead of
|
||||
assuming one linear revision when multiple modules are enabled.
|
||||
- Treat migrations as release artifacts. Unreleased migrations may be squashed
|
||||
or rewritten before a stable release; released revision IDs are immutable
|
||||
once an installation may have recorded them. Each stable release records its
|
||||
public migration heads in `docs/migration-release-baselines.json`.
|
||||
|
||||
## Install, Uninstall, And Catalogs
|
||||
|
||||
@@ -290,6 +510,31 @@ capabilities with `usePlatformUiCapabilities("admin.sections")`, filters them
|
||||
by `anyOf`/`allOf`, and renders them without importing the contributing module's
|
||||
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
|
||||
|
||||
Icons are resolved centrally by core.
|
||||
@@ -354,14 +599,221 @@ 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
|
||||
- FastAPI routers may import the published
|
||||
`govoplan_access.backend.auth.dependencies` dependency API
|
||||
- FastAPI routers may import the published `govoplan_access.auth` dependency API
|
||||
- the transitional allowlist is expected to stay empty
|
||||
|
||||
Any future exception is extraction debt and must be temporary, documented in the
|
||||
script with a reason, and removed when a capability/API/event contract replaces
|
||||
it.
|
||||
|
||||
## Boundary Decision Register
|
||||
|
||||
These durable decisions close older exploratory core issues. Implementation
|
||||
work should live in the owning module repositories once a boundary is clear.
|
||||
|
||||
Decision principles:
|
||||
|
||||
- Prefer connector-first when an external specialist system is likely to remain
|
||||
the system of record.
|
||||
- Create a native module only when GovOPlaN must own domain semantics,
|
||||
permissions, audit, retention, configuration-package fragments, or workflow
|
||||
state.
|
||||
- Keep optional behavior behind core-mediated capabilities, events, DTOs, route
|
||||
contributions, and UI contribution points.
|
||||
- Do not create repositories just because a possible product area exists.
|
||||
|
||||
### Templates And Reporting
|
||||
|
||||
Tracking: `govoplan-core#190`, `govoplan-templates#1`,
|
||||
`govoplan-reporting#1`.
|
||||
|
||||
Decision: templates and reporting are separate modules.
|
||||
|
||||
`govoplan-templates` owns:
|
||||
|
||||
- reusable renderable templates for letters, permits, emails, forms, reports,
|
||||
certificates, and notices
|
||||
- template versioning, merge-field declarations, rendering profiles, output
|
||||
format choices, and preview contracts
|
||||
- template package fragments that other modules can reference
|
||||
|
||||
`govoplan-reporting` owns:
|
||||
|
||||
- report definitions, data selection, dashboards, BI views, scheduled outputs,
|
||||
and export targets
|
||||
- report permissions, report execution history, generated report evidence, and
|
||||
report-specific retention inputs
|
||||
- downstream export handoff to files, dataflow, connectors, or publication
|
||||
surfaces
|
||||
|
||||
Boundary:
|
||||
|
||||
- Templates do not own data selection, aggregation, scheduling, or BI semantics.
|
||||
- Reporting may call template rendering through a capability when a formatted
|
||||
report output is needed.
|
||||
- Campaign, mail, files, workflow, and cases use templates/reporting through
|
||||
capabilities and DTOs, never direct imports.
|
||||
|
||||
### Sources, RSS, Datasources, And Dataflow
|
||||
|
||||
Tracking: `govoplan-core#192`, `govoplan-core#197`,
|
||||
`govoplan-core#198`, `govoplan-connectors#3`,
|
||||
`govoplan-connectors#4`.
|
||||
|
||||
Decision: do not create `govoplan-datasources` or `govoplan-dataflow` until a
|
||||
first executable use case proves that connector/reporting/workflow ownership is
|
||||
too narrow.
|
||||
|
||||
First slice:
|
||||
|
||||
- `govoplan-connectors` owns RSS/Atom consume/emit connector profiles,
|
||||
connector health, external references, source lifecycle metadata, and
|
||||
source/publish capability boundaries.
|
||||
- `govoplan-files` owns file-backed governed locations and uploaded/stored file
|
||||
evidence.
|
||||
- `govoplan-reporting` owns report/data views and scheduled outputs.
|
||||
- `govoplan-workflow` owns process state, approvals, scheduling of process
|
||||
steps, and human review.
|
||||
|
||||
Future `govoplan-datasources` is justified when GovOPlaN needs a broad source
|
||||
catalogue for SQL databases, CSV/Excel files, APIs, RSS feeds, uploaded files,
|
||||
and governed file locations with shared ownership, credentials, schema
|
||||
discovery, refresh cadence, provenance, and permission boundaries.
|
||||
|
||||
Future `govoplan-dataflow` is justified when GovOPlaN needs first-class
|
||||
pipelines for ingestion, transformation, validation, scheduling, lineage,
|
||||
publication, audit events, reruns, and source-to-source workflows.
|
||||
|
||||
Monthly extraction/transformation work should start as a configuration package
|
||||
and module collaboration across connectors, files, workflow, reporting, and
|
||||
possibly templates. Create datasources/dataflow repositories only after that
|
||||
package exposes repeated contracts that do not belong to an existing module.
|
||||
|
||||
### Calendar, Scheduling, And Appointments
|
||||
|
||||
Tracking: `govoplan-core#193`, `govoplan-calendar#1`,
|
||||
`govoplan-calendar#2`, `govoplan-scheduling#1`,
|
||||
`govoplan-appointments#1`.
|
||||
|
||||
Decision: use three separate modules.
|
||||
|
||||
`govoplan-calendar` owns:
|
||||
|
||||
- calendar collections, events, recurrence, availability/free-busy, resources,
|
||||
iCalendar import/export, CalDAV/Open-Xchange-style calendar adapters, and
|
||||
calendar WebUI surfaces
|
||||
|
||||
`govoplan-scheduling` owns:
|
||||
|
||||
- Terminfindung, meeting-time polls, participant availability collection,
|
||||
candidate-slot ranking, conflict explanations, reminders, and the handoff
|
||||
from a selected slot to calendar/appointment/workflow modules
|
||||
|
||||
`govoplan-appointments` owns:
|
||||
|
||||
- Terminbuchung/fixed-slot appointment booking, appointment types, booking
|
||||
rules, capacity, cancellation/no-show state, public/internal booking flows,
|
||||
and appointment evidence
|
||||
|
||||
Boundary:
|
||||
|
||||
- Calendar provides time primitives and external calendar integration.
|
||||
- Scheduling chooses a suitable time.
|
||||
- Appointments owns booked appointment workflows and public/internal booking
|
||||
semantics.
|
||||
- Mail and notifications deliver invitations/reminders through capabilities.
|
||||
|
||||
### Forms And Workflow Handoff
|
||||
|
||||
Tracking: `govoplan-core#194`, `govoplan-forms#1`.
|
||||
|
||||
Decision: forms are a reusable module boundary, with runtime behavior separated
|
||||
from workflow semantics.
|
||||
|
||||
`govoplan-forms` owns:
|
||||
|
||||
- form definitions, schemas, validation rules, field visibility rules,
|
||||
localization, versioning, admin editing, and reusable form package fragments
|
||||
|
||||
`govoplan-forms-runtime` owns, when implemented:
|
||||
|
||||
- public/internal submissions, drafts, submitted values, validation evidence,
|
||||
attachment references, submission receipts, and handoff events
|
||||
|
||||
Boundary:
|
||||
|
||||
- Forms do not own cases, workflow transitions, tasks, or portal identity.
|
||||
- Workflow/cases consume form submission events and evidence references.
|
||||
- Files owns uploaded file storage and file permissions.
|
||||
- Reporting/dataflow may consume submitted data through governed DTOs or
|
||||
source lifecycle contracts.
|
||||
|
||||
### OpenDesk Integration Profile
|
||||
|
||||
Tracking: `govoplan-core#195`, `govoplan-connectors#5`,
|
||||
`govoplan-idm#1`, `govoplan-mail#5`, `govoplan-calendar#2`,
|
||||
`govoplan-connectors#1`.
|
||||
|
||||
Decision: OpenDesk is an integration profile, not a monolithic module.
|
||||
|
||||
Ownership:
|
||||
|
||||
- identity: `govoplan-idm` plus `govoplan-access`
|
||||
- mail/groupware: `govoplan-mail`
|
||||
- calendar: `govoplan-calendar`
|
||||
- files/documents: `govoplan-files` and later `govoplan-dms`
|
||||
- projects/tasks: `govoplan-connectors` OpenProject connector first
|
||||
- inventory/health/profile diagnostics: `govoplan-connectors`
|
||||
|
||||
The OpenDesk profile should describe required connector profiles, shared
|
||||
identity assumptions, health checks, and optional module combinations. It must
|
||||
not create direct module-to-module imports.
|
||||
|
||||
### Project Management And OpenProject
|
||||
|
||||
Tracking: `govoplan-core#196`, `govoplan-connectors#1`.
|
||||
|
||||
Decision: connector-first. Do not create a native `govoplan-projects` module
|
||||
yet.
|
||||
|
||||
OpenProject integration belongs in `govoplan-connectors` first:
|
||||
|
||||
- profile test
|
||||
- project and work-package lookup
|
||||
- external-reference storage
|
||||
- selected publish/synchronize capabilities for tasks, workflow, or cases
|
||||
|
||||
A native project module is justified only if GovOPlaN needs to own project
|
||||
semantics beyond cases, tasks, workflow, appointments, documents, and reporting,
|
||||
for example portfolios, project budgets, project-level resource planning, or
|
||||
governed project records that cannot remain in OpenProject.
|
||||
|
||||
### Public-Sector Integration Landscape
|
||||
|
||||
Tracking: `govoplan-core#186`, `govoplan-core#215`,
|
||||
`govoplan-connectors#2`, `govoplan-connectors#3`.
|
||||
|
||||
Decision: core owns strategy and routing; connectors owns executable
|
||||
integration catalogue entries and operator inventory.
|
||||
|
||||
Core documents:
|
||||
|
||||
- product-level integration strategy
|
||||
- native-vs-connector decisions
|
||||
- owning module routing
|
||||
- roadmap sequencing
|
||||
|
||||
`govoplan-connectors` owns:
|
||||
|
||||
- connector entry schema
|
||||
- external system catalogue
|
||||
- connector profiles and diagnostics
|
||||
- source consume/publish lifecycle
|
||||
- external references
|
||||
|
||||
When a target needs executable behavior, create the implementation issue in the
|
||||
owning module repository and keep only cross-module decisions in core.
|
||||
|
||||
## Module Lifecycle
|
||||
|
||||
Core exposes the installed module catalog through the admin API and WebUI. The
|
||||
@@ -565,6 +1017,8 @@ directory with:
|
||||
|
||||
- `GOVOPLAN_INSTALLER_RUN_DIR`
|
||||
- `GOVOPLAN_DATABASE_URL`
|
||||
- `GOVOPLAN_DATABASE_URL_PGTOOLS` for PostgreSQL URLs converted to the
|
||||
`postgresql://` form expected by `pg_dump`, `pg_restore`, and `psql`
|
||||
- `GOVOPLAN_DATABASE_BACKUP_PATH`
|
||||
- `GOVOPLAN_DATABASE_BACKUP_METADATA`
|
||||
|
||||
@@ -631,10 +1085,20 @@ Backend verification from core:
|
||||
|
||||
```bash
|
||||
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
|
||||
./.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
|
||||
```
|
||||
|
||||
`scripts/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:
|
||||
|
||||
```bash
|
||||
cd /mnt/DATA/git/govoplan-core
|
||||
bash scripts/check-module-matrix.sh
|
||||
```
|
||||
|
||||
Core WebUI host verification:
|
||||
|
||||
```bash
|
||||
|
||||
105
docs/POLICY_CONTRACTS.md
Normal file
105
docs/POLICY_CONTRACTS.md
Normal file
@@ -0,0 +1,105 @@
|
||||
# GovOPlaN Policy Contracts
|
||||
|
||||
GovOPlaN has several policy families that are moving out of core into owning
|
||||
modules. The shared kernel contract keeps their decision and provenance shape
|
||||
consistent while each module still owns its domain rules.
|
||||
|
||||
## Current Policy Inventory
|
||||
|
||||
| Policy area | Current owner | Runtime surface | Notes |
|
||||
| --- | --- | --- | --- |
|
||||
| Privacy retention | `govoplan-policy` routes with compatibility helpers in core | `/api/v1/admin/privacy-retention/policies/{scope}` and `/explain` | System, tenant, user, group, and campaign sources merge into the effective retention policy. Parent locks block lower-level widening. |
|
||||
| Mail profile policy | `govoplan-mail` | `/api/v1/mail/policies/{scope}` | Uses the same source-step path format for system, tenant, owner, and campaign provenance. |
|
||||
| RBAC/access policy | `govoplan-access` | access capabilities in `govoplan_core.core.access` | Permission decisions should use access capability contracts. Explain responses should adopt `PolicyDecision` when an API-level explanation is added. |
|
||||
| Governance defaults | `govoplan-admin` plus `govoplan-access` materializer | admin settings, governance template routes, access materialization capability | System governance can block tenant-local groups, roles, and API keys. |
|
||||
| Delegation and ownership policy | access/campaign/mail/files modules | capability checks and owner-scoped APIs | Source provenance should use this contract when policies become externally explainable. |
|
||||
|
||||
## Policy Decision
|
||||
|
||||
The shared DTO lives in `govoplan_core.core.policy.PolicyDecision`.
|
||||
|
||||
```json
|
||||
{
|
||||
"allowed": false,
|
||||
"reason": "Parent retention policy locks lower-level changes.",
|
||||
"source_path": [
|
||||
{
|
||||
"scope_type": "system",
|
||||
"scope_id": null,
|
||||
"path": "system",
|
||||
"label": "System",
|
||||
"applied_fields": ["allow_lower_level_limits"],
|
||||
"policy": {}
|
||||
}
|
||||
],
|
||||
"requirements": ["raw_campaign_json_retention_days"],
|
||||
"details": {
|
||||
"blocked_fields": ["raw_campaign_json_retention_days"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`allowed` is the effective answer for the checked action. `reason` is a stable,
|
||||
human-readable summary. `source_path` lists the policy sources that explain the
|
||||
answer. `requirements` lists machine-readable blockers or prerequisites, and
|
||||
`details` carries domain-specific structured context.
|
||||
|
||||
Every source step should be concrete enough for an operator to understand the
|
||||
decision without knowing internal merge rules. Use real scope labels such as
|
||||
`System`, `Tenant`, `Owner user`, `Group`, or a campaign/profile name. Include
|
||||
the stable `path`, the fields applied by that step, and the local policy
|
||||
fragment that caused them. This lets UIs render explanations like
|
||||
`System: Allow > Tenant: Deny without override` without additional lookups.
|
||||
If a policy family cannot expose the full local fragment for security reasons,
|
||||
it must still include a redacted structured value that identifies the applied
|
||||
field and the effective allow/deny or lock state.
|
||||
|
||||
## Source Path Format
|
||||
|
||||
Policy source paths are stable string identifiers for provenance steps:
|
||||
|
||||
- `system`
|
||||
- `<scope_type>:<url-encoded-scope-id>`
|
||||
|
||||
Supported scope types are `system`, `tenant`, `user`, `group`, and `campaign`.
|
||||
Examples:
|
||||
|
||||
- `tenant:4a45b4fe-1d86-43ce-9d10-6022333f4d4b`
|
||||
- `campaign:campaign%2Fwith%20space`
|
||||
|
||||
Use `policy_source_path()` and `parse_policy_source_path()` instead of building
|
||||
or splitting these strings manually.
|
||||
|
||||
## Retention Explain Endpoint
|
||||
|
||||
`GET /api/v1/admin/privacy-retention/policies/{scope_type}/explain` returns:
|
||||
|
||||
- `scope_type` and optional `scope_id`
|
||||
- `decision`, using the shared `PolicyDecision` shape
|
||||
- `effective_policy`
|
||||
- optional `parent_policy`
|
||||
- `effective_policy_sources`
|
||||
- `parent_policy_sources`
|
||||
- `blocked_fields`
|
||||
|
||||
The endpoint is read-only. Enforcement remains in the existing policy write
|
||||
path. For lower-level scopes, `blocked_fields` is derived from the parent
|
||||
policy's `allow_lower_level_limits`; clients can use it to disable local
|
||||
controls before attempting a write.
|
||||
|
||||
## Frontend Contract
|
||||
|
||||
Policy UIs must:
|
||||
|
||||
- render effective source provenance when `effective_policy_sources` is present
|
||||
- display a field-level path when the source data is shown next to a specific
|
||||
setting, using concrete source labels and stop at the first non-overridable
|
||||
deny/lock
|
||||
- disable local field controls when the parent policy sets that field's
|
||||
lower-level limit to `false`
|
||||
- avoid sending locked fields or re-enable attempts in save payloads
|
||||
- show inherited values separately from local overrides
|
||||
|
||||
The core WebUI helper `privacyRetentionParentAllowsField()` centralizes the
|
||||
field-lock decision used by the retention editor and its lightweight module
|
||||
tests.
|
||||
134
docs/POSTBOX_E2EE_ARCHITECTURE.md
Normal file
134
docs/POSTBOX_E2EE_ARCHITECTURE.md
Normal file
@@ -0,0 +1,134 @@
|
||||
# Postbox End-To-End Encryption Architecture
|
||||
|
||||
This document records the strategic encryption target for GovOPlaN postboxes.
|
||||
It does not require the first postbox implementation to ship full E2EE, but it
|
||||
defines the architecture so early data models and APIs do not make the stronger
|
||||
model impossible.
|
||||
|
||||
The core principle is that a postbox can become a trusted administrative
|
||||
communication channel without requiring the server to see plaintext content.
|
||||
The server may route, store, authorize, audit, retain, and expire messages while
|
||||
message bodies and attachments remain client-encrypted.
|
||||
|
||||
## Goals
|
||||
|
||||
- asynchronous encrypted delivery for internal and portal-facing postboxes
|
||||
- personal, organizational, role-bound, and function-bound postboxes
|
||||
- attachments encrypted with the message
|
||||
- access based on current role/function membership when configured
|
||||
- honest retraction and expiry semantics
|
||||
- auditable key access, delivery, and fetch events
|
||||
- support for external recipients without platform accounts
|
||||
- replaceable identity and trust providers
|
||||
|
||||
## Envelope Model
|
||||
|
||||
The target model is envelope encryption:
|
||||
|
||||
- Generate one random data encryption key per message or attachment set.
|
||||
- Encrypt content with an authenticated encryption algorithm.
|
||||
- Wrap the data encryption key for each authorized recipient or role mailbox.
|
||||
- Store only ciphertext, wrapped keys, signed manifests, and governed metadata
|
||||
on the server.
|
||||
|
||||
Algorithm choices should remain replaceable behind a crypto profile. The first
|
||||
profile should prefer standard, reviewed primitives such as HPKE for key
|
||||
wrapping and AEAD encryption for content.
|
||||
|
||||
## Identity And Device Keys
|
||||
|
||||
The platform should distinguish:
|
||||
|
||||
- account identity
|
||||
- tenant membership
|
||||
- role/function assignment
|
||||
- device key
|
||||
- postbox binding
|
||||
|
||||
Identity providers and directories can authenticate users and provide membership
|
||||
facts, but they must not see postbox private keys or message plaintext.
|
||||
|
||||
The trust layer should provide:
|
||||
|
||||
- public key directory
|
||||
- account or identity signing keys
|
||||
- per-device encryption keys
|
||||
- device registration and revocation
|
||||
- key rotation and epoch tracking
|
||||
- recovery policy hooks
|
||||
|
||||
## Role And Function Postboxes
|
||||
|
||||
Role-bound access needs special handling. A postbox can be bound to an
|
||||
organizational unit and a role or function. Current members can access current
|
||||
messages according to policy; former members should lose access to not-yet
|
||||
fetched material when revocation is still technically enforceable.
|
||||
|
||||
The target design should support role encryption keys or an equivalent
|
||||
rewrapping service:
|
||||
|
||||
- sender encrypts the content key for the role/function postbox
|
||||
- access service verifies current membership and required assurance
|
||||
- trust service rewraps the content key to the actor's current device key
|
||||
- audit records the key access decision and fetch event
|
||||
|
||||
Key epochs are required when role membership changes. Older messages may remain
|
||||
readable according to policy, but new access must use the current epoch.
|
||||
|
||||
## External Recipients
|
||||
|
||||
External recipients may need one-time or time-limited access without a full
|
||||
platform account. The target model should support capability links or invitation
|
||||
tokens that are:
|
||||
|
||||
- scoped to specific message or attachment resources
|
||||
- time-limited
|
||||
- optionally one-time
|
||||
- protected by an out-of-band secret, passphrase, or stronger external identity
|
||||
proof
|
||||
- revocable before key fetch
|
||||
- fully audited
|
||||
|
||||
## Retraction Semantics
|
||||
|
||||
GovOPlaN should be honest about retraction.
|
||||
|
||||
Before a recipient fetches a key or decrypts content, the system can revoke
|
||||
tokens, remove wrapped-key access, expire links, and delete ciphertext according
|
||||
to retention policy.
|
||||
|
||||
After a recipient has decrypted or copied plaintext, the system cannot make the
|
||||
recipient forget it. The platform can only record access, revoke future access,
|
||||
notify parties, and apply legal or organizational controls.
|
||||
|
||||
The UI must explain this distinction whenever it offers expiry, retraction, or
|
||||
message withdrawal.
|
||||
|
||||
## Server Responsibilities
|
||||
|
||||
The server remains important even when content is encrypted:
|
||||
|
||||
- store ciphertext and signed manifests
|
||||
- store routing and policy metadata
|
||||
- enforce access before key release or rewrapping
|
||||
- provide public key directory access
|
||||
- emit notifications without plaintext content
|
||||
- record audit events
|
||||
- enforce retention and expiry where possible
|
||||
- expose diagnostics for delivery and key-access failures
|
||||
|
||||
## Module Ownership
|
||||
|
||||
- `govoplan-postbox` owns postbox bindings, postbox messages, message metadata,
|
||||
and postbox UI.
|
||||
- `govoplan-identity-trust` owns device keys, public key directory, key epochs,
|
||||
and assurance integration.
|
||||
- `govoplan-access` owns current identity, membership, function, delegation, and
|
||||
permission decisions.
|
||||
- `govoplan-policy` owns retention, retraction, and security policy decisions.
|
||||
- `govoplan-audit` owns durable audit traces.
|
||||
- `govoplan-files` owns managed file storage when encrypted postbox attachments
|
||||
are backed by file objects.
|
||||
|
||||
No module should import another module's internals to decrypt content. All
|
||||
interaction must use capabilities, DTOs, and audited service contracts.
|
||||
276
docs/PUBLIC_SECTOR_INTEGRATION_STRATEGY.md
Normal file
276
docs/PUBLIC_SECTOR_INTEGRATION_STRATEGY.md
Normal file
@@ -0,0 +1,276 @@
|
||||
# Public-Sector Integration Strategy
|
||||
|
||||
GovOPlaN should integrate with the existing public-sector software landscape
|
||||
before deciding to replace specialist workflows. This document is the core
|
||||
strategy index. The executable connector catalogue lives in
|
||||
`govoplan-connectors/docs/PUBLIC_SECTOR_INTEGRATION_CATALOGUE.md`.
|
||||
|
||||
## Strategy Labels
|
||||
|
||||
Use one or more of these labels for every external system family:
|
||||
|
||||
- `integrate`: GovOPlaN talks to the system through a stable API/protocol.
|
||||
- `link`: GovOPlaN stores external references and opens the external system for
|
||||
source-of-truth work.
|
||||
- `import`: GovOPlaN consumes data or files into governed module storage.
|
||||
- `synchronize`: GovOPlaN keeps selected records aligned both ways or through a
|
||||
source-of-truth rule.
|
||||
- `replace selected workflow`: GovOPlaN may own a narrow workflow where the
|
||||
external product is weak, but does not replace the whole product family.
|
||||
- `no first-class support`: GovOPlaN only stores manual references unless a
|
||||
deployment project creates a specific connector.
|
||||
|
||||
## Initial Classification
|
||||
|
||||
| System family | Examples | Default strategy | Likely owner |
|
||||
| --- | --- | --- | --- |
|
||||
| File providers | SMB/CIFS, WebDAV, Nextcloud, Seafile, SFTP, S3 | integrate, import, link | `govoplan-files`, connector inventory in `govoplan-connectors` |
|
||||
| Project/task management | OpenProject, Jira, Redmine, Microsoft Planner | link, synchronize selected records, replace selected workflow only after proof | `govoplan-connectors`, later `govoplan-tasks` or workflow modules |
|
||||
| Identity providers | LDAP, Active Directory, OIDC, SAML, OpenDesk IDM | integrate, synchronize | `govoplan-idm`, `govoplan-access` |
|
||||
| Mail and groupware | IMAP/SMTP, Open-Xchange, Exchange/M365, CalDAV/CardDAV | integrate, link | `govoplan-mail`, `govoplan-calendar`, `govoplan-connectors` |
|
||||
| DMS/e-file/archive | d.velop/d.3, enaio, ELO, Fabasoft, CMIS, VIS/eAkte | link, import, synchronize selected metadata | `govoplan-dms`, `govoplan-files`, `govoplan-records` |
|
||||
| ERP/finance/procurement | SAP, MACH, Infoma, DATEV, procurement feeds | export, import, synchronize; do not replace by default | `govoplan-erp`, `govoplan-procurement`, `govoplan-ledger`, `govoplan-payments` |
|
||||
| Public-sector transport | FIT-Connect, XTA/OSCI, Peppol access points | integrate, publish, receive | dedicated protocol modules plus `govoplan-connectors` inventory |
|
||||
| Standards registries | XRepository, XOE/V catalogues | link, import metadata/cache | `govoplan-connectors`, `govoplan-xoev` |
|
||||
| Publication/data exchange | RSS, open-data APIs, API feeds, CSV/Excel drops | consume, publish, transform | proposed `govoplan-datasources`, proposed `govoplan-dataflow`, `govoplan-reporting` |
|
||||
| Collaboration suites | Matrix, Jitsi, BigBlueButton, Nextcloud Talk, Collabora/OnlyOffice | integrate, link; native behavior only for governed evidence | `govoplan-connectors`, `govoplan-dms`, `govoplan-workflow` |
|
||||
| Specialist Fachverfahren | register-specific and domain-specific systems | link first; integrate/import when a real project supplies contracts | domain module or deployment-specific connector |
|
||||
|
||||
## Landscape Catalogue
|
||||
|
||||
This catalogue is intentionally implementation-oriented. Each entry records the
|
||||
first API/auth/data assumptions needed to turn an inventory entry into a
|
||||
connector or module issue.
|
||||
|
||||
### Citizen And Service Portals
|
||||
|
||||
- Strategy: integrate/link first; replace selected intake workflow only when a
|
||||
GovOPlaN portal package owns the complete journey.
|
||||
- Protocol/API surface: REST/JSON APIs, form submission webhooks, OIDC/SAML
|
||||
login, eID interfaces where available, file-upload callbacks, case-status
|
||||
callbacks.
|
||||
- Auth model: OIDC/SAML service clients, signed webhook secrets, tenant-scoped
|
||||
API keys, later eID/trust-provider handoff.
|
||||
- Data shape: applicant identity reference, application form payload,
|
||||
attachment references, consent declarations, status events, receipt IDs.
|
||||
- Deployment assumptions: externally reachable HTTPS, reverse proxy, portal DMZ
|
||||
separation, strict CSRF/origin settings, large upload path.
|
||||
- Risks: personal data exposure, duplicate identity mapping, partial
|
||||
submissions, upload malware, inconsistent portal status models.
|
||||
- MVP test path: submit a test application with one file, create a form
|
||||
submission/case/task stub, return a receipt and status reference.
|
||||
- Owner/priority: `govoplan-portal`, `govoplan-forms-runtime`,
|
||||
`govoplan-files`, Wave 1.
|
||||
|
||||
### DMS, E-File, Records, And Archives
|
||||
|
||||
- Strategy: link/import/synchronize selected metadata; do not replace the DMS by
|
||||
default.
|
||||
- Protocol/API surface: CMIS, WebDAV, vendor REST APIs, S3/object archive
|
||||
staging, file-plan export/import, archive handoff APIs.
|
||||
- Auth model: service accounts, OAuth/OIDC where supported, mTLS for regulated
|
||||
archives, secret references for vendor tokens.
|
||||
- Data shape: document ID, version, file-plan/classification code, retention
|
||||
metadata, owner/case reference, external URL, checksum, lock/legal-hold state.
|
||||
- Deployment assumptions: usually internal network or VPN, strict storage
|
||||
quotas, existing retention policies, archive immutability requirements.
|
||||
- Risks: record duplication, broken legal hold, permission mismatch, version
|
||||
drift, destructive retention/export mistakes.
|
||||
- MVP test path: create a connector inventory entry, test read-only metadata
|
||||
lookup, link one GovOPlaN file/case evidence item to an external document.
|
||||
- Owner/priority: `govoplan-dms`, `govoplan-records`, `govoplan-files`,
|
||||
`govoplan-connectors`, Wave 2/5.
|
||||
|
||||
### ERP, Finance, Procurement, And Accounting
|
||||
|
||||
- Strategy: export/import/synchronize selected records; replacement only by
|
||||
narrow domain decision.
|
||||
- Protocol/API surface: vendor REST/SOAP APIs, CSV/XML batch exchange, SFTP,
|
||||
XRechnung/Peppol, XBestellung/procurement feeds, payment reconciliation files.
|
||||
- Auth model: service accounts, client certificates, mTLS, SFTP keys, token
|
||||
references, environment-specific account separation.
|
||||
- Data shape: debtor/creditor reference, payment request, invoice, order,
|
||||
budget/cost-center code, booking status, receipt/evidence reference.
|
||||
- Deployment assumptions: batch windows, finance-system approval workflows,
|
||||
test tenants often separated from production by vendor process.
|
||||
- Risks: financial posting errors, double export, tax/legal data retention,
|
||||
inconsistent master data, irreversible accounting handoff.
|
||||
- MVP test path: dry-run export of one payment/accounting handoff file with
|
||||
checksum, validation report, and no remote posting.
|
||||
- Owner/priority: `govoplan-payments`, `govoplan-ledger`,
|
||||
`govoplan-xrechnung`, `govoplan-erp`, `govoplan-procurement`, Wave 1/6.
|
||||
|
||||
### Identity, IAM, And Directory Services
|
||||
|
||||
- Strategy: integrate/synchronize; access remains GovOPlaN's local
|
||||
authorization boundary.
|
||||
- Protocol/API surface: LDAP, Active Directory, SCIM, OIDC, SAML, OpenDesk IDM
|
||||
APIs, group membership sync, account deactivation feeds.
|
||||
- Auth model: bind accounts, service clients, OIDC/SAML metadata, SCIM tokens,
|
||||
certificate-backed clients where required.
|
||||
- Data shape: account, user, group, membership, role claim, tenant/org-unit
|
||||
mapping, status, external directory ID.
|
||||
- Deployment assumptions: directory is usually internal; identity provider may
|
||||
be organization-wide and not GovOPlaN-owned.
|
||||
- Risks: privilege escalation through group mapping, stale memberships, account
|
||||
collision, deprovisioning latency, tenant-boundary mistakes.
|
||||
- MVP test path: read-only directory profile test, map one external group to a
|
||||
tenant group, show a dry-run membership diff.
|
||||
- Owner/priority: `govoplan-idm`, `govoplan-access`, Wave 1.
|
||||
|
||||
### Groupware, Mail, Calendar, And Collaboration
|
||||
|
||||
- Strategy: integrate/link; native behavior only where GovOPlaN needs governed
|
||||
evidence or process state.
|
||||
- Protocol/API surface: IMAP/SMTP, CalDAV/CardDAV, Open-Xchange APIs, Microsoft
|
||||
Graph/EWS, Matrix APIs, Jitsi/BigBlueButton APIs, Collabora/OnlyOffice
|
||||
integration points.
|
||||
- Auth model: service accounts, delegated OAuth/OIDC, app passwords, mailbox
|
||||
credentials, groupware-specific tokens, secret references.
|
||||
- Data shape: mailbox folder/message references, event/free-busy data, meeting
|
||||
URL, chat room ID, participant list, document-editing session reference.
|
||||
- Deployment assumptions: often internal/existing tenant infrastructure; mail
|
||||
and calendar may be separate from identity even in OpenDesk-style stacks.
|
||||
- Risks: mail credential exposure, calendar privacy, double invitations, room
|
||||
booking conflicts, chat/document data escaping retention rules.
|
||||
- MVP test path: profile test for mailbox/calendar reachability, read-only
|
||||
folder/free-busy lookup, create a non-production event/message draft.
|
||||
- Owner/priority: `govoplan-mail`, `govoplan-calendar`,
|
||||
`govoplan-connectors`, Wave 1/2.
|
||||
|
||||
### Payment And Public Cashier Systems
|
||||
|
||||
- Strategy: integrate/export/import; keep the payment provider or cashier as
|
||||
source of settlement truth.
|
||||
- Protocol/API surface: payment provider APIs, redirect/callback flows,
|
||||
reconciliation files, SEPA/export formats, cash-register/cashier interfaces.
|
||||
- Auth model: provider API keys, signed webhooks, client certificates, mTLS,
|
||||
tenant-specific merchant accounts.
|
||||
- Data shape: payment intent, amount/currency, payer reference, provider
|
||||
transaction ID, settlement status, receipt, refund/cancellation reference.
|
||||
- Deployment assumptions: public callback URLs, strict environment separation,
|
||||
PCI-sensitive providers, finance reconciliation cadence.
|
||||
- Risks: duplicate charges, callback replay, amount mismatch, refund workflow
|
||||
gaps, evidence-retention mistakes.
|
||||
- MVP test path: sandbox payment intent, signed callback verification, receipt
|
||||
evidence link, reconciliation dry-run.
|
||||
- Owner/priority: `govoplan-payments`, `govoplan-ledger`, Wave 1/6.
|
||||
|
||||
### Reporting, BI, Open Data, And Publication
|
||||
|
||||
- Strategy: consume/publish/transform; native reporting owns GovOPlaN views, not
|
||||
every external BI product.
|
||||
- Protocol/API surface: SQL read replicas, CSV/Excel export/import, REST APIs,
|
||||
RSS/Atom, open-data APIs, SFTP/WebDAV publication targets.
|
||||
- Auth model: read-only DB users, API tokens, SFTP keys, OAuth clients, public
|
||||
anonymous publication profiles where appropriate.
|
||||
- Data shape: dataset metadata, schema/version, report parameters, generated
|
||||
file references, publication URL, freshness/lineage, validation results.
|
||||
- Deployment assumptions: publication can be public or internal; generated
|
||||
datasets need retention and provenance.
|
||||
- Risks: leaking restricted data, stale publications, schema drift, expensive
|
||||
queries, untraceable manual transformations.
|
||||
- MVP test path: publish one report/export as a governed file plus RSS/Atom
|
||||
entry with checksum, timestamp, and permission check.
|
||||
- Owner/priority: `govoplan-reporting`, `govoplan-connectors`, possible future
|
||||
`govoplan-datasources`/`govoplan-dataflow`, Wave 2.
|
||||
|
||||
### Public-Sector Protocols And Registries
|
||||
|
||||
- Strategy: integrate/publish/receive; protocol modules own protocol semantics.
|
||||
- Protocol/API surface: FIT-Connect, XTA/OSCI, XRepository, XOE/V, XRechnung,
|
||||
XBestellung, Peppol, registry-specific Fachverfahren APIs.
|
||||
- Auth model: certificates, mTLS, service accounts, destination credentials,
|
||||
protocol-specific trust anchors and key rotation.
|
||||
- Data shape: transport envelope, payload schema/version, destination IDs,
|
||||
receipt/acknowledgement, message status, standard-specific metadata.
|
||||
- Deployment assumptions: regulated trust chains, test/prod endpoint
|
||||
separation, formal onboarding, strict logging and retention expectations.
|
||||
- Risks: invalid schemas, failed delivery receipts, certificate expiry, wrong
|
||||
destination routing, protocol version drift.
|
||||
- MVP test path: validate a sample payload against a schema, test endpoint
|
||||
reachability in sandbox, store receipt/evidence reference.
|
||||
- Owner/priority: `govoplan-fit-connect`, `govoplan-xoev`,
|
||||
`govoplan-xrechnung`, `govoplan-xta-osci`, `govoplan-connectors`, Wave 1/2.
|
||||
|
||||
### File Providers And Shared Storage
|
||||
|
||||
- Strategy: integrate/import/link; files module owns GovOPlaN file semantics.
|
||||
- Protocol/API surface: SMB/CIFS, WebDAV, Nextcloud, Seafile, SFTP, S3,
|
||||
local/object storage profiles.
|
||||
- Auth model: service accounts, user credentials, app tokens, OAuth where
|
||||
supported, secret references, environment variables for deployment-managed
|
||||
credentials.
|
||||
- Data shape: file ID/path, provider object ID, checksum, MIME type, size,
|
||||
version/ETag, owner, permission snapshot, imported file reference.
|
||||
- Deployment assumptions: internal networks, large files, existing shares,
|
||||
variable permissions, provider-specific rate limits.
|
||||
- Risks: permission mismatch, stale imports, overwrites, duplicate files, path
|
||||
traversal, storage growth.
|
||||
- MVP test path: profile test, list folder, import one file into governed
|
||||
storage, keep provider reference and checksum.
|
||||
- Owner/priority: `govoplan-files`, `govoplan-connectors`, Wave 0/1.
|
||||
|
||||
### Project, Task, And Case-Adjacent Systems
|
||||
|
||||
- Strategy: connector-first for OpenProject/Jira/Redmine; native module only
|
||||
when GovOPlaN owns project semantics.
|
||||
- Protocol/API surface: OpenProject API v3, webhooks, Jira/Redmine REST APIs,
|
||||
Microsoft Graph for Planner/Project where applicable.
|
||||
- Auth model: API tokens, OAuth/OIDC apps, webhook secrets, service accounts.
|
||||
- Data shape: project ID, work package/task ID, status, assignee reference,
|
||||
external URL, version/lock token, publish/sync trace.
|
||||
- Deployment assumptions: external project tool remains source of truth for
|
||||
broad project management; GovOPlaN links selected records.
|
||||
- Risks: task duplication, bidirectional sync conflicts, permission mismatch,
|
||||
over-mirroring comments/attachments.
|
||||
- MVP test path: OpenProject profile test, project/work-package lookup,
|
||||
external-reference round-trip.
|
||||
- Owner/priority: `govoplan-connectors`, later `govoplan-tasks`/workflow/cases
|
||||
consumers, Wave 0/2.
|
||||
|
||||
### Specialist Fachverfahren
|
||||
|
||||
- Strategy: link first; integrate/import only when a deployment project supplies
|
||||
concrete contracts and a domain owner.
|
||||
- Protocol/API surface: vendor APIs, CSV/XML batch imports, SFTP, database
|
||||
views, message queues, protocol-specific transports.
|
||||
- Auth model: usually service accounts, VPN, mTLS, SFTP keys, or vendor tokens.
|
||||
- Data shape: domain-specific record IDs, status, applicant/person references,
|
||||
file/evidence references, case/status events.
|
||||
- Deployment assumptions: strongly local/vendor-specific, often no stable test
|
||||
API, data model differs by jurisdiction.
|
||||
- Risks: brittle vendor contracts, legal source-of-truth ambiguity, high
|
||||
customization cost, migration expectations.
|
||||
- MVP test path: inventory entry and manual external-reference link; require a
|
||||
project-specific connector issue before automation.
|
||||
- Owner/priority: domain module or deployment-specific connector, case by case.
|
||||
|
||||
## Prioritization Rules
|
||||
|
||||
1. Start with connectors that unblock Wave 0 or Wave 1 reference journeys.
|
||||
2. Prefer open standards and self-hosted/open-source APIs where they are common
|
||||
in public-sector deployments.
|
||||
3. Treat inventory-only entries as useful because operators need a map of their
|
||||
software landscape even before automation exists.
|
||||
4. Keep connector code in the owning connector/protocol module. Domain modules
|
||||
consume capabilities, DTOs, external references, and events through core.
|
||||
5. Every executable connector needs health diagnostics, secret-reference
|
||||
handling, lifecycle state, audit events, and retirement behavior.
|
||||
|
||||
## Connector Catalogue Handoff
|
||||
|
||||
`govoplan-connectors` owns the detailed catalogue entry shape:
|
||||
|
||||
- connector type key
|
||||
- category and owner module
|
||||
- supported directions and trigger modes
|
||||
- credential and secret handling
|
||||
- health check and diagnostics payload
|
||||
- external-reference shape
|
||||
- required capabilities and optional module combinations
|
||||
- lifecycle support
|
||||
|
||||
Core should only keep strategy, routing, and cross-module architecture notes.
|
||||
Connector implementation and public-sector target inventory belong in
|
||||
`govoplan-connectors`.
|
||||
@@ -1,291 +0,0 @@
|
||||
# Multi Seal Mail - Current RBAC and Resource-Access Model
|
||||
|
||||
**Updated:** 2026-06-16
|
||||
**Current migration head:** `f5a6b7c8d9e0`
|
||||
|
||||
## Authorization Equation
|
||||
|
||||
An operation is permitted only when every applicable layer allows it:
|
||||
|
||||
```text
|
||||
effective role/API-key capability
|
||||
AND resource ownership/share access
|
||||
AND workflow state
|
||||
AND active governance/policy constraints
|
||||
```
|
||||
|
||||
RBAC answers what an actor may do. ACLs answer which resource the actor may do it to. Workflow state and policy decide whether the operation is currently valid.
|
||||
|
||||
## Identity and Scope
|
||||
|
||||
```text
|
||||
Account global login identity
|
||||
+- User membership tenant-local identity
|
||||
+- direct tenant roles
|
||||
+- active group memberships
|
||||
| +- inherited tenant roles
|
||||
+- tenant-local API keys
|
||||
|
||||
Account
|
||||
+- direct system-role assignments
|
||||
```
|
||||
|
||||
A browser session has one active tenant membership. System privileges do not silently grant tenant data access. API keys remain tenant-local and receive the intersection of their configured scopes and their owner's live tenant scopes on every request.
|
||||
|
||||
## Wildcards
|
||||
|
||||
```text
|
||||
tenant:* every canonical tenant permission
|
||||
system:* every canonical system permission
|
||||
* legacy alias interpreted as tenant:* only
|
||||
```
|
||||
|
||||
Tenant wildcards never grant system permissions.
|
||||
|
||||
## Canonical Tenant Permissions - 53
|
||||
|
||||
### Campaigns
|
||||
|
||||
```text
|
||||
campaign:read
|
||||
campaign:create
|
||||
campaign:update
|
||||
campaign:copy
|
||||
campaign:archive
|
||||
campaign:delete
|
||||
campaign:share
|
||||
campaign:validate
|
||||
campaign:build
|
||||
campaign:review
|
||||
campaign:send_test
|
||||
campaign:queue
|
||||
campaign:control
|
||||
campaign:send
|
||||
campaign:retry
|
||||
campaign:reconcile
|
||||
```
|
||||
|
||||
### Recipients
|
||||
|
||||
```text
|
||||
recipients:read
|
||||
recipients:write
|
||||
recipients:import
|
||||
recipients:export
|
||||
```
|
||||
|
||||
### Files
|
||||
|
||||
```text
|
||||
files:read
|
||||
files:download
|
||||
files:upload
|
||||
files:organize
|
||||
files:share
|
||||
files:delete
|
||||
files:admin
|
||||
```
|
||||
|
||||
### Reports and Audit
|
||||
|
||||
```text
|
||||
reports:read
|
||||
reports:export
|
||||
reports:send
|
||||
audit:read
|
||||
```
|
||||
|
||||
### Mail Servers
|
||||
|
||||
```text
|
||||
mail_servers:read
|
||||
mail_servers:use
|
||||
mail_servers:test
|
||||
mail_servers:write
|
||||
mail_servers:manage_credentials
|
||||
```
|
||||
|
||||
### Tenant Administration
|
||||
|
||||
```text
|
||||
admin:users:read
|
||||
admin:users:create
|
||||
admin:users:update
|
||||
admin:users:suspend
|
||||
|
||||
admin:groups:read
|
||||
admin:groups:write
|
||||
admin:groups:manage_members
|
||||
|
||||
admin:roles:read
|
||||
admin:roles:write
|
||||
admin:roles:assign
|
||||
|
||||
admin:api_keys:read
|
||||
admin:api_keys:create
|
||||
admin:api_keys:revoke
|
||||
|
||||
admin:settings:read
|
||||
admin:settings:write
|
||||
admin:policies:read
|
||||
admin:policies:write
|
||||
```
|
||||
|
||||
## Canonical System Permissions - 18
|
||||
|
||||
```text
|
||||
system:tenants:read
|
||||
system:tenants:create
|
||||
system:tenants:update
|
||||
system:tenants:suspend
|
||||
|
||||
system:accounts:read
|
||||
system:accounts:create
|
||||
system:accounts:update
|
||||
system:accounts:suspend
|
||||
|
||||
system:roles:read
|
||||
system:roles:write
|
||||
system:roles:assign
|
||||
|
||||
system:access:read
|
||||
system:access:assign
|
||||
|
||||
system:audit:read
|
||||
system:settings:read
|
||||
system:settings:write
|
||||
system:governance:read
|
||||
system:governance:write
|
||||
```
|
||||
|
||||
`system:access:*` remains as a compatibility/read and assignment boundary for cross-tenant/system access handling. It is not a separate primary UI area.
|
||||
|
||||
## Default Tenant Roles
|
||||
|
||||
- **Owner:** `tenant:*`. At least one active operational owner must remain.
|
||||
- **Tenant administrator:** settings, policies, users, groups, roles and API keys plus read access to campaigns/files/reports/audit. Real delivery remains separately delegable.
|
||||
- **Administrator (legacy):** all tenant permissions for upgraded installations.
|
||||
- **Access administrator:** membership and assignment management within delegation limits.
|
||||
- **Campaign manager:** prepare, validate and build campaigns; no review approval or real delivery by default.
|
||||
- **Reviewer:** inspect and approve prepared campaign messages.
|
||||
- **Sender:** mock-test, queue, control, send, retry and reconcile prepared campaigns; can use/test approved mail profiles.
|
||||
- **File manager:** managed file operations without campaign delivery rights.
|
||||
- **Viewer:** read campaigns, recipients, files and reports.
|
||||
- **Auditor:** read campaigns, recipient evidence, reports and audit records; export detailed evidence.
|
||||
|
||||
## Default System Roles
|
||||
|
||||
- **System owner:** `system:*`, protected. At least one active account must retain it.
|
||||
- **System administrator:** all specific system permissions, editable and not protected.
|
||||
- **System auditor:** read-only system registry/settings/governance/audit role, editable.
|
||||
|
||||
## Delegation Ceiling
|
||||
|
||||
For role definition, assignment and API-key creation:
|
||||
|
||||
```text
|
||||
requested scopes subset of actor delegateable scopes
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
1. Tenant roles may contain tenant scopes only.
|
||||
2. System roles may contain system scopes only.
|
||||
3. Definition rights and assignment rights are separate.
|
||||
4. Group definition and group membership management are separate.
|
||||
5. API-key scopes are intersected with the owner's current effective scopes on every request.
|
||||
6. Suspended accounts, users, tenants or groups stop contributing access immediately.
|
||||
7. Administrative updates are field-sensitive; a user with only status authority cannot change role assignments.
|
||||
|
||||
## Campaign Ownership and ACLs
|
||||
|
||||
A campaign has exactly one owner:
|
||||
|
||||
```text
|
||||
owner user OR owner group
|
||||
```
|
||||
|
||||
Additional active shares may target users or groups with `read` or `write`.
|
||||
|
||||
Resolution:
|
||||
|
||||
- owner user: read and write;
|
||||
- member of owner group: read and write;
|
||||
- explicit read share: read;
|
||||
- explicit write share: read and write;
|
||||
- `tenant:*`: tenant-wide ACL bypass;
|
||||
- ordinary campaign permission without ownership/share: no object access.
|
||||
|
||||
ACLs do not add capabilities. A write share still needs the specific permission for update, validation, review, send, report, retry or reconciliation.
|
||||
|
||||
## Sensitive Recipient Boundary
|
||||
|
||||
Recipient-complete campaign JSON, message data and job detail require `recipients:read`. Recipient edits require `recipients:write`; exports require `recipients:export`; import is reserved for the dedicated recipient import/list workflow.
|
||||
|
||||
## Files
|
||||
|
||||
| Permission | Operations |
|
||||
|---|---|
|
||||
| `files:read` | list, search, inspect, resolve metadata |
|
||||
| `files:download` | download file bytes and generated ZIP archives |
|
||||
| `files:upload` | upload files and ZIP contents |
|
||||
| `files:organize` | create folders, rename, move, copy and bulk rename |
|
||||
| `files:share` | create/revoke file shares |
|
||||
| `files:delete` | delete/hide files and folders subject to retention |
|
||||
| `files:admin` | tenant-wide administration of user/group file spaces |
|
||||
|
||||
## Mail Servers
|
||||
|
||||
| Permission | Boundary |
|
||||
|---|---|
|
||||
| `mail_servers:read` | profile metadata and effective policy visibility |
|
||||
| `mail_servers:use` | select an approved profile without reading secrets |
|
||||
| `mail_servers:test` | run server-side connection tests |
|
||||
| `mail_servers:write` | define/edit profiles in allowed scopes |
|
||||
| `mail_servers:manage_credentials` | create/replace SMTP/IMAP secrets or campaign-level credentials where policy allows |
|
||||
|
||||
Reusable encrypted profiles now exist. Effective usability is also constrained by hierarchical mail-profile policy, ownership, allowed/forced profile sets, credential inheritance mode, the lower-level override switch for that mode, and allow/deny patterns.
|
||||
|
||||
## Sessions, API Keys and CSRF
|
||||
|
||||
- Browser login creates an HttpOnly session cookie and a separate readable CSRF cookie.
|
||||
- Unsafe cookie-authenticated requests require matching CSRF cookie/header and stored CSRF hash.
|
||||
- API keys remain supported for CLI/automation and do not use browser CSRF.
|
||||
- Login responses still expose a compatibility session token in the response body; the WebUI does not persist it.
|
||||
|
||||
## Legacy Compatibility
|
||||
|
||||
Runtime aliases remain only for names that are no longer canonical, including:
|
||||
|
||||
```text
|
||||
campaign:write
|
||||
attachments:read
|
||||
attachments:write
|
||||
admin:users
|
||||
admin:users:write
|
||||
admin:api_keys:write
|
||||
admin:settings
|
||||
system:tenants:write
|
||||
system:access:write
|
||||
```
|
||||
|
||||
Canonical scopes are not widened by runtime alias expansion after migration.
|
||||
|
||||
## Deferred Permission Families
|
||||
|
||||
Add these only with their corresponding implemented features:
|
||||
|
||||
```text
|
||||
templates:*
|
||||
address_books:*
|
||||
recipient_lists:*
|
||||
connectors:*
|
||||
dsar:*
|
||||
system:monitoring:read
|
||||
system:backups:run
|
||||
system:backups:restore
|
||||
system:updates:apply
|
||||
system:updates:rollback
|
||||
```
|
||||
|
||||
A separate `retention:*` family is not currently canonical because retention is managed through system settings and tenant policy scopes. Add it only if retention operation duties need separation from general policy/settings administration.
|
||||
@@ -1,129 +0,0 @@
|
||||
# Release Catalog Workflow
|
||||
|
||||
GovOPlaN release catalogs are published by `govoplan-web` as static JSON and
|
||||
verified by `govoplan-core` before installer plans are accepted.
|
||||
|
||||
Private signing keys must stay outside all git repositories. Public keyrings
|
||||
are published with the website.
|
||||
|
||||
## One-Time Key Setup
|
||||
|
||||
Create the first catalog signing key on the release machine:
|
||||
|
||||
```bash
|
||||
cd /mnt/DATA/git/govoplan-core
|
||||
KEY_DIR="$HOME/.config/govoplan/release-keys"
|
||||
mkdir -p "$KEY_DIR"
|
||||
./.venv/bin/python scripts/generate-catalog-keypair.py \
|
||||
--key-id release-key-1 \
|
||||
--private-key "$KEY_DIR/release-key-1.pem" \
|
||||
--public-key "$KEY_DIR/release-key-1.pub" \
|
||||
--keyring "$KEY_DIR/catalog-keyring.json"
|
||||
```
|
||||
|
||||
Keep `release-key-1.pem` private. The generated keyring contains only public
|
||||
material.
|
||||
|
||||
## Publish Current Release Catalog
|
||||
|
||||
Generate the signed catalog into `govoplan-web`:
|
||||
|
||||
```bash
|
||||
cd /mnt/DATA/git/govoplan-core
|
||||
KEY_DIR="$HOME/.config/govoplan/release-keys"
|
||||
scripts/publish-release-catalog.sh \
|
||||
--version 0.1.4 \
|
||||
--sequence 202607071340 \
|
||||
--catalog-signing-key "release-key-1=$KEY_DIR/release-key-1.pem" \
|
||||
--build-web
|
||||
```
|
||||
|
||||
This writes:
|
||||
|
||||
- `/mnt/DATA/git/govoplan-web/public/catalogs/v1/channels/stable.json`
|
||||
- `/mnt/DATA/git/govoplan-web/public/catalogs/v1/keyring.json`
|
||||
|
||||
The wrapper validates the catalog with core using the generated public keyring.
|
||||
|
||||
## Publish After A New Release
|
||||
|
||||
For normal module/core releases, first tag and push the module/core repos. Then
|
||||
publish the website catalog:
|
||||
|
||||
```bash
|
||||
cd /mnt/DATA/git/govoplan-core
|
||||
KEY_DIR="$HOME/.config/govoplan/release-keys"
|
||||
scripts/publish-release-catalog.sh \
|
||||
--version <x.y.z> \
|
||||
--catalog-signing-key "release-key-1=$KEY_DIR/release-key-1.pem" \
|
||||
--build-web \
|
||||
--commit \
|
||||
--tag \
|
||||
--push
|
||||
```
|
||||
|
||||
The website tag is `catalog-v<x.y.z>`. The public URL is:
|
||||
|
||||
```text
|
||||
https://govoplan.add-ideas.de/catalogs/v1/channels/stable.json
|
||||
```
|
||||
|
||||
The public keyring URL is:
|
||||
|
||||
```text
|
||||
https://govoplan.add-ideas.de/catalogs/v1/keyring.json
|
||||
```
|
||||
|
||||
## Integrated Release Script
|
||||
|
||||
`scripts/push-release-tag.sh` can publish the web catalog after module and core
|
||||
tags have been pushed:
|
||||
|
||||
```bash
|
||||
cd /mnt/DATA/git/govoplan-core
|
||||
KEY_DIR="$HOME/.config/govoplan/release-keys"
|
||||
scripts/push-release-tag.sh \
|
||||
--bump subversion \
|
||||
--publish-web-catalog \
|
||||
--catalog-signing-key "release-key-1=$KEY_DIR/release-key-1.pem" \
|
||||
--build-web-catalog
|
||||
```
|
||||
|
||||
Use `--catalog-signing-key` more than once during a key rotation window. The
|
||||
catalog will contain multiple signatures and the public keyring will include the
|
||||
corresponding public keys.
|
||||
|
||||
## Consumer Configuration
|
||||
|
||||
On a GovOPlaN installation that should consume the official stable catalog:
|
||||
|
||||
```bash
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_URL=https://govoplan.add-ideas.de/catalogs/v1/channels/stable.json
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_CACHE=/srv/govoplan/runtime/catalog-cache/stable.json
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_REQUIRE_SIGNATURE=true
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_APPROVED_CHANNELS=stable
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_TRUSTED_KEYS_FILE=/srv/govoplan/trust/catalog-keyring.json
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_SEQUENCE_STATE=/srv/govoplan/runtime/catalog-sequences.json
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_ENFORCE_SEQUENCE=true
|
||||
```
|
||||
|
||||
For production, copy the public keyring into deployment configuration and pin it
|
||||
locally. Do not rely on a URL-fetched keyring as the only trust root.
|
||||
|
||||
## Core Updates
|
||||
|
||||
`stable.json` includes a top-level `core_release` section for operator/update
|
||||
tooling. Core is intentionally not listed as a normal module entry, because it
|
||||
must not be added to saved enabled-module state. Core upgrades should remain an
|
||||
operator-supervised package update with restart and health checks.
|
||||
|
||||
## Key Rotation
|
||||
|
||||
1. Generate the next private key outside git.
|
||||
2. Run `publish-release-catalog.sh` with both signing keys.
|
||||
3. Publish the web catalog/keyring.
|
||||
4. Roll the new public keyring into installations.
|
||||
5. Stop signing with the old key after the supported fleet trusts the new key.
|
||||
6. Mark compromised keys as revoked in the public keyring and publish a higher
|
||||
sequence catalog signed by a trusted uncompromised key.
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
# GovOPlaN Release Dependencies
|
||||
|
||||
Release installs must not depend on sibling checkout paths. Local development can keep editable installs and `file:` WebUI links, but release packaging should resolve modules from tagged git refs or from a package registry.
|
||||
This document owns release package composition, signed package catalogs,
|
||||
license checks, catalog publishing, migration baselines, and the final release
|
||||
checklist.
|
||||
|
||||
## Backend
|
||||
Operator runtime configuration and module install/uninstall execution live in
|
||||
`DEPLOYMENT_OPERATOR_GUIDE.md`.
|
||||
|
||||
## Backend Packages
|
||||
|
||||
Release installs must not depend on sibling checkout paths. Local development
|
||||
can keep editable installs and `file:` WebUI links, but release packaging must
|
||||
resolve modules from tagged git refs or from a package registry.
|
||||
|
||||
Local development:
|
||||
|
||||
@@ -18,280 +27,41 @@ cd /mnt/DATA/git/govoplan-core
|
||||
./.venv/bin/python -m pip install -r requirements-release.txt
|
||||
```
|
||||
|
||||
`.[server]` is resolved relative to the current working directory. If you create the virtualenv elsewhere, still run the install command from the core checkout:
|
||||
`.[server]` is resolved relative to the current working directory. If you
|
||||
create the virtualenv elsewhere, still run the install command from the core
|
||||
checkout:
|
||||
|
||||
```bash
|
||||
cd /mnt/DATA/git/govoplan-core
|
||||
/tmp/govoplan-release-test/bin/python -m pip install -r requirements-release.txt
|
||||
```
|
||||
|
||||
`requirements-release.txt` pins the module repositories to the release tag. Update those refs when cutting a release:
|
||||
`requirements-release.txt` pins the module repositories to the release tag.
|
||||
Update those refs when cutting a release:
|
||||
|
||||
```text
|
||||
govoplan-access git@git.add-ideas.de:add-ideas/govoplan-access.git v0.1.4
|
||||
govoplan-admin git@git.add-ideas.de:add-ideas/govoplan-admin.git v0.1.4
|
||||
govoplan-tenancy git@git.add-ideas.de:add-ideas/govoplan-tenancy.git v0.1.4
|
||||
govoplan-policy git@git.add-ideas.de:add-ideas/govoplan-policy.git v0.1.4
|
||||
govoplan-audit git@git.add-ideas.de:add-ideas/govoplan-audit.git v0.1.4
|
||||
govoplan-files git@git.add-ideas.de:add-ideas/govoplan-files.git v0.1.4
|
||||
govoplan-mail git@git.add-ideas.de:add-ideas/govoplan-mail.git v0.1.4
|
||||
govoplan-campaign git@git.add-ideas.de:add-ideas/govoplan-campaign.git v0.1.4
|
||||
govoplan-calendar git@git.add-ideas.de:add-ideas/govoplan-calendar.git v0.1.4
|
||||
govoplan-access git@git.add-ideas.de:add-ideas/govoplan-access.git v0.1.6
|
||||
govoplan-admin git@git.add-ideas.de:add-ideas/govoplan-admin.git v0.1.6
|
||||
govoplan-tenancy git@git.add-ideas.de:add-ideas/govoplan-tenancy.git v0.1.6
|
||||
govoplan-organizations git@git.add-ideas.de:add-ideas/govoplan-organizations.git v0.1.6
|
||||
govoplan-identity git@git.add-ideas.de:add-ideas/govoplan-identity.git v0.1.6
|
||||
govoplan-policy git@git.add-ideas.de:add-ideas/govoplan-policy.git v0.1.6
|
||||
govoplan-audit git@git.add-ideas.de:add-ideas/govoplan-audit.git v0.1.6
|
||||
govoplan-files git@git.add-ideas.de:add-ideas/govoplan-files.git v0.1.6
|
||||
govoplan-mail git@git.add-ideas.de:add-ideas/govoplan-mail.git v0.1.6
|
||||
govoplan-campaign git@git.add-ideas.de:add-ideas/govoplan-campaign.git v0.1.6
|
||||
govoplan-calendar git@git.add-ideas.de:add-ideas/govoplan-calendar.git v0.1.6
|
||||
```
|
||||
|
||||
## Runtime Module Package Changes
|
||||
## WebUI Packages
|
||||
|
||||
The admin module manager can hot-enable and hot-disable packages that are
|
||||
already installed. It does not install or uninstall Python/npm packages from
|
||||
inside the running server.
|
||||
Local development uses `webui/package.json`, which may point at sibling module
|
||||
checkouts while active development is happening.
|
||||
|
||||
For runtime package changes, create an operator install plan in Admin > System >
|
||||
Modules. The module manager shows the trusted installer preflight status and
|
||||
blocks unsafe uninstalls before the operator touches packages.
|
||||
|
||||
Preflight from the server shell:
|
||||
|
||||
```bash
|
||||
govoplan-module-installer --format shell
|
||||
```
|
||||
|
||||
Apply from a controlled operator shell while maintenance mode is active:
|
||||
|
||||
```bash
|
||||
govoplan-module-installer --apply --build-webui
|
||||
```
|
||||
|
||||
For real install/uninstall work, prefer supervised mode with the deployment's
|
||||
restart command and health endpoint:
|
||||
|
||||
```bash
|
||||
govoplan-module-installer \
|
||||
--supervise \
|
||||
--migrate \
|
||||
--build-webui \
|
||||
--health-url http://127.0.0.1:8000/health \
|
||||
--restart-command '<restart govoplan server>'
|
||||
```
|
||||
|
||||
To let the admin UI trigger package work without executing pip/npm inside a
|
||||
FastAPI request, run the installer daemon in a separate operator shell. This is
|
||||
the preferred development/early-production mode for now because the operator can
|
||||
watch output, stop before queueing risky changes, and keep restart commands
|
||||
deployment-specific:
|
||||
|
||||
```bash
|
||||
govoplan-module-installer \
|
||||
--daemon \
|
||||
--migrate \
|
||||
--build-webui \
|
||||
--database-backup-command 'pg_dump --format=custom "$GOVOPLAN_DATABASE_URL" > "$GOVOPLAN_DATABASE_BACKUP_PATH"' \
|
||||
--database-restore-check-command 'pg_restore --list "$GOVOPLAN_DATABASE_BACKUP_PATH" >/dev/null' \
|
||||
--database-restore-command 'pg_restore --clean --if-exists --dbname "$GOVOPLAN_DATABASE_URL" "$GOVOPLAN_DATABASE_BACKUP_PATH"' \
|
||||
--health-url http://127.0.0.1:8000/health \
|
||||
--restart-command '<restart govoplan server>'
|
||||
```
|
||||
|
||||
Admin > System > Modules can then queue the saved install plan as a supervised
|
||||
request. Install rows can be planned directly from the approved package catalog;
|
||||
uninstall rows are generated from installed, disabled modules so the Python
|
||||
distribution and WebUI package names do not need to be typed by hand. The
|
||||
daemon claims one queued request at a time and writes request/run records below
|
||||
`runtime/module-installer`. For process-manager one-shot usage or tests, use
|
||||
`--daemon-once`. The daemon also writes
|
||||
`runtime/module-installer/daemon.status.json`; check it with:
|
||||
|
||||
```bash
|
||||
govoplan-module-installer --daemon-status --format json
|
||||
```
|
||||
|
||||
The installer uses a runtime lock, snapshots `pip freeze` plus WebUI
|
||||
`package.json`/`package-lock.json`, writes a run record below
|
||||
`runtime/module-installer/runs`, and marks planned rows as applied only after
|
||||
all commands succeed. When `--migrate` is used with a `sqlite:///` database URL,
|
||||
the installer also snapshots the SQLite database with SQLite's backup API before
|
||||
running migrations. For other database engines, pass external backup/restore
|
||||
hooks:
|
||||
|
||||
```bash
|
||||
govoplan-module-installer \
|
||||
--supervise \
|
||||
--migrate \
|
||||
--database-backup-command 'pg_dump --format=custom "$GOVOPLAN_DATABASE_URL" > "$GOVOPLAN_DATABASE_BACKUP_PATH"' \
|
||||
--database-restore-check-command 'pg_restore --list "$GOVOPLAN_DATABASE_BACKUP_PATH" >/dev/null' \
|
||||
--database-restore-command 'pg_restore --clean --if-exists --dbname "$GOVOPLAN_DATABASE_URL" "$GOVOPLAN_DATABASE_BACKUP_PATH"' \
|
||||
--health-url http://127.0.0.1:8000/health \
|
||||
--restart-command '<restart govoplan server>'
|
||||
```
|
||||
|
||||
The backup command runs before migrations. The restore-check command validates
|
||||
the produced backup artifact before migrations proceed, without restoring over
|
||||
the live database. The restore command is stored in the run record and runs
|
||||
during rollback unless an override is passed to `--rollback`.
|
||||
|
||||
Supervised mode treats package command failure, migration failure, restart
|
||||
failure, and health timeout as rollback triggers. It restores the Python/WebUI
|
||||
package snapshots, re-runs the restart command when supplied, and restores the
|
||||
saved install plan state so the operator can correct it. The supervisor must
|
||||
run outside the FastAPI server process; the admin UI saves and validates plans
|
||||
but does not mutate packages from an HTTP request.
|
||||
|
||||
After a successful install plan, the installer adds installed modules to saved
|
||||
startup state by default so the restarted server can discover and enable them.
|
||||
After a successful uninstall plan, the installer removes uninstalled modules
|
||||
from saved startup state by default. Use
|
||||
`--no-activate-installed-modules` or
|
||||
`--keep-uninstalled-modules-in-desired` only for staged rollout workflows that
|
||||
will update module state separately.
|
||||
|
||||
Uninstall is non-destructive by default. A planned uninstall row can set
|
||||
`destroy_data: true` to request destructive module retirement. The module must
|
||||
provide an automated retirement provider, and the installer snapshots the
|
||||
database before dropping module-owned tables. For SQLite this uses the built-in
|
||||
snapshot path; for PostgreSQL or another non-SQLite database, provide
|
||||
`--database-backup-command`, `--database-restore-check-command`, and
|
||||
`--database-restore-command`. If a destructive run fails during package removal,
|
||||
the installer restores the database snapshot before returning the failed run
|
||||
result; supervised restart/health failures also roll back through the normal
|
||||
supervisor path.
|
||||
|
||||
Package rollback is automatic. SQLite database rollback is automatic for
|
||||
installer runs that used `--migrate` and captured a database snapshot.
|
||||
Non-SQLite rollback is automatic when the run used
|
||||
`--database-backup-command` and `--database-restore-command`; otherwise migrated
|
||||
non-SQLite runs are blocked before package changes are applied.
|
||||
|
||||
Rollback uses the saved run snapshot:
|
||||
|
||||
```bash
|
||||
govoplan-module-installer --rollback <run-id>
|
||||
govoplan-module-installer --rollback <run-id> --database-restore-command '<override restore command>'
|
||||
```
|
||||
|
||||
Database hook commands run with these environment variables:
|
||||
|
||||
- `GOVOPLAN_INSTALLER_RUN_DIR`: the run snapshot directory
|
||||
- `GOVOPLAN_DATABASE_URL`: the configured database URL
|
||||
- `GOVOPLAN_DATABASE_BACKUP_PATH`: a suggested backup artifact path inside the
|
||||
run directory
|
||||
- `GOVOPLAN_DATABASE_BACKUP_METADATA`: optional JSON metadata path that backup
|
||||
commands may write for operator diagnostics
|
||||
|
||||
Avoid embedding secrets directly in commands; prefer environment variables,
|
||||
service credentials, or deployment-local secret injection.
|
||||
|
||||
Inspect installer history and lock state from the operator shell:
|
||||
|
||||
```bash
|
||||
govoplan-module-installer --list-runs --format json
|
||||
govoplan-module-installer --show-run <run-id> --format json
|
||||
govoplan-module-installer --lock-status --format json
|
||||
govoplan-module-installer --list-requests --format json
|
||||
govoplan-module-installer --show-request <request-id> --format json
|
||||
govoplan-module-installer --cancel-request <request-id> --format json
|
||||
govoplan-module-installer --retry-request <request-id> --format json
|
||||
```
|
||||
|
||||
Package catalogs can be local files or remote static resources, for example
|
||||
served by `govoplan-web`. Set `GOVOPLAN_MODULE_PACKAGE_CATALOG` for a local file
|
||||
or `GOVOPLAN_MODULE_PACKAGE_CATALOG_URL` for a remote catalog matching
|
||||
`docs/module-package-catalog.example.json`; the admin UI will show those entries
|
||||
and can save them into the install plan. This keeps the release approval
|
||||
decision outside the running server while avoiding hand-typed package refs.
|
||||
Remote catalogs can be cached for offline inspection:
|
||||
|
||||
```bash
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_URL=https://govoplan.example/catalogs/v1/channels/stable.json
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_CACHE=/srv/govoplan/runtime/catalog-cache/stable.json
|
||||
```
|
||||
|
||||
Validate the catalog before handing it to operators:
|
||||
|
||||
```bash
|
||||
govoplan-module-installer --validate-package-catalog docs/module-package-catalog.example.json --format json
|
||||
```
|
||||
|
||||
Release catalogs should be signed, channel-gated, expiring, and sequence
|
||||
tracked. The supported signing format is an Ed25519 signature over the
|
||||
canonical catalog JSON object with the `signature` and `signatures` fields
|
||||
removed. Core accepts the legacy single `signature` field and the newer
|
||||
`signatures` array used during key rotation. Sign a catalog with:
|
||||
|
||||
```bash
|
||||
govoplan-module-installer \
|
||||
--sign-package-catalog docs/module-package-catalog.example.json \
|
||||
--catalog-signing-key-id release-key-1 \
|
||||
--catalog-signing-private-key /path/to/ed25519-private.pem
|
||||
```
|
||||
|
||||
Validate an approved release catalog with:
|
||||
|
||||
```bash
|
||||
govoplan-module-installer \
|
||||
--validate-package-catalog docs/module-package-catalog.example.json \
|
||||
--require-signed-catalog \
|
||||
--approved-catalog-channel stable \
|
||||
--catalog-trusted-key release-key-1=<base64-ed25519-public-key> \
|
||||
--format json
|
||||
```
|
||||
|
||||
For the admin UI/daemon path, configure the same policy through environment
|
||||
variables:
|
||||
|
||||
```bash
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG=/path/to/catalog.json
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_REQUIRE_SIGNATURE=true
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_APPROVED_CHANNELS=stable
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_TRUSTED_KEYS='{"release-key-1":"<base64-ed25519-public-key>"}'
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_SEQUENCE_STATE=/srv/govoplan/runtime/catalog-sequences.json
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_ENFORCE_SEQUENCE=true
|
||||
```
|
||||
|
||||
Trusted keys can also be loaded from
|
||||
`GOVOPLAN_MODULE_PACKAGE_CATALOG_TRUSTED_KEYS_FILE`. A URL-backed keyring is
|
||||
supported for development and tightly controlled deployments through
|
||||
`GOVOPLAN_MODULE_PACKAGE_CATALOG_TRUSTED_KEYS_URL` plus
|
||||
`GOVOPLAN_MODULE_PACKAGE_CATALOG_TRUSTED_KEYS_CACHE`, but production systems
|
||||
should pin trusted keys locally.
|
||||
|
||||
Catalog entries can declare `license_features`. If
|
||||
`GOVOPLAN_LICENSE_ENFORCEMENT=true`, core blocks planning catalog installs
|
||||
whose required features are not present in the configured offline license:
|
||||
|
||||
```bash
|
||||
GOVOPLAN_LICENSE_FILE=/srv/govoplan/license.json
|
||||
GOVOPLAN_LICENSE_TRUSTED_KEYS_FILE=/srv/govoplan/trust/license-keyring.json
|
||||
GOVOPLAN_LICENSE_ENFORCEMENT=true
|
||||
```
|
||||
|
||||
See `docs/CATALOG_TRUST_AND_LICENSING.md` for key rotation, replay protection,
|
||||
and licensing details. See `docs/RELEASE_CATALOG_WORKFLOW.md` for the concrete
|
||||
release-machine workflow that generates signing keys and publishes signed
|
||||
catalogs through `govoplan-web`. Unsigned catalogs remain usable for local
|
||||
development when signature enforcement is off, but the admin UI labels them as
|
||||
unsigned.
|
||||
|
||||
Install rows must use tagged package/git refs or registry packages, not local
|
||||
`file:` or workspace links. The installer daemon can run `npm install` and
|
||||
`npm run build` for WebUI package changes; that is the supported path. Browser
|
||||
remote bundles are still experimental and should be treated as a controlled
|
||||
deployment option, not the normal install/uninstall mechanism.
|
||||
|
||||
Module manifests can declare core compatibility bounds and uninstall guard
|
||||
providers. Preflight blocks incompatible manifest contracts/core versions,
|
||||
active modules, desired startup state, protected modules, and active dependents.
|
||||
Default uninstall is non-destructive: module data and schema remain dormant if
|
||||
the package is removed. Persistent-data guards therefore warn by default instead
|
||||
of requiring export/delete. A module that supports explicit data/schema
|
||||
retirement should register a retirement provider. When `destroy_data` is set on
|
||||
an uninstall plan row, that provider is allowed to destroy module-owned data
|
||||
after the installer has captured a database snapshot; otherwise it is used only
|
||||
for preflight reporting.
|
||||
|
||||
## WebUI
|
||||
|
||||
Local development uses `webui/package.json`, which may point at sibling module checkouts while active development is happening.
|
||||
|
||||
Release WebUI installs should use `webui/package.release.json`. It points module dependencies at the same tagged git repositories. After the module tags referenced there exist, generate the committed release lockfile without touching the development package files:
|
||||
Release WebUI installs should use `webui/package.release.json`. It points
|
||||
module dependencies at the same tagged git repositories. After the module tags
|
||||
referenced there exist, generate the committed release lockfile without
|
||||
touching the development package files:
|
||||
|
||||
```bash
|
||||
cd /mnt/DATA/git/govoplan-core
|
||||
@@ -300,16 +70,48 @@ cd webui
|
||||
PATH=/home/zemion/.nvm/versions/node/v22.22.3/bin:$PATH /home/zemion/.nvm/versions/node/v22.22.3/bin/npm run build
|
||||
```
|
||||
|
||||
The module repositories include root-level npm package manifests so git installs can resolve `@govoplan/access-webui`, `@govoplan/admin-webui`, `@govoplan/files-webui`, `@govoplan/mail-webui`, `@govoplan/campaign-webui`, and `@govoplan/calendar-webui` from repository roots even though their source lives below `webui/src`.
|
||||
The module repositories include root-level npm package manifests so git
|
||||
installs can resolve `@govoplan/access-webui`, `@govoplan/admin-webui`,
|
||||
`@govoplan/files-webui`, `@govoplan/mail-webui`,
|
||||
`@govoplan/campaign-webui`, and `@govoplan/calendar-webui` from repository
|
||||
roots even though their source lives below `webui/src`.
|
||||
|
||||
The normal release path is automated by `scripts/push-release-tag.sh`: it bumps or accepts the target version, updates Python/WebUI/module manifest versions, commits/tags/pushes the module repositories first, regenerates `webui/package-lock.release.json`, and then commits/tags/pushes core. If the working tree has already been bumped, pass the current version explicitly:
|
||||
### Release Lockfile Strategy
|
||||
|
||||
The supported release composition currently is the full GovOPlaN product: core
|
||||
plus access, admin, tenancy, organizations, identity, policy, audit,
|
||||
dashboard, files, mail, campaign, calendar, docs, and ops. Keep one committed
|
||||
full-product release lockfile at
|
||||
`webui/package-lock.release.json`, generated from
|
||||
`webui/package.release.json` in a clean release workspace. Development
|
||||
`package-lock.json` may continue to point at local `file:` dependencies.
|
||||
|
||||
Frontend module permutations are regression-tested through
|
||||
`GOVOPLAN_WEBUI_MODULE_PACKAGES` and temporary build output, not through
|
||||
committed lockfiles for every possible combination. If a smaller composition
|
||||
becomes a separately shipped product, add an explicit release manifest and
|
||||
lockfile pair for that product, for example
|
||||
`package.release.files-mail.json` and `package-lock.release.files-mail.json`,
|
||||
generated in a clean release workspace from tagged git dependencies.
|
||||
|
||||
## Release Tag Script
|
||||
|
||||
The normal release path is automated by `scripts/push-release-tag.sh`: it bumps
|
||||
or accepts the target version, updates Python/WebUI/module manifest versions,
|
||||
commits/tags/pushes the module repositories first, regenerates
|
||||
`webui/package-lock.release.json`, and then commits/tags/pushes core. If the
|
||||
working tree has already been bumped, pass the current version explicitly:
|
||||
|
||||
```bash
|
||||
cd /mnt/DATA/git/govoplan-core
|
||||
scripts/push-release-tag.sh --version 0.1.2
|
||||
scripts/push-release-tag.sh --version 0.1.6
|
||||
```
|
||||
|
||||
The script also includes GovOPlaN roadmap/scaffold module repositories that do not yet have package metadata. Those repositories are committed, tagged, and pushed with the same release tag, but they are tag-only until they contain `pyproject.toml`, module manifests, or WebUI packages. Tag-only repositories are not listed in `requirements-release.txt` or `webui/package.release.json`.
|
||||
The script also includes GovOPlaN roadmap/scaffold module repositories that do
|
||||
not yet have package metadata. Those repositories are committed, tagged, and
|
||||
pushed with the same release tag, but they are tag-only until they contain
|
||||
`pyproject.toml`, module manifests, or WebUI packages. Tag-only repositories
|
||||
are not listed in `requirements-release.txt` or `webui/package.release.json`.
|
||||
|
||||
Current tag-only module repositories:
|
||||
|
||||
@@ -325,7 +127,6 @@ Current tag-only module repositories:
|
||||
- `govoplan-idm`
|
||||
- `govoplan-ledger`
|
||||
- `govoplan-notifications`
|
||||
- `govoplan-ops`
|
||||
- `govoplan-payments`
|
||||
- `govoplan-portal`
|
||||
- `govoplan-reporting`
|
||||
@@ -338,17 +139,486 @@ Current tag-only module repositories:
|
||||
- `govoplan-xrechnung`
|
||||
- `govoplan-xta-osci`
|
||||
|
||||
### Release lockfile strategy
|
||||
## Catalog Trust And Licensing
|
||||
|
||||
The supported release composition currently is the full Multi Seal Mail product: core plus access, admin, tenancy, policy, audit, files, mail, campaign, and calendar. Keep one committed full-product release lockfile at `webui/package-lock.release.json`, generated from `webui/package.release.json` in a clean release workspace. Development `package-lock.json` may continue to point at local `file:` dependencies.
|
||||
GovOPlaN module install and uninstall must remain operator-controlled. The
|
||||
running server may plan and validate package changes, but package mutation is
|
||||
performed by the separate installer daemon or an operator shell during
|
||||
maintenance mode.
|
||||
|
||||
Frontend module permutations are regression-tested through `GOVOPLAN_WEBUI_MODULE_PACKAGES` and temporary build output, not through committed lockfiles for every possible combination. If a smaller composition becomes a separately shipped product, add an explicit release manifest and lockfile pair for that product, for example `package.release.files-mail.json` and `package-lock.release.files-mail.json`, generated in a clean release workspace from tagged git dependencies.
|
||||
`govoplan-web` is the public static distribution surface for official catalog
|
||||
resources:
|
||||
|
||||
- signed module package catalogs, grouped by release channel
|
||||
- public catalog keyrings
|
||||
- public license verification keyrings
|
||||
- examples and operator-facing download paths
|
||||
|
||||
`govoplan-core` is the verifier and orchestrator:
|
||||
|
||||
- fetches a local or remote module catalog
|
||||
- verifies catalog signatures against configured trusted keys
|
||||
- enforces approved release channels
|
||||
- rejects expired or not-yet-valid catalogs
|
||||
- records accepted catalog sequence numbers for replay protection
|
||||
- checks catalog entry license feature requirements before planning installs
|
||||
- writes installer plans and request records
|
||||
|
||||
Feature and platform modules own their package artifacts, manifests, migration
|
||||
metadata, retirement providers, and optional lifecycle behavior.
|
||||
|
||||
Core accepts either a local catalog file or a remote URL:
|
||||
|
||||
```bash
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG=/srv/govoplan/catalogs/stable.json
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_URL=https://govoplan.example/catalogs/v1/channels/stable.json
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_CACHE=/srv/govoplan/runtime/catalog-cache/stable.json
|
||||
```
|
||||
|
||||
If both file and URL are set, the URL wins. The cache is used when a remote
|
||||
fetch fails, so an operator can still inspect the last known catalog. A cached
|
||||
catalog must still pass signature, freshness, channel, and replay validation.
|
||||
|
||||
An official catalog is a JSON object with:
|
||||
|
||||
- `catalog_version`
|
||||
- `channel`
|
||||
- `sequence`
|
||||
- `generated_at`
|
||||
- `not_before` when delayed activation is needed
|
||||
- `expires_at`
|
||||
- `modules`
|
||||
- `signatures`
|
||||
|
||||
Each module entry can declare:
|
||||
|
||||
- backend package name and pinned install reference
|
||||
- WebUI package name and pinned install reference
|
||||
- display metadata and tags
|
||||
- `license_features`, the feature entitlements required to plan that install
|
||||
|
||||
The signature is Ed25519 over canonical JSON with both `signature` and
|
||||
`signatures` removed. Core accepts the legacy single `signature` field and the
|
||||
new `signatures` array.
|
||||
|
||||
Trusted catalog keys are configured locally:
|
||||
|
||||
```bash
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_TRUSTED_KEYS_FILE=/srv/govoplan/trust/catalog-keyring.json
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_TRUSTED_KEYS='{"release-key-1":"<base64 public key>"}'
|
||||
```
|
||||
|
||||
For development or tightly controlled deployments, a keyring can be read from a
|
||||
URL and cached:
|
||||
|
||||
```bash
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_TRUSTED_KEYS_URL=https://govoplan.example/catalogs/v1/keyring.json
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_TRUSTED_KEYS_CACHE=/srv/govoplan/runtime/catalog-cache/keyring.json
|
||||
```
|
||||
|
||||
Production installations should pin the trusted keyring locally or ship it
|
||||
through deployment configuration. Fetching trusted keys from the same public
|
||||
origin as the catalog is convenient, but that origin must not become the only
|
||||
trust root.
|
||||
|
||||
## Dependency Audits
|
||||
|
||||
Dependency vulnerability checks are documented in
|
||||
[`DEPENDENCY_AUDITS.md`](DEPENDENCY_AUDITS.md). The local audit runner is:
|
||||
|
||||
```bash
|
||||
cd /mnt/DATA/git/govoplan-core
|
||||
bash scripts/check-dependency-audits.sh
|
||||
```
|
||||
|
||||
The Gitea workflow in `.gitea/workflows/dependency-audit.yml` runs the same
|
||||
check against release dependency refs on pushes, pull requests, and a weekly
|
||||
schedule.
|
||||
|
||||
Keyring entries support:
|
||||
|
||||
- `key_id`
|
||||
- `public_key` or `public_key_base64`
|
||||
- `status`: `active`, `next`, `retired`, `revoked`, or `disabled`
|
||||
- `not_before`
|
||||
- `not_after`
|
||||
|
||||
Rotation process:
|
||||
|
||||
1. Add the next public key to the local trusted keyring with status `next`.
|
||||
2. Publish catalogs signed by both current and next keys.
|
||||
3. Upgrade installations so the next key is locally trusted.
|
||||
4. Promote the next key to `active`.
|
||||
5. Retire the old key only after every supported installation trusts the new
|
||||
key.
|
||||
6. Mark a compromised key `revoked` and publish a higher sequence catalog
|
||||
signed by an uncompromised key.
|
||||
|
||||
Use replay state in production:
|
||||
|
||||
```bash
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_SEQUENCE_STATE=/srv/govoplan/runtime/catalog-sequences.json
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_ENFORCE_SEQUENCE=true
|
||||
```
|
||||
|
||||
Core records the accepted sequence per channel after a catalog entry is planned
|
||||
from the admin interface. With strict sequence enforcement, a previously
|
||||
accepted sequence is rejected; without strict enforcement, only older sequences
|
||||
are rejected. Catalogs should always expire.
|
||||
|
||||
The sequence state file is operational state, not a trust root. Keep it on
|
||||
persistent storage and include it in normal backups:
|
||||
|
||||
```json
|
||||
{
|
||||
"channels": {
|
||||
"stable": {
|
||||
"last_sequence": 42,
|
||||
"accepted_at": "2026-07-07T12:00:00Z",
|
||||
"key_id": "release-key-1",
|
||||
"source": "https://govoplan.example/catalogs/v1/channels/stable.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If the file is lost, restore it from backup. If no backup exists, reconstruct
|
||||
each channel from the highest sequence already accepted in installer run
|
||||
records, release records, or the currently deployed module package set. Do not
|
||||
lower `last_sequence` to make an older catalog pass; publish a new higher
|
||||
sequence catalog when the accepted point is uncertain.
|
||||
|
||||
If the file is corrupted, copy it aside for incident review, validate the
|
||||
current signed catalog with channel and freshness enforcement, then rewrite the
|
||||
state with the known accepted sequence. Keep
|
||||
`GOVOPLAN_MODULE_PACKAGE_CATALOG_REQUIRE_SIGNATURE=true` and approved-channel
|
||||
checks enabled during recovery. Temporarily disabling
|
||||
`GOVOPLAN_MODULE_PACKAGE_CATALOG_ENFORCE_SEQUENCE` allows revalidating the same
|
||||
sequence, but older sequences remain rejected once the reconstructed
|
||||
`last_sequence` is in place.
|
||||
|
||||
Approved channels are deployment policy:
|
||||
|
||||
```bash
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_APPROVED_CHANNELS=stable,lts
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_REQUIRE_SIGNATURE=true
|
||||
```
|
||||
|
||||
The admin UI can display other catalog metadata, but core rejects catalogs from
|
||||
unapproved channels when validation is configured.
|
||||
|
||||
Catalog entries can require license features:
|
||||
|
||||
```json
|
||||
"license_features": ["module.mail", "support.standard"]
|
||||
```
|
||||
|
||||
Core checks those requirements against an offline license file before allowing
|
||||
the entry into the install plan.
|
||||
|
||||
```bash
|
||||
GOVOPLAN_LICENSE_FILE=/srv/govoplan/license.json
|
||||
GOVOPLAN_LICENSE_ENFORCEMENT=true
|
||||
GOVOPLAN_LICENSE_TRUSTED_KEYS_FILE=/srv/govoplan/trust/license-keyring.json
|
||||
```
|
||||
|
||||
License files are JSON objects with:
|
||||
|
||||
- `license_id`
|
||||
- `subject`
|
||||
- `features`
|
||||
- `valid_from`
|
||||
- `valid_until`
|
||||
- `signature`
|
||||
|
||||
Issue or renew a license from an operator/release shell that has the Ed25519
|
||||
private key:
|
||||
|
||||
```bash
|
||||
govoplan-module-installer \
|
||||
--issue-license /srv/govoplan/license.json \
|
||||
--license-id customer-2026-07 \
|
||||
--license-subject "Example Municipality" \
|
||||
--license-feature module.mail \
|
||||
--license-feature support.standard \
|
||||
--license-valid-until 2027-07-31T23:59:59Z \
|
||||
--license-signing-key-id license-issuer-1 \
|
||||
--license-signing-private-key /srv/govoplan/secrets/license-issuer-1.pem \
|
||||
--format json
|
||||
```
|
||||
|
||||
Validate an imported license without exposing secrets:
|
||||
|
||||
```bash
|
||||
govoplan-module-installer \
|
||||
--validate-license /srv/govoplan/license.json \
|
||||
--license-trusted-key license-issuer-1="<base64 public key>" \
|
||||
--require-trusted-license \
|
||||
--license-required-feature module.mail \
|
||||
--format json
|
||||
```
|
||||
|
||||
The CLI and admin module catalog panel report the license id, subject,
|
||||
validity window, signing key id, signed/trusted state, available features, and
|
||||
missing entitlements for the configured package catalog. They do not expose
|
||||
private signing material.
|
||||
|
||||
License enforcement can run in observe-only mode by leaving
|
||||
`GOVOPLAN_LICENSE_ENFORCEMENT` unset. In that mode, missing or invalid license
|
||||
data is surfaced as a warning but does not block planning.
|
||||
|
||||
Renewal is an ordinary re-issuance with a new `license_id`, extended
|
||||
`valid_until`, and the full intended feature set. Import the renewed JSON to
|
||||
`GOVOPLAN_LICENSE_FILE`, keep the previous file for audit, and validate it
|
||||
before setting enforcement.
|
||||
|
||||
Revocation is handled through the trusted license keyring. Mark a compromised
|
||||
or invalid issuer key as `revoked` or `disabled`, publish or deploy the updated
|
||||
keyring, then reissue affected licenses with an active key. Installations that
|
||||
run with `GOVOPLAN_LICENSE_ENFORCEMENT=true` reject licenses signed only by a
|
||||
revoked key after the local keyring is updated.
|
||||
|
||||
Emergency fallback is deliberately explicit. Operators can temporarily unset
|
||||
`GOVOPLAN_LICENSE_ENFORCEMENT` to keep package planning observable while a
|
||||
license or keyring is recovered. Record the change in the operational incident
|
||||
log, keep catalog signature and channel enforcement enabled, and restore
|
||||
license enforcement after a trusted renewal validates successfully.
|
||||
|
||||
Licensing is intentionally separate from open-source code licensing. The
|
||||
catalog/license mechanism can govern support channels, official release
|
||||
eligibility, hosted update access, professional support, or commercial
|
||||
entitlements without changing the source license of the repositories.
|
||||
|
||||
Production-grade distribution still needs remote registry/git artifact
|
||||
resolution before package-manager apply, a hardened catalog publishing pipeline
|
||||
in `govoplan-web`, and automated key rotation and emergency revocation drills.
|
||||
|
||||
## Release Catalog Publishing
|
||||
|
||||
GovOPlaN release catalogs are published by `govoplan-web` as static JSON and
|
||||
verified by `govoplan-core` before installer plans are accepted. Private signing
|
||||
keys must stay outside all git repositories. Public keyrings are published with
|
||||
the website.
|
||||
|
||||
Create the first catalog signing key on the release machine:
|
||||
|
||||
```bash
|
||||
cd /mnt/DATA/git/govoplan-core
|
||||
KEY_DIR="$HOME/.config/govoplan/release-keys"
|
||||
mkdir -p "$KEY_DIR"
|
||||
./.venv/bin/python scripts/generate-catalog-keypair.py \
|
||||
--key-id release-key-1 \
|
||||
--private-key "$KEY_DIR/release-key-1.pem" \
|
||||
--public-key "$KEY_DIR/release-key-1.pub" \
|
||||
--keyring "$KEY_DIR/catalog-keyring.json"
|
||||
```
|
||||
|
||||
Keep `release-key-1.pem` private. The generated keyring contains only public
|
||||
material.
|
||||
|
||||
Generate the signed catalog into `govoplan-web`:
|
||||
|
||||
```bash
|
||||
cd /mnt/DATA/git/govoplan-core
|
||||
KEY_DIR="$HOME/.config/govoplan/release-keys"
|
||||
scripts/publish-release-catalog.sh \
|
||||
--version <x.y.z> \
|
||||
--sequence 202607071340 \
|
||||
--catalog-signing-key "release-key-1=$KEY_DIR/release-key-1.pem" \
|
||||
--build-web
|
||||
```
|
||||
|
||||
This writes:
|
||||
|
||||
- `/mnt/DATA/git/govoplan-web/public/catalogs/v1/channels/stable.json`
|
||||
- `/mnt/DATA/git/govoplan-web/public/catalogs/v1/keyring.json`
|
||||
|
||||
The wrapper validates the catalog with core using the generated public keyring.
|
||||
|
||||
For normal module/core releases, first audit and record migration baselines,
|
||||
then tag and push the module/core repos. Finally publish the website catalog:
|
||||
|
||||
```bash
|
||||
cd /mnt/DATA/git/govoplan-core
|
||||
./.venv/bin/python scripts/release-migration-audit.py --strict
|
||||
```
|
||||
|
||||
```bash
|
||||
cd /mnt/DATA/git/govoplan-core
|
||||
KEY_DIR="$HOME/.config/govoplan/release-keys"
|
||||
scripts/publish-release-catalog.sh \
|
||||
--version <x.y.z> \
|
||||
--catalog-signing-key "release-key-1=$KEY_DIR/release-key-1.pem" \
|
||||
--build-web \
|
||||
--commit \
|
||||
--tag \
|
||||
--push
|
||||
```
|
||||
|
||||
The website tag is `catalog-v<x.y.z>`. The public URL is:
|
||||
|
||||
```text
|
||||
https://govoplan.add-ideas.de/catalogs/v1/channels/stable.json
|
||||
```
|
||||
|
||||
The public keyring URL is:
|
||||
|
||||
```text
|
||||
https://govoplan.add-ideas.de/catalogs/v1/keyring.json
|
||||
```
|
||||
|
||||
`scripts/push-release-tag.sh` can publish the web catalog after module and core
|
||||
tags have been pushed. It runs the migration release audit in automatic mode:
|
||||
warning-only before the first recorded migration baseline, strict after a
|
||||
baseline exists. Add `--strict-migration-audit` when you want to force strict
|
||||
mode explicitly:
|
||||
|
||||
```bash
|
||||
cd /mnt/DATA/git/govoplan-core
|
||||
KEY_DIR="$HOME/.config/govoplan/release-keys"
|
||||
scripts/push-release-tag.sh \
|
||||
--bump subversion \
|
||||
--strict-migration-audit \
|
||||
--publish-web-catalog \
|
||||
--catalog-signing-key "release-key-1=$KEY_DIR/release-key-1.pem" \
|
||||
--build-web-catalog
|
||||
```
|
||||
|
||||
Use `--catalog-signing-key` more than once during a key rotation window. The
|
||||
catalog will contain multiple signatures and the public keyring will include the
|
||||
corresponding public keys.
|
||||
|
||||
On a GovOPlaN installation that should consume the official stable catalog:
|
||||
|
||||
```bash
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_URL=https://govoplan.add-ideas.de/catalogs/v1/channels/stable.json
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_CACHE=/srv/govoplan/runtime/catalog-cache/stable.json
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_REQUIRE_SIGNATURE=true
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_APPROVED_CHANNELS=stable
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_TRUSTED_KEYS_FILE=/srv/govoplan/trust/catalog-keyring.json
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_SEQUENCE_STATE=/srv/govoplan/runtime/catalog-sequences.json
|
||||
GOVOPLAN_MODULE_PACKAGE_CATALOG_ENFORCE_SEQUENCE=true
|
||||
```
|
||||
|
||||
For production, copy the public keyring into deployment configuration and pin it
|
||||
locally. Do not rely on a URL-fetched keyring as the only trust root.
|
||||
|
||||
`stable.json` includes a top-level `core_release` section for operator/update
|
||||
tooling. Core is intentionally not listed as a normal module entry because it
|
||||
must not be added to saved enabled-module state. Core upgrades should remain an
|
||||
operator-supervised package update with restart and health checks.
|
||||
|
||||
Key rotation for published catalogs:
|
||||
|
||||
1. Generate the next private key outside git.
|
||||
2. Run `publish-release-catalog.sh` with both signing keys.
|
||||
3. Publish the web catalog/keyring.
|
||||
4. Roll the new public keyring into installations.
|
||||
5. Stop signing with the old key after the supported fleet trusts the new key.
|
||||
6. Mark compromised keys as revoked in the public keyring and publish a higher
|
||||
sequence catalog signed by a trusted uncompromised key.
|
||||
|
||||
## PostgreSQL Release Check
|
||||
|
||||
Release candidates should pass a disposable PostgreSQL migration and startup
|
||||
smoke check before tagging or publishing catalogs. Start the local testbed,
|
||||
then run the permutation check from the core checkout:
|
||||
|
||||
```bash
|
||||
cd /mnt/DATA/git/govoplan-core/dev/postgres
|
||||
cp .env.example .env
|
||||
docker compose --env-file .env up -d
|
||||
|
||||
cd /mnt/DATA/git/govoplan-core
|
||||
set -a
|
||||
. dev/postgres/.env
|
||||
set +a
|
||||
./.venv/bin/python scripts/postgres-integration-check.py \
|
||||
--database-url "$GOVOPLAN_POSTGRES_DATABASE_URL" \
|
||||
--reset-schema
|
||||
```
|
||||
|
||||
The script checks migrations and `/health` startup for core-only, files-only,
|
||||
mail-only, campaign-only, campaign+files, campaign+mail, and full-product
|
||||
module sets. `--reset-schema` is destructive and must only be used against a
|
||||
throwaway database.
|
||||
|
||||
## Migration Baselines
|
||||
|
||||
Development migrations may be small and numerous while a feature is moving.
|
||||
Before a stable release, unreleased migrations may be rewritten or squashed into
|
||||
a release-level baseline or release-to-release upgrade migration. After a
|
||||
release tag has shipped, released migration revision IDs are immutable.
|
||||
|
||||
The release policy is:
|
||||
|
||||
- unreleased migrations may be folded before release;
|
||||
- released migrations are never rewritten or deleted;
|
||||
- each stable release records the public migration head revisions in
|
||||
`docs/migration-release-baselines.json`;
|
||||
- fresh installations should apply release-level baselines/upgrades, not
|
||||
unreleased create-then-rename churn;
|
||||
- release-to-release schema changes should be folded into one reviewed
|
||||
migration per migration owner where practical.
|
||||
|
||||
Audit the current graph during release preparation:
|
||||
|
||||
```bash
|
||||
cd /mnt/DATA/git/govoplan-core
|
||||
./.venv/bin/python scripts/release-migration-audit.py
|
||||
```
|
||||
|
||||
Generate the reviewed/manual squash checklist:
|
||||
|
||||
```bash
|
||||
./.venv/bin/python scripts/release-migration-audit.py --squash-plan
|
||||
```
|
||||
|
||||
After the release migrations have been reviewed and the graph is final, record
|
||||
the release baseline:
|
||||
|
||||
```bash
|
||||
./.venv/bin/python scripts/release-migration-audit.py --record-release <x.y.z>
|
||||
```
|
||||
|
||||
Use strict mode to verify that the current heads are recorded:
|
||||
|
||||
```bash
|
||||
./.venv/bin/python scripts/release-migration-audit.py --strict
|
||||
```
|
||||
|
||||
`scripts/push-release-tag.sh` runs the audit by default in automatic mode:
|
||||
non-strict while no release baseline exists, strict after the first baseline is
|
||||
recorded. Pass `--warn-migration-audit` for an explicit non-strict audit,
|
||||
`--strict-migration-audit` to force strict mode, or `--skip-migration-audit`
|
||||
only for emergency/manual release work.
|
||||
|
||||
Before the first stable release, fold the current development chain into the
|
||||
first public baseline and record that baseline in
|
||||
`docs/migration-release-baselines.json`. The tracking issue is
|
||||
`add-ideas/govoplan-core#223`.
|
||||
|
||||
## Related Operator Documents
|
||||
|
||||
- `DEPLOYMENT_OPERATOR_GUIDE.md`: runtime environment, explicit migrations,
|
||||
backup/restore commands, module installer daemon/supervisor operation, and
|
||||
rollback drills.
|
||||
- `REMOTE_WEBUI_BUNDLES.md`: experimental browser-loaded module bundles for
|
||||
controlled deployments; normal releases use package builds.
|
||||
|
||||
## Release Checklist
|
||||
|
||||
- Keep Python package versions, WebUI package versions, and git tags aligned.
|
||||
- Tag core, access, admin, tenancy, policy, audit, files, mail, campaign, calendar, and scaffold module repositories together.
|
||||
- Update `requirements-release.txt` and `webui/package.release.json` when the release tag changes.
|
||||
- Generate the committed full-product release lockfile from `package.release.json` with `scripts/generate-release-lock.sh`.
|
||||
- Add separate release manifest/lockfile pairs only for module compositions that are shipped as their own products.
|
||||
- Tag core, access, admin, tenancy, policy, audit, files, mail, campaign,
|
||||
calendar, and scaffold module repositories together.
|
||||
- Update `requirements-release.txt` and `webui/package.release.json` when the
|
||||
release tag changes.
|
||||
- Generate the committed full-product release lockfile from
|
||||
`package.release.json` with `scripts/generate-release-lock.sh`.
|
||||
- Run `scripts/release-migration-audit.py --strict` after recording a release
|
||||
baseline.
|
||||
- Run the PostgreSQL release check against a disposable database.
|
||||
- Publish the signed catalog through the release catalog publishing flow above.
|
||||
- Add separate release manifest/lockfile pairs only for module compositions
|
||||
that are shipped as their own products.
|
||||
- Do not commit local sibling paths into release manifests.
|
||||
|
||||
161
docs/REMOTE_WEBUI_BUNDLES.md
Normal file
161
docs/REMOTE_WEBUI_BUNDLES.md
Normal file
@@ -0,0 +1,161 @@
|
||||
# Remote WebUI Bundle Loading
|
||||
|
||||
GovOPlaN WebUI modules normally ship through the core WebUI package graph:
|
||||
install a tagged npm/git dependency, run `npm install`, rebuild the shell, and
|
||||
restart or reload the served assets. Remote WebUI bundles are an experimental
|
||||
future path for controlled deployments where a backend-enabled module is not in
|
||||
the local WebUI package graph and the operator wants the shell to load its
|
||||
frontend without rebuilding core.
|
||||
|
||||
This design defines the target guardrails. The current rebuild/reload path
|
||||
remains the default production path.
|
||||
|
||||
## Current Rebuild Path
|
||||
|
||||
The supported release path is:
|
||||
|
||||
1. Install or remove backend and WebUI package dependencies through the trusted
|
||||
installer CLI/daemon.
|
||||
2. Snapshot package state before mutation.
|
||||
3. Run `npm install` and optionally `npm run build`.
|
||||
4. Restart or reload the served WebUI assets.
|
||||
5. Use installer rollback if package apply, restart, or health checks fail.
|
||||
|
||||
Strengths:
|
||||
|
||||
- package manager and lockfile semantics stay conventional
|
||||
- CSP can stay strict because all code is served as built assets
|
||||
- rollback restores package files and lockfiles
|
||||
- local development uses sibling workspace dependencies naturally
|
||||
|
||||
Costs:
|
||||
|
||||
- frontend changes require a rebuild/reload
|
||||
- hot enabling a module with frontend code is not possible in the running shell
|
||||
- failed rebuilds happen at install time, not at lazy module-load time
|
||||
|
||||
## Remote Bundle Path
|
||||
|
||||
Remote loading is only for modules that are enabled by the backend and absent
|
||||
from `virtual:govoplan-installed-modules`. The backend manifest exposes:
|
||||
|
||||
- `FrontendModule.asset_manifest`
|
||||
- `asset_manifest_integrity`
|
||||
- `asset_manifest_signature`
|
||||
- `asset_manifest_public_key_id`
|
||||
- `asset_manifest_contract_version`
|
||||
|
||||
The WebUI shell fetches the asset manifest, verifies manifest integrity and/or
|
||||
signature, validates the manifest contract, fetches the entry bundle, verifies
|
||||
the entry integrity, imports the bundle, validates the exported
|
||||
`PlatformWebModule`, and applies backend metadata before registering routes,
|
||||
navigation, and UI capabilities.
|
||||
|
||||
Unsigned and unhashed manifests are skipped. Entries without integrity are
|
||||
skipped. A module id mismatch is skipped.
|
||||
|
||||
## Asset Manifest Contract
|
||||
|
||||
Contract version `1`:
|
||||
|
||||
```json
|
||||
{
|
||||
"contractVersion": "1",
|
||||
"moduleId": "files",
|
||||
"entry": "./files-webui.remote.js",
|
||||
"entryIntegrity": "SHA-256-<base64-or-hex-digest>",
|
||||
"moduleExport": "default"
|
||||
}
|
||||
```
|
||||
|
||||
The backend manifest carries the manifest-level trust metadata. The remote
|
||||
asset manifest carries the concrete entry URL and entry digest.
|
||||
|
||||
## Compatibility Checks
|
||||
|
||||
Before a remote bundle is accepted:
|
||||
|
||||
- backend module must be enabled
|
||||
- local WebUI module with the same id must be absent
|
||||
- manifest contract must be supported by the shell
|
||||
- manifest `moduleId`, exported module `id`, and backend module id must match
|
||||
- backend metadata remains authoritative for label, version, dependencies,
|
||||
nav, and runtime UI capability exposure
|
||||
- future contract versions must declare required shell capabilities so old
|
||||
shells fail closed
|
||||
|
||||
Remote bundles must not broaden backend permissions. They can only contribute
|
||||
routes/nav/capabilities that the backend metadata and existing permission
|
||||
checks allow.
|
||||
|
||||
## CSP
|
||||
|
||||
The current implementation imports verified entry bytes through a blob URL. A
|
||||
production CSP for this mode must explicitly allow:
|
||||
|
||||
- `connect-src` for the approved asset-manifest and bundle origins
|
||||
- `script-src` for `blob:` only when remote loading is enabled
|
||||
- no `unsafe-inline` requirement for remote modules
|
||||
|
||||
If an installation cannot allow `blob:` scripts, the follow-up implementation
|
||||
should use signed same-origin module assets with static URLs instead of blob
|
||||
imports. Remote loading must be disableable by configuration so strict-CSP
|
||||
deployments can keep the rebuild path only.
|
||||
|
||||
## Cache Invalidation
|
||||
|
||||
The shell cache key is:
|
||||
|
||||
```text
|
||||
<module-id>:<asset-manifest-url>:<backend-module-version>
|
||||
```
|
||||
|
||||
Release catalogs should publish immutable manifest and entry URLs or change at
|
||||
least one cache-key component on every release. Emergency rollback can point the
|
||||
backend manifest at a previous immutable manifest URL or lower the enabled
|
||||
module version after the backend package rollback.
|
||||
|
||||
Browsers may still cache remote responses. Approved asset servers should use:
|
||||
|
||||
- long cache lifetimes only for content-addressed immutable assets
|
||||
- short cache lifetimes or explicit revalidation for channel/latest manifest
|
||||
aliases
|
||||
- `Cache-Control: no-store` for emergency override manifests
|
||||
|
||||
## Rollback
|
||||
|
||||
Remote WebUI rollback is metadata rollback, not package-manager rollback:
|
||||
|
||||
- if the backend package install rolls back, the previous backend frontend
|
||||
metadata returns
|
||||
- if only remote assets are bad, publish a new manifest URL or revert the
|
||||
backend/frontend metadata to the last known good manifest
|
||||
- failed remote loading must degrade by omitting the remote module frontend,
|
||||
not by breaking the shell
|
||||
|
||||
Installer run records should eventually include remote asset manifest URLs,
|
||||
integrity, signature key ids, and load-test results when a plan enables a
|
||||
remote frontend.
|
||||
|
||||
## Local And Development Behavior
|
||||
|
||||
Local development should keep using workspace/file dependencies and Vite. Remote
|
||||
loading is useful for integration testing release artifacts, not for day-to-day
|
||||
module UI development.
|
||||
|
||||
Development deployments may use unsigned catalogs and local asset servers only
|
||||
when signature/integrity enforcement is intentionally disabled. The remote
|
||||
loader itself still requires an integrity hash or a verifiable signature.
|
||||
|
||||
## Follow-Up Slices
|
||||
|
||||
1. Add a server-side remote-bundle policy flag and surface whether remote
|
||||
loading is enabled in platform metadata.
|
||||
2. Add CSP documentation/config generation for strict rebuild-only mode versus
|
||||
controlled remote-bundle mode.
|
||||
3. Add an installer/catalog preflight that validates remote WebUI asset
|
||||
manifests and records verified identity in installer run records.
|
||||
4. Add Playwright coverage for a signed test remote bundle, failed digest, bad
|
||||
module id, cache-key refresh, and fallback when the module is unavailable.
|
||||
5. Add release tooling to emit immutable remote asset manifests with digest,
|
||||
signature, key id, and rollback metadata.
|
||||
216
docs/UI_UX_DECISION_LEDGER.md
Normal file
216
docs/UI_UX_DECISION_LEDGER.md
Normal file
@@ -0,0 +1,216 @@
|
||||
# GovOPlaN UI/UX Decision Ledger
|
||||
|
||||
This ledger records product UI/UX decisions that affect admin, settings,
|
||||
configuration, connector, policy, and module-management surfaces. It is a
|
||||
binding design reference: future implementation should follow these decisions
|
||||
unless the decision is explicitly revised here and affected screens are updated
|
||||
to match.
|
||||
|
||||
Active tracking issue: `add-ideas/govoplan-core#225`.
|
||||
|
||||
## Operating Rule
|
||||
|
||||
GovOPlaN must expose advanced platform capability without presenting the user
|
||||
with every option at once. Non-technical users should be able to complete common
|
||||
workflows through guided, plain-language flows. Expert and diagnostic detail may
|
||||
exist, but it must be deliberately layered.
|
||||
|
||||
The ethical design doctrine in `INTERFACE_ETHICS_AND_DESIGN_DOCTRINE.md` is the
|
||||
normative baseline for this ledger. A screen can be visually quiet and still be
|
||||
ethically complete only when it preserves context, consequence,
|
||||
contestability, responsibility, and traceability at the point of action.
|
||||
|
||||
## Binding Decisions
|
||||
|
||||
| ID | Decision | Status | Applies To |
|
||||
| --- | --- | --- | --- |
|
||||
| UX-001 | Use progressive disclosure by default. Common decisions stay visible; advanced or hazardous options live in collapsed panels, later wizard steps, or explicit advanced sections. | Accepted | Admin, settings, connector setup, policy editors, module operations |
|
||||
| UX-002 | Raw JSON is not a primary configuration editor. Every normal configuration path needs typed controls, validation, and help text. JSON may be shown for import/export, diagnostics, or expert inspection only. | Accepted | All admin/configuration UIs |
|
||||
| UX-003 | Prefer guided workflows over option dumps for setup and risky changes. Use wizards for connector setup, configuration package import, module install/uninstall, destructive actions, and policy changes with broad impact. | Accepted | Connectors, package import, module lifecycle, governance/policy |
|
||||
| UX-004 | Discover technical values when possible. Ask for the smallest user-known input, then discover and prefill technical fields for review. | Accepted | File connectors, mail/groupware, public URLs, future external providers |
|
||||
| UX-005 | Disabled actions and failed steps must explain why they are unavailable, who can fix them, and where to go next. Silent disabled states are not acceptable for primary actions. | Accepted | All primary actions |
|
||||
| UX-006 | Explanations must be available but quiet. Use short inline text and expose richer explanations through help affordances, side panels, expandable sections, or review steps. | Accepted | All complex forms and flows |
|
||||
| UX-007 | Creation/editing should prefer modals or focused step flows when it reduces page clutter. Overview and comparison screens remain full-page. | Accepted | Settings/admin surfaces |
|
||||
| UX-008 | Similar concepts must use shared placement and components: server/credential/policy rows, problem lists, review steps, advanced panels, confirmation modals, and empty/error states. | Accepted | Core WebUI and module WebUIs |
|
||||
| UX-009 | Preflight and diagnostics are product UX. Validation, policy, permission, dependency, and capability failures must be written for operators before exposing internal details. | Accepted | Installer, connectors, policy, package import |
|
||||
| UX-010 | Context, decision, and consequence must be visible together for actions that affect rights, duties, records, money, communication, retention, external systems, or workflow state. | Accepted | Workflow, admin, portal, policy, connector, records, payments |
|
||||
| UX-011 | Navigation is not consent. Route changes, panel switches, and passive selection must not execute consequential actions without an explicit action surface. | Accepted | All WebUI surfaces |
|
||||
| UX-012 | Automated actions must remain inspectable. The UI must show the system actor, trigger, policy result, observed effects, and failure/manual-intervention state when automation changes administrative state. | Accepted | Workflow, automation, connectors, tasks, audit |
|
||||
| UX-013 | Contestable decisions must expose provenance. Denials, locks, generated outputs, calculated defaults, policy decisions, access decisions, and retention decisions need a reachable source path. | Accepted | Policy, access, templates, workflow, retention, records |
|
||||
| UX-014 | Retraction, expiry, undo, rollback, and delete controls must state the real limit of the operation. Corrective or future-only actions must not be described as if they undo already observed effects. | Accepted | Postbox, files, records, installer, workflow, payments |
|
||||
|
||||
## Confirmed Implementation Decisions
|
||||
|
||||
These decisions were accepted on 2026-07-09 for the first implementation slice.
|
||||
They shape reusable components and screen structure. Future changes must revise
|
||||
this section and update affected screens.
|
||||
|
||||
### DUE-001: Primary Admin Configuration Shell
|
||||
|
||||
Decision: admin/configuration surfaces should standardize on a two-zone layout.
|
||||
|
||||
- Left or top area: searchable overview/list, status, and primary actions.
|
||||
- Main area: selected item summary and common settings.
|
||||
- Modal/wizard: create, connect, edit, test, review, and confirm actions.
|
||||
- Collapsed advanced panels: rarely used technical fields.
|
||||
|
||||
Use this for file connectors and mail servers first, then migrate policy,
|
||||
retention, API keys, and module operations.
|
||||
|
||||
### DUE-002: Wizard Step Model
|
||||
|
||||
Decision: standard wizard steps and names use this baseline:
|
||||
|
||||
1. Choose type or scope.
|
||||
2. Enter essentials.
|
||||
3. Discover or test.
|
||||
4. Configure ownership and policy.
|
||||
5. Review changes and blockers.
|
||||
6. Save or submit for operator action.
|
||||
|
||||
Not every wizard needs every step, but flows should use these names and order
|
||||
where applicable.
|
||||
|
||||
This applies to explicit assisted setup, onboarding, import, preflight, and
|
||||
risky multi-step operations. It is not the default shape for ordinary create or
|
||||
edit dialogs.
|
||||
|
||||
### DUE-003: Explanation Placement
|
||||
|
||||
Decision: richer explanations should use this placement model:
|
||||
|
||||
- Short helper text below labels only when it prevents common mistakes.
|
||||
- Tooltips for icon-only controls and compact terms.
|
||||
- Expandable "Why?" or "Details" blocks for contextual explanations.
|
||||
- Right-side detail panel or review step for preflight/provenance/diagnostics.
|
||||
|
||||
Avoid permanently visible paragraphs inside dense admin cards.
|
||||
|
||||
### DUE-004: Advanced Options Contract
|
||||
|
||||
Decision: advanced options are fields that are needed for control, compatibility,
|
||||
or diagnostics but are not part of the common setup path.
|
||||
|
||||
- protocol-specific endpoints, ports, path overrides, TLS/signing toggles,
|
||||
timeout/retry tuning, raw headers, migration/destructive flags, and fallback
|
||||
compatibility settings are advanced.
|
||||
- names, descriptions, provider type, base URL, ownership, policy mode, and
|
||||
basic credentials are not advanced.
|
||||
|
||||
Advanced fields must still be editable through typed controls.
|
||||
|
||||
### DUE-005: Blocker Language Contract
|
||||
|
||||
Decision: all disabled or blocked primary actions should use a shared structured
|
||||
reason object.
|
||||
|
||||
Shape:
|
||||
|
||||
- `summary`: short plain-language reason.
|
||||
- `details`: optional explanation.
|
||||
- `required_action`: what needs to happen.
|
||||
- `actor`: who can do it, for example system administrator or tenant admin.
|
||||
- `target`: where to go or which setting/capability is missing.
|
||||
- `technical_details`: optional expandable developer/operator data.
|
||||
|
||||
For simple missing required fields, highlight the fields and put the structured
|
||||
reason in a compact hover/focus bubble on the disabled primary action instead of
|
||||
adding a large persistent warning block.
|
||||
|
||||
### DUE-006: First Migration Surface
|
||||
|
||||
Decision: convert file connectors first, then mail servers. They share the same
|
||||
server/credential/policy model, are high-value, and will prove the reusable
|
||||
patterns quickly.
|
||||
|
||||
### DUE-007: Adaptive Create/Edit Forms
|
||||
|
||||
Decision: ordinary create/edit dialogs should show the full editable state in an
|
||||
adaptive form, not force a linear wizard.
|
||||
|
||||
- The user chooses a type, provider, credential mode, or policy mode.
|
||||
- The dialog immediately adjusts to show only the fields relevant to that state.
|
||||
- Editing an existing object uses the same field grouping and layout as creating
|
||||
it, so users can recognize the state they configured.
|
||||
- Discovery and test actions must give visible feedback in the same dialog:
|
||||
directly usable, discovered alternative, credentials needed/rejected, or not
|
||||
found with the next action the user can take.
|
||||
- Wizard shells remain available for assisted setup, first-run guidance,
|
||||
imports, discovery-heavy flows, and operational preflight workflows.
|
||||
|
||||
## Implementation Sequence
|
||||
|
||||
| Phase | Scope | Output |
|
||||
| --- | --- | --- |
|
||||
| 0 | UX inventory | List every admin/settings/configuration surface, classify it, and record whether it violates a binding decision. |
|
||||
| 1 | Core primitives | Shared wizard shell, advanced panel, help affordance, blocker callout, problem list, review step, and discovery/test result components. |
|
||||
| 2 | File connectors | Adaptive create/edit for provider/server, credential, discovery/test, ownership/policy, plus optional assisted wizard later. |
|
||||
| 3 | Mail servers | Same adaptive pattern as files, adapted to server/credential/policy and test-send/test-login behavior. |
|
||||
| 4 | Policy/retention editors | Effective value first, provenance visible, override/edit in modal, blocked edits explained. |
|
||||
| 5 | Module/package operations | Step-based install/uninstall flow with preflight, maintenance, daemon handoff, migration, and rollback explanation. |
|
||||
| 6 | Remaining settings/admin screens | Apply inventory findings by priority and remove one-off layouts. |
|
||||
|
||||
## Current Surface Inventory
|
||||
|
||||
This is the phase-0 inventory baseline. It should be extended as each screen is
|
||||
converted or reviewed.
|
||||
|
||||
| Surface | Repository | UX State | Next Action |
|
||||
| --- | --- | --- | --- |
|
||||
| File connector settings | `govoplan-files` | First adaptive modal slice started: connections and credentials now use full-state create/edit forms with conditional fields, advanced panels, and blocker primitives. Wizard shell is retained for later assisted setup. Central policy card still needs a layered editor. | Finish provider discovery/test-in-flow, then convert policy editing. |
|
||||
| Mail server settings | `govoplan-mail` / `govoplan-core` | Uses the shared server/credential model visually, but create/edit still needs the same adaptive pattern as files. | Migrate to adaptive server/credential/policy dialogs, with optional assisted wizard later. |
|
||||
| Connector policy/effective rows | `govoplan-core`, module UIs | Effective-policy direction exists, but many editors still expose broad option sets. | Put effective value first, move overrides into modal, and explain blocked edits. |
|
||||
| Admin module management | `govoplan-admin` | Has preflight concepts, but operational choices are still technical and dense. | Convert install/uninstall/package changes to operator wizards. |
|
||||
| Configuration packages | `govoplan-admin` | Catalog/import work exists, but package editing can still drift toward technical fields. | Add guided import/review/problem-list flow. |
|
||||
| Retention and privacy | `govoplan-core` | Functional editor exists; consequence language and provenance can be stronger. | Layer advanced retention options and add review for broad changes. |
|
||||
| API keys | `govoplan-access` / admin UI | Security-sensitive creation needs least-privilege guidance. | Add scoped creation wizard with expiry/owner review. |
|
||||
| User settings | `govoplan-core` | Preferences persistence exists; interface navigation issue was fixed earlier, but the surface still needs UX review. | Keep simple sections, remove double-click traps, and add quiet explanations. |
|
||||
|
||||
## Impact Index
|
||||
|
||||
| Surface | Current Risk | Expected Pattern |
|
||||
| --- | --- | --- |
|
||||
| File connectors | Too many technical fields and unclear setup order. | Adaptive create/edit form with optional assisted wizard, discovery/test, credential binding, policy review, and advanced protocol panel. |
|
||||
| Mail servers | Similar server/credential/policy concepts risk diverging from files. | Same tree/list and adaptive server/credential/policy model as file connectors. |
|
||||
| Connector credentials | Security-sensitive details can overwhelm users. | Separate credential flow with secret-reference language and test result explanation. |
|
||||
| Policy and effective settings | Users need to know why a value is inherited or locked. | Effective row first, source/provenance, local override action, actionable blocked reason. |
|
||||
| Module install/uninstall | Operationally risky, currently inherently technical. | Operator wizard with preflight, maintenance, daemon handoff, review, and rollback explanation. |
|
||||
| Configuration packages | Could become package JSON editing. | Package catalog/import wizard using provider data requirements and problem lists. |
|
||||
| Retention/privacy | High-risk settings need explanation and provenance. | Layered editor with plain-language consequences and review. |
|
||||
| Automation/workflow commands | Hidden side effects would undermine accountability. | Action/effect preview, system-actor display, command record, retry/quarantine/manual states, and audit links. |
|
||||
| Postbox and encrypted communication | Retraction and access can be misunderstood. | Honest key-fetch/decryption state, expiry limits, recipient/device access provenance, and delivery evidence. |
|
||||
| API keys | Security-sensitive creation and scope selection. | Scoped creation wizard, least-privilege suggestions, clear expiry/owner explanation. |
|
||||
| User settings | Needs clarity and persistence across profile/interface/preferences. | Simple settings sections with immediate feedback and no double-click navigation traps. |
|
||||
|
||||
## Review Checklist
|
||||
|
||||
Every new or changed admin/configuration surface should answer:
|
||||
|
||||
- What is the common path, and is it visible without noise?
|
||||
- Which fields are advanced, and are they collapsed by default?
|
||||
- Is every configuration value editable through typed controls?
|
||||
- Does the flow avoid JSON as the primary editor?
|
||||
- Does the screen explain disabled actions and failed validation in plain
|
||||
language?
|
||||
- Does it say who can fix a blocker and where?
|
||||
- Does it reuse existing core patterns for wizard steps, problem lists, modals,
|
||||
help, and review?
|
||||
- Is there a review or preflight step before broad, destructive, or risky
|
||||
changes?
|
||||
- Does the action surface show consequence, reversibility, and audit evidence
|
||||
when rights, duties, records, money, communication, external systems, or
|
||||
workflow state are affected?
|
||||
- If automation is involved, can the user see the trigger, system actor,
|
||||
observed effects, and failure/manual-intervention state?
|
||||
- Are technical details available without being the first thing the user sees?
|
||||
|
||||
## Revision Rule
|
||||
|
||||
When a UX decision changes:
|
||||
|
||||
1. Update this ledger.
|
||||
2. Update the affected shared components.
|
||||
3. Update existing screens listed in the impact index.
|
||||
4. Add or update Gitea issues for any remaining surfaces that still follow the
|
||||
old decision.
|
||||
5. Sync the wiki.
|
||||
71
docs/audits/2026-07-09-dependency-audit.md
Normal file
71
docs/audits/2026-07-09-dependency-audit.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# Dependency Audit - 2026-07-09
|
||||
|
||||
Commands:
|
||||
|
||||
```bash
|
||||
cd /mnt/DATA/git/govoplan-core
|
||||
bash scripts/check-dependency-audits.sh
|
||||
```
|
||||
|
||||
Status: remediated.
|
||||
|
||||
Initial result:
|
||||
|
||||
- Python audit failed: 24 advisories were reported across `cryptography`,
|
||||
`pip`, `python-multipart`, `pyzipper`, and `starlette`.
|
||||
- npm production audit passed: `npm audit --omit=dev` reported 0
|
||||
vulnerabilities.
|
||||
|
||||
Python findings:
|
||||
|
||||
| Package | Installed | Advisory count | Minimum reported fix |
|
||||
| --- | ---: | ---: | --- |
|
||||
| `cryptography` | `44.0.0` | 5 | `48.0.1` |
|
||||
| `pip` | `26.0.1` | 3 | `26.1.2` |
|
||||
| `python-multipart` | `0.0.17` | 7 | `0.0.31` |
|
||||
| `pyzipper` | `0.3.6` | 1 | `0.4.0` |
|
||||
| `starlette` | `0.41.3` | 8 | `1.3.1` |
|
||||
|
||||
Private GovOPlaN packages were skipped by `pip-audit` because they are not
|
||||
published on PyPI. That is expected for local editable development installs.
|
||||
|
||||
The remediation below upgrades those dependencies and records the compatibility
|
||||
checks run against core, files, and campaign behavior.
|
||||
|
||||
## Remediation
|
||||
|
||||
Remediation applied on 2026-07-09:
|
||||
|
||||
- upgraded core's FastAPI floor to `fastapi>=0.139,<1`, resolving Starlette to
|
||||
`starlette==1.3.1`
|
||||
- upgraded core's cryptography floor to `cryptography>=48.0.1,<50`, resolving
|
||||
to `cryptography==49.0.0`
|
||||
- declared the files module upload parser dependency as
|
||||
`python-multipart>=0.0.31,<1`, resolving to `python-multipart==0.0.32`
|
||||
- upgraded the campaign ZIP dependency to `pyzipper>=0.4,<1`, resolving to
|
||||
`pyzipper==0.4.0`
|
||||
- upgraded the local audit environment to `pip==26.1.2`
|
||||
- removed the obsolete local `govoplan-module-multimailer` editable install
|
||||
from the audit environment so the audit reflects the split module product
|
||||
|
||||
Post-remediation result:
|
||||
|
||||
- `bash scripts/check-dependency-audits.sh`: passed, no known Python
|
||||
vulnerabilities found and npm production audit reported 0 vulnerabilities.
|
||||
- `python -m pip check`: passed.
|
||||
- `bash scripts/check-module-matrix.sh`: passed.
|
||||
- `python -m unittest tests.test_api_smoke`: passed.
|
||||
- campaign encrypted/plain ZIP smoke with `pyzipper==0.4.0`: passed.
|
||||
|
||||
Notes:
|
||||
|
||||
- `pip-audit` still reports private GovOPlaN packages as skipped because they
|
||||
are not published on PyPI. That is expected for editable local development
|
||||
installs.
|
||||
- `httpx2>=2.5,<3` is included in development requirements so Starlette's
|
||||
`TestClient` uses the non-deprecated backend. `httpx==0.28.1` remains in dev
|
||||
requirements for tests that mock connector HTTP responses directly.
|
||||
- Split-module API routers now use Starlette's renamed
|
||||
`HTTP_422_UNPROCESSABLE_CONTENT` status constant. This preserves the 422
|
||||
status code while avoiding the deprecated `HTTP_422_UNPROCESSABLE_ENTITY`
|
||||
alias.
|
||||
@@ -179,6 +179,12 @@
|
||||
"description": "GovOPlaN Identity Trust module behavior or integration.",
|
||||
"exclusive": false
|
||||
},
|
||||
{
|
||||
"name": "module/identity",
|
||||
"color": "bfd4f2",
|
||||
"description": "GovOPlaN Identity module behavior or integration.",
|
||||
"exclusive": false
|
||||
},
|
||||
{
|
||||
"name": "module/idm",
|
||||
"color": "0052cc",
|
||||
@@ -209,6 +215,12 @@
|
||||
"description": "GovOPlaN Ops module behavior or integration.",
|
||||
"exclusive": false
|
||||
},
|
||||
{
|
||||
"name": "module/organizations",
|
||||
"color": "bfdadc",
|
||||
"description": "GovOPlaN Organizations module behavior or integration.",
|
||||
"exclusive": false
|
||||
},
|
||||
{
|
||||
"name": "module/payments",
|
||||
"color": "bfd4f2",
|
||||
@@ -227,6 +239,12 @@
|
||||
"description": "GovOPlaN Portal module behavior or integration.",
|
||||
"exclusive": false
|
||||
},
|
||||
{
|
||||
"name": "module/postbox",
|
||||
"color": "d93f0b",
|
||||
"description": "GovOPlaN Postbox module behavior or integration.",
|
||||
"exclusive": false
|
||||
},
|
||||
{
|
||||
"name": "module/reporting",
|
||||
"color": "c2e0c6",
|
||||
|
||||
4
docs/migration-release-baselines.json
Normal file
4
docs/migration-release-baselines.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"version": 1,
|
||||
"releases": []
|
||||
}
|
||||
@@ -15,6 +15,22 @@
|
||||
"python_ref": "govoplan-files @ git+ssh://git@git.add-ideas.de/add-ideas/govoplan-files.git@v0.1.4",
|
||||
"webui_package": "@govoplan/files-webui",
|
||||
"webui_ref": "git+ssh://git@git.add-ideas.de/add-ideas/govoplan-files.git#v0.1.4",
|
||||
"artifact_integrity": {
|
||||
"python": {
|
||||
"ref": "govoplan-files @ git+ssh://git@git.add-ideas.de/add-ideas/govoplan-files.git@v0.1.4",
|
||||
"sha256": "<sha256 of the resolved Python artifact>",
|
||||
"sbom_url": "https://govoplan.add-ideas.de/sbom/govoplan-files-0.1.4.spdx.json",
|
||||
"provenance_url": "https://govoplan.add-ideas.de/provenance/govoplan-files-0.1.4.intoto.jsonl",
|
||||
"git_ref": "refs/tags/v0.1.4"
|
||||
},
|
||||
"webui": {
|
||||
"ref": "git+ssh://git@git.add-ideas.de/add-ideas/govoplan-files.git#v0.1.4",
|
||||
"sha256": "<sha256 of the resolved WebUI package artifact>",
|
||||
"sbom_url": "https://govoplan.add-ideas.de/sbom/govoplan-files-webui-0.1.4.spdx.json",
|
||||
"provenance_url": "https://govoplan.add-ideas.de/provenance/govoplan-files-webui-0.1.4.intoto.jsonl",
|
||||
"git_ref": "refs/tags/v0.1.4"
|
||||
}
|
||||
},
|
||||
"license_features": ["module.files"],
|
||||
"tags": ["official", "service-module"]
|
||||
},
|
||||
@@ -28,8 +44,53 @@
|
||||
"python_ref": "govoplan-mail @ git+ssh://git@git.add-ideas.de/add-ideas/govoplan-mail.git@v0.1.4",
|
||||
"webui_package": "@govoplan/mail-webui",
|
||||
"webui_ref": "git+ssh://git@git.add-ideas.de/add-ideas/govoplan-mail.git#v0.1.4",
|
||||
"artifact_integrity": {
|
||||
"python": {
|
||||
"ref": "govoplan-mail @ git+ssh://git@git.add-ideas.de/add-ideas/govoplan-mail.git@v0.1.4",
|
||||
"sha256": "<sha256 of the resolved Python artifact>",
|
||||
"sbom_url": "https://govoplan.add-ideas.de/sbom/govoplan-mail-0.1.4.spdx.json",
|
||||
"provenance_url": "https://govoplan.add-ideas.de/provenance/govoplan-mail-0.1.4.intoto.jsonl",
|
||||
"git_ref": "refs/tags/v0.1.4"
|
||||
},
|
||||
"webui": {
|
||||
"ref": "git+ssh://git@git.add-ideas.de/add-ideas/govoplan-mail.git#v0.1.4",
|
||||
"sha256": "<sha256 of the resolved WebUI package artifact>",
|
||||
"sbom_url": "https://govoplan.add-ideas.de/sbom/govoplan-mail-webui-0.1.4.spdx.json",
|
||||
"provenance_url": "https://govoplan.add-ideas.de/provenance/govoplan-mail-webui-0.1.4.intoto.jsonl",
|
||||
"git_ref": "refs/tags/v0.1.4"
|
||||
}
|
||||
},
|
||||
"license_features": ["module.mail"],
|
||||
"tags": ["official", "service-module"]
|
||||
},
|
||||
{
|
||||
"module_id": "dashboard",
|
||||
"name": "Dashboard",
|
||||
"description": "Configurable user home assembled from module-provided widgets.",
|
||||
"version": "0.1.6",
|
||||
"action": "install",
|
||||
"python_package": "govoplan-dashboard",
|
||||
"python_ref": "govoplan-dashboard @ git+ssh://git@git.add-ideas.de/add-ideas/govoplan-dashboard.git@v0.1.6",
|
||||
"webui_package": "@govoplan/dashboard-webui",
|
||||
"webui_ref": "git+ssh://git@git.add-ideas.de/add-ideas/govoplan-dashboard.git#v0.1.6",
|
||||
"artifact_integrity": {
|
||||
"python": {
|
||||
"ref": "govoplan-dashboard @ git+ssh://git@git.add-ideas.de/add-ideas/govoplan-dashboard.git@v0.1.6",
|
||||
"sha256": "<sha256 of the resolved Python artifact>",
|
||||
"sbom_url": "https://govoplan.add-ideas.de/sbom/govoplan-dashboard-0.1.6.spdx.json",
|
||||
"provenance_url": "https://govoplan.add-ideas.de/provenance/govoplan-dashboard-0.1.6.intoto.jsonl",
|
||||
"git_ref": "refs/tags/v0.1.6"
|
||||
},
|
||||
"webui": {
|
||||
"ref": "git+ssh://git@git.add-ideas.de/add-ideas/govoplan-dashboard.git#v0.1.6",
|
||||
"sha256": "<sha256 of the resolved WebUI package artifact>",
|
||||
"sbom_url": "https://govoplan.add-ideas.de/sbom/govoplan-dashboard-webui-0.1.6.spdx.json",
|
||||
"provenance_url": "https://govoplan.add-ideas.de/provenance/govoplan-dashboard-webui-0.1.6.intoto.jsonl",
|
||||
"git_ref": "refs/tags/v0.1.6"
|
||||
}
|
||||
},
|
||||
"license_features": ["module.dashboard"],
|
||||
"tags": ["official", "platform-module"]
|
||||
}
|
||||
],
|
||||
"signatures": [
|
||||
|
||||
Reference in New Issue
Block a user