Compare commits

...

4 Commits

Author SHA1 Message Date
8b80afbd60 feat(calendar): run scheduled outbox recovery
Some checks failed
Dependency Audit / dependency-audit (push) Failing after 18s
Security Audit / security-audit (push) Failing after 13s
2026-07-20 17:05:17 +02:00
8255665349 chore(gitea): add the user-story issue type 2026-07-20 17:03:23 +02:00
2fc3b66c07 docs: add capability and infrastructure fit assessment 2026-07-20 16:50:06 +02:00
9e7103f613 docs: define the interface pattern language 2026-07-20 16:49:30 +02:00
13 changed files with 2285 additions and 9 deletions

View File

@@ -12,7 +12,8 @@ ENABLED_MODULES=tenancy,organizations,identity,access,admin,dashboard,policy,aud
CELERY_ENABLED=true CELERY_ENABLED=true
REDIS_URL=redis://127.0.0.1:6379/0 REDIS_URL=redis://127.0.0.1:6379/0
CELERY_QUEUES=send_email,append_sent,default CELERY_QUEUES=send_email,append_sent,notifications,calendar,default
CALENDAR_OUTBOX_TERMINAL_RETENTION_DAYS=90
CORS_ORIGINS=https://govoplan.example.org CORS_ORIGINS=https://govoplan.example.org
AUTH_COOKIE_SECURE=true AUTH_COOKIE_SECURE=true

View File

@@ -16,7 +16,8 @@ DATABASE_URL=postgresql+psycopg://govoplan:govoplan-dev@127.0.0.1:55433/govoplan
GOVOPLAN_DATABASE_URL_PGTOOLS=postgresql://govoplan:govoplan-dev@127.0.0.1:55433/govoplan GOVOPLAN_DATABASE_URL_PGTOOLS=postgresql://govoplan:govoplan-dev@127.0.0.1:55433/govoplan
REDIS_URL=redis://127.0.0.1:56379/0 REDIS_URL=redis://127.0.0.1:56379/0
CELERY_ENABLED=true CELERY_ENABLED=true
CELERY_QUEUES=send_email,append_sent,default CELERY_QUEUES=send_email,append_sent,notifications,calendar,default
CALENDAR_OUTBOX_TERMINAL_RETENTION_DAYS=90
ENABLED_MODULES=tenancy,organizations,identity,access,admin,dashboard,policy,audit,campaigns,files,mail,calendar,docs,ops ENABLED_MODULES=tenancy,organizations,identity,access,admin,dashboard,policy,audit,campaigns,files,mail,calendar,docs,ops
CORS_ORIGINS=http://127.0.0.1:5173,http://localhost:5173 CORS_ORIGINS=http://127.0.0.1:5173,http://localhost:5173

View File

@@ -1,7 +1,7 @@
# Production-Like Development Profile # Production-Like Development Profile
This profile runs the shared services that production depends on while keeping This profile runs the shared services that production depends on while keeping
API, worker, and WebUI code in the editable local repositories. API, worker, scheduler, and WebUI code in the editable local repositories.
It provides: It provides:
@@ -10,6 +10,7 @@ It provides:
- explicit `ENABLED_MODULES` - explicit `ENABLED_MODULES`
- local durable file storage under `runtime/production-like/files` - local durable file storage under `runtime/production-like/files`
- a Celery worker process using the same queues as the API - a Celery worker process using the same queues as the API
- a Celery beat process for durable retry and recovery schedules
Start it from the meta repository: Start it from the meta repository:
@@ -37,7 +38,7 @@ password changes:
cp dev/production-like/.env.example dev/production-like/.env cp dev/production-like/.env.example dev/production-like/.env
``` ```
The API and worker use: The API, worker, and scheduler use:
```text ```text
DATABASE_URL=postgresql+psycopg://govoplan:govoplan-dev@127.0.0.1:55433/govoplan DATABASE_URL=postgresql+psycopg://govoplan:govoplan-dev@127.0.0.1:55433/govoplan
@@ -45,7 +46,7 @@ REDIS_URL=redis://127.0.0.1:56379/0
CELERY_ENABLED=true CELERY_ENABLED=true
``` ```
Stop the launched API/WebUI/worker with `Ctrl+C`. The PostgreSQL and Redis Stop the launched API/WebUI/worker/scheduler with `Ctrl+C`. The PostgreSQL and Redis
containers keep running by default so the next launch is fast. To stop them too: containers keep running by default so the next launch is fast. To stop them too:
```bash ```bash

View File

@@ -0,0 +1,349 @@
# GovOPlaN Capability and IT-Infrastructure Fit Assessment
## Assessment record
| Field | Value |
| --- | --- |
| Assessment ID | `campaign-reference-2026-07-20` |
| Schema | `govoplan.fit-assessment/0.1.0` |
| Assessed on | 2026-07-20 |
| Product snapshot | Untagged workspace at meta commit `05ae81d64195`; this is not a release artifact |
| Configuration basis | Root `.env.example` and the production-like development profile |
| Scope | Campaign-centric internal pilot and small-production candidate |
| Explicitly postponed | Workflow and workflow-driven user stories |
| Machine-readable companion | [`capability-fit-current.json`](capability-fit-current.json) |
| Input schema | [`capability-fit.schema.json`](capability-fit.schema.json) |
This is a fit assessment, not a production approval or security certification.
It deliberately does not infer implementation from a repository, issue, or
manifest existing. A conclusion needs code plus a route/contract, test,
operational drill, configured example, or explicit evidence that the capability
is absent.
The checkout contained unrelated uncommitted work when this assessment was
made. A dirty repository is recorded below, but local-only changes do not count
as an integrated release capability. Tests run against the dirty workspace are
useful implementation evidence and are labelled as such; they do not turn the
workspace into a reproducible release.
## Controlled status vocabulary
| Status | Meaning |
| --- | --- |
| `verified` | The stated capability is implemented and directly exercised by evidence appropriate to the stated scope. Conditions and target-environment proof may still remain. |
| `available_unconfigured` | An implementation and supporting evidence exist, but the target endpoint, credentials, policy, or deployment component has not been configured and exercised. |
| `partial` | A useful subset exists, but one or more material parts of the stated journey or operational requirement are missing or unproved. |
| `scaffold` | Contracts, models, routes, or UI structure exist, but the end-to-end capability is not yet usable. |
| `external_system` | GovOPlaN expects the deployment or another system to supply this capability; integration requirements must still be assessed. |
| `planned` | The capability is represented only by a concept, backlog item, or design direction. |
| `not_fit` | Evidence shows that the current composition cannot meet the stated requirement. |
| `not_assessed` | The requirement or target environment is not sufficiently known to reach a conclusion. |
Status alone is not enough. Every row also states its evidence scope and
conditions. For example, a unit-tested SMTP adapter is
`available_unconfigured`, not `verified` for an organization's mail system.
## Executive conclusion
GovOPlaN is a credible candidate for a controlled, Campaign-centric internal
pilot using local accounts, PostgreSQL, durable single-node file storage, and a
non-production SMTP/IMAP service. The module contract, Campaign authoring and
validation paths, managed attachments, mail-profile boundary, local audit
records, and operator status surface all have direct code/test evidence.
It is not yet possible to call the current workspace a supported small-production
distribution. The production-like profile intentionally runs only PostgreSQL
and Redis in containers; API, WebUI, worker, and scheduler processes still run
from editable source trees. A target deployment must supply TLS termination,
process supervision, secret injection, monitoring, backup storage, and recovery
procedures. The open [Core backup/restore issue #29](https://git.add-ideas.de/add-ideas/govoplan-core/issues/29)
is a production gate. Identity federation, external audit export, and a tested
disaster-recovery plan are also not complete.
The current recommendation is therefore:
- **Pilot:** fit with conditions and a bounded proof of concept.
- **Small production:** partial fit; do not approve until the proof checks and
operational gates below pass against a clean, pinned release candidate.
- **Workflow:** planned and postponed; it is not part of either recommended
composition in this assessment.
## Pinned composition
The configured reference composition comes from the meta repository's
`ENABLED_MODULES`. Module versions come from the actual manifests. `Dirty`
means that repository had uncommitted changes at assessment time.
| Module | Repository commit | Manifest version | Dirty | Role in this assessment |
| --- | --- | ---: | :---: | --- |
| Core runtime | `govoplan-core@e6f7c45f0a95` | server `0.3.0` | yes | API, registry, migration orchestration, shared WebUI, sessions and kernel contracts |
| `tenancy` | `govoplan-tenancy@1dde03854733` | 0.1.8 | no | tenant context and lifecycle |
| `organizations` | `govoplan-organizations@45cda1a33f18` | 0.1.8 | no | organization model |
| `identity` | `govoplan-identity@7a1710af896f` | 0.1.8 | yes | normalized internal identity directory |
| `access` | `govoplan-access@ab07075a679b` | 0.1.8 | yes | local authentication, sessions, API keys and RBAC |
| `admin` | `govoplan-admin@c9e1fb287f50` | 0.1.8 | no | administration surfaces |
| `dashboard` | `govoplan-dashboard@a315a7c62b1d` | 0.1.8 | no | module-aware home surface |
| `policy` | `govoplan-policy@2511fbb5a864` | 0.1.8 | no | policy explanation/configuration boundary |
| `audit` | `govoplan-audit@5e4f84a789ea` | 0.1.8 | no | database audit records and retrying audit outbox |
| `campaigns` | `govoplan-campaign@2e593b7fa412` | 0.1.8 | yes | Campaign authoring, build, delivery control and reporting |
| `files` | `govoplan-files@f3210234d35a` | 0.1.8 | yes | managed files and Campaign attachments |
| `mail` | `govoplan-mail@b0337b2d261a` | 0.1.8 | yes | SMTP/IMAP profiles and transports |
| `calendar` | `govoplan-calendar@371a00aff51c` | 0.1.8 | yes | optional calendar; not needed by the Campaign pilot |
| `docs` | `govoplan-docs@f2ade1d62475` | 0.1.8 | yes | configured-system documentation |
| `ops` | `govoplan-ops@341773a4ff8a` | 0.1.8 | no | readiness and deployment-profile visibility |
No tagged release or configuration package is pinned. That is a reproducibility
gap, not a harmless omission. The static contract scan found 43 interface
contracts, 29 providers, and no contract errors in this workspace. This proves
the scanned manifest graph is internally consistent; it does not prove the
behavior of every repository in that graph.
`govoplan-addresses@f19350e65d76` (manifest 0.1.8, dirty) is an optional extension
for reusable recipient sources. It is not enabled in the pinned root profile and
must be added explicitly when the pilot needs address lists or CardDAV.
## Recommended scenarios
### Campaign pilot
Use one internal tenant or office, controlled operators, local GovOPlaN accounts,
and non-critical recipient volumes. Enable:
```text
tenancy,organizations,identity,access,admin,dashboard,policy,audit,campaigns,files,mail,docs,ops
```
Add `addresses` only when reusable address books/lists or CardDAV are in scope.
Leave Calendar and Workflow out unless the pilot has an explicit journey for
them. The minimum topology is one supervised API process, one built WebUI, one
PostgreSQL database, durable local file storage, and one Redis/Celery worker when
asynchronous delivery is enabled. Use a dedicated non-production SMTP/IMAP
account and a restricted recipient allow-list.
### Small-production candidate
Use a reverse proxy/TLS endpoint, built WebUI assets, separately supervised API
and worker processes, PostgreSQL with measured backup/restore, Redis with
persistence, and durable shared or object storage. Run one scheduler only when a
selected module needs scheduled recovery. Multiple scheduler replicas require
leader election or an external lock, which is not established by this report.
This topology is a recommendation from the [Ops scalability profiles](https://git.add-ideas.de/add-ideas/govoplan-ops/src/branch/main/docs/SCALABILITY_PROFILES.md),
not a currently shipped production Compose/Kubernetes/systemd package.
## Functional capability matrix
| Capability | Status | Evidence and scope | Conditions, gaps, or exclusions |
| --- | --- | --- | --- |
| Module-aware API/WebUI composition | `verified` | Core registry tests cover installed manifests, route contribution, missing modules, and module permutations; the static contract scan passed. | The pinned workspace is dirty and untagged; repeat on a clean release candidate. |
| Local tenants, accounts, sessions, API keys and RBAC | `verified` | Access/tenancy manifests, auth dependency tests, cookie/CSRF API smoke tests, and role/permission contracts. | External identity providers are not included in this conclusion. |
| Campaign draft authoring, validation, recipient import, build, execution snapshot and mock send | `verified` | Core API smoke tests exercise create/validate/build/mock-send, frozen delivery configuration, policy gates, job deltas and reconciliation; Campaign-focused tests passed in this workspace. | Current Campaign UI/code also contains substantial unintegrated WIP; usability and release integration need separate acceptance. |
| Managed Campaign attachments and local file storage | `verified` | Files capability/route tests, Campaign attachment-build tests, and local-storage backend code. | The deployment must provide a durable path and include files in database/storage backup plans. |
| SMTP send, IMAP append and mailbox/profile policy | `available_unconfigured` | Mail adapters, encrypted profile model, helper tests, Campaign mail-policy smoke tests, and a GreenMail-oriented runbook/testbed. | No target mail server, TLS chain, throttling, sender policy, bounce/reply process, or real delivery receipt was exercised here. |
| Delivery retry, uncertainty and reconciliation | `partial` | Campaign API smoke tests include worker-loss/outcome-unknown reconciliation and frozen job evidence. | A target-provider failure drill and operational alerting are still required; local Campaign audit-proof work is not release-integrated. |
| Reusable address lists and Campaign recipient-source integration | `available_unconfigured` | Address list/recipient capability and Campaign optional lookup tests passed; manifests expose optional interfaces. | `addresses` is not in the pinned profile. Configure permissions and data governance before use. |
| CardDAV address synchronization | `available_unconfigured` | Discovery, preview/conflict, two-way create/update/delete and disconnect tests passed in the current Addresses workspace. | Requires target-server interoperability, credentials, CA/TLS, rate-limit, conflict and restore drills. |
| File connectors (WebDAV/Nextcloud/Seafile/SMB/S3 import) | `partial` | Provider descriptors and browse/import helper tests exist; S3 connector tests passed. | Coverage varies by provider and optional dependency. No target content system was exercised; connector egress and provenance policy need review. |
| Local audit log and governed-event retry outbox | `verified` | Audit module contract plus enqueue/dispatch/failure-for-retry tests passed. | Central audit/SIEM export, retention enforcement and operational monitoring are not verified. |
| Configured-system documentation and Ops status pages | `verified` | Docs/Ops manifests contribute protected routes and WebUI packages; Ops code checks database, Redis, workers, storage and deployment-security settings. | This does not replace external monitoring or a target runbook. |
| Calendar/CalDAV integration | `partial` | Calendar storage/sync tests exist; durable external-write outbox, worker recovery and retention are local WIP in this snapshot. | Not required for the Campaign pilot and must not be treated as release-integrated yet. Bulk synchronized-calendar migration semantics remain separate work. |
| External LDAP/AD, OIDC/SAML or SCIM identity integration | `scaffold` | IDM owns normalized assignment APIs and documents connector boundaries. | Provider connectors, login callback flow and target directory reconciliation are not an implemented end-to-end capability. Use local accounts for this pilot. |
| Export-control/embargo-list screening | `planned` | Product-level [GovOPlaN #12](https://git.add-ideas.de/add-ideas/govoplan/issues/12) defines the consumer-independent user story. | No screening provider, list provenance, matching policy, review flow or legal evidence exists in this composition. |
| Workflow-driven journeys and views | `planned` | Workflow contracts/concepts exist outside this assessment. | Explicitly postponed. Do not include Workflow in pilot or production claims from this report. |
## Infrastructure matrix
| Component | Status | Current evidence | Target requirement / gap |
| --- | --- | --- | --- |
| WebUI and API | `verified` | FastAPI app, module routes, shared WebUI host, health endpoint, dev smoke and module-permutation tests. | Build immutable, matching frontend/backend artifacts and supervise them; no production image/service bundle is supplied here. |
| Background workers | `available_unconfigured` | Celery app, Campaign queues, Redis configuration and production-like launcher. | Run target broker/worker heartbeat and failure drills; split queues when provider limits or load justify it. |
| Scheduler | `partial` | A separately launched Celery beat process and Calendar recovery schedule exist in local WIP. | Keep single-instance until leader election/locking is proved; add process supervision and missed-schedule alerts. |
| PostgreSQL | `verified` | Production target in settings/operator docs, migration tracks and a disposable integration-check harness. | Target HA, patching, connection limits, WAL/archive policy and restore time are external deployment decisions. |
| Redis/queues | `available_unconfigured` | Redis-backed Celery configuration, health ping and append-only production-like container. | Target availability, persistence, eviction, authentication/TLS and queue-loss behavior were not assessed. |
| Local file storage | `verified` | Local backend, configured root, fallback-root tests and Ops writability check. | Suitable only for a durable single-node/shared path with backup; it blocks independent API scaling when node-local. |
| S3-compatible object storage | `partial` | S3 backend and connector code plus mocked browse/import tests. | Exercise the chosen service, credentials, CA, versioning, lifecycle, multipart/size behavior, restore and consistency expectations. |
| Reverse proxy and TLS | `external_system` | Core validates explicit CORS and secure-cookie posture; Ops reports unsafe production settings. | Deployment must provide certificates, proxy/header policy, request limits, logs and renewal monitoring. |
| Local identity and authorization | `verified` | Password/session/API-key/RBAC capabilities and tests. | Establish account lifecycle, MFA expectation, protected bootstrap and break-glass procedure. |
| Federated identity | `scaffold` | IDM boundary and assignment APIs. | Select and implement/test the actual OIDC/SAML/LDAP/SCIM path before requiring federation. |
| Application secret encryption | `verified` | Stable `MASTER_KEY_B64` contract and encrypted mail-credential paths. | Rotation and loss-recovery procedure need target validation. |
| Secret store and injection | `external_system` | Environment/file references are supported and templates avoid populated secrets. | Choose Vault/KMS/Kubernetes/systemd/environment mechanism, restrict access, rotate credentials and prevent secret exposure in logs/backups. |
| SMTP/IMAP and other connectors | `available_unconfigured` | Protocol adapters and development testbeds. | Target endpoints, egress, DNS, CA, throttling, service accounts and data-processing terms remain environment-specific. |
| Health/readiness | `verified` | `/health`, protected `/health/details`, and Ops checks for DB, Redis, workers, storage, maintenance and cookie/CORS posture. | Add external probes and distinguish liveness from dependency readiness for the chosen orchestrator. |
| Metrics, logs and alerting | `partial` | Correlation IDs, slow-request/query metrics in logs, worker inspection and operator status are implemented. | No bundled metrics exporter, log collector, dashboards, queue-depth alerts, pager route or SLO is verified. |
| Audit | `partial` | Local audit tables and retry outbox are verified. | Retention, tamper-evident export, privileged access review and SIEM integration are unproved. |
| Backup and restore | `partial` | Operator guide and installer hooks describe `pg_dump`/`pg_restore`; SQLite and simulated installer rollback drills exist. | [Core #29](https://git.add-ideas.de/add-ideas/govoplan-core/issues/29) remains open. No target PostgreSQL + files + secrets restore drill or measured RTO/RPO exists. |
| Disaster recovery | `not_assessed` | The Ops guide asks for RPO/RTO and restore drills. | No agreed RPO/RTO, off-site copy, failover topology, dependency recovery order, communications plan or exercise evidence was supplied. |
The scalability and sizing documentation delivered the documentation portions
of [Core #217](https://git.add-ideas.de/add-ideas/govoplan-core/issues/217) and
[Core #219](https://git.add-ideas.de/add-ideas/govoplan-core/issues/219).
[Core #28](https://git.add-ideas.de/add-ideas/govoplan-core/issues/28) records the
operator-documentation slice. These closed tickets are evidence of documented
models, not evidence that an organization's production environment has passed
them.
## Trust, data-flow and network boundaries
| Boundary / flow | Data and trust | Required controls |
| --- | --- | --- |
| Browser -> reverse proxy -> WebUI/API | Session and CSRF cookies, campaign content, recipient personal data and managed files cross the public/client boundary. | HTTPS, exact origins, secure cookies, request/body limits, tenant/RBAC enforcement, security headers and access logs. |
| API -> PostgreSQL | Tenants, identities, permissions, campaign drafts/snapshots/jobs, connector metadata and audit evidence enter the primary trusted data store. | Dedicated DB identity, encrypted transport where networked, least privilege, migration control, backup/restore and retention. |
| API/worker -> file/object storage | Campaign attachments and generated evidence may contain personal or confidential content. | Private buckets/paths, encryption, scoped credentials, malware/content policy where required, lifecycle and coordinated restore. |
| API -> Redis -> worker | Queue messages and job identifiers cross from request processing to an asynchronous trust zone. PostgreSQL remains the durable business-state authority. | Private/authenticated broker, bounded payloads, idempotent claims, queue monitoring and worker isolation. |
| Worker -> SMTP/IMAP | Recipient addresses, message bodies and attachments leave GovOPlaN; IMAP append stores a sent copy externally. | Approved service account, TLS/CA policy, recipient/sender policy, rate limits, outcome reconciliation and disclosure/legal basis. |
| Connector worker -> CardDAV/WebDAV/Seafile/SMB/S3/CalDAV | Address data, files or calendars cross an organizational/system boundary in both directions depending on connector mode. | Explicit direction, scoped credentials, endpoint allow-list, provenance, conflict policy, retry/reconciliation and target interoperability test. |
| Operator -> installer/catalog/migration plane | A highly privileged process can mutate packages, schemas and desired module state. | Separate operator identity, signed/pinned catalogs, maintenance mode, immutable run records, backups, rollback checks and restricted network access. |
| API/audit -> monitoring or SIEM | Operational metadata and potentially personal audit context may leave GovOPlaN. | Data minimization, retention/access policy, authenticated transport, integrity and documented processor/location. No sink is verified today. |
Typical network requirements are inbound HTTPS to the deployment proxy and
private connectivity from API/workers to PostgreSQL and Redis. Outbound access
may be required to SMTP submission, IMAP, HTTPS-based connectors/object storage,
DNS, NTP, certificate validation, monitoring and the signed module catalog.
Ports and destinations must come from the selected infrastructure; common
defaults such as PostgreSQL 5432, Redis 6379, SMTP 465/587 and IMAP 993 are not
an allow-list.
## Known assumptions, gaps and risks
Facts:
- The production-like profile is a development validation composition, not a
production deployment artifact.
- The assessed workspace is untagged and several key repositories are dirty.
- Workflow is postponed.
- The default composition does not enable Addresses.
- Health/readiness checks exist; an external monitoring stack does not.
Assumptions that require confirmation:
- The pilot can use local accounts and one internal tenant/office.
- A controlled non-production SMTP/IMAP account and safe recipients are
available.
- Campaign volume is below the measured limits of a single worker and database.
- Local durable storage is acceptable for the pilot and all recipient data has
an approved legal basis and retention policy.
Highest risks:
1. A dirty, untagged workspace cannot be reproduced or promoted safely.
2. Real SMTP/IMAP behavior, throttling and ambiguous outcomes have not been
proven against the target provider.
3. Backup/restore and disaster recovery are not demonstrated across database,
files, keys and deployment configuration.
4. External identity, monitoring, secret-store and reverse-proxy controls are
deployment gaps rather than GovOPlaN-delivered components.
5. Local Campaign and Calendar WIP can look complete in the checkout while
remaining absent from the remote release baseline.
6. Data classification, retention, recipient consent/legal basis and external
disclosure rules are not assessed for a concrete organization.
## Proof checks before promotion
1. Create a clean release candidate that pins every module/package and WebUI
artifact; rerun the contract, module-permutation and focused test gates.
2. Run a target-like Campaign from import through validation, attachment build,
queue, SMTP acceptance, IMAP append, reporting and audit using safe data.
3. Drill transient SMTP failure, accepted-but-local-commit-lost uncertainty,
worker restart, Redis interruption and manual reconciliation without a
duplicate send.
4. Restore PostgreSQL, managed files, configuration and encrypted credentials
into an isolated environment; measure RPO and RTO.
5. Validate proxy/TLS, CORS, cookies, headers, body limits, account bootstrap,
maintenance access and secret redaction.
6. Measure representative recipient/file volume, queue age, database growth,
send rate and provider throttling; set capacity and alert thresholds.
7. Confirm audit/retention/privacy/legal requirements and any SIEM or archive
export before using production personal data.
## Reusable assessment questionnaire
Answers should contain no secrets and no unnecessary personal data. Each answer
must be marked `answered`, `assumed`, `not_applicable`, or `not_assessed` and may
link evidence.
### Scope and outcomes
- What outcome and reference journey must GovOPlaN support?
- Which users, roles, tenants, organization units and delegated functions take
part?
- Which journey steps are mandatory, optional, manual, external, or explicitly
postponed?
- What constitutes pilot success and production acceptance?
### Data, privacy, records and policy
- Which data classes enter database, files, messages, calendars, addresses,
logs and audit evidence?
- What are the legal basis, purpose, minimization, access, residency, retention,
deletion, archive and legal-hold requirements?
- Which external systems/processors receive data, and in which jurisdictions?
- Which decisions require four-eyes approval, explainability or immutable
evidence?
### Identity and integrations
- Are local accounts acceptable, or are OIDC, SAML, LDAP/AD or SCIM mandatory?
- What are the MFA, joiner/mover/leaver, service-account and break-glass rules?
- Which SMTP/IMAP, file/DMS, CardDAV/CalDAV, ERP, API or event endpoints are in
scope? Record protocol/version, direction, auth, CA, rate limit and owner.
- Which integrations may be unavailable, and what degraded/manual behavior is
acceptable?
### Workload and growth
- Tenants, named/active/concurrent users and peak requests?
- Campaigns per period, recipients per Campaign, send window, attachment sizes,
import size and retry peak?
- Managed files, database and audit volume now and over the retention window?
- Connector batches, queue depth/age, scheduled jobs and external rate limits?
### Availability, hosting and operations
- Required service hours, planned maintenance, availability, RPO and RTO?
- Hosting, network zones, egress/proxy/DNS/NTP/CA, data-residency and
air-gap constraints?
- Who operates PostgreSQL, Redis, storage, TLS, identity, secrets, monitoring,
backups and incident response?
- What deployment, patch, migration, rollback, restore and DR drills must pass?
### Procurement and decisions
- Required open-source/license, support, accessibility, security, certification,
interoperability and procurement conditions?
- Which requirements are blockers, accepted risks, residual risks or later
roadmap work?
- Who owns each decision, evidence item and next review date?
For every capability and infrastructure conclusion, record the requirement,
status from the controlled vocabulary, evidence scope, evidence links,
assumptions, gaps, risks, recommendation and proof check. Reassessment must pin a
new composition and review any row whose code, evidence, configuration or target
requirement changed.
## Evidence used in this slice
- [Production-like profile](../dev/production-like/README.md) and
[Compose dependencies](../dev/production-like/docker-compose.yml)
- [Module contracts and install boundaries](MODULE_CONTRACTS_AND_INSTALLS.md)
- [Core deployment operator guide](https://git.add-ideas.de/add-ideas/govoplan-core/src/branch/main/docs/DEPLOYMENT_OPERATOR_GUIDE.md)
- [Ops scalability profiles](https://git.add-ideas.de/add-ideas/govoplan-ops/src/branch/main/docs/SCALABILITY_PROFILES.md)
- Actual module manifests in the pinned repositories and the static contract
checker in this meta repository
- Core module-system/API smoke/auth/install-config tests, plus focused Campaign,
Files, Mail, Audit and Addresses tests
- [Campaign delivery runbook](https://git.add-ideas.de/add-ideas/govoplan-campaign/src/branch/main/docs/CAMPAIGN_DELIVERY_RUNBOOK.md)
Checks run for this first slice against the current workspace:
- static manifest/interface contract scan: 43 contracts, 29 providers, no issues
- selected Core module-composition, auth/CSRF, health, Campaign journey,
reconciliation and install-configuration tests: 14 passed
- Campaign tests: 14 passed
- Files tests: 14 passed
- Mail tests: 22 passed
- Audit tests: 5 passed
- Addresses tests: 14 passed (one non-failing SQLite resource warning)
- JSON Schema validation of the machine-readable assessment: passed
These checks are evidence for the rows above; they are not a substitute for the
clean-release and target-environment proof checks.

View File

@@ -3,6 +3,11 @@
GovOPlaN modules should choose their page layout by the kind of work the user is GovOPlaN modules should choose their page layout by the kind of work the user is
doing, not by the repository that owns the feature. doing, not by the repository that owns the feature.
These concise layout choices are one canonical input to the broader
[`INTERFACE_PATTERN_LANGUAGE.md`](INTERFACE_PATTERN_LANGUAGE.md). The current
route and rollout evidence lives in
[`INTERFACE_SURFACE_INVENTORY.md`](INTERFACE_SURFACE_INVENTORY.md).
## Structured Data Directories ## Structured Data Directories
Use a full-available-space workspace for structured data directories: files, Use a full-available-space workspace for structured data directories: files,
@@ -41,6 +46,9 @@ Principles:
summaries, and dashboard widgets. summaries, and dashboard widgets.
- Collapsible panels and segmented controls are appropriate when a dense - Collapsible panels and segmented controls are appropriate when a dense
configuration area needs controlled disclosure. configuration area needs controlled disclosure.
- A collapsible card whose sole content is a table gives that table the full
available card body; avoid nested cards, duplicate padding, inner max-widths,
and nested scrolling.
- Avoid forcing workflow/configuration pages into a file-explorer style unless - Avoid forcing workflow/configuration pages into a file-explorer style unless
the primary interaction is genuinely directory browsing. the primary interaction is genuinely directory browsing.

View File

@@ -140,6 +140,7 @@ Use one `type/*` label:
- `type/bug` - `type/bug`
- `type/feature` - `type/feature`
- `type/user-story`
- `type/task` - `type/task`
- `type/debt` - `type/debt`
- `type/docs` - `type/docs`

View File

@@ -0,0 +1,392 @@
# GovOPlaN Interface Pattern Language
This document is the cross-repository pattern language for GovOPlaN user
interfaces. It turns the existing ethical doctrine, binding UI/UX decisions,
layout principles, and module boundary into a common composition and review
grammar. It does not replace those sources.
The companion [interface surface inventory](INTERFACE_SURFACE_INVENTORY.md)
records which surfaces the current code contributes and where each surface
enters the rollout.
## Source Of Truth And Precedence
Use the narrowest owning document when changing a rule:
1. `govoplan-core/docs/INTERFACE_ETHICS_AND_DESIGN_DOCTRINE.md` owns why a
consequential interface must preserve context, decision, consequence,
responsibility, contestability, and traceability.
2. `govoplan-core/docs/UI_UX_DECISION_LEDGER.md` owns accepted product decisions
such as progressive disclosure, adaptive forms, blocker language, guided
operations, and the platform theme contract.
3. `docs/FRONTEND_LAYOUT_PRINCIPLES.md` owns the high-level choice between a
full-space structured-data workspace and a heading/menu/card workflow or
configuration surface.
4. `govoplan-core/docs/MODULE_ARCHITECTURE.md` owns the shell, route, navigation,
UI-capability, and shared-component boundaries.
5. This document owns the common pattern names, placement grammar, wording and
state conventions, focused-view composition, and definition of done across
those sources.
If two rules appear to conflict, do not create a third local convention. Record
the conflict in the owning decision ledger, resolve it there, and update the
affected patterns and surfaces together.
## Product Contract
GovOPlaN should feel calm because it shows what is relevant to the task, not
because it hides authority, risk, or evidence. Every surface follows these
rules:
- Start with the user's current object and task.
- Show common actions before advanced controls.
- Keep context, status, problems, and the next action spatially connected.
- Make consequential effects explicit before execution and observed effects
inspectable afterwards.
- Treat permissions, policy, privacy, and module availability as behavior, not
decoration.
- Keep optional modules optional. Compose through core route and UI-capability
contracts, never sibling-private components.
- Preserve a stable way back to the containing object and the broader system.
- Do not let navigation, selection, or a view switch imply consent.
## Surface Archetypes
Choose an archetype from the task, then specialize it for the domain. A route
may contain more than one bounded archetype, but it should have one dominant
one.
| Archetype | Use when | Standard anatomy | Do not use when |
| --- | --- | --- | --- |
| Directory or explorer | Users browse hierarchical collections such as files, mailboxes, calendars, addresses, or records. | Collection/source pane, collection actions, filter in the pane it affects, main list/content pane, optional detail pane. | The content is a set of unrelated settings or workflow stages. |
| List-detail workspace | Users repeatedly find objects, inspect one, and act without losing list context. | Search/filter/list, persistent selected-object context, detail/actions, stable selection and URL. | A single guided operation is the primary task. |
| Focused task view | Only a bounded composition is needed to complete one task. | Task identity and reason, selected object, necessary module regions/actions, progress or status, obvious exit to the full system. | Hiding a surface would obscure a consequence, blocker, or required evidence. |
| Create or edit | Users change one coherent object state. | Adaptive typed form, field-level validation, advanced section, save/cancel, unsaved-change guard. | Discovery-heavy setup or a broad consequential change needs staged review. |
| Guided setup or import | The user must discover, upload, map, test, or preflight before a safe result exists. | Named steps, current progress, preserved inputs, validation/problem list, review, resumable completion where work is durable. | An ordinary edit can be understood as one coherent form. |
| Review or decision | A person must inspect evidence and deliberately approve, reject, send, publish, or otherwise commit. | Decision context, evidence/problems, consequence and reversibility, authority/provenance, explicit action, resulting record. | The interaction is passive inspection. |
| Monitoring, progress, or report | Users observe asynchronous or aggregate state and intervene when needed. | Summary, filters, durable job/item state, last update, retry/reconcile/intervention, detail and evidence. | A toast is sufficient for a short, non-durable local action. |
| Administration or configuration | Users compare and configure separate concerns. | Heading and scope, grouped subnavigation, overview/list plus selected details, adaptive editor or guided risky operation, effective policy and source. | The primary task is browsing one structured object space. |
| Dashboard | Users need a task-oriented starting point across modules. | Prioritized actionable widgets, scoped status, clear destination per widget, explicit refresh/staleness. | It merely duplicates every module navigation item or metric. |
| Public service or entry | An unauthenticated or external participant starts or resumes a service. | Service identity, eligibility/context, privacy and evidence expectations, accessible form/task, save/resume or handoff. | The actor is performing internal administration. |
## Placement Grammar
### Shell And Navigation
- The global title bar and rail belong to core. A module contributes routes,
navigation metadata, and explicit UI capabilities; it does not reproduce the
shell.
- Global navigation answers "which service area?" Local subnavigation answers
"which stable facet of this object or area?" A progress indicator answers
"where am I in this operation?" Do not use those three controls
interchangeably.
- Keep the current tenant, actor, object, and selected version or scope stable
across local navigation. Guard unsaved work before navigation.
- Permission and capability filtering happens before view composition. A
missing menu item is not evidence that an actor lacks backend access, and a
visible item is never authorization by itself.
- Route, selection, panel, and view changes must not execute consequential
actions.
### Page And Workspace
- Structured directories use the full available content space and persistent
panes. They do not add a decorative heading row that reduces working height.
- Workflow, configuration, dashboard, and explanatory pages may use a heading.
The heading names the task or scoped object and contains only route-level
actions.
- Put filters beside the list or pane they affect. Put bulk actions immediately
above or beside the current selection. Put object actions with the object
detail, not in the global title bar.
- Full-page create and edit surfaces put their persistent action cluster in the
upper-right of the page heading. `Discard` comes before `Save …`, with the
primary save action at the far right. Keep both controls in the same place
across validation, loading, and saved states; guard unsaved work when the
user discards or navigates away.
- A page or panel has one visually primary action for its current state. Put
secondary actions beside it. Separate destructive actions and name their real
effect.
- Dialog actions use a stable footer: cancel/back first, then the primary action
at the end. Header and footer stay fixed while long bodies scroll.
- Use cards for independent groups, summaries, and settings blocks. Do not wrap
every region in a card or nest cards merely to create spacing.
- When a collapsible card contains one table and no other content, the table
uses the card's full available width and body height. The card/table region
owns overflow; do not add an inner max-width, decorative wrapper, duplicate
padding, or nested scroll container that reduces the working area.
- Row actions in tables are icon-only controls in a stable rightmost action
column. Order them by intent: inspect/open, edit, copy/duplicate,
transfer/share/download, retry/restore, then remove/delete last. Omit actions
that do not apply without closing the gap or changing the relative order.
Every icon has a translated accessible name and matching tooltip. Separate
destructive actions visually, and use a named confirmation/review surface
when the consequence cannot be understood from the icon and row context.
- Transient feedback should not shift the workspace. Durable failures, partial
results, and blockers remain attached to the affected item or operation.
### Detail And Explanation
- Keep the selected object's identity and material status visible while its
detail changes.
- Short field help sits with the label. Longer "Why?", policy source,
diagnostics, or provenance belongs in an expandable area, detail panel, or
review step.
- Empty space is not an error. An empty state states what is empty, why that can
happen, and the permitted next action. Do not show creation actions to actors
who cannot create.
## Visual Grammar
- Core owns the appearance contract and shared CSS tokens. Modules use core
colors, spacing, radii, shadows, focus treatment, status colors, and disabled
treatment; module CSS may specialize layout only.
- Establish hierarchy through spacing, typography, grouping, and placement
before adding borders or color.
- Color never carries status or required action alone. Pair it with text and,
where useful, an icon.
- Icons support recognition but do not replace accessible names. Use the core
icon-name mapping for navigation.
- Keep list columns, tree indentation, headers, dialog dimensions, and action
positions stable as content changes.
- Density is a user preference, not a license to remove labels, focus targets,
explanations, or consequences.
- Respect system/light/dark themes and reduced-motion preferences through the
core contract. Do not build module-local theme systems.
## Wording Grammar
Use the same noun for the same domain object in navigation, headings, fields,
actions, states, API-facing explanations, and documentation. Prefer the most
specific user-facing noun: "Recipients" rather than "Data", "Delivery job"
rather than "Process", and "Mail profile" rather than "Configuration" when
that is what the user is acting on.
Actions use a verb plus the object or consequence:
- Prefer `Save campaign`, `Review messages`, `Queue delivery`, `Retry failed
deliveries`, or `Delete calendar`.
- Avoid `Submit`, `OK`, `Continue`, or `Execute` when a more precise action is
available.
- Use `Continue` only when it advances a reversible guided flow without
committing the final effect.
- Do not say `Undo` when the system can only cancel future work, create a
correction, supersede a record, or request retraction.
State text describes observed state, not optimism. Use stable shared terms where
they fit: `Draft`, `Ready for review`, `Blocked`, `Queued`, `Running`,
`Retry scheduled`, `Partially completed`, `Completed`, `Failed`, and
`Cancelled`. Domain-specific states may refine these terms but should not give a
shared term a contradictory meaning.
Blocked and failed actions use the structured language from DUE-005:
- what is unavailable or failed
- why, in plain language
- what must happen next
- who can do it
- where to go
- optional technical details behind deliberate disclosure
Errors should identify the affected object and whether saved state or external
effects may already exist. Never expose raw exception text as the only user
message.
## State Contract
Every surface implements the states it can reach; it does not render a blank
region while waiting or collapse distinct outcomes into a generic error.
| State | Required treatment |
| --- | --- |
| Loading | Keep the stable shell and context visible. Name what is loading; preserve usable prior data when safe. |
| Empty | State the scope and reason, then show only permitted next actions. |
| Validation problem | Attach the problem to the field/item and provide a navigable summary when problems span regions or steps. |
| Permission denied | Name the unavailable action or object, the required actor/role where safe, and a valid exit. Do not leak protected data. |
| Capability unavailable | Distinguish not installed, disabled, not configured, unhealthy, and not permitted when the actor may know. Give the responsible actor and target. |
| Offline or unreachable | Preserve local context and unsaved input, show last-known/stale state, and offer a safe retry. Do not present network absence as an authentication failure. |
| Stale or conflicting | Show which data changed, preserve both values where feasible, and offer reload, merge, or explicit overwrite according to policy. |
| Partial result | Show completed and incomplete effects separately. Never label a partial operation successful without qualification. |
| Asynchronous work | Show durable job identity, queued/running/retry/block/final state, last update, progress if meaningful, and leave/return behavior. |
| Success | State the resulting object/effect and provide its evidence or destination. Use a transient toast only when the result is already visible and durable elsewhere. |
| Destructive or corrective action | Preview scope, downstream effects, reversibility limit, evidence, and required confirmation or approval. |
Long-running or external work must expose retry and reconciliation as observable
states. The UI must not imply that a request and its external effect were one
atomic success when an outbox, worker, or remote system sits between them.
## Consequence And Provenance
Before an action affects records, rights, policy, retention, communications,
money, external systems, or workflow state, its action surface must answer the
decision-surface questions in the interface doctrine. At minimum show:
- affected object and scope
- acting identity or system actor and relevant authority
- immediate and possible downstream effects
- whether the operation is reversible, cancellable, corrective, or final
- blockers and their resolution path
- audit/evidence that will be created
- effective policy or configuration source when it changes the decision
After execution, users must be able to reach the command/job, observed effects,
policy result, failures, retries, reconciliation outcome, actor, time, and source
data that explain the result. Provenance may be quiet by default, but it must not
be absent.
Privacy follows the same rule: lists, previews, logs, notifications, and
diagnostics show only the personal or secret data needed for the actor's task.
Redaction must be explicit enough that users do not mistake a redacted value for
missing source data.
## Focused Views
A focused view is a declarative UI composition for a task. It selects the
routes, local regions, navigation entries, and actions relevant to that task
after installed-module, capability, permission, and policy filtering. It does
not change backend authorization or domain state.
A view definition must be able to explain:
- its stable identifier, label, and task purpose
- the current object/scope and default destination
- included navigation and contributed regions/actions, with deterministic order
- the visible escape to the containing module and full system
- why the view is active and how the user may switch when switching is allowed
- what happens to unsaved work when entering, leaving, or switching views
Focused views follow these invariants:
- Do not hide a blocker, material consequence, provenance, or required review
merely to make the screen quieter.
- Preserve the global tenant/actor context and provide an obvious exit.
- Filter unavailable contributions without leaving broken separators, empty
groups, or dead destinations.
- A manual or automatic switch is navigation, not consent. Guard unsaved work
and never execute a domain action as a side effect.
- Display why a non-manual default was selected, for example a role or task
default, without exposing protected policy details.
- Treat an unknown or invalid view as a recoverable fallback to the normal
module surface.
When more than one source proposes a focused view, use this precedence:
1. a manual view pinned for the current user session
2. a current-task suggestion, including a future workflow-step suggestion
3. the user's saved default
4. the role or tenant default
5. the normal full interface
Show the active source and an escape to the full interface. A task or workflow
suggestion is never an authorization change and never locks the user into the
composition; tenant policy may constrain which views are selectable, but it
must not hide required evidence or remove that escape. Workflow implementation
is explicitly postponed and is not a prerequisite for defining, manually
selecting, testing, or piloting focused views. A future workflow module may
request a view through a core contract; it must not own the view composition
implementation.
## Accessibility And Responsive Contract
- Every action is reachable and operable by keyboard in a logical order.
- Use semantic headings, landmarks, labels, tables/lists, and native controls
before adding ARIA. Icon-only controls need stable accessible names.
- Focus is visible. Dialogs trap focus, announce their name, and return focus to
the control that opened them. Validation moves or links focus to the first
relevant problem without losing the problem summary.
- Loading, saved, failed, queued, progress, and externally updated states are
announced without repeatedly interrupting the user.
- Disabled primary actions need a focusable explanation; a pointer-only tooltip
is insufficient.
- Do not rely on color, hover, drag-and-drop, pointer precision, or animation as
the only interaction. Provide keyboard and explicit-control equivalents.
- At narrow widths and high zoom, preserve task order and action access. Collapse
secondary panes into an explicit drawer/step and never move a destructive
action into the primary position.
- Honor reduced motion. Avoid motion that implies progress when the operation is
merely waiting.
- Truncation has an accessible full-value path. Personal or secret values remain
redacted according to permission and policy in that path.
## Component Ownership
Core already exports shell, navigation, access-boundary, form, dialog, loading,
status, policy/provenance, blocker, review, table, tree, message-display, and
unsaved-change primitives. Reuse them when their contract fits.
Do not promote a component only because two screens look similar. Promote it to
`@govoplan/core-webui` after a second consumer or a clear platform contract has
proved shared behavior, accessibility, state, and extension needs. Modules own
domain composition, wording, and policy semantics; core owns generic contracts
and appearance.
## Test Expectations
For every changed surface, select tests from each applicable layer:
- route and permission tests: module enabled/disabled permutations, route guard,
contribution filtering, fallback, and direct-link behavior
- behavior tests: primary task, validation, unsaved-change guard, confirmation,
retry/reconcile, partial result, and leave/return behavior
- accessibility tests: semantic names/roles, keyboard order, focus entry/return,
live-state announcements, and non-color status meaning
- state tests: loading, empty, denied, capability-missing, stale/conflict,
offline, partial, success, and destructive/corrective outcomes as applicable
- composition tests: absent optional module, duplicate/unknown contribution,
deterministic ordering, and focused-view fallback
- presentation checks: supported widths/zoom, light/dark/system theme, reduced
motion, comfortable/compact density, and long translated text
- i18n checks: user-facing strings owned by the rendering package and structural
audits passing
- visual regression: useful for geometry and hierarchy after behavior and
accessibility assertions exist; never the only evidence
If the current harness cannot automate a required check, record the gap and the
manual evidence in the owning issue. "Not tested" is an inventory state, not a
reason to infer that a pattern is satisfied.
## Definition Of Done For A Surface
- The dominant task and archetype are recorded in the inventory.
- Placement, action hierarchy, wording, and every reachable state follow this
pattern language or an explicit ledger exception.
- Permission, capability, privacy, and redaction behavior are verified.
- Consequence, reversibility, authority, evidence, and provenance are present
where applicable.
- Keyboard, focus, announcement, responsive, theme, density, motion, and i18n
behavior are covered in proportion to the surface.
- Optional modules remain optional and no sibling-private UI import was added.
- Behavioral/accessibility evidence is linked from the rollout matrix and issue.
- Configured-system help can reach the applicable pattern or reference topic
when [Docs #15](https://git.add-ideas.de/add-ideas/govoplan-docs/issues/15)
supplies that experience.
## First Pilot: Campaign
[Campaign #74](https://git.add-ideas.de/add-ideas/govoplan-campaign/issues/74)
is the first full-domain audit and migration. It should prove patterns before
generic extraction:
- [#59](https://git.add-ideas.de/add-ideas/govoplan-campaign/issues/59) and
[#73](https://git.add-ideas.de/add-ideas/govoplan-campaign/issues/73): stable,
accessible preview and attachment-detail overlays
- [#63](https://git.add-ideas.de/add-ideas/govoplan-campaign/issues/63): review
stages, outcomes, blockers, and intervention vocabulary
- [#62](https://git.add-ideas.de/add-ideas/govoplan-campaign/issues/62): explicit
synchronous/asynchronous send mode and durable delivery progress
- [#65](https://git.add-ideas.de/add-ideas/govoplan-campaign/issues/65): one
coherent report filtering and count-affordance model
- [#35](https://git.add-ideas.de/add-ideas/govoplan-campaign/issues/35): guided
first-campaign entry
These slices do not depend on the Workflow runtime. Campaign's current
domain-owned review/send state is enough to prove layout, wording, focused-view,
progress, intervention, and evidence patterns.
## Revision Procedure
1. Record a changed product decision in the core UI/UX decision ledger.
2. Update the relevant pattern here without copying the full owning doctrine.
3. Update the surface inventory and rollout owner/issues.
4. Change shared components only where the proven contract belongs to core.
5. Migrate and test affected module surfaces.
6. Publish configured-system pattern/reference help through the Docs module.

View File

@@ -0,0 +1,236 @@
# GovOPlaN Interface Surface Inventory And Rollout
This is the initial evidence inventory for the product-wide interface pattern
language. It records code contributions, not an assertion that every listed
surface is complete, enabled in a deployment, usable, or compliant.
The applicable design contract is
[`INTERFACE_PATTERN_LANGUAGE.md`](INTERFACE_PATTERN_LANGUAGE.md).
## Snapshot And Method
Snapshot date: 2026-07-20.
Evidence was read from tracked Git `HEAD` in the local GovOPlaN checkouts:
- core routes and fallback behavior in `govoplan-core/webui/src/App.tsx`
- every present `govoplan-*/webui/src/module.ts`
- the matching backend `src/*/backend/manifest.py`
- named UI capabilities and contribution identifiers in each `module.ts`
- Campaign nested routes in its tracked `CampaignWorkspace.tsx` and
`SectionSidebar.tsx`
Tracked `HEAD` is used as the integrated baseline. Dirty worktree changes are
not treated as delivered behavior. One material exception is called out in the
Campaign inventory: local WIP folds the tracked `recipient-data` surface into
`recipients`, but that change is not yet part of the baseline.
Runtime visibility remains conditional on the module being packaged and
enabled, server metadata, installed optional capabilities, the authenticated
actor, tenant context, route permission guards, and inner-surface permission
checks. A route in this inventory therefore means "the code contributes this
route when its module is active", not "every user sees it".
Inventory states:
- **Contributed**: a route or named UI capability exists in tracked source.
- **Metadata gap**: frontend runtime source contributes a route but the backend
manifest does not describe the same route/navigation surface.
- **Unreviewed**: the surface has not yet completed the pattern, state,
accessibility, privacy, and consequence audit. This is the default unless an
issue supplies verification evidence.
- **Pilot**: the surface is in the Campaign-first rollout.
## Core Shell Surfaces
| Surface | Owner and code evidence | Audience/access evidence | Primary task and target archetype | Audit / rollout |
| --- | --- | --- | --- | --- |
| Public landing and login | `govoplan-core` `PublicLandingPage`; rendered while no authenticated principal exists | Unauthenticated; maintenance and backend-reachability context are shell inputs | Understand the service and authenticate; public entry | Unreviewed; later public-entry audit |
| Session/bootstrap state | `govoplan-core` `App.tsx` and `AppShell` | All browser sessions during bootstrap | Understand that session/platform state is loading; state contract | Unreviewed; core shell |
| `/` authenticated redirect | `govoplan-core` chooses the first visible navigation destination | Authenticated; result depends on visible nav contributions | Enter the actor's first accessible service area; navigation behavior, not a content page | Unreviewed; focused-view/default-route work must preserve this fallback |
| `/dashboard` fallback | `govoplan-core` `DashboardPage` only when the Dashboard module is absent | Authenticated; no route-specific scope in core | Cross-module starting point; dashboard | Unreviewed; compare with module dashboard before shared changes |
| `/settings` | `govoplan-core` `SettingsPage` | Authenticated; contributed sections and integrations filter internally | Profile, UI/workspace preference, local connection, and user-scoped integration settings; configuration | Unreviewed; Core #225 program |
| Shell chrome | `AppShell`, `Titlebar`, `IconRail`, `BreadcrumbBar`, `HelpMenu`, language menu, unsaved-change provider | Public/authenticated variants; nav filtered later | Tenant/actor context, global navigation, help, language, session and maintenance state | Unreviewed; platform-owned prerequisite for focused views |
## Direct Module Route Contributions
The access guard column reports only the route-level declaration in
`module.ts`. Inner APIs and controls may impose additional checks.
| Route | Owner / render evidence | Route-level access evidence | Primary task | Target archetype | Status / priority |
| --- | --- | --- | --- | --- | --- |
| `/admin` | `govoplan-access` `AdminPage` | Any core `adminReadScopes` | Administer system and tenant concerns assembled from module sections | Administration/configuration | Contributed; unreviewed; P1 under [Core #225](https://git.add-ideas.de/add-ideas/govoplan-core/issues/225) |
| `/address-book` | `govoplan-addresses` `AddressBookPage` | `addresses:contact:read` | Browse and manage contacts, address books, and lists | Directory/list-detail | Contributed; unreviewed; P2 after Campaign |
| `/calendar` | `govoplan-calendar` `CalendarPage` | `calendar:event:read` | Browse calendars/events and act on calendar data | Directory/list-detail | Contributed; metadata gap; unreviewed; P2 after Campaign |
| `/campaigns` | `govoplan-campaign` `CampaignListPage` | `campaigns:campaign:read` | Find, compare, create, and open campaigns | List-detail entry | Pilot; P1 [Campaign #74](https://git.add-ideas.de/add-ideas/govoplan-campaign/issues/74) |
| `/campaigns/:campaignId/*` | `govoplan-campaign` `CampaignResourceRoute` and `CampaignWorkspace` | `campaigns:campaign:read`, plus resource probe | Configure, review, send, and inspect one campaign/version | List-detail workspace containing edit, review, monitoring, and evidence surfaces | Pilot; P1 Campaign #74 |
| `/operator` | `govoplan-campaign` `OperatorQueuePage` | Any campaign queue/review/send scope declared by the module | Monitor and intervene in campaign jobs | Monitoring/work queue | Pilot; P1 Campaign #74 |
| `/reports` | `govoplan-campaign` inline `ReportsPage` | `campaigns:report:read` | Reach campaign reporting; current component identifies itself as prepared for later functionality | Reporting | Pilot inventory; implementation maturity explicitly incomplete; P2 after campaign report pilot |
| `/templates` | `govoplan-campaign` `TemplatesPage` | No route guard declared in `module.ts` | Browse/manage campaign templates | Directory/list-detail | Pilot audit; permission intent must be verified; P2 |
| `/dashboard` | `govoplan-dashboard` `DashboardPage` | No route-specific scope | Assemble module-provided actionable widgets | Dashboard | Contributed; unreviewed; P2 |
| `/docs` | `govoplan-docs` `DocsPage` | Docs read or system/tenant settings read scopes | Read configured, available, and evidence-aware documentation | Documentation directory/reference | Contributed; unreviewed; P1 [Docs #15](https://git.add-ideas.de/add-ideas/govoplan-docs/issues/15) after initial pattern content |
| `/files` | `govoplan-files` `FilesPage` | `files:file:read` | Browse folders/files and perform managed-file work | Directory/explorer | Contributed; metadata gap; unreviewed; P2 after Campaign |
| `/idm` | `govoplan-idm` `IdmPage` | Any IDM assignment/write or organization function-assign scope | Inspect and govern identity/function assignments | List-detail/configuration | Contributed; unreviewed; P2 |
| `/mail` | `govoplan-mail` `MailboxPage` | `mail:mailbox:read` | Browse mailboxes and messages | Directory/list-detail | Contributed; metadata gap; unreviewed; P2 after Campaign |
| `/notifications` | `govoplan-notifications` `NotificationCenterPage` | `notifications:notification:read` | Inspect and acknowledge notification state | List-detail/inbox | Contributed without a nav item or backend frontend metadata; navigation intent unknown; P2 discovery |
| `/ops` | `govoplan-ops` `OpsPage` | Ops read or system/tenant settings read scopes | Inspect runtime health and readiness | Monitoring | Contributed; unreviewed; P2 |
| `/organizations` | `govoplan-organizations` `OrganizationsPage` | Organization model/unit/function or admin settings read scopes | Model and inspect organizational structures/functions | Directory/list-detail | Contributed; unreviewed; P2 |
| `/scheduling` | `govoplan-scheduling` `SchedulingPage` | `scheduling:schedule:read` | Plan and decide scheduling requests and availability | List-detail/guided decision | Contributed; metadata gap; unreviewed; P2 |
## Manifest And Runtime Route Alignment
Backend route metadata lets operators, Docs, release tooling, and remote bundle
loading reason about the configured interface without executing module UI code.
`module.ts` remains the executable local route/render source. Missing metadata
is recorded here as an evidence gap; this inventory does not infer whether each
gap is intentional.
| Module | `module.ts` routes | Backend manifest frontend routes | Backend nav alignment | Result |
| --- | --- | --- | --- | --- |
| Access | `/admin` | `/admin` | Aligned | Described |
| Addresses | `/address-book` | `/address-book` | Aligned | Described |
| Admin | No direct route; `admin.sections` | None | Not applicable | Composed surface |
| Audit | No direct route; `admin.sections` | None | Not applicable | Composed surface |
| Calendar | `/calendar` | None | `/calendar` nav exists | Metadata gap |
| Campaign | Five routes | None | Four top-level nav items exist | Metadata gap; wildcard resource route is also undescribed |
| Dashboard | `/dashboard` | `/dashboard` | Aligned | Described |
| Docs | `/docs` | `/docs` | Aligned | Described |
| Files | `/files` | None | `/files` nav exists | Metadata gap |
| IDM | `/idm` | `/idm` | Aligned | Described |
| Mail | `/mail` | None | `/mail` nav exists | Metadata gap |
| Notifications | `/notifications` | No frontend metadata | No nav item | Metadata and discovery gap |
| Ops | `/ops` | `/ops` | Aligned | Described |
| Organizations | `/organizations` | `/organizations` | Aligned | Described |
| Policy | No direct route; `admin.sections` | None | Not applicable | Composed surface |
| Scheduling | `/scheduling` | None | `/scheduling` nav exists | Metadata gap |
Before a release claims a complete configured-system route inventory, add a
contract check or explicit exceptions so executable routes and manifest
metadata cannot silently diverge.
## Composed Surfaces And Extension Points
These surfaces are active only when the host and contributing modules are
enabled and the actor passes the declared filters.
| Host surface | Contributor and evidence | Contributed regions/actions | Pattern implication | Audit |
| --- | --- | --- | --- | --- |
| `/admin` | Access host (`AdminPage`) | System tenants/users/roles, tenant users/groups/roles/API keys/settings, function-role mappings, user/group mail and file connector scopes | One stable admin information architecture must contain both host-owned and contributed sections | Unreviewed; P1 Core #225 |
| `/admin` | `govoplan-admin` `admin.sections` | Overview; system settings; configuration changes; configuration packages; role/group templates; module management | Configuration, guided operations, review/preflight, consequence | In progress under Core #225; surface-level evidence still needed |
| `/admin` | `govoplan-audit` `admin.sections` | System audit; tenant audit | Evidence/provenance and reporting | Unreviewed |
| `/admin` | `govoplan-files` `admin.sections` and `files.connectors` | System and tenant file connections plus scoped connector managers used by Access | Adaptive configuration, discovery/test, policy and credentials | First migration family in Core #225; verification incomplete in this inventory |
| `/admin` | `govoplan-organizations` `admin.sections` | Tenant organization settings | Configuration/list-detail | Unreviewed |
| `/admin` | `govoplan-policy` `admin.sections` | System, tenant, group, and user retention | Effective value, source/provenance, consequential configuration | Unreviewed; Core #225 phase 4 |
| `/admin` and `/settings` | `govoplan-mail` `mail.profiles` | System/tenant/group/user mail profile and policy managers | Same server/credential/policy grammar as file connectors | Unreviewed; Core #225 mail migration |
| `/settings` | Core host | Profile; interface; workspace; local connection | Personal configuration with adaptive forms and immediate feedback | Unreviewed |
| `/settings` | Files and Mail named capabilities | User-scoped file connections and mail profiles/policy | Optional integration regions disappear cleanly when capability absent | Unreviewed |
| `/settings` | `govoplan-notifications` `settings.sections` | Notification preferences | Personal configuration | Unreviewed |
| `/dashboard` | Dashboard host and `dashboard.widgets` | Installed-modules widget; Ops health widget when Ops contributes it | Widget ordering, staleness, permissions, destination behavior | Unreviewed |
| `/organizations` | IDM `organizations.functionActions` | Action leading to assignment view filtered by IDM scopes | Cross-module context action through explicit capability | Unreviewed |
| Campaign attachments/import | Files `files.fileExplorer` | Folder tree, managed chooser, file listing/pattern resolution/sharing | Optional domain composition without sibling-private imports | Pilot audit under Campaign #74 |
| Campaign review/send | Mail runtime `mail.devMailbox` | Mock-mail verification when backend advertises runtime capability | Optional review stage with unavailable/optional states | Pilot audit under Campaign #63/#62 |
Other named capability exports (`files.connectors`, `organizations.functionPicker`,
and mail profile validation) are contracts consumed inside the composed surfaces
above; they are not independent routes.
## Campaign Pilot Surface Map
Campaign is detailed first because it exercises almost every archetype. The
tracked baseline still contains a dedicated `recipient-data` section. The dirty
local WIP redirects that path into `recipients` and removes it from the sidebar;
do not mark that consolidation delivered until
[Campaign #67](https://git.add-ideas.de/add-ideas/govoplan-campaign/issues/67)
is integrated or the issue state is corrected.
Campaign already consumes core primitives including `ModuleSubnav`, `Card`,
`PageTitle`, `Button`, `LoadingFrame`, `DismissibleAlert`, `FormField`,
`StatusBadge`, `MetricCard`, `Dialog`, `ConfirmDialog`, `FileDropZone`,
`MessageDisplayPanel`, policy components, access/module capabilities, and
unsaved-navigation guards. Reuse alone does not prove that the composition or
states satisfy the pattern.
| Surface / code evidence | Primary task | Target pattern | Material consequence/state | Known issue / rollout |
| --- | --- | --- | --- | --- |
| Campaign list (`CampaignListPage`) | Find, compare, create, open | List-detail entry | Campaign lifecycle/status and creation | Audit in [#74](https://git.add-ideas.de/add-ideas/govoplan-campaign/issues/74); guided entry [#35](https://git.add-ideas.de/add-ideas/govoplan-campaign/issues/35) |
| Overview (`CampaignOverviewPage`) | Understand/edit campaign identity, version, access, lifecycle | Object overview plus adaptive edit | Lock/archive/delete/access changes need real consequence and reversibility wording | #74; integrate/reconcile #67 before migration claims |
| Fields (`CampaignFieldsPage`) | Define recipient/template field schema | Structured editor | Schema changes can invalidate recipient/template data | #74 audit |
| Attachments/files (`AttachmentsDataPage`, `AttachmentRulesOverlay`) | Select sources and attachment/ZIP rules | Directory chooser plus adaptive rule editor | Missing or mismatched files affect built messages | #74; attachment-detail [#59](https://git.add-ideas.de/add-ideas/govoplan-campaign/issues/59) |
| Recipients (`RecipientDataPage`) | Select/import/map/edit recipients and per-recipient values/files | Import/mapping plus list-detail editor | Personal data, validation, bulk activation, file links | #74; guided entry #35 |
| Recipient data (`RecipientDetailsPage` in tracked baseline) | Inspect/edit a dedicated recipient-data view | List-detail editor | Personal data and send eligibility | Local WIP removes this separate surface; #67 integration state must decide baseline |
| Template (`TemplateDataPage`, placeholder/expression dialogs) | Author subject/body and preview substitutions | Adaptive editor plus stable preview | Generated communication content and unresolved expressions | #74; stable overlay [#73](https://git.add-ideas.de/add-ideas/govoplan-campaign/issues/73) |
| Mail settings (`MailSettingsPage` settings view) | Select/configure campaign mail transport | Adaptive configuration | Credentials, SMTP/IMAP destinations, test outcomes | #74; align with Core #225 mail pattern |
| Campaign settings (`GlobalSettingsPage` settings view) | Configure campaign behavior | Adaptive configuration | Can alter validation/build/send behavior | #74 audit |
| Mail policy (`MailSettingsPage` policy view) | Inspect/override effective mail policy | Effective policy/provenance editor | Inheritance and locks affect allowed delivery | #74; Core #225 policy pattern |
| Campaign policy (`GlobalSettingsPage` policy view) | Inspect/override campaign policy | Effective policy/provenance editor | Inheritance, actor authority, and blocked edits | #74; Core #225 policy pattern |
| Review/send (`ReviewSendPage`) | Validate, build, mock-test, confirm/send, inspect results | Guided review/decision plus durable progress | External communication, partial effects, retries, evidence | Intervention vocabulary [#63](https://git.add-ideas.de/add-ideas/govoplan-campaign/issues/63); sync/async progress [#62](https://git.add-ideas.de/add-ideas/govoplan-campaign/issues/62) |
| Message and attachment detail overlays | Inspect one built/mock message and its attachment links | Stable detail/review dialog | Personal data, exact outbound content, reviewed state | Implement/verify [#59](https://git.add-ideas.de/add-ideas/govoplan-campaign/issues/59) and [#73](https://git.add-ideas.de/add-ideas/govoplan-campaign/issues/73) together |
| Campaign report (`CampaignReportPage`) | Filter and inspect delivery outcomes | Reporting/list-detail | Partial, failed, skipped, SMTP/IMAP outcomes and retries | Filtering [#65](https://git.add-ideas.de/add-ideas/govoplan-campaign/issues/65), dependent on [Core #263](https://git.add-ideas.de/add-ideas/govoplan-core/issues/263) |
| Audit (`CampaignAuditPage`) | Inspect campaign evidence/history | Provenance timeline/report | Actor/action/effect trace | #74 audit |
| JSON (`CampaignJsonView`) | Inspect expert representation | Advanced diagnostics/reference | Raw data may contain personal/configuration values; not a primary editor | #74 privacy/redaction audit |
| Create wizard (`CreateWizard`) | Seed a campaign through basics, sender, fields, recipients, template, attachments, review, send | Guided setup | Current steps mix creation and later consequential delivery; completion semantics need audit | Guided first campaign [#35](https://git.add-ideas.de/add-ideas/govoplan-campaign/issues/35) |
| Review/send wizard routes | Alternate guided review/send shells | Guided review | Tracked routes exist; implementation relationship to `ReviewSendPage` must be established, not guessed | #74 inventory decision |
| Operator queue (`OperatorQueuePage`) | Monitor jobs and intervene | Monitoring/work queue | Retry/pause/reconcile and system actor/effect evidence | #74, then #62 vocabulary |
| Top-level reports placeholder | Enter cross-campaign reports | Reporting | Component explicitly says functionality is prepared for later passes | Keep marked incomplete; do not infer parity with per-campaign report |
| Templates route (`TemplatesPage`) | Browse template records | Directory/list-detail | Template availability and later generated outputs | #74 audit; verify missing route guard intent |
The five review stages currently named in code are `Validate and inspect`,
`Build and review`, `Mock send and verify`, `Confirm and send`, and `Delivery
results`. Campaign #63 owns the intervention and status vocabulary; Workflow is
not required to define or implement it.
## Repositories Without A WebUI Route Contribution
The following local repositories contain a backend manifest but no
`webui/src/module.ts` at this snapshot:
`govoplan-approvals`, `govoplan-assets`, `govoplan-booking`,
`govoplan-certificates`, `govoplan-committee`, `govoplan-consultation`,
`govoplan-contracts`, `govoplan-dist-lists`, `govoplan-evaluation`,
`govoplan-facilities`, `govoplan-forms-runtime`, `govoplan-grants`,
`govoplan-helpdesk`, `govoplan-identity`, `govoplan-inspections`,
`govoplan-issue-reporting`, `govoplan-learning`, `govoplan-permits`,
`govoplan-poll`, `govoplan-procurement`, `govoplan-records`,
`govoplan-resources`, `govoplan-rest`, `govoplan-risk-compliance`,
`govoplan-soap`, `govoplan-tenancy`, and `govoplan-transparency`.
This is only negative route evidence. It does not classify the backend module's
maturity or decide that it needs a WebUI. Connector-only, capability-only, or
backend-only modules may remain intentionally headless.
## Rollout Matrix
| Order | Scope | Current evidence | Target | Owner / issue | Verification gate | Status |
| --- | --- | --- | --- | --- | --- | --- |
| 0 | Product grammar and route inventory | Doctrine, ledger, layout rules, module contract, current route sources | One reconciled pattern language and evidence inventory | Meta [#11](https://git.add-ideas.de/add-ideas/govoplan/issues/11) | Docs links/diff checks; issue/wiki sync after integration | Initial slice in this document |
| 1 | Campaign baseline integration | Closed work and local WIP can differ from tracked baseline | Integrated, testable baseline before migration claims | Campaign #67 and tracker cleanup | Clean scoped diff, behavior tests, build, issue evidence | Must precede claiming Campaign migration complete |
| 2 | Campaign previews/details | Existing message/attachment overlays and known overflow/geometry issues | Stable header/body/footer, accessible long-content detail | Campaign #59 and #73 | Keyboard/focus/scroll behavior, long content, responsive and translated text | P1 ready |
| 3 | Campaign review/interventions | Five domain-owned stages with unresolved intervention language | Clear stages, outcomes, blockers, next actor/action, reviewed evidence | Campaign #63 | State matrix behavior/accessibility tests and agreed vocabulary | P1 needs product wording decision |
| 4 | Campaign send/progress | Synchronous/asynchronous behavior is not explicit enough | Pre-send mode/consequence plus durable leave/return progress, retry and reconciliation | Campaign #62 | Sync and async behavior, partial/failure/retry, reload/return tests | P1 ready after stage vocabulary |
| 5 | Campaign report filtering | Duplicate/inconsistent filter models are reported | One shared status/list/filter/count model | Campaign #65 and Core #263 | Query/filter behavior, keyboard, counts, large result set | P1 blocked on shared DataGrid direction |
| 6 | Guided first campaign | Existing wizard routes and ordinary workspace overlap | Task-oriented entry that hands off clearly to normal editing/review | Campaign #35 | First-run flow, resume/back, validation, optional modules, no implicit send | P1 after core pilot patterns stabilize |
| 7 | Prove/extract generic primitives | Core already exports many primitives; Campaign composition still unreviewed | Extract only contracts with a second consumer or clear platform ownership | Core #225 plus bounded follow-ups | Core behavior/accessibility tests and module-permutation tests | After Campaign proof |
| 8 | Configured-system pattern help | Docs route and classification exist | Role/config-aware pattern and route/field/blocker help | Docs #15 | Topic grouping, audience filtering, stable links/anchors | P1 after initial pattern IDs stabilize |
| 9 | Admin/configuration family | Phase inventory and connector primitives exist in the ledger | Apply the pattern to files, mail, policy, retention, packages, modules, API keys, settings | Core #225 and module children | Per-surface state/accessibility/consequence evidence | Parallel where independent of Campaign shared decisions |
| 10 | Remaining direct routes | Routes are contributed; most are unreviewed | Per-module bounded audit and migration plan | New module issues derived from this inventory | Applicable definition-of-done gates | P2 after Campaign, not a bulk rewrite |
| 11 | Manifest/runtime alignment | Several executable routes are absent from manifest metadata | Declared alignment or explicit validated exception | Core contract issue to create | Automated manifest/module route check and configured Docs verification | Discovery follow-up |
Workflow/user-story implementation is postponed. It is not on the critical path
for rows 0 through 10. Focused views can be specified, manually selected, and
tested through core composition contracts; a later workflow step may become one
activation source without changing the proven surface patterns.
## Inventory Maintenance
When a route, nav item, named UI capability, host section, or Campaign workspace
surface changes:
1. Update the owner, evidence, task, archetype, and consequence here.
2. Link the implementation issue and verification evidence.
3. Keep "unreviewed" until state, permission/privacy, consequence/provenance,
accessibility, responsive, theme, i18n, and applicable async behavior have
been checked.
4. Re-scan both `module.ts` and the backend manifest; do not infer one from the
other.
5. Recreate the inventory from a clean release lockfile before using it as
release evidence.

View File

@@ -0,0 +1,968 @@
{
"$schema": "./capability-fit.schema.json",
"schema_version": "0.1.0",
"assessment_id": "campaign-reference-2026-07-20",
"assessed_at": "2026-07-20",
"scope": {
"title": "Campaign-centric internal pilot and small-production candidate",
"reference_journeys": [
"Internal operator authors, validates, builds, queues, sends and reconciles an email Campaign with managed attachments",
"Operator inspects delivery and audit evidence"
],
"postponed": [
"Workflow and workflow-driven user stories"
]
},
"release": {
"kind": "workspace_snapshot",
"ref": "workspace-2026-07-20",
"meta_commit": "05ae81d64195",
"reproducible": false,
"configuration_packages": [],
"notes": [
"The snapshot is untagged.",
"Dirty repositories are recorded and local-only work is not treated as release-integrated."
]
},
"composition": [
{
"module_id": "core",
"repository": "govoplan-core",
"commit": "e6f7c45f0a95",
"manifest_version": "server-0.3.0",
"enabled": true,
"dirty": true,
"role": "API, registry, migrations, sessions, kernel contracts and shared WebUI"
},
{
"module_id": "tenancy",
"repository": "govoplan-tenancy",
"commit": "1dde03854733",
"manifest_version": "0.1.8",
"enabled": true,
"dirty": false,
"role": "Tenant context and lifecycle"
},
{
"module_id": "organizations",
"repository": "govoplan-organizations",
"commit": "45cda1a33f18",
"manifest_version": "0.1.8",
"enabled": true,
"dirty": false,
"role": "Organization model"
},
{
"module_id": "identity",
"repository": "govoplan-identity",
"commit": "7a1710af896f",
"manifest_version": "0.1.8",
"enabled": true,
"dirty": true,
"role": "Normalized internal identity directory"
},
{
"module_id": "access",
"repository": "govoplan-access",
"commit": "ab07075a679b",
"manifest_version": "0.1.8",
"enabled": true,
"dirty": true,
"role": "Local authentication, sessions, API keys and RBAC"
},
{
"module_id": "admin",
"repository": "govoplan-admin",
"commit": "c9e1fb287f50",
"manifest_version": "0.1.8",
"enabled": true,
"dirty": false,
"role": "Administration surfaces"
},
{
"module_id": "dashboard",
"repository": "govoplan-dashboard",
"commit": "a315a7c62b1d",
"manifest_version": "0.1.8",
"enabled": true,
"dirty": false,
"role": "Module-aware home surface"
},
{
"module_id": "policy",
"repository": "govoplan-policy",
"commit": "2511fbb5a864",
"manifest_version": "0.1.8",
"enabled": true,
"dirty": false,
"role": "Policy explanation and configuration boundary"
},
{
"module_id": "audit",
"repository": "govoplan-audit",
"commit": "5e4f84a789ea",
"manifest_version": "0.1.8",
"enabled": true,
"dirty": false,
"role": "Database audit records and retrying audit outbox"
},
{
"module_id": "campaigns",
"repository": "govoplan-campaign",
"commit": "2e593b7fa412",
"manifest_version": "0.1.8",
"enabled": true,
"dirty": true,
"role": "Campaign authoring, build, delivery control and reporting"
},
{
"module_id": "files",
"repository": "govoplan-files",
"commit": "f3210234d35a",
"manifest_version": "0.1.8",
"enabled": true,
"dirty": true,
"role": "Managed files and Campaign attachments"
},
{
"module_id": "mail",
"repository": "govoplan-mail",
"commit": "b0337b2d261a",
"manifest_version": "0.1.8",
"enabled": true,
"dirty": true,
"role": "SMTP and IMAP profiles and transports"
},
{
"module_id": "calendar",
"repository": "govoplan-calendar",
"commit": "371a00aff51c",
"manifest_version": "0.1.8",
"enabled": true,
"dirty": true,
"role": "Optional calendar outside the Campaign pilot minimum"
},
{
"module_id": "docs",
"repository": "govoplan-docs",
"commit": "f2ade1d62475",
"manifest_version": "0.1.8",
"enabled": true,
"dirty": true,
"role": "Configured-system documentation"
},
{
"module_id": "ops",
"repository": "govoplan-ops",
"commit": "341773a4ff8a",
"manifest_version": "0.1.8",
"enabled": true,
"dirty": false,
"role": "Readiness and deployment-profile visibility"
},
{
"module_id": "addresses",
"repository": "govoplan-addresses",
"commit": "f19350e65d76",
"manifest_version": "0.1.8",
"enabled": false,
"dirty": true,
"role": "Optional reusable recipient sources and CardDAV"
}
],
"deployment_profile": {
"id": "production-like-dev",
"status": "partial",
"description": "PostgreSQL and Redis run in containers while API, WebUI, worker and scheduler run from editable source trees.",
"evidence": [
{
"kind": "configuration",
"scope": "current_workspace",
"locator": "govoplan/dev/production-like/docker-compose.yml"
},
{
"kind": "documentation",
"scope": "documented_model",
"locator": "govoplan/dev/production-like/README.md"
}
]
},
"questionnaire": {
"scope_outcomes": [
{
"id": "outcome.reference_journey",
"question": "Which journey is assessed?",
"state": "answered",
"answer": "An internal operator authors, validates, builds, queues, sends and reconciles a Campaign with managed attachments.",
"evidence": []
},
{
"id": "outcome.workflow",
"question": "Is Workflow in scope?",
"state": "answered",
"answer": "No; Workflow is planned and explicitly postponed.",
"evidence": []
}
],
"data_policy": [
{
"id": "data.classification",
"question": "Which data classes and legal bases apply?",
"state": "not_assessed",
"answer": null,
"evidence": []
},
{
"id": "data.retention",
"question": "What retention, deletion, archive and legal-hold rules apply?",
"state": "not_assessed",
"answer": null,
"evidence": []
}
],
"identity_integrations": [
{
"id": "identity.pilot",
"question": "May the pilot use local GovOPlaN accounts?",
"state": "assumed",
"answer": "Yes; federation is outside the verified composition.",
"evidence": []
},
{
"id": "integration.mail",
"question": "Which target SMTP/IMAP service and policy apply?",
"state": "not_assessed",
"answer": null,
"evidence": []
}
],
"workload_growth": [
{
"id": "workload.campaign",
"question": "What are Campaign frequency, recipients per Campaign, send window, import size and attachment volume?",
"state": "not_assessed",
"answer": null,
"evidence": []
},
{
"id": "workload.platform",
"question": "What are tenant, user, concurrency, file, database, queue and audit growth assumptions?",
"state": "not_assessed",
"answer": null,
"evidence": []
}
],
"availability_operations": [
{
"id": "availability.rto_rpo",
"question": "What availability, RPO and RTO are required?",
"state": "not_assessed",
"answer": null,
"evidence": []
},
{
"id": "operations.ownership",
"question": "Who operates database, queue, storage, TLS, secrets, monitoring, backup and incident response?",
"state": "not_assessed",
"answer": null,
"evidence": []
}
],
"procurement_decisions": [
{
"id": "procurement.constraints",
"question": "Which licensing, accessibility, security, certification, support and procurement conditions are mandatory?",
"state": "not_assessed",
"answer": null,
"evidence": []
}
]
},
"capabilities": [
{
"id": "platform.composition",
"requirement": "Compose enabled backend and WebUI modules without hard optional-module dependencies.",
"status": "verified",
"evidence": [
{
"kind": "test",
"scope": "committed_source",
"locator": "govoplan-core/tests/test_module_system.py"
},
{
"kind": "contract",
"scope": "current_workspace",
"locator": "govoplan/tools/checks/check-contracts.py",
"note": "43 contracts, 29 providers, no issues"
}
],
"conditions": [
"Repeat checks on a clean pinned release candidate."
],
"gaps": [
"The current snapshot is dirty and untagged."
],
"risks": [
"A working module graph can still be unreproducible."
],
"recommendation": "Use the minimal Campaign composition and pin all artifacts before promotion.",
"proof_check": "Run contract, migration, API and WebUI module-permutation gates on the release candidate."
},
{
"id": "access.local",
"requirement": "Provide tenant-scoped local accounts, sessions, API keys and RBAC.",
"status": "verified",
"evidence": [
{
"kind": "test",
"scope": "committed_source",
"locator": "govoplan-access/tests/test_auth_dependencies.py"
},
{
"kind": "test",
"scope": "committed_source",
"locator": "govoplan-core/tests/test_api_smoke.py#cookie-session-csrf"
}
],
"conditions": [
"Pilot accepts local accounts."
],
"gaps": [
"MFA and federated lifecycle are not part of this conclusion."
],
"risks": [
"Manual account lifecycle may not satisfy production identity policy."
],
"recommendation": "Use controlled local pilot accounts and define break-glass/bootstrap rules.",
"proof_check": "Exercise joiner, role change, suspension and protected-owner recovery."
},
{
"id": "campaign.journey",
"requirement": "Author, validate, build, queue, send, reconcile and report a Campaign with frozen execution evidence.",
"status": "verified",
"evidence": [
{
"kind": "test",
"scope": "committed_source",
"locator": "govoplan-core/tests/test_api_smoke.py#campaign-create-validate-build-mock-send"
},
{
"kind": "test",
"scope": "current_workspace",
"locator": "govoplan-campaign/tests",
"note": "14 tests passed"
}
],
"conditions": [
"This verifies implementation paths, not target-provider delivery."
],
"gaps": [
"Substantial Campaign UI/code WIP is not release-integrated."
],
"risks": [
"Local WIP can make the checkout look more complete than the release baseline."
],
"recommendation": "Integrate and retest Campaign work before usability or production acceptance.",
"proof_check": "Run the complete journey with safe data and the target-like mail service."
},
{
"id": "files.managed_attachments",
"requirement": "Store and resolve managed Campaign attachments on durable storage.",
"status": "verified",
"evidence": [
{
"kind": "test",
"scope": "current_workspace",
"locator": "govoplan-files/tests",
"note": "14 tests passed"
},
{
"kind": "test",
"scope": "current_workspace",
"locator": "govoplan-campaign/tests/test_attachment_building.py"
}
],
"conditions": [
"Deployment provides a durable storage root."
],
"gaps": [
"Target backup and restore are not verified."
],
"risks": [
"Node-local storage prevents safe independent API scaling."
],
"recommendation": "Use durable local storage for the pilot and assess object/shared storage before scaling.",
"proof_check": "Back up and restore files together with database references."
},
{
"id": "mail.smtp_imap",
"requirement": "Send Campaign mail through SMTP and optionally append sent messages through IMAP.",
"status": "available_unconfigured",
"evidence": [
{
"kind": "test",
"scope": "current_workspace",
"locator": "govoplan-mail/tests",
"note": "22 tests passed"
},
{
"kind": "documentation",
"scope": "documented_model",
"locator": "govoplan-campaign/docs/CAMPAIGN_DELIVERY_RUNBOOK.md"
}
],
"conditions": [
"Use a dedicated non-production service account and safe recipients."
],
"gaps": [
"No target provider, TLS chain, throttling or bounce/reply process was exercised."
],
"risks": [
"Ambiguous provider outcomes can cause duplicate-send risk if reconciled incorrectly."
],
"recommendation": "Run target-like interoperability and failure drills before production use.",
"proof_check": "Prove SMTP acceptance, IMAP append, throttling and outcome reconciliation."
},
{
"id": "addresses.recipient_sources",
"requirement": "Select reusable address lists as Campaign recipient sources.",
"status": "available_unconfigured",
"evidence": [
{
"kind": "test",
"scope": "current_workspace",
"locator": "govoplan-addresses/tests",
"note": "14 tests passed"
}
],
"conditions": [
"Enable the Addresses module explicitly."
],
"gaps": [
"Addresses is disabled in the pinned root profile."
],
"risks": [
"Recipient governance may differ between source data and frozen Campaign evidence."
],
"recommendation": "Enable only when reusable lists are a pilot requirement.",
"proof_check": "Build a Campaign from a source list and verify immutable recipient provenance."
},
{
"id": "audit.local",
"requirement": "Retain tenant/system audit evidence and retry governed audit events.",
"status": "verified",
"evidence": [
{
"kind": "test",
"scope": "current_workspace",
"locator": "govoplan-audit/tests",
"note": "5 tests passed"
}
],
"conditions": [
"Conclusion covers local database evidence only."
],
"gaps": [
"No central sink, retention enforcement or tamper-evident archive is verified."
],
"risks": [
"Local audit evidence may not satisfy organizational records or SIEM requirements."
],
"recommendation": "Define retention and export requirements before production approval.",
"proof_check": "Exercise privileged-event review, retention and any required external export."
},
{
"id": "identity.federation",
"requirement": "Integrate external LDAP/AD, OIDC/SAML or SCIM identity infrastructure.",
"status": "scaffold",
"evidence": [
{
"kind": "documentation",
"scope": "documented_model",
"locator": "govoplan-idm/README.md"
}
],
"conditions": [],
"gaps": [
"No end-to-end provider connector or federated login is verified."
],
"risks": [
"Federation-dependent organizations cannot use the current pilot composition without extra implementation."
],
"recommendation": "Use local pilot accounts or assess and implement the selected provider path.",
"proof_check": "Run provider metadata, login/provisioning, deprovisioning and failure tests."
},
{
"id": "compliance.export_control",
"requirement": "Screen persons and organizations against embargo/sanctions lists with review evidence.",
"status": "planned",
"evidence": [
{
"kind": "issue",
"scope": "documented_model",
"locator": "https://git.add-ideas.de/add-ideas/govoplan/issues/12"
}
],
"conditions": [],
"gaps": [
"No provider, list provenance, match policy, review flow or legal evidence exists."
],
"risks": [
"The current composition must not be represented as performing export-control screening."
],
"recommendation": "Keep outside pilot claims until the user story is implemented and legally validated.",
"proof_check": "Validate list ingestion, versioning, matching, false-positive review and audit evidence."
},
{
"id": "workflow",
"requirement": "Orchestrate the journey through Workflow.",
"status": "planned",
"evidence": [
{
"kind": "observation",
"scope": "documented_model",
"locator": "Assessment scope",
"note": "Explicitly postponed"
}
],
"conditions": [],
"gaps": [
"Workflow is outside this assessment."
],
"risks": [
"Including it would overstate the assessed composition."
],
"recommendation": "Do not enable or claim Workflow for this reference pilot.",
"proof_check": "Reassess in a later Workflow-focused composition."
}
],
"infrastructure": [
{
"id": "runtime.web_api",
"requirement": "Serve matching WebUI and API artifacts with health endpoints.",
"status": "verified",
"evidence": [
{
"kind": "test",
"scope": "committed_source",
"locator": "govoplan-core/tests/test_module_system.py"
},
{
"kind": "route",
"scope": "committed_source",
"locator": "govoplan-core/src/govoplan_core/server/fastapi.py#/health"
}
],
"conditions": [
"Build immutable matching artifacts for promotion."
],
"gaps": [
"No production image or service bundle is supplied by the profile."
],
"risks": [
"Editable source processes are unsuitable as a production artifact."
],
"recommendation": "Package and supervise WebUI/API from one release candidate.",
"proof_check": "Deploy the built artifacts and run health/module-route checks."
},
{
"id": "runtime.worker",
"requirement": "Run durable asynchronous Campaign jobs.",
"status": "available_unconfigured",
"evidence": [
{
"kind": "configuration",
"scope": "current_workspace",
"locator": "govoplan/tools/launch/launch-production-like-dev.sh"
}
],
"conditions": [
"Redis and a supervised worker are required when Celery is enabled."
],
"gaps": [
"Target heartbeat, restart and queue-age alerting are not proved."
],
"risks": [
"Queued work can stall silently without monitoring."
],
"recommendation": "Start one worker for the pilot and split queues only after measurement.",
"proof_check": "Interrupt and restart a worker while preserving job/reconciliation safety."
},
{
"id": "runtime.scheduler",
"requirement": "Run periodic recovery and cleanup safely.",
"status": "partial",
"evidence": [
{
"kind": "test",
"scope": "current_workspace",
"locator": "govoplan-core/tests/test_calendar_outbox_worker.py"
}
],
"conditions": [
"Relevant Calendar work is local WIP."
],
"gaps": [
"No distributed leader election or target supervision is established."
],
"risks": [
"Multiple schedulers can duplicate periodic dispatch without locking."
],
"recommendation": "Omit from the Campaign-only pilot or run one supervised instance.",
"proof_check": "Prove missed-schedule recovery and single-leader behavior."
},
{
"id": "data.postgresql",
"requirement": "Persist application state in PostgreSQL with explicit migrations.",
"status": "verified",
"evidence": [
{
"kind": "configuration",
"scope": "committed_source",
"locator": "govoplan/dev/postgres"
},
{
"kind": "test",
"scope": "committed_source",
"locator": "govoplan/tools/checks/postgres-integration-check.py"
}
],
"conditions": [
"Target database remains deployment-owned."
],
"gaps": [
"HA, patching, WAL policy and capacity are not assessed."
],
"risks": [
"A single unprotected database is a system-wide failure point."
],
"recommendation": "Use managed or dedicated PostgreSQL with explicit migration and backup controls.",
"proof_check": "Run migrations and restore a target-like database."
},
{
"id": "queue.redis",
"requirement": "Provide the Celery broker and queue persistence.",
"status": "available_unconfigured",
"evidence": [
{
"kind": "configuration",
"scope": "current_workspace",
"locator": "govoplan/dev/production-like/docker-compose.yml#redis"
}
],
"conditions": [],
"gaps": [
"Authentication, TLS, eviction, HA and queue-loss policy are not assessed."
],
"risks": [
"Broker loss or eviction can delay work even when database business state survives."
],
"recommendation": "Configure private persistent Redis and monitor queue age/depth.",
"proof_check": "Exercise broker interruption and worker recovery."
},
{
"id": "storage.local",
"requirement": "Persist managed files on a durable single-node/shared path.",
"status": "verified",
"evidence": [
{
"kind": "contract",
"scope": "committed_source",
"locator": "govoplan-files/src/govoplan_files/backend/storage/backends.py"
}
],
"conditions": [
"Path is durable, private, writable and backed up."
],
"gaps": [
"Node-local storage cannot support independent API replicas."
],
"risks": [
"Files can be lost or become inconsistent with database state."
],
"recommendation": "Use for a bounded pilot only with coordinated backup.",
"proof_check": "Restore files and verify all database references."
},
{
"id": "storage.object",
"requirement": "Use S3-compatible storage for independently scalable file persistence.",
"status": "partial",
"evidence": [
{
"kind": "test",
"scope": "current_workspace",
"locator": "govoplan-files/tests/test_connector_providers.py"
}
],
"conditions": [],
"gaps": [
"No chosen target service or storage-backend interoperability drill."
],
"risks": [
"Provider semantics, CA or lifecycle mismatch can break file access/retention."
],
"recommendation": "Select and exercise the target object store before horizontal scaling.",
"proof_check": "Upload, retrieve, version, back up and restore representative objects."
},
{
"id": "edge.proxy_tls",
"requirement": "Terminate HTTPS and enforce proxy/security policy.",
"status": "external_system",
"evidence": [
{
"kind": "route",
"scope": "committed_source",
"locator": "govoplan-ops/src/govoplan_ops/backend/api/v1/routes.py#deployment-security"
}
],
"conditions": [],
"gaps": [
"No proxy, certificates, renewal, header or request-limit configuration is shipped here."
],
"risks": [
"Incorrect proxy/cookie/CORS configuration can expose sessions or block legitimate use."
],
"recommendation": "Supply and monitor the edge through the target platform.",
"proof_check": "Run external TLS/header/cookie/CORS and upload-limit tests."
},
{
"id": "security.secret_store",
"requirement": "Inject and rotate master, database, mail and connector secrets.",
"status": "external_system",
"evidence": [
{
"kind": "configuration",
"scope": "committed_source",
"locator": "govoplan/.env.example"
}
],
"conditions": [],
"gaps": [
"No target secret manager or rotation drill is selected."
],
"risks": [
"Loss of the master key makes encrypted credentials unavailable; leakage compromises connectors."
],
"recommendation": "Use target-native secret injection and document rotation/recovery.",
"proof_check": "Rotate a non-production credential and recover from a protected backup."
},
{
"id": "operations.monitoring",
"requirement": "Detect API, database, worker, queue, storage and delivery degradation.",
"status": "partial",
"evidence": [
{
"kind": "route",
"scope": "committed_source",
"locator": "govoplan-ops/src/govoplan_ops/backend/api/v1/routes.py#/ops/readiness"
},
{
"kind": "contract",
"scope": "committed_source",
"locator": "govoplan-core/src/govoplan_core/server/fastapi.py#slow-request-logging"
}
],
"conditions": [],
"gaps": [
"No metrics exporter, log collector, dashboards, alert routes or SLO is verified."
],
"risks": [
"Failures and queue backlog can remain unnoticed."
],
"recommendation": "Integrate external monitoring before small production.",
"proof_check": "Trigger each readiness/delivery failure and verify an actionable alert."
},
{
"id": "operations.backup_restore",
"requirement": "Back up and restore database, files, configuration and keys as a coherent service.",
"status": "partial",
"evidence": [
{
"kind": "documentation",
"scope": "documented_model",
"locator": "govoplan-core/docs/DEPLOYMENT_OPERATOR_GUIDE.md"
},
{
"kind": "issue",
"scope": "documented_model",
"locator": "https://git.add-ideas.de/add-ideas/govoplan-core/issues/29"
}
],
"conditions": [],
"gaps": [
"No target full-service restore drill or measured RPO/RTO exists."
],
"risks": [
"Partial restore can produce missing files, unusable secrets or inconsistent evidence."
],
"recommendation": "Treat Core #29 and a target restore drill as a production gate.",
"proof_check": "Restore the whole service into an isolated environment and measure it."
},
{
"id": "operations.disaster_recovery",
"requirement": "Recover the service after site or dependency loss within agreed RPO/RTO.",
"status": "not_assessed",
"evidence": [
{
"kind": "absence",
"scope": "current_workspace",
"locator": "No target DR plan or exercise evidence supplied"
}
],
"conditions": [],
"gaps": [
"RPO/RTO, off-site copies, recovery order, failover, communications and exercise schedule are unknown."
],
"risks": [
"Service and evidence may be unrecoverable after a major incident."
],
"recommendation": "Define and exercise DR before any availability commitment.",
"proof_check": "Run a documented end-to-end recovery exercise."
}
],
"data_flows": [
{
"id": "browser.api",
"from": "User browser",
"to": "Reverse proxy and GovOPlaN WebUI/API",
"data": [
"Session and CSRF cookies",
"Campaign content",
"Recipient personal data",
"Managed files"
],
"trust_boundary": "Client/public to application",
"controls": [
"HTTPS",
"Exact CORS origins",
"Secure cookies",
"Tenant and RBAC enforcement",
"Request limits"
]
},
{
"id": "api.database",
"from": "GovOPlaN API and workers",
"to": "PostgreSQL",
"data": [
"Tenant and identity records",
"Campaign drafts, snapshots and jobs",
"Connector metadata",
"Audit evidence"
],
"trust_boundary": "Application to primary state store",
"controls": [
"Dedicated database identity",
"Private or encrypted transport",
"Migrations",
"Backup and retention"
]
},
{
"id": "api.queue.worker",
"from": "GovOPlaN API",
"to": "Redis and Celery worker",
"data": [
"Job identifiers",
"Queue routing and retry metadata"
],
"trust_boundary": "Request plane to asynchronous processing plane",
"controls": [
"Private authenticated broker",
"Bounded payloads",
"Idempotent claims",
"Queue monitoring"
]
},
{
"id": "worker.mail",
"from": "GovOPlaN Campaign worker",
"to": "External SMTP and IMAP services",
"data": [
"Recipient addresses",
"Message bodies",
"Attachments",
"Sent-message copy"
],
"trust_boundary": "GovOPlaN to external communication provider",
"controls": [
"Scoped service account",
"TLS and CA policy",
"Sender and recipient policy",
"Rate limits",
"Outcome reconciliation"
]
},
{
"id": "worker.connectors",
"from": "GovOPlaN connector worker",
"to": "External address, file, object or calendar service",
"data": [
"Addresses",
"Files and provenance",
"Calendar resources"
],
"trust_boundary": "GovOPlaN to organizational/external content systems",
"controls": [
"Explicit sync direction",
"Scoped credentials",
"Endpoint allow-list",
"Provenance",
"Conflict and reconciliation policy"
]
}
],
"assumptions": [
"The pilot can use local accounts and one internal tenant or office.",
"A dedicated non-production SMTP/IMAP account and safe recipients are available.",
"Pilot load fits one API and one worker until measured otherwise.",
"Durable local storage is acceptable for the pilot."
],
"open_questions": [
"What are the target organization's data classes, legal bases, retention and external-disclosure rules?",
"Which identity, mail, file, address and monitoring systems are mandatory?",
"What are Campaign volume, concurrency, growth, availability, RPO and RTO?",
"Who owns each external runtime component and operational control?",
"Which accessibility, security, support and procurement constraints are mandatory?"
],
"risks": [
{
"id": "risk.reproducibility",
"statement": "The dirty, untagged workspace cannot be reproduced as a release.",
"impact": "Uncertain deployed behavior and unsafe promotion or rollback.",
"treatment": "Integrate scoped work and create a clean pinned release candidate.",
"owner": null,
"residual_risk": "Module and environment differences still require release-environment verification."
},
{
"id": "risk.delivery_provider",
"statement": "Target SMTP/IMAP behavior and failure modes are unproved.",
"impact": "Failed, delayed or duplicate communication and incomplete evidence.",
"treatment": "Run target-like interoperability, throttling and uncertainty drills.",
"owner": null,
"residual_risk": "External provider outages and ambiguous outcomes remain operational risks."
},
{
"id": "risk.recovery",
"statement": "Backup/restore and disaster recovery are not demonstrated across all state and keys.",
"impact": "Irrecoverable or inconsistent service after loss.",
"treatment": "Complete Core #29 and an isolated full-service restore/DR exercise.",
"owner": null,
"residual_risk": "Recovery time and data loss remain bounded by the selected external infrastructure."
}
],
"recommendations": [
"Proceed only with a controlled internal Campaign pilot after the bounded proof checks pass.",
"Use the minimal composition and enable Addresses only for an explicit reusable-recipient journey.",
"Do not claim Workflow, export-control screening, identity federation or production DR as implemented.",
"Treat a clean release candidate, target mail proof, monitoring and coherent restore drill as production gates."
],
"proof_checks": [
"Pin and build a clean matching backend/WebUI release candidate and rerun cross-repository gates.",
"Run a safe target-like Campaign through SMTP acceptance, IMAP append, reporting and audit.",
"Drill worker, Redis and ambiguous-delivery failures without duplicate sends.",
"Restore PostgreSQL, managed files, configuration and encrypted credentials and measure RPO/RTO.",
"Validate proxy/TLS, cookies/CORS, account bootstrap, secret redaction, monitoring and alert delivery.",
"Measure representative Campaign/file/queue/database load and external throttling."
]
}

View File

@@ -0,0 +1,298 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://git.add-ideas.de/add-ideas/govoplan/src/branch/main/docs/capability-fit.schema.json",
"title": "GovOPlaN capability and infrastructure fit assessment",
"type": "object",
"additionalProperties": false,
"required": [
"schema_version",
"assessment_id",
"assessed_at",
"scope",
"release",
"composition",
"deployment_profile",
"questionnaire",
"capabilities",
"infrastructure",
"data_flows",
"assumptions",
"open_questions",
"risks",
"recommendations",
"proof_checks"
],
"properties": {
"$schema": {
"type": "string",
"format": "uri-reference"
},
"schema_version": {
"const": "0.1.0"
},
"assessment_id": {
"$ref": "#/$defs/non_empty_string"
},
"assessed_at": {
"type": "string",
"format": "date"
},
"scope": {
"type": "object",
"additionalProperties": false,
"required": ["title", "reference_journeys", "postponed"],
"properties": {
"title": { "$ref": "#/$defs/non_empty_string" },
"reference_journeys": {
"type": "array",
"minItems": 1,
"items": { "$ref": "#/$defs/non_empty_string" }
},
"postponed": {
"type": "array",
"items": { "$ref": "#/$defs/non_empty_string" }
}
}
},
"release": {
"type": "object",
"additionalProperties": false,
"required": ["kind", "ref", "meta_commit", "reproducible", "configuration_packages"],
"properties": {
"kind": {
"enum": ["tagged_release", "release_candidate", "workspace_snapshot"]
},
"ref": { "$ref": "#/$defs/non_empty_string" },
"meta_commit": { "$ref": "#/$defs/non_empty_string" },
"reproducible": { "type": "boolean" },
"configuration_packages": {
"type": "array",
"items": { "$ref": "#/$defs/non_empty_string" }
},
"notes": {
"type": "array",
"items": { "$ref": "#/$defs/non_empty_string" }
}
}
},
"composition": {
"type": "array",
"minItems": 1,
"items": { "$ref": "#/$defs/module" }
},
"deployment_profile": {
"type": "object",
"additionalProperties": false,
"required": ["id", "status", "description", "evidence"],
"properties": {
"id": { "$ref": "#/$defs/non_empty_string" },
"status": { "$ref": "#/$defs/status" },
"description": { "$ref": "#/$defs/non_empty_string" },
"evidence": {
"type": "array",
"minItems": 1,
"items": { "$ref": "#/$defs/evidence" }
}
}
},
"questionnaire": {
"type": "object",
"additionalProperties": false,
"required": [
"scope_outcomes",
"data_policy",
"identity_integrations",
"workload_growth",
"availability_operations",
"procurement_decisions"
],
"properties": {
"scope_outcomes": { "$ref": "#/$defs/answers" },
"data_policy": { "$ref": "#/$defs/answers" },
"identity_integrations": { "$ref": "#/$defs/answers" },
"workload_growth": { "$ref": "#/$defs/answers" },
"availability_operations": { "$ref": "#/$defs/answers" },
"procurement_decisions": { "$ref": "#/$defs/answers" }
}
},
"capabilities": {
"type": "array",
"minItems": 1,
"items": { "$ref": "#/$defs/assessed_item" }
},
"infrastructure": {
"type": "array",
"minItems": 1,
"items": { "$ref": "#/$defs/assessed_item" }
},
"data_flows": {
"type": "array",
"minItems": 1,
"items": { "$ref": "#/$defs/data_flow" }
},
"assumptions": { "$ref": "#/$defs/string_list" },
"open_questions": { "$ref": "#/$defs/string_list" },
"risks": {
"type": "array",
"items": { "$ref": "#/$defs/risk" }
},
"recommendations": { "$ref": "#/$defs/string_list" },
"proof_checks": { "$ref": "#/$defs/string_list" }
},
"$defs": {
"non_empty_string": {
"type": "string",
"minLength": 1
},
"string_list": {
"type": "array",
"items": { "$ref": "#/$defs/non_empty_string" }
},
"status": {
"enum": [
"verified",
"available_unconfigured",
"partial",
"scaffold",
"external_system",
"planned",
"not_fit",
"not_assessed"
]
},
"evidence": {
"type": "object",
"additionalProperties": false,
"required": ["kind", "scope", "locator"],
"properties": {
"kind": {
"enum": [
"test",
"route",
"contract",
"drill",
"documentation",
"configuration",
"issue",
"absence",
"observation"
]
},
"scope": {
"enum": [
"committed_source",
"current_workspace",
"documented_model",
"target_environment"
]
},
"locator": { "$ref": "#/$defs/non_empty_string" },
"note": { "type": "string" }
}
},
"module": {
"type": "object",
"additionalProperties": false,
"required": [
"module_id",
"repository",
"commit",
"manifest_version",
"enabled",
"dirty",
"role"
],
"properties": {
"module_id": { "$ref": "#/$defs/non_empty_string" },
"repository": { "$ref": "#/$defs/non_empty_string" },
"commit": {
"type": "string",
"pattern": "^[0-9a-f]{7,40}$"
},
"manifest_version": { "$ref": "#/$defs/non_empty_string" },
"enabled": { "type": "boolean" },
"dirty": { "type": "boolean" },
"role": { "$ref": "#/$defs/non_empty_string" }
}
},
"answers": {
"type": "array",
"items": { "$ref": "#/$defs/answer" }
},
"answer": {
"type": "object",
"additionalProperties": false,
"required": ["id", "question", "state", "answer", "evidence"],
"properties": {
"id": { "$ref": "#/$defs/non_empty_string" },
"question": { "$ref": "#/$defs/non_empty_string" },
"state": {
"enum": ["answered", "assumed", "not_applicable", "not_assessed"]
},
"answer": {
"type": ["string", "array", "null"],
"items": { "type": "string" }
},
"evidence": {
"type": "array",
"items": { "$ref": "#/$defs/evidence" }
}
}
},
"assessed_item": {
"type": "object",
"additionalProperties": false,
"required": [
"id",
"requirement",
"status",
"evidence",
"conditions",
"gaps",
"risks",
"recommendation",
"proof_check"
],
"properties": {
"id": { "$ref": "#/$defs/non_empty_string" },
"requirement": { "$ref": "#/$defs/non_empty_string" },
"status": { "$ref": "#/$defs/status" },
"evidence": {
"type": "array",
"items": { "$ref": "#/$defs/evidence" }
},
"conditions": { "$ref": "#/$defs/string_list" },
"gaps": { "$ref": "#/$defs/string_list" },
"risks": { "$ref": "#/$defs/string_list" },
"recommendation": { "type": "string" },
"proof_check": { "type": "string" }
}
},
"data_flow": {
"type": "object",
"additionalProperties": false,
"required": ["id", "from", "to", "data", "trust_boundary", "controls"],
"properties": {
"id": { "$ref": "#/$defs/non_empty_string" },
"from": { "$ref": "#/$defs/non_empty_string" },
"to": { "$ref": "#/$defs/non_empty_string" },
"data": { "$ref": "#/$defs/string_list" },
"trust_boundary": { "$ref": "#/$defs/non_empty_string" },
"controls": { "$ref": "#/$defs/string_list" }
}
},
"risk": {
"type": "object",
"additionalProperties": false,
"required": ["id", "statement", "impact", "treatment", "owner", "residual_risk"],
"properties": {
"id": { "$ref": "#/$defs/non_empty_string" },
"statement": { "$ref": "#/$defs/non_empty_string" },
"impact": { "$ref": "#/$defs/non_empty_string" },
"treatment": { "$ref": "#/$defs/non_empty_string" },
"owner": { "type": ["string", "null"] },
"residual_risk": { "$ref": "#/$defs/non_empty_string" }
}
}
}
}

View File

@@ -11,6 +11,12 @@
"description": "New user-visible behavior or platform capability.", "description": "New user-visible behavior or platform capability.",
"exclusive": true "exclusive": true
}, },
{
"name": "type/user-story",
"color": "1d76db",
"description": "End-to-end user journey or real-world process story used to steer product slices.",
"exclusive": true
},
{ {
"name": "type/task", "name": "type/task",
"color": "1d76db", "color": "1d76db",

View File

@@ -27,12 +27,14 @@ STOP_DEPENDENCIES_ON_EXIT="${GOVOPLAN_STOP_PROFILE_DEPENDENCIES_ON_EXIT:-0}"
LOG_DIR="$META_ROOT/runtime/production-like/logs" LOG_DIR="$META_ROOT/runtime/production-like/logs"
BACKEND_LOG="$LOG_DIR/backend.log" BACKEND_LOG="$LOG_DIR/backend.log"
WORKER_LOG="$LOG_DIR/worker.log" WORKER_LOG="$LOG_DIR/worker.log"
BEAT_LOG="$LOG_DIR/beat.log"
FRONTEND_LOG="$LOG_DIR/frontend.log" FRONTEND_LOG="$LOG_DIR/frontend.log"
BACKEND_URL="http://$BACKEND_HOST:$BACKEND_PORT" BACKEND_URL="http://$BACKEND_HOST:$BACKEND_PORT"
FRONTEND_URL="http://$FRONTEND_HOST:$FRONTEND_PORT" FRONTEND_URL="http://$FRONTEND_HOST:$FRONTEND_PORT"
backend_pid="" backend_pid=""
worker_pid="" worker_pid=""
beat_pid=""
frontend_pid="" frontend_pid=""
fail() { fail() {
@@ -54,7 +56,7 @@ export DATABASE_URL="${DATABASE_URL:-${GOVOPLAN_PRODUCTION_LIKE_DATABASE_URL:-po
export GOVOPLAN_DATABASE_URL_PGTOOLS="${GOVOPLAN_DATABASE_URL_PGTOOLS:-${GOVOPLAN_PRODUCTION_LIKE_DATABASE_URL_PGTOOLS:-postgresql://govoplan:govoplan-dev@127.0.0.1:55433/govoplan}}" export GOVOPLAN_DATABASE_URL_PGTOOLS="${GOVOPLAN_DATABASE_URL_PGTOOLS:-${GOVOPLAN_PRODUCTION_LIKE_DATABASE_URL_PGTOOLS:-postgresql://govoplan:govoplan-dev@127.0.0.1:55433/govoplan}}"
export REDIS_URL="${REDIS_URL:-${GOVOPLAN_PRODUCTION_LIKE_REDIS_URL:-redis://127.0.0.1:56379/0}}" export REDIS_URL="${REDIS_URL:-${GOVOPLAN_PRODUCTION_LIKE_REDIS_URL:-redis://127.0.0.1:56379/0}}"
export CELERY_ENABLED="${CELERY_ENABLED:-true}" export CELERY_ENABLED="${CELERY_ENABLED:-true}"
export CELERY_QUEUES="${CELERY_QUEUES:-send_email,append_sent,default}" export CELERY_QUEUES="${CELERY_QUEUES:-send_email,append_sent,notifications,calendar,default}"
export FILE_STORAGE_BACKEND="${FILE_STORAGE_BACKEND:-local}" export FILE_STORAGE_BACKEND="${FILE_STORAGE_BACKEND:-local}"
export FILE_STORAGE_LOCAL_ROOT="${FILE_STORAGE_LOCAL_ROOT:-$META_ROOT/runtime/production-like/files}" export FILE_STORAGE_LOCAL_ROOT="${FILE_STORAGE_LOCAL_ROOT:-$META_ROOT/runtime/production-like/files}"
export DEV_AUTO_MIGRATE_ENABLED="${DEV_AUTO_MIGRATE_ENABLED:-false}" export DEV_AUTO_MIGRATE_ENABLED="${DEV_AUTO_MIGRATE_ENABLED:-false}"
@@ -146,6 +148,9 @@ cleanup() {
if [ -n "${worker_pid:-}" ] && kill -0 "$worker_pid" 2>/dev/null; then if [ -n "${worker_pid:-}" ] && kill -0 "$worker_pid" 2>/dev/null; then
kill "$worker_pid" 2>/dev/null || true kill "$worker_pid" 2>/dev/null || true
fi fi
if [ -n "${beat_pid:-}" ] && kill -0 "$beat_pid" 2>/dev/null; then
kill "$beat_pid" 2>/dev/null || true
fi
if [ "$STOP_DEPENDENCIES_ON_EXIT" = "1" ]; then if [ "$STOP_DEPENDENCIES_ON_EXIT" = "1" ]; then
compose down >/dev/null 2>&1 || true compose down >/dev/null 2>&1 || true
fi fi
@@ -160,6 +165,7 @@ trap cleanup EXIT INT TERM
mkdir -p "$LOG_DIR" "$FILE_STORAGE_LOCAL_ROOT" mkdir -p "$LOG_DIR" "$FILE_STORAGE_LOCAL_ROOT"
: > "$BACKEND_LOG" : > "$BACKEND_LOG"
: > "$WORKER_LOG" : > "$WORKER_LOG"
: > "$BEAT_LOG"
: > "$FRONTEND_LOG" : > "$FRONTEND_LOG"
port_is_free "$BACKEND_HOST" "$BACKEND_PORT" || fail "$BACKEND_URL is already in use" port_is_free "$BACKEND_HOST" "$BACKEND_PORT" || fail "$BACKEND_URL is already in use"
@@ -200,6 +206,14 @@ printf 'Starting Celery worker for queues %s\n' "$CELERY_QUEUES"
) >"$WORKER_LOG" 2>&1 & ) >"$WORKER_LOG" 2>&1 &
worker_pid="$!" worker_pid="$!"
printf 'Starting Celery beat for durable recovery schedules\n'
(
cd "$ROOT"
"$PYTHON" -m celery -A govoplan_core.celery_app:celery beat \
--loglevel INFO
) >"$BEAT_LOG" 2>&1 &
beat_pid="$!"
printf 'Starting GovOPlaN WebUI at %s\n' "$FRONTEND_URL" printf 'Starting GovOPlaN WebUI at %s\n' "$FRONTEND_URL"
( (
cd "$WEBUI_ROOT" cd "$WEBUI_ROOT"
@@ -235,10 +249,11 @@ Files: $FILE_STORAGE_LOCAL_ROOT
Logs: Logs:
Backend: $BACKEND_LOG Backend: $BACKEND_LOG
Worker: $WORKER_LOG Worker: $WORKER_LOG
Beat: $BEAT_LOG
WebUI: $FRONTEND_LOG WebUI: $FRONTEND_LOG
Docker dependencies remain running after Ctrl+C unless GOVOPLAN_STOP_PROFILE_DEPENDENCIES_ON_EXIT=1. Docker dependencies remain running after Ctrl+C unless GOVOPLAN_STOP_PROFILE_DEPENDENCIES_ON_EXIT=1.
Press Ctrl+C to stop API, worker, and WebUI. Press Ctrl+C to stop API, worker, beat, and WebUI.
EOF EOF
wait wait

View File

@@ -19,7 +19,7 @@ usage() {
Usage: tools/launch/production-like-dev.sh <command> [--yes] Usage: tools/launch/production-like-dev.sh <command> [--yes]
Commands: Commands:
start Start the production-like API, worker, WebUI, PostgreSQL, and Redis profile. start Start the production-like API, worker, scheduler, WebUI, PostgreSQL, and Redis profile.
stop Stop PostgreSQL and Redis profile containers. stop Stop PostgreSQL and Redis profile containers.
status Show profile container status and validate the effective environment. status Show profile container status and validate the effective environment.
seed Run migrations and seed development data against the profile database. seed Run migrations and seed development data against the profile database.
@@ -27,7 +27,7 @@ Commands:
validate-config Validate the profile environment only. validate-config Validate the profile environment only.
The start command delegates to tools/launch/launch-production-like-dev.sh. Stop/reset The start command delegates to tools/launch/launch-production-like-dev.sh. Stop/reset
operate on Docker dependencies; API/WebUI/worker processes started by the operate on Docker dependencies; API/WebUI/worker/scheduler processes started by the
launcher are stopped with Ctrl+C in that launcher terminal. launcher are stopped with Ctrl+C in that launcher terminal.
EOF EOF
} }