mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-11 13:17:07 +00:00
feat(design): leave the design queue by switching the design service off
The design queue skipped a hand-kept UI_LESS_ROLES list in cli/meta/roles/design. The decision now lives in each role: a web-app- or web-svc- role without a UI to design sets design.enabled: false in its meta/services.yml, and design_disabled() reads that flag. web-svc-design, the provider, stays out by its entity name. A new lint, test_design_off_reason.py, requires a design entry in every web-app- and web-svc- role and, where the entry is switched off, a "# nocheck: design-off Reason: <text>" on the design: line or the comment lines directly above it. The rule is in the suppression catalog, and requirement 037 decision 13 describes it. Twelve roles switch design off with a reason checked against their code: asset and simpleicons were already off; file, onlyoffice, bridgy-fed and mig were on and no longer receive the shared CSS and design script; cdn, collabora, coturn, legal, mirror and xmpp had no entry. The four that were on drop their bond and their design variant overrides, which the disabled-bond and variants-static-override lints reject on a literal false. The queue lists 77 candidates; HEAD's list also counted bridgy-fed, mig, collabora and onlyoffice. Cosmos diagrams and the integration matrix are regenerated. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
fb12d81ca2
commit
25a1f08ab7
33 files changed
+227
-84
No files matched your search
@@ -1,8 +1,8 @@
|
||||
"""Work queue of the corporate-design routine.
|
||||
|
||||
A role is a candidate when it is a ``web-app-`` or ``web-svc-`` role with a web
|
||||
UI of its own and its lifecycle sits inside the tested envelope. Every
|
||||
candidate carries exactly one state:
|
||||
A role is a candidate when it is a ``web-app-`` or ``web-svc-`` role, its
|
||||
lifecycle sits inside the tested envelope and its ``design`` service is not
|
||||
switched off with ``enabled: false``. Every candidate carries exactly one state:
|
||||
|
||||
* ``review``: its design spec is untracked or modified and waits for approval.
|
||||
* ``new``: HEAD carries no design spec for it.
|
||||
@@ -45,19 +45,7 @@ BASE_PATHS: tuple[str, ...] = (
|
||||
"utils/design/palette.py",
|
||||
)
|
||||
UI_PREFIXES: tuple[str, ...] = ("web-app-", "web-svc-")
|
||||
UI_LESS_ROLES: frozenset[str] = frozenset(
|
||||
{
|
||||
"web-svc-asset",
|
||||
"web-svc-cdn",
|
||||
"web-svc-coturn",
|
||||
"web-svc-design",
|
||||
"web-svc-file",
|
||||
"web-svc-legal",
|
||||
"web-svc-mirror",
|
||||
"web-svc-simpleicons",
|
||||
"web-svc-xmpp",
|
||||
}
|
||||
)
|
||||
DESIGN_ENTITY = "design"
|
||||
|
||||
STATE_REVIEW = "review"
|
||||
STATE_NEW = "new"
|
||||
@@ -324,9 +312,25 @@ def _primary_version(services: object, role: str) -> str | None:
|
||||
return str(entry["version"]).strip() or None
|
||||
|
||||
|
||||
def design_disabled(role_dir: Path) -> bool:
|
||||
"""Whether a role switches its ``design`` service off.
|
||||
|
||||
Args:
|
||||
role_dir: Directory of the role.
|
||||
|
||||
Returns:
|
||||
``True`` when ``meta/services.yml`` sets ``design.enabled`` to the
|
||||
literal ``false``; a templated or missing flag counts as on.
|
||||
"""
|
||||
entry = read_yaml_file(role_dir / ROLE_FILE_META_SERVICES).get(DESIGN_ENTITY)
|
||||
return isinstance(entry, dict) and entry.get("enabled") is False
|
||||
|
||||
|
||||
def _is_candidate(role_dir: Path, envelope: frozenset[str]) -> bool:
|
||||
role = role_dir.name
|
||||
if not role.startswith(UI_PREFIXES) or role in UI_LESS_ROLES:
|
||||
if not role.startswith(UI_PREFIXES) or get_entity_name(role) == DESIGN_ENTITY:
|
||||
return False
|
||||
if design_disabled(role_dir):
|
||||
return False
|
||||
return get_role_lifecycle(role_dir, role_name=role) in envelope
|
||||
|
||||
@@ -338,10 +342,11 @@ def candidate_roles(roles_dir: Path) -> list[str]:
|
||||
roles_dir: Directory holding the roles.
|
||||
|
||||
Returns:
|
||||
Sorted names of the ``web-app-`` and ``web-svc-`` roles that have a web
|
||||
UI of their own and carry a lifecycle inside the tested envelope. A
|
||||
role without a ``design`` service entry is included: its design pass
|
||||
adds the entry.
|
||||
Sorted names of the ``web-app-`` and ``web-svc-`` roles that carry a
|
||||
lifecycle inside the tested envelope and do not switch their ``design``
|
||||
service off (see :func:`design_disabled`). ``web-svc-design``, the
|
||||
provider, is no candidate. A role without a ``design`` service entry is
|
||||
included: its design pass adds the entry.
|
||||
"""
|
||||
envelope = tested_lifecycles()
|
||||
return [
|
||||
|
||||
@@ -75,6 +75,7 @@ The placement rule is per check. The catalog "Position" column uses these labels
|
||||
| `raw-docker` | same or above; head (first 30 lines) | [test_no_raw_docker.py](../../../../tests/integration/infrastructure/docker/test_no_raw_docker.py) | Marks a single line or a whole file under `roles/` as legitimately calling `docker` / `docker compose` / `docker-compose` directly. |
|
||||
| `hardcoded-dns-resolver` | same or above | [test_no_hardcoded_dns_resolvers.py](../../../../tests/lint/repository/network/test_no_hardcoded_dns_resolvers.py) | Marks a line that needs a literal IP from `NETWORK_PUBLIC_DNS_RESOLVERS` where the substitution point cannot consume the variable (CoreDNS non-Jinja templates, host-bootstrap shell, doc examples). |
|
||||
| `dynamic-flag` | same line OR comment block above key | [test_dynamic_flags.py](../../../../tests/integration/roles/meta/services/test_dynamic_flags.py) | Marks a `roles/*/meta/services.yml` flag whose value stays literal. Per-flag (same line) for databases. Block-level (comment block above) when both flags stay literal. |
|
||||
| `design-off` | line or comment block above `design:` | [test_design_off_reason.py](../../../../tests/integration/roles/meta/services/test_design_off_reason.py) | Required with `Reason: <text>` on a `design.enabled: false` in a `web-app-`/`web-svc-` role. Keeps the role out of the design queue and off the shared CSS. |
|
||||
| `native-metrics` | comment block above | [test_native_metrics_contract.py](../../../../tests/integration/roles/meta/services/prometheus/test_native_metrics_contract.py) | Marks a role whose `services.prometheus.native_metrics.enabled` and `templates/prometheus.yml.j2` presence are intentionally inconsistent. Reserved for prepared-but-default-off scrape fragments (operator opt-in). |
|
||||
| `prometheus-scrape` | same or above | [test_roles_with_service.py](../../../../tests/unit/python/plugins/lookup/test_roles_with_service.py) | Documents a `services.prometheus.scrape: false` opt-out in `roles/<role>/meta/services.yml`. The role keeps `services.prometheus.{enabled,shared}: true` (so the role-wiring contract stays satisfied) but `roles_with_service('prometheus')` drops it from `PROMETHEUS_TARGET_ROLES_JSON`. Reserved for 301-redirect-only vhosts that never serve a request through lua-resty-prometheus, so they emit no `app="<role>"` label and have no scrape target. The marker accompanies the `scrape:` data flag the lookup honors. |
|
||||
| `matomo-track` | same or above | [test_roles_with_service.py](../../../../tests/unit/python/plugins/lookup/test_roles_with_service.py) | Documents a `services.matomo.track: false` opt-out in `roles/<role>/meta/services.yml`. The role keeps `services.matomo.{enabled,shared}: true` (so the role-wiring contract stays satisfied) but `roles_with_service('matomo')` drops it from `MATOMO_TARGET_ROLES_JSON` and the matomo tracker e2e contract. Reserved for static-file (autoindex) and 301-redirect vhosts that carry no user-facing HTML page worth a `_paq` tracker. The marker accompanies the `track:` data flag the lookup honors. |
|
||||
|
||||
@@ -106,19 +106,19 @@ Notes:
|
||||
| ↓ row wires → col | akaunting | baserow | bigbluebutton | bluesky | bookwyrm | bridgy-fed | chess | confluence | dashboard | decidim | ↓ row wires → col | discourse | erpnext | espocrm | fediwall | fider | flowise | friendica | funkwhale | fusiondirectory | gitea | ↓ row wires → col | gitlab | hugo | jenkins | jira | jitsi | joomla | keycloak | kix | lam | listmonk | ↓ row wires → col | litellm | littlejs | magento | mailu | mastodon | matomo | matrix | mattermost | mediawiki | mig | ↓ row wires → col | minio | mini-qr | mobilizon | moodle | n8n | navigator | nextcloud | odoo | opencloud | openproject | ↓ row wires → col | opentalk | openwebui | peertube | pgadmin | phpldapadmin | phpmyadmin | pixelfed | postmarks | pretix | prometheus | ↓ row wires → col | roulette-wheel | shopware | snipe-it | socialhome | sphinx | suitecrm | taiga | wordpress | xwiki | yourls | ↓ row wires → col | zammad | asset | cdn | collabora | coturn | design | file | html | legal | libretranslate | ↓ row wires → col | logout | onlyoffice | simpleicons | xmpp |
|
||||
| **zammad** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-app-zammad/meta/services.yml) | ❌ | **zammad** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **zammad** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | [✅](https://admin-docs.zammad.org/en/latest/settings/security/third-party/saml.html) | ❌ | ❌ | ❌ | **zammad** | [☑️](../../roles/web-app-zammad/meta/services.yml) | ❌ | ❌ | [✅](https://admin-docs.zammad.org/en/latest/channels/email/index.html) | ❌ | [☑️](../../roles/web-app-zammad/meta/services.yml) | ❌ | ❌ | ❌ | ❌ | **zammad** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **zammad** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-app-zammad/meta/services.yml) | **zammad** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **zammad** | — | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-app-zammad/meta/services.yml) | ❌ | ❌ | ❌ | ❌ | **zammad** | [☑️](../../roles/web-app-zammad/meta/services.yml) | ❌ | ❌ | ❌ |
|
||||
| **asset** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **asset** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **asset** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **asset** | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-asset/meta/services.yml) | ❌ | ❌ | ❌ | ❌ | **asset** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **asset** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-asset/meta/services.yml) | **asset** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **asset** | ❌ | — | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-asset/meta/services.yml) | ❌ | ❌ | ❌ | ❌ | **asset** | ❌ | ❌ | ❌ | ❌ |
|
||||
| **cdn** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-cdn/meta/services.yml) | ❌ | **cdn** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **cdn** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **cdn** | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-cdn/meta/services.yml) | ❌ | ❌ | ❌ | ❌ | **cdn** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **cdn** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-cdn/meta/services.yml) | **cdn** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **cdn** | ❌ | ❌ | — | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **cdn** | ❌ | ❌ | ❌ | ❌ |
|
||||
| **collabora** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **collabora** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **collabora** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **collabora** | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-collabora/meta/services.yml) | ❌ | ❌ | ❌ | ❌ | **collabora** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **collabora** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-collabora/meta/services.yml) | **collabora** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **collabora** | ❌ | ❌ | ❌ | — | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **collabora** | ❌ | ❌ | ❌ | ❌ |
|
||||
| **coturn** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **coturn** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **coturn** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **coturn** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **coturn** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **coturn** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-coturn/meta/services.yml) | **coturn** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **coturn** | ❌ | ❌ | ❌ | ❌ | — | ❌ | ❌ | ❌ | ❌ | ❌ | **coturn** | ❌ | ❌ | ❌ | ❌ |
|
||||
| **cdn** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-cdn/meta/services.yml) | ❌ | **cdn** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **cdn** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **cdn** | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-cdn/meta/services.yml) | ❌ | ❌ | ❌ | ❌ | **cdn** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **cdn** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-cdn/meta/services.yml) | **cdn** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **cdn** | ❌ | ❌ | — | ❌ | ❌ | [☑️](../../roles/web-svc-cdn/meta/services.yml) | ❌ | ❌ | ❌ | ❌ | **cdn** | ❌ | ❌ | ❌ | ❌ |
|
||||
| **collabora** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **collabora** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **collabora** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **collabora** | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-collabora/meta/services.yml) | ❌ | ❌ | ❌ | ❌ | **collabora** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **collabora** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-collabora/meta/services.yml) | **collabora** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **collabora** | ❌ | ❌ | ❌ | — | ❌ | [☑️](../../roles/web-svc-collabora/meta/services.yml) | ❌ | ❌ | ❌ | ❌ | **collabora** | ❌ | ❌ | ❌ | ❌ |
|
||||
| **coturn** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **coturn** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **coturn** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **coturn** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **coturn** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **coturn** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-coturn/meta/services.yml) | **coturn** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **coturn** | ❌ | ❌ | ❌ | ❌ | — | [☑️](../../roles/web-svc-coturn/meta/services.yml) | ❌ | ❌ | ❌ | ❌ | **coturn** | ❌ | ❌ | ❌ | ❌ |
|
||||
| **design** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **design** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **design** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **design** | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-design/meta/services.yml) | ❌ | ❌ | ❌ | ❌ | **design** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **design** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-design/meta/services.yml) | **design** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **design** | ❌ | ❌ | [☑️](../../roles/web-svc-design/meta/services.yml) | ❌ | ❌ | — | ❌ | ❌ | ❌ | ❌ | **design** | ❌ | ❌ | ❌ | ❌ |
|
||||
| **file** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **file** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **file** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **file** | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-file/meta/services.yml) | ❌ | ❌ | ❌ | ❌ | **file** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **file** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-file/meta/services.yml) | **file** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **file** | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-file/meta/services.yml) | — | ❌ | ❌ | ❌ | **file** | ❌ | ❌ | ❌ | ❌ |
|
||||
| **html** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **html** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **html** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **html** | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-html/meta/services.yml) | ❌ | ❌ | ❌ | ❌ | **html** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **html** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-html/meta/services.yml) | **html** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **html** | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-html/meta/services.yml) | ❌ | — | ❌ | ❌ | **html** | ❌ | ❌ | ❌ | ❌ |
|
||||
| **legal** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **legal** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **legal** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **legal** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **legal** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **legal** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-legal/meta/services.yml) | **legal** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **legal** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | — | ❌ | **legal** | ❌ | ❌ | ❌ | ❌ |
|
||||
| **legal** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **legal** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **legal** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **legal** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **legal** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **legal** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-legal/meta/services.yml) | **legal** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **legal** | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-legal/meta/services.yml) | ❌ | ❌ | — | ❌ | **legal** | ❌ | ❌ | ❌ | ❌ |
|
||||
| **libretranslate** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **libretranslate** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **libretranslate** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-libretranslate/meta/services.yml) | ❌ | ❌ | ❌ | **libretranslate** | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-libretranslate/meta/services.yml) | ❌ | ❌ | ❌ | ❌ | **libretranslate** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **libretranslate** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-libretranslate/meta/services.yml) | **libretranslate** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **libretranslate** | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-libretranslate/meta/services.yml) | ❌ | ❌ | ❌ | — | **libretranslate** | [☑️](../../roles/web-svc-libretranslate/meta/services.yml) | ❌ | ❌ | ❌ |
|
||||
| ↓ row wires → col | akaunting | baserow | bigbluebutton | bluesky | bookwyrm | bridgy-fed | chess | confluence | dashboard | decidim | ↓ row wires → col | discourse | erpnext | espocrm | fediwall | fider | flowise | friendica | funkwhale | fusiondirectory | gitea | ↓ row wires → col | gitlab | hugo | jenkins | jira | jitsi | joomla | keycloak | kix | lam | listmonk | ↓ row wires → col | litellm | littlejs | magento | mailu | mastodon | matomo | matrix | mattermost | mediawiki | mig | ↓ row wires → col | minio | mini-qr | mobilizon | moodle | n8n | navigator | nextcloud | odoo | opencloud | openproject | ↓ row wires → col | opentalk | openwebui | peertube | pgadmin | phpldapadmin | phpmyadmin | pixelfed | postmarks | pretix | prometheus | ↓ row wires → col | roulette-wheel | shopware | snipe-it | socialhome | sphinx | suitecrm | taiga | wordpress | xwiki | yourls | ↓ row wires → col | zammad | asset | cdn | collabora | coturn | design | file | html | legal | libretranslate | ↓ row wires → col | logout | onlyoffice | simpleicons | xmpp |
|
||||
| **logout** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **logout** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **logout** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **logout** | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-logout/meta/services.yml) | ❌ | ❌ | ❌ | ❌ | **logout** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **logout** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-logout/meta/services.yml) | **logout** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **logout** | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-logout/meta/services.yml) | ❌ | ❌ | ❌ | ❌ | **logout** | — | ❌ | ❌ | ❌ |
|
||||
| **onlyoffice** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **onlyoffice** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **onlyoffice** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **onlyoffice** | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-onlyoffice/meta/services.yml) | ❌ | ❌ | ❌ | ❌ | **onlyoffice** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **onlyoffice** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-onlyoffice/meta/services.yml) | **onlyoffice** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **onlyoffice** | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-onlyoffice/meta/services.yml) | ❌ | ❌ | ❌ | ❌ | **onlyoffice** | ❌ | — | ❌ | ❌ |
|
||||
| **simpleicons** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-simpleicons/meta/services.yml) | ❌ | **simpleicons** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **simpleicons** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-simpleicons/meta/services.yml) | ❌ | ❌ | ❌ | **simpleicons** | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-simpleicons/meta/services.yml) | ❌ | ❌ | ❌ | ❌ | **simpleicons** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **simpleicons** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-simpleicons/meta/services.yml) | **simpleicons** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **simpleicons** | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-simpleicons/meta/services.yml) | ❌ | ❌ | ❌ | ❌ | **simpleicons** | ❌ | ❌ | — | ❌ |
|
||||
| **xmpp** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **xmpp** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **xmpp** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-xmpp/meta/services.yml) | ❌ | ❌ | ❌ | **xmpp** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **xmpp** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **xmpp** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-xmpp/meta/services.yml) | **xmpp** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **xmpp** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **xmpp** | [☑️](../../roles/web-svc-xmpp/meta/services.yml) | ❌ | ❌ | — |
|
||||
| **xmpp** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **xmpp** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **xmpp** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-xmpp/meta/services.yml) | ❌ | ❌ | ❌ | **xmpp** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **xmpp** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **xmpp** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-xmpp/meta/services.yml) | **xmpp** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | **xmpp** | ❌ | ❌ | ❌ | ❌ | ❌ | [☑️](../../roles/web-svc-xmpp/meta/services.yml) | ❌ | ❌ | ❌ | ❌ | **xmpp** | [☑️](../../roles/web-svc-xmpp/meta/services.yml) | ❌ | ❌ | — |
|
||||
|
||||
## Maintenance
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ These choices are settled at requirement creation time and bound the implementat
|
||||
10. **Verification.** Every change passes `make quality-high` and a minimal compose deploy against the running stack: `make compose-deploy apps=<role> variant=0 disable=<every disableable service except design>` (default `initialize` mode, no teardown, single pass, no `full_cycle`). CSS and branding iterations run without a redeploy through `make design-sync app=<role> variant=0` (re-renders shared CSS, role `style.css` and the generated logo assets). A changed `design.js`, task, template or `meta/` file runs through `make compose-role-sync role=<role> variant=0`, which re-runs only the app role against the running stack and renders the CSP hash in the vhost with it. A role pass runs `make test` and the lint targets of the file types it touched after its last edit, and closes with a role sync and the complete role spec; a pass that changed provisioning runs that role sync twice, and the second run reports no change for the tasks it added. `make quality-high` runs once per two or three role passes, at every merge of the main branch and before a role is committed. Each role is also asserted with one further base color, blue `#001f3f`, through `base=` on the sync targets. Swarm verification is out of scope.
|
||||
11. **Review gallery.** Each role gets its own private Artifact with at least 20 views, each captured in light and dark mode and in a desktop (1440×900) and a mobile (390×844) viewport, so at least 80 screenshots of the designed state per role. The views favour detail-rich surfaces: settings, administration, forms, lists and detail pages, logged in where the app has accounts, with idempotently seeded showcase content where a list or detail page would otherwise be empty. `make design-gallery app=<role>` captures them in one spec run and copies them to `/tmp/design-gallery/<role>/`. A comparison with the app before the design is captured on request only: `before=true` adds every view with every injected snippet stripped from the document (the body filter wraps its injections in `<!--infinito-inj-->` markers). The operator approves or rejects by comment.
|
||||
12. **Frontend and backend.** Every role is styled and tested on its frontend and, where the app has one, on its separate backend (admin surface such as `wp-admin`, the Shopware or Magento admin, the Joomla administrator). A role with a backend shows backend views in its gallery in addition to the frontend views, and its Playwright spec covers both surfaces.
|
||||
13. **Scope.** In-scope roles are invokable, carry a lifecycle inside the tested envelope (`alpha` to `maintenance`), and expose a web UI.
|
||||
13. **Scope.** In-scope roles are invokable, carry a lifecycle inside the tested envelope (`alpha` to `maintenance`), and expose a web UI. A `web-app-` or `web-svc-` role without a UI to design sets `design.enabled: false` in its `meta/services.yml` with `# nocheck: design-off Reason: <text>`, which a lint enforces, and `make design-queue` skips it: `web-app-bridgy-fed`, `web-app-mig` (operator decision), `web-svc-asset`, `web-svc-cdn`, `web-svc-collabora`, `web-svc-coturn`, `web-svc-file`, `web-svc-legal`, `web-svc-mirror`, `web-svc-onlyoffice`, `web-svc-simpleicons` and `web-svc-xmpp`.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
@@ -55,7 +55,6 @@ A role is checked when its frontend and, where present, its backend are styled,
|
||||
- [ ] web-app-bigbluebutton
|
||||
- [ ] web-app-bluesky
|
||||
- [ ] web-app-bookwyrm
|
||||
- [ ] web-app-bridgy-fed
|
||||
- [ ] web-app-checkmk
|
||||
- [ ] web-app-chess
|
||||
- [ ] web-app-dashboard
|
||||
@@ -90,7 +89,6 @@ A role is checked when its frontend and, where present, its backend are styled,
|
||||
- [ ] web-app-matrix
|
||||
- [ ] web-app-mattermost
|
||||
- [ ] web-app-mediawiki
|
||||
- [ ] web-app-mig
|
||||
- [ ] web-app-mini-qr
|
||||
- [ ] web-app-mobilizon
|
||||
- [ ] web-app-moodle
|
||||
@@ -126,12 +124,9 @@ A role is checked when its frontend and, where present, its backend are styled,
|
||||
- [ ] web-app-xwiki
|
||||
- [ ] web-app-yourls
|
||||
- [ ] web-app-zammad
|
||||
- [ ] web-svc-collabora
|
||||
- [ ] web-svc-html
|
||||
- [ ] web-svc-legal
|
||||
- [ ] web-svc-libretranslate
|
||||
- [ ] web-svc-logout
|
||||
- [ ] web-svc-onlyoffice
|
||||
|
||||
## Cross-linking
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ flowchart LR
|
||||
dep_web_app_matomo["web-app-matomo 🐳🐝"]
|
||||
dep_web_app_prometheus["web-app-prometheus 🐳🐝"]
|
||||
dep_web_app_stalwart["web-app-stalwart 🐳🐝"]
|
||||
dep_web_svc_design["web-svc-design 💻"]
|
||||
end
|
||||
subgraph role [web-app-bridgy-fed 🐳🐝]
|
||||
svc_logout["logout ❌"]
|
||||
@@ -29,7 +28,7 @@ flowchart LR
|
||||
svc_dashboard["dashboard"]
|
||||
svc_email["email ❌"]
|
||||
svc_matomo["matomo"]
|
||||
svc_design["design"]
|
||||
svc_design["design ❌"]
|
||||
svc_prometheus["prometheus"]
|
||||
svc_bridgy_fed["bridgy-fed"]
|
||||
svc_tor["tor"]
|
||||
@@ -40,7 +39,6 @@ flowchart LR
|
||||
dep_web_app_matomo -. "0..1" .-> svc_matomo
|
||||
dep_web_app_prometheus -. "0..1" .-> svc_prometheus
|
||||
dep_web_app_stalwart -- "0..0" --> svc_email
|
||||
dep_web_svc_design -. "0..1" .-> svc_design
|
||||
linkStyle 2,5 stroke:red;
|
||||
```
|
||||
|
||||
|
||||
@@ -28,10 +28,11 @@ matomo:
|
||||
# nocheck: matomo-track - root serves Werkzeug's default 404 without </head>/<body>, head injection cannot anchor
|
||||
track: false
|
||||
# nocheck: playwright-service-flag - design consumer, no Playwright surface (provider: web-svc-design)
|
||||
# nocheck: dynamic-flag
|
||||
# nocheck: design-off Reason: flask_app serves only federation endpoints; '/' answers Werkzeug's bare 404
|
||||
design:
|
||||
bond: 1
|
||||
enabled: "{{ 'web-svc-design' in group_names }}"
|
||||
shared: "{{ 'web-svc-design' in group_names }}"
|
||||
enabled: false
|
||||
shared: false
|
||||
# nocheck: matomo-track - same 404-without-anchors page, shared CSS <link> cannot inject
|
||||
track: false
|
||||
prometheus:
|
||||
|
||||
@@ -14,9 +14,6 @@
|
||||
prometheus:
|
||||
enabled: true
|
||||
shared: true
|
||||
design:
|
||||
enabled: true
|
||||
shared: true
|
||||
tor:
|
||||
enabled: true
|
||||
- services:
|
||||
@@ -29,8 +26,5 @@
|
||||
prometheus:
|
||||
enabled: false
|
||||
shared: false
|
||||
design:
|
||||
enabled: false
|
||||
shared: false
|
||||
tor:
|
||||
enabled: true
|
||||
@@ -23,7 +23,6 @@ flowchart LR
|
||||
dep_web_app_keycloak["web-app-keycloak 🐳🐝"]
|
||||
dep_web_app_matomo["web-app-matomo 🐳🐝"]
|
||||
dep_web_app_prometheus["web-app-prometheus 🐳🐝"]
|
||||
dep_web_svc_design["web-svc-design 💻"]
|
||||
end
|
||||
subgraph role [web-app-mig 🐳🐝]
|
||||
svc_logout["logout ❌"]
|
||||
@@ -32,7 +31,7 @@ flowchart LR
|
||||
svc_matomo["matomo"]
|
||||
svc_redis["redis"]
|
||||
svc_mig["mig"]
|
||||
svc_design["design"]
|
||||
svc_design["design ❌"]
|
||||
svc_prometheus["prometheus"]
|
||||
svc_tor["tor"]
|
||||
end
|
||||
@@ -42,7 +41,6 @@ flowchart LR
|
||||
dep_web_app_keycloak -- "0..0" --> svc_sso
|
||||
dep_web_app_matomo -. "0..1" .-> svc_matomo
|
||||
dep_web_app_prometheus -. "0..1" .-> svc_prometheus
|
||||
dep_web_svc_design -. "0..1" .-> svc_design
|
||||
linkStyle 3 stroke:red;
|
||||
```
|
||||
|
||||
|
||||
@@ -49,10 +49,11 @@ mig:
|
||||
mem_limit: 256m
|
||||
pids_limit: 256
|
||||
# nocheck: playwright-service-flag — design consumer, no Playwright surface (provider: web-svc-design)
|
||||
# nocheck: dynamic-flag
|
||||
# nocheck: design-off Reason: out of the design scope by operator decision; the pinned image's graph never renders (TODO.md)
|
||||
design:
|
||||
bond: 1
|
||||
enabled: "{{ 'web-svc-design' in group_names }}"
|
||||
shared: "{{ 'web-svc-design' in group_names }}"
|
||||
enabled: false
|
||||
shared: false
|
||||
prometheus:
|
||||
bond: 1
|
||||
enabled: "{{ 'web-app-prometheus' in group_names }}"
|
||||
|
||||
@@ -16,9 +16,6 @@
|
||||
prometheus:
|
||||
enabled: true
|
||||
shared: true
|
||||
design:
|
||||
enabled: true
|
||||
shared: true
|
||||
tor:
|
||||
enabled: true
|
||||
- services:
|
||||
@@ -33,8 +30,5 @@
|
||||
prometheus:
|
||||
enabled: false
|
||||
shared: false
|
||||
design:
|
||||
enabled: false
|
||||
shared: false
|
||||
tor:
|
||||
enabled: true
|
||||
@@ -28,6 +28,7 @@ matomo:
|
||||
# nocheck: matomo-track
|
||||
track: false
|
||||
# nocheck: dynamic-flag
|
||||
# nocheck: design-off Reason: the asset domain redirects onto web-svc-file, which serves the copied assets; no page of its own
|
||||
design:
|
||||
enabled: false
|
||||
shared: false
|
||||
|
||||
@@ -27,6 +27,7 @@ flowchart LR
|
||||
svc_build["build"]
|
||||
svc_matomo["matomo"]
|
||||
svc_javascript["javascript"]
|
||||
svc_design["design ❌"]
|
||||
svc_prometheus["prometheus"]
|
||||
svc_tor["tor"]
|
||||
end
|
||||
|
||||
@@ -48,6 +48,12 @@ javascript:
|
||||
enabled: false
|
||||
shared: true
|
||||
canonical: cdn
|
||||
# nocheck: playwright-service-flag — design consumer, no Playwright surface (provider: web-svc-design)
|
||||
# nocheck: dynamic-flag
|
||||
# nocheck: design-off Reason: serves the shared stylesheets and the npm-mirrored libraries the other roles load; its only HTML is nginx's autoindex listing (templates/proxy.conf.j2)
|
||||
design:
|
||||
enabled: false
|
||||
shared: false
|
||||
# nocheck: playwright-service-flag — /metrics endpoint covered by web-app-prometheus's own spec
|
||||
prometheus:
|
||||
bond: 1
|
||||
|
||||
@@ -27,6 +27,7 @@ flowchart LR
|
||||
svc_matomo["matomo"]
|
||||
svc_redis["redis"]
|
||||
svc_collabora["collabora"]
|
||||
svc_design["design ❌"]
|
||||
svc_prometheus["prometheus"]
|
||||
svc_tor["tor"]
|
||||
end
|
||||
|
||||
@@ -40,6 +40,11 @@ collabora:
|
||||
proxy:
|
||||
service_key: collabora
|
||||
lifecycle: beta
|
||||
# nocheck: dynamic-flag
|
||||
# nocheck: design-off Reason: '/' answers a plain OK, the admin console is off and the editor opens only as a POST from the WOPI host (Nextcloud)
|
||||
design:
|
||||
enabled: false
|
||||
shared: false
|
||||
prometheus:
|
||||
bond: 1
|
||||
enabled: "{{ 'web-app-prometheus' in group_names }}"
|
||||
|
||||
@@ -48,6 +48,7 @@ flowchart LR
|
||||
svc_coturn["coturn"]
|
||||
svc_gateway["gateway"]
|
||||
svc_redis["redis"]
|
||||
svc_design["design ❌"]
|
||||
svc_prometheus["prometheus"]
|
||||
svc_tor["tor ❌"]
|
||||
svc_container_backup["container_backup"]
|
||||
|
||||
@@ -42,6 +42,11 @@ redis:
|
||||
disabled: true
|
||||
enabled: false
|
||||
shared: "{{ 'svc-db-redis' in group_names }}"
|
||||
# nocheck: dynamic-flag
|
||||
# nocheck: design-off Reason: TURN/STUN relay; its only HTTP is a gateway answering a plain-text OK (templates/compose.yml.j2)
|
||||
design:
|
||||
enabled: false
|
||||
shared: false
|
||||
# nocheck: variants-coverage — the tor conjunct is the clearnet-variant-tor invariant below, so no variant may pin the true polarity on an onion node
|
||||
# nocheck: bond-baseline — same reason: variant 0 must not pin the scrape consumer on
|
||||
prometheus:
|
||||
|
||||
@@ -47,13 +47,13 @@ flowchart LR
|
||||
dpt_web_app_bigbluebutton["web-app-bigbluebutton 🐳🐝"]
|
||||
dpt_web_app_bluesky["web-app-bluesky 🐳🐝"]
|
||||
dpt_web_app_bookwyrm["web-app-bookwyrm 🐳🐝"]
|
||||
dpt_web_app_bridgy_fed["web-app-bridgy-fed 🐳🐝"]
|
||||
dpt_web_app_checkmk["web-app-checkmk 🐳🐝"]
|
||||
dpt_web_app_chess["web-app-chess 🐳🐝"]
|
||||
dpt_web_app_confluence["web-app-confluence 🐳🐝"]
|
||||
dpt_web_app_dashboard["web-app-dashboard 🐳🐝"]
|
||||
dpt_web_app_decidim["web-app-decidim 🐳🐝"]
|
||||
dpt_web_app_discourse["web-app-discourse 🐳🐝"]
|
||||
dpt_web_app_erpnext["web-app-erpnext 🐳🐝"]
|
||||
dpt_more["..."]
|
||||
end
|
||||
dep_svc_net_tor -. "0..1" .-> svc_tor
|
||||
@@ -65,13 +65,13 @@ flowchart LR
|
||||
svc_design -. "0..1" .-> dpt_web_app_bigbluebutton
|
||||
svc_design -. "0..1" .-> dpt_web_app_bluesky
|
||||
svc_design -. "0..1" .-> dpt_web_app_bookwyrm
|
||||
svc_design -. "0..1" .-> dpt_web_app_bridgy_fed
|
||||
svc_design -. "0..1" .-> dpt_web_app_checkmk
|
||||
svc_design -. "0..1" .-> dpt_web_app_chess
|
||||
svc_design -. "0..1" .-> dpt_web_app_confluence
|
||||
svc_design -. "0..1" .-> dpt_web_app_dashboard
|
||||
svc_design -. "0..1" .-> dpt_web_app_decidim
|
||||
svc_design -. "0..1" .-> dpt_web_app_discourse
|
||||
svc_design -. "0..1" .-> dpt_web_app_erpnext
|
||||
```
|
||||
|
||||
Solid `1:1` edges are fixed relationships; dashed `0..1` edges are conditional (enabled only in matching deployments); red `0..0` edges are turned off in this role. Node markers show the role's deploy modes (💻 host, 🐳 compose, 🐝 swarm); ❌ marks a service that is explicitly turned off, and ⚙️ an Ansible role dependency declared in `meta/main.yml`.
|
||||
|
||||
@@ -18,12 +18,11 @@ flowchart LR
|
||||
dep_svc_net_tor["svc-net-tor 🐳🐝"]
|
||||
dep_web_app_matomo["web-app-matomo 🐳🐝"]
|
||||
dep_web_app_prometheus["web-app-prometheus 🐳🐝"]
|
||||
dep_web_svc_design["web-svc-design 💻"]
|
||||
end
|
||||
subgraph role [web-svc-file 💻]
|
||||
svc_file["file"]
|
||||
svc_matomo["matomo"]
|
||||
svc_design["design"]
|
||||
svc_design["design ❌"]
|
||||
svc_prometheus["prometheus"]
|
||||
svc_tor["tor"]
|
||||
end
|
||||
@@ -33,7 +32,6 @@ flowchart LR
|
||||
dep_svc_net_tor -. "0..1" .-> svc_tor
|
||||
dep_web_app_matomo -. "0..1" .-> svc_matomo
|
||||
dep_web_app_prometheus -. "0..1" .-> svc_prometheus
|
||||
dep_web_svc_design -. "0..1" .-> svc_design
|
||||
svc_file -- "1:1" --> dpt_web_svc_asset
|
||||
```
|
||||
|
||||
|
||||
@@ -18,10 +18,11 @@ matomo:
|
||||
shared: "{{ 'web-app-matomo' in group_names }}"
|
||||
# nocheck: matomo-track
|
||||
track: false
|
||||
# nocheck: dynamic-flag
|
||||
# nocheck: design-off Reason: plain file server; its only HTML is nginx's autoindex listing (templates/proxy.conf.j2)
|
||||
design:
|
||||
bond: 1
|
||||
enabled: "{{ 'web-svc-design' in group_names }}"
|
||||
shared: "{{ 'web-svc-design' in group_names }}"
|
||||
enabled: false
|
||||
shared: false
|
||||
prometheus:
|
||||
bond: 1
|
||||
enabled: "{{ 'web-app-prometheus' in group_names }}"
|
||||
|
||||
@@ -12,9 +12,6 @@
|
||||
prometheus:
|
||||
enabled: true
|
||||
shared: true
|
||||
design:
|
||||
enabled: true
|
||||
shared: true
|
||||
tor:
|
||||
enabled: true
|
||||
- services:
|
||||
@@ -24,8 +21,5 @@
|
||||
prometheus:
|
||||
enabled: false
|
||||
shared: false
|
||||
design:
|
||||
enabled: false
|
||||
shared: false
|
||||
tor:
|
||||
enabled: true
|
||||
@@ -22,6 +22,7 @@ flowchart LR
|
||||
subgraph role [web-svc-legal]
|
||||
svc_legal["legal ❌"]
|
||||
svc_html["html"]
|
||||
svc_design["design ❌"]
|
||||
svc_prometheus["prometheus"]
|
||||
svc_tor["tor"]
|
||||
end
|
||||
|
||||
@@ -17,6 +17,11 @@ html:
|
||||
bond: 1
|
||||
enabled: true
|
||||
shared: true
|
||||
# nocheck: dynamic-flag
|
||||
# nocheck: design-off Reason: renders the imprint into web-svc-html's web root, where web-svc-html's design applies and its design spec covers the page
|
||||
design:
|
||||
enabled: false
|
||||
shared: false
|
||||
prometheus:
|
||||
bond: 1
|
||||
enabled: "{{ 'web-app-prometheus' in group_names }}"
|
||||
|
||||
@@ -24,6 +24,7 @@ flowchart LR
|
||||
subgraph role [web-svc-mirror 💻]
|
||||
svc_dashboard["dashboard"]
|
||||
svc_mirror["mirror"]
|
||||
svc_design["design ❌"]
|
||||
svc_prometheus["prometheus"]
|
||||
svc_tor["tor"]
|
||||
end
|
||||
|
||||
@@ -17,6 +17,12 @@ mirror:
|
||||
pids_limit: 64
|
||||
min_storage: "1GB"
|
||||
lifecycle: alpha
|
||||
# nocheck: playwright-service-flag — design consumer, no Playwright surface (provider: web-svc-design)
|
||||
# nocheck: dynamic-flag
|
||||
# nocheck: design-off Reason: proxies whitelisted third-party assets under '/<origin host>/'; '/' answers 404 (templates/proxy.conf.j2)
|
||||
design:
|
||||
enabled: false
|
||||
shared: false
|
||||
# nocheck: playwright-service-flag — /metrics endpoint covered by web-app-prometheus's own spec
|
||||
prometheus:
|
||||
bond: 1
|
||||
|
||||
@@ -25,14 +25,13 @@ flowchart LR
|
||||
dep_svc_net_tor["svc-net-tor 🐳🐝"]
|
||||
dep_web_app_matomo["web-app-matomo 🐳🐝"]
|
||||
dep_web_app_prometheus["web-app-prometheus 🐳🐝"]
|
||||
dep_web_svc_design["web-svc-design 💻"]
|
||||
end
|
||||
subgraph role [web-svc-onlyoffice 🐳🐝]
|
||||
svc_matomo["matomo"]
|
||||
svc_redis["redis"]
|
||||
svc_postgres["postgres"]
|
||||
svc_onlyoffice["onlyoffice"]
|
||||
svc_design["design"]
|
||||
svc_design["design ❌"]
|
||||
svc_prometheus["prometheus"]
|
||||
svc_tor["tor"]
|
||||
svc_container_backup["container_backup"]
|
||||
@@ -46,7 +45,6 @@ flowchart LR
|
||||
dep_svc_net_tor -. "0..1" .-> svc_tor
|
||||
dep_web_app_matomo -. "0..1" .-> svc_matomo
|
||||
dep_web_app_prometheus -. "0..1" .-> svc_prometheus
|
||||
dep_web_svc_design -. "0..1" .-> svc_design
|
||||
svc_matomo -. "0..1" .-> dpt_web_app_nextcloud
|
||||
```
|
||||
|
||||
|
||||
@@ -50,10 +50,11 @@ onlyoffice:
|
||||
proxy:
|
||||
service_key: onlyoffice
|
||||
lifecycle: beta
|
||||
# nocheck: dynamic-flag
|
||||
# nocheck: design-off Reason: document server; standalone it serves only static notice pages, the editors render only inside a host app that signs their configuration with the JWT secret
|
||||
design:
|
||||
bond: 1
|
||||
enabled: "{{ 'web-svc-design' in group_names }}"
|
||||
shared: "{{ 'web-svc-design' in group_names }}"
|
||||
enabled: false
|
||||
shared: false
|
||||
prometheus:
|
||||
bond: 1
|
||||
enabled: "{{ 'web-app-prometheus' in group_names }}"
|
||||
|
||||
@@ -18,9 +18,6 @@
|
||||
prometheus:
|
||||
enabled: true
|
||||
shared: true
|
||||
design:
|
||||
enabled: true
|
||||
shared: true
|
||||
tor:
|
||||
enabled: true
|
||||
- services:
|
||||
@@ -37,8 +34,5 @@
|
||||
prometheus:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
design:
|
||||
enabled: false
|
||||
shared: false # nocheck: variants-static-override backup shared stays literally true
|
||||
tor:
|
||||
enabled: true
|
||||
@@ -22,6 +22,7 @@ redis:
|
||||
shared: "{{ 'svc-db-redis' in group_names }}"
|
||||
# nocheck: dynamic-flag
|
||||
# nocheck: playwright-service-flag — design consumer, no Playwright surface (provider: web-svc-design)
|
||||
# nocheck: design-off Reason: icon API; '/' redirects to the docs or answers plain text, every other route returns an SVG or PNG
|
||||
design:
|
||||
enabled: false
|
||||
shared: false
|
||||
|
||||
@@ -26,6 +26,7 @@ flowchart LR
|
||||
svc_prometheus["prometheus"]
|
||||
svc_sso["sso"]
|
||||
svc_ldap["ldap"]
|
||||
svc_design["design ❌"]
|
||||
svc_xmpp["xmpp"]
|
||||
svc_tor["tor"]
|
||||
svc_container_backup["container_backup"]
|
||||
|
||||
@@ -17,6 +17,12 @@ ldap:
|
||||
bond: 1
|
||||
enabled: "{{ 'svc-db-openldap' in group_names }}"
|
||||
shared: "{{ 'svc-db-openldap' in group_names }}"
|
||||
# nocheck: playwright-service-flag — design consumer, no Playwright surface (provider: web-svc-design)
|
||||
# nocheck: dynamic-flag
|
||||
# nocheck: design-off Reason: XMPP clients connect over 5222/5269; the only HTTP page is ejabberd's built-in web admin on /admin behind HTTP Basic (templates/configuration.yml.j2)
|
||||
design:
|
||||
enabled: false
|
||||
shared: false
|
||||
xmpp:
|
||||
healthcheck:
|
||||
test: ["CMD", "ejabberdctl", "status"]
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
"""Every ``web-app-`` and ``web-svc-`` role declares a ``design`` entry in
|
||||
``meta/services.yml``, and a role that switches it off says why.
|
||||
|
||||
``design.enabled: false`` keeps a role out of the design queue
|
||||
(``make design-queue``) and off the shared CSS and the design script. The
|
||||
``design:`` line or the contiguous comment lines directly above it carry the
|
||||
marker and the reason on one comment line:
|
||||
|
||||
# nocheck: design-off Reason: <why the role has no UI to design>
|
||||
design:
|
||||
enabled: false
|
||||
shared: false
|
||||
|
||||
``web-svc-design``, the provider, is exempt.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import unittest
|
||||
|
||||
from cli.meta.roles.design import DESIGN_ENTITY, UI_PREFIXES, design_disabled
|
||||
from utils.annotations.suppress import line_has_rule
|
||||
from utils.cache.files import read_text
|
||||
from utils.roles.applications.services.registry import read_yaml_file
|
||||
from utils.roles.entity.name import get_entity_name
|
||||
from utils.roles.mapping import ROLE_FILE_META_SERVICES
|
||||
|
||||
from . import PROJECT_ROOT
|
||||
|
||||
_RULE = "design-off"
|
||||
_REASON = re.compile(r"#.*\breason\b\s*:\s*\S", re.IGNORECASE)
|
||||
_DESIGN_KEY = re.compile(rf"^{DESIGN_ENTITY}\s*:")
|
||||
|
||||
|
||||
def justified(lines: list[str]) -> bool:
|
||||
"""Whether the top-level ``design:`` key carries the marker and a reason.
|
||||
|
||||
Args:
|
||||
lines: Lines of a ``meta/services.yml``.
|
||||
|
||||
Returns:
|
||||
``True`` when the key line or the contiguous comment lines directly
|
||||
above it hold ``# nocheck: design-off`` and ``Reason: <text>``.
|
||||
"""
|
||||
index = next((i for i, line in enumerate(lines) if _DESIGN_KEY.match(line)), None)
|
||||
if index is None:
|
||||
return False
|
||||
block = [lines[index]]
|
||||
above = index - 1
|
||||
while above >= 0 and lines[above].lstrip().startswith("#"):
|
||||
block.append(lines[above])
|
||||
above -= 1
|
||||
has_rule = any(line_has_rule(line, _RULE) for line in block)
|
||||
return has_rule and any(_REASON.search(line) for line in block)
|
||||
|
||||
|
||||
class TestDesignOffReason(unittest.TestCase):
|
||||
def test_every_ui_role_declares_design_and_justifies_switching_it_off(
|
||||
self,
|
||||
) -> None:
|
||||
offenders: list[str] = []
|
||||
roles_dir = PROJECT_ROOT / "roles"
|
||||
for role_dir in sorted(p for p in roles_dir.iterdir() if p.is_dir()):
|
||||
role = role_dir.name
|
||||
services = role_dir / ROLE_FILE_META_SERVICES
|
||||
if not role.startswith(UI_PREFIXES) or not services.is_file():
|
||||
continue
|
||||
if get_entity_name(role) == DESIGN_ENTITY:
|
||||
continue
|
||||
if DESIGN_ENTITY not in read_yaml_file(services):
|
||||
offenders.append(f"{role}: declares no '{DESIGN_ENTITY}' entry")
|
||||
continue
|
||||
if design_disabled(role_dir) and not justified(
|
||||
read_text(str(services)).splitlines()
|
||||
):
|
||||
offenders.append(
|
||||
f"{role}: 'design.enabled: false' without "
|
||||
f"'# nocheck: {_RULE} Reason: ...'"
|
||||
)
|
||||
|
||||
if offenders:
|
||||
self.fail(
|
||||
"Every web-app-/web-svc- role declares a 'design' entry in "
|
||||
"meta/services.yml. A role that sets 'enabled: false' leaves the "
|
||||
"design queue and the shared CSS, so it MUST say why: put "
|
||||
f"'# nocheck: {_RULE} Reason: <why there is no UI to design>' on "
|
||||
"the 'design:' line or the comment lines directly above it.\n\n"
|
||||
"Offenders:\n" + "\n".join(f"- {line}" for line in offenders)
|
||||
)
|
||||
|
||||
def test_reason_detection(self) -> None:
|
||||
cases = {
|
||||
"marker and reason above": (
|
||||
[f"# nocheck: dynamic-flag, {_RULE} Reason: no page", "design:"],
|
||||
True,
|
||||
),
|
||||
"marker without reason": ([f"# nocheck: {_RULE}", "design:"], False),
|
||||
"reason without marker": (
|
||||
["# nocheck: dynamic-flag Reason: x", "design:"],
|
||||
False,
|
||||
),
|
||||
"blank line breaks the block": (
|
||||
[f"# nocheck: {_RULE} Reason: no page", "", "design:"],
|
||||
False,
|
||||
),
|
||||
"marker and reason on the key line": (
|
||||
[f"design: # nocheck: {_RULE} Reason: no page"],
|
||||
True,
|
||||
),
|
||||
}
|
||||
for name, (lines, expected) in cases.items():
|
||||
with self.subTest(case=name):
|
||||
self.assertEqual(justified(lines), expected)
|
||||
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
unittest.main()
|
||||
@@ -263,12 +263,23 @@ class TestCandidateRoles(unittest.TestCase):
|
||||
self._role("web-app-demo", {"demo": {}, "design": self.CONSUMER})
|
||||
self.assertEqual(candidate_roles(self.roles_dir), [])
|
||||
|
||||
def test_ui_less_provider_is_skipped(self) -> None:
|
||||
def test_role_that_switches_design_off_is_skipped(self) -> None:
|
||||
self._role(
|
||||
"web-svc-cdn", {"cdn": {"lifecycle": "beta"}, "design": self.CONSUMER}
|
||||
"web-svc-cdn", {"cdn": {"lifecycle": "beta"}, "design": {"enabled": False}}
|
||||
)
|
||||
self.assertEqual(candidate_roles(self.roles_dir), [])
|
||||
|
||||
def test_templated_design_flag_keeps_the_role(self) -> None:
|
||||
flag = "{{ 'web-svc-design' in group_names }}"
|
||||
self._role(
|
||||
"web-app-demo", {"demo": {"lifecycle": "beta"}, "design": {"enabled": flag}}
|
||||
)
|
||||
self.assertEqual(candidate_roles(self.roles_dir), ["web-app-demo"])
|
||||
|
||||
def test_design_provider_is_skipped(self) -> None:
|
||||
self._role("web-svc-design", {"design": {"lifecycle": "beta"}})
|
||||
self.assertEqual(candidate_roles(self.roles_dir), [])
|
||||
|
||||
def test_roles_outside_the_ui_categories_are_skipped(self) -> None:
|
||||
for name in ("svc-db-demo", "drv-demo", "web-opt-rdr-demo", "update"):
|
||||
self._role(name, {"demo": {"lifecycle": "beta"}, "design": self.CONSUMER})
|
||||
|
||||
Reference in new issue
Block a user