rcf-lite 0.19.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -0
- package/bin/rcf.js +5 -0
- package/blueprints/application-admin-console/CHANGELOG.md +11 -0
- package/blueprints/application-admin-console/README.md +98 -0
- package/blueprints/application-admin-console/blueprint.json +226 -0
- package/blueprints/application-admin-console/contributions/adrs/adr-2201-application-admin-console-capability-vocabulary.json +25 -0
- package/blueprints/application-admin-console/contributions/adrs/adr-2202-application-admin-console-baseline-roles.json +25 -0
- package/blueprints/application-admin-console/contributions/adrs/adr-2203-application-admin-console-invite-transport.json +20 -0
- package/blueprints/application-admin-console/contributions/adrs/adr-2204-application-admin-console-audit-retention.json +20 -0
- package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-001.json +18 -0
- package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-002.json +18 -0
- package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-003.json +18 -0
- package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-004.json +18 -0
- package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-005.json +18 -0
- package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-006.json +18 -0
- package/blueprints/application-admin-console/contributions/tacs/tac-2201-application-admin-console-shell.json +40 -0
- package/blueprints/application-admin-console/contributions/tacs/tac-2202-application-admin-console-capability-discovery.json +44 -0
- package/blueprints/application-admin-console/contributions/tacs/tac-2203-application-admin-console-permission-matrix.json +34 -0
- package/blueprints/application-admin-console/contributions/tacs/tac-2204-application-admin-console-audit-view.json +40 -0
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21101.json +34 -0
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21102.json +34 -0
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21103.json +34 -0
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21104.json +28 -0
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21105.json +34 -0
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21106.json +27 -0
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21107.json +27 -0
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21108.json +27 -0
- package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21109.json +33 -0
- package/blueprints/application-admin-console/docs/topics.md +35 -0
- package/blueprints/application-admin-console/guide/application-admin-console.md +29 -0
- package/blueprints/application-admin-console/probe-packs/application-admin-console.pack.mjs +182 -0
- package/blueprints/application-api-rest/docs/topics.md +5 -0
- package/blueprints/application-charts/CHANGELOG.md +12 -0
- package/blueprints/application-charts/README.md +73 -0
- package/blueprints/application-charts/blueprint.json +26 -0
- package/blueprints/application-charts/contributions/adrs/adr-1901-application-charts-engine-choice.json +25 -0
- package/blueprints/application-charts/contributions/adrs/adr-1902-application-charts-accessible-palette.json +25 -0
- package/blueprints/application-charts/contributions/adrs/adr-1903-application-charts-motion.json +25 -0
- package/blueprints/application-charts/contributions/requirements/application-charts-req-001.json +15 -0
- package/blueprints/application-charts/contributions/requirements/application-charts-req-002.json +15 -0
- package/blueprints/application-charts/contributions/requirements/application-charts-req-003.json +15 -0
- package/blueprints/application-charts/contributions/requirements/application-charts-req-004.json +15 -0
- package/blueprints/application-charts/contributions/tacs/tac-1901-application-charts-render-shell.json +42 -0
- package/blueprints/application-charts/contributions/tacs/tac-1902-application-charts-keyboard-traversal.json +40 -0
- package/blueprints/application-charts/contributions/user-stories/application-charts-us-18101.json +35 -0
- package/blueprints/application-charts/contributions/user-stories/application-charts-us-18102.json +35 -0
- package/blueprints/application-charts/contributions/user-stories/application-charts-us-18103.json +35 -0
- package/blueprints/application-charts/contributions/user-stories/application-charts-us-18104.json +35 -0
- package/blueprints/application-charts/contributions/user-stories/application-charts-us-18105.json +35 -0
- package/blueprints/application-charts/contributions/user-stories/application-charts-us-18106.json +35 -0
- package/blueprints/application-charts/docs/topics.md +37 -0
- package/blueprints/application-charts/guide/application-charts.md +44 -0
- package/blueprints/application-charts/probe-packs/application-charts.pack.mjs +191 -0
- package/blueprints/application-dashboard/CHANGELOG.md +10 -0
- package/blueprints/application-dashboard/README.md +102 -0
- package/blueprints/application-dashboard/assets/guidance/dashboard-design.md +124 -0
- package/blueprints/application-dashboard/blueprint.json +29 -0
- package/blueprints/application-dashboard/contributions/adrs/adr-2001-application-dashboard-primary-kpi-enum.json +25 -0
- package/blueprints/application-dashboard/contributions/adrs/adr-2002-application-dashboard-timeframe-presets.json +25 -0
- package/blueprints/application-dashboard/contributions/adrs/adr-2003-application-dashboard-export-formats.json +25 -0
- package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-001.json +15 -0
- package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-002.json +15 -0
- package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-003.json +15 -0
- package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-004.json +15 -0
- package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-005.json +15 -0
- package/blueprints/application-dashboard/contributions/tacs/tac-2001-application-dashboard-tile-grid.json +47 -0
- package/blueprints/application-dashboard/contributions/tacs/tac-2002-application-dashboard-filter-chrome.json +41 -0
- package/blueprints/application-dashboard/contributions/tacs/tac-2003-application-dashboard-export-handle.json +35 -0
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19101.json +35 -0
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19102.json +35 -0
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19103.json +35 -0
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19104.json +35 -0
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19105.json +35 -0
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19106.json +35 -0
- package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19107.json +35 -0
- package/blueprints/application-dashboard/docs/topics.md +43 -0
- package/blueprints/application-dashboard/guide/application-dashboard.md +48 -0
- package/blueprints/application-dashboard/probe-packs/application-dashboard.pack.mjs +231 -0
- package/blueprints/application-datatable/CHANGELOG.md +8 -0
- package/blueprints/application-datatable/README.md +43 -0
- package/blueprints/application-datatable/blueprint.json +33 -0
- package/blueprints/application-datatable/contributions/adrs/adr-1801-application-datatable-pattern-choice.json +25 -0
- package/blueprints/application-datatable/contributions/adrs/adr-1802-application-datatable-url-state.json +20 -0
- package/blueprints/application-datatable/contributions/adrs/adr-1803-application-datatable-page-size.json +20 -0
- package/blueprints/application-datatable/contributions/adrs/adr-1804-application-datatable-selection-persistence.json +20 -0
- package/blueprints/application-datatable/contributions/requirements/application-datatable-req-001.json +15 -0
- package/blueprints/application-datatable/contributions/requirements/application-datatable-req-002.json +15 -0
- package/blueprints/application-datatable/contributions/requirements/application-datatable-req-003.json +15 -0
- package/blueprints/application-datatable/contributions/requirements/application-datatable-req-004.json +15 -0
- package/blueprints/application-datatable/contributions/requirements/application-datatable-req-005.json +15 -0
- package/blueprints/application-datatable/contributions/requirements/application-datatable-req-006.json +15 -0
- package/blueprints/application-datatable/contributions/tacs/tac-1801-application-datatable-shell.json +50 -0
- package/blueprints/application-datatable/contributions/tacs/tac-1802-application-datatable-query-adapter.json +39 -0
- package/blueprints/application-datatable/contributions/tacs/tac-1803-application-datatable-selection-model.json +28 -0
- package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17101.json +44 -0
- package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17102.json +44 -0
- package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17103.json +44 -0
- package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17104.json +44 -0
- package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17105.json +44 -0
- package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17106.json +44 -0
- package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17107.json +44 -0
- package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17108.json +44 -0
- package/blueprints/application-datatable/contributions/user-stories/application-datatable-us-17109.json +44 -0
- package/blueprints/application-datatable/docs/topics.md +35 -0
- package/blueprints/application-datatable/guide/application-datatable.md +38 -0
- package/blueprints/application-datatable/probe-packs/application-datatable.pack.mjs +240 -0
- package/blueprints/application-error-handling/docs/topics.md +5 -0
- package/blueprints/application-notifications-in-app/CHANGELOG.md +9 -0
- package/blueprints/application-notifications-in-app/README.md +80 -0
- package/blueprints/application-notifications-in-app/blueprint.json +30 -0
- package/blueprints/application-notifications-in-app/contributions/adrs/adr-2101-application-notifications-in-app-live-region-role-mapping.json +25 -0
- package/blueprints/application-notifications-in-app/contributions/adrs/adr-2102-application-notifications-in-app-toast-timeout-floor.json +25 -0
- package/blueprints/application-notifications-in-app/contributions/adrs/adr-2103-application-notifications-in-app-retention-window.json +25 -0
- package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-001.json +15 -0
- package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-002.json +15 -0
- package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-003.json +15 -0
- package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-004.json +15 -0
- package/blueprints/application-notifications-in-app/contributions/requirements/application-notifications-in-app-req-005.json +15 -0
- package/blueprints/application-notifications-in-app/contributions/tacs/tac-2101-application-notifications-in-app-live-region.json +46 -0
- package/blueprints/application-notifications-in-app/contributions/tacs/tac-2102-application-notifications-in-app-centre.json +52 -0
- package/blueprints/application-notifications-in-app/contributions/tacs/tac-2103-application-notifications-in-app-preferences.json +40 -0
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20101.json +35 -0
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20102.json +35 -0
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20103.json +35 -0
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20104.json +35 -0
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20105.json +35 -0
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20106.json +26 -0
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20107.json +26 -0
- package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20108.json +26 -0
- package/blueprints/application-notifications-in-app/docs/topics.md +39 -0
- package/blueprints/application-notifications-in-app/guide/application-notifications-in-app.md +47 -0
- package/blueprints/application-notifications-in-app/probe-packs/application-notifications-in-app.pack.mjs +328 -0
- package/blueprints/application-spa/docs/topics.md +5 -0
- package/blueprints/delivery-ci-workflows/docs/topics.md +5 -0
- package/blueprints/deploy-cloudflare-workers/docs/topics.md +5 -0
- package/blueprints/email-smtp-resend/docs/topics.md +5 -0
- package/blueprints/observability-essentials/docs/topics.md +5 -0
- package/blueprints/observability-logging/CHANGELOG.md +5 -0
- package/blueprints/observability-logging/README.md +1 -1
- package/blueprints/observability-logging/blueprint.json +113 -21
- package/blueprints/observability-logging/docs/topics.md +5 -0
- package/blueprints/observability-probe-endpoints/docs/topics.md +5 -0
- package/blueprints/persistence-data-d1/docs/topics.md +5 -0
- package/blueprints/persistence-data-sqlite/docs/topics.md +5 -0
- package/blueprints/security-auth-clerk/CHANGELOG.md +5 -0
- package/blueprints/security-auth-clerk/blueprint.json +2 -1
- package/blueprints/security-auth-clerk/docs/topics.md +5 -0
- package/blueprints/security-auth-keycloak/CHANGELOG.md +5 -0
- package/blueprints/security-auth-keycloak/blueprint.json +2 -1
- package/blueprints/security-auth-keycloak/docs/topics.md +5 -0
- package/blueprints/security-auth-magic-link/CHANGELOG.md +5 -0
- package/blueprints/security-auth-magic-link/blueprint.json +2 -1
- package/blueprints/security-auth-magic-link/docs/topics.md +5 -0
- package/blueprints/security-auth-oauth2/CHANGELOG.md +5 -0
- package/blueprints/security-auth-oauth2/blueprint.json +2 -1
- package/blueprints/security-auth-oauth2/docs/topics.md +5 -0
- package/blueprints/security-secrets-management/docs/topics.md +5 -0
- package/fixtures/canary-manifest.json +9 -9
- package/package.json +2 -2
- package/rcf/code-nodes/cn-098.json +13 -0
- package/rcf/code-nodes/cn-099.json +13 -0
- package/rcf/code-nodes/cn-100.json +13 -0
- package/rcf/code-nodes/cn-101.json +13 -0
- package/rcf/code-nodes/cn-102.json +13 -0
- package/rcf/code-nodes/cn-103.json +13 -0
- package/rcf/code-nodes/cn-104.json +13 -0
- package/rcf/code-nodes/cn-105.json +13 -0
- package/rcf/code-nodes/cn-106.json +13 -0
- package/rcf/code-nodes/cn-107.json +14 -0
- package/rcf/code-nodes/cn-108.json +13 -0
- package/rcf/code-nodes/cn-109.json +12 -0
- package/rcf/code-nodes/cn-110.json +12 -0
- package/rcf/code-nodes/cn-111.json +14 -0
- package/rcf/code-nodes/cn-112.json +14 -0
- package/rcf/code-nodes/cn-113.json +12 -0
- package/rcf/code-nodes/cn-114.json +13 -0
- package/rcf/code-nodes/cn-115.json +13 -0
- package/rcf/code-nodes/cn-116.json +12 -0
- package/rcf/code-nodes/cn-117.json +13 -0
- package/rcf/code-nodes/cn-118.json +13 -0
- package/rcf/code-nodes/cn-119.json +13 -0
- package/rcf/code-nodes/cn-120.json +13 -0
- package/rcf/code-nodes/cn-121.json +12 -0
- package/rcf/code-nodes/cn-122.json +12 -0
- package/rcf/code-nodes/cn-123.json +13 -0
- package/rcf/code-nodes/cn-124.json +13 -0
- package/rcf/code-nodes/cn-125.json +13 -0
- package/rcf/code-nodes/cn-126.json +13 -0
- package/rcf/code-nodes/cn-127.json +12 -0
- package/rcf/code-nodes/cn-128.json +14 -0
- package/rcf/code-nodes/cn-129.json +14 -0
- package/rcf/code-nodes/cn-130.json +14 -0
- package/rcf/code-nodes/cn-131.json +15 -0
- package/rcf/code-nodes/cn-132.json +12 -0
- package/rcf/code-nodes/cn-133.json +13 -0
- package/rcf/evals/eval-001.json +55 -0
- package/rcf/fbs/fbs-035.json +18 -0
- package/rcf/fbs/fbs-036.json +22 -0
- package/rcf/fbs/fbs-037.json +19 -0
- package/rcf/fbs/fbs-038.json +19 -0
- package/rcf/fbs/fbs-039.json +21 -0
- package/rcf/fbs/fbs-040.json +20 -0
- package/rcf/fbs/fbs-041.json +13 -0
- package/rcf/fbs/fbs-042.json +13 -0
- package/rcf/requirements/req-016.json +37 -0
- package/rcf/requirements/req-017.json +18 -0
- package/rcf/requirements/req-018.json +18 -0
- package/rcf/requirements/req-019.json +38 -0
- package/rcf/requirements/req-020.json +13 -0
- package/rcf/requirements/req-021.json +13 -0
- package/rcf/requirements/req-022.json +13 -0
- package/rcf/requirements/req-023.json +14 -0
- package/rcf/test-suites/ts-045.json +46 -0
- package/rcf/test-suites/ts-046.json +78 -0
- package/rcf/test-suites/ts-047.json +54 -0
- package/rcf/test-suites/ts-048.json +54 -0
- package/rcf/test-suites/ts-049.json +70 -0
- package/rcf/test-suites/ts-050.json +69 -0
- package/rcf/test-suites/ts-051.json +22 -0
- package/rcf/test-suites/ts-052.json +20 -0
- package/rcf/user-stories/us-1601.json +37 -0
- package/rcf/user-stories/us-1701.json +56 -0
- package/rcf/user-stories/us-1801.json +40 -0
- package/rcf/user-stories/us-1901.json +40 -0
- package/rcf/user-stories/us-2001.json +50 -0
- package/rcf/user-stories/us-2101.json +45 -0
- package/rcf/user-stories/us-2201.json +60 -0
- package/rcf/user-stories/us-2301.json +51 -0
- package/releases/releases.yaml +20 -1
- package/src/blueprint/apply.js +98 -1
- package/src/blueprint/capabilities.js +318 -0
- package/src/blueprint/loader.js +247 -0
- package/src/browser-verify/boot.js +180 -0
- package/src/browser-verify/index.js +13 -0
- package/src/browser-verify/manifest-writer.js +31 -6
- package/src/browser-verify/pack-browser.js +294 -0
- package/src/browser-verify/pack-loader.js +176 -0
- package/src/browser-verify/pack-runner.js +193 -0
- package/src/browser-verify/pack-schema.js +155 -0
- package/src/browser-verify/runner.js +24 -1
- package/src/cli/blueprint.js +92 -0
- package/src/cli/browser-verify.js +147 -7
- package/src/cli/create.js +14 -0
- package/src/cli/eval-coverage.js +221 -0
- package/src/cli/eval.js +43 -0
- package/src/cli/finalise.js +64 -0
- package/src/cli/help.js +4 -0
- package/src/core/errors/index.js +7 -0
- package/src/core/store/ids.js +5 -1
- package/src/core/store/init.js +4 -0
- package/src/core/store/loader.js +4 -0
- package/src/core/store/validator.js +8 -1
- package/src/core/store/walker.js +71 -2
- package/src/core/store/writer.js +4 -0
- package/src/eval/judge.js +338 -0
- package/src/finalise/index.js +8 -0
- package/src/finalise/ingest.js +27 -0
- package/src/finalise/ship-without-eval.js +123 -0
- package/src/query/eval-coverage.js +162 -0
- package/src/verify/chain/index.js +67 -0
- package/src/verify/cli/run.js +15 -0
- package/src/verify/engine/index.js +10 -0
- package/src/verify/verdict/index.js +46 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"usId": "application-datatable-US-17107",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"reqId": "application-datatable-REQ-001",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "approved",
|
|
7
|
+
"title": "The rendered table shell uses the ARIA APG pattern that matches the surface's interactivity",
|
|
8
|
+
"asA": "assistive-tech user reading the datatable",
|
|
9
|
+
"iWant": "the shell to render as an ARIA APG table for read-only rows and as an ARIA APG grid once cells contain interactive controls",
|
|
10
|
+
"soThat": "the assistive-tech pattern matches the interactivity of the surface (ADR-1801)",
|
|
11
|
+
"acceptanceCriteria": [
|
|
12
|
+
{
|
|
13
|
+
"id": "AC-17107-1",
|
|
14
|
+
"description": "Given a datatable shell that renders interactive per-row controls (sort buttons, selection checkboxes, inline actions), the rendered element is a `<table role=\"grid\">` with `<th>` cells scoped to `col`; a read-only variant that renders no per-row interactive controls stays on the plain `<table>` pattern. The check reads the accessibility tree at the shell route and asserts the presence of the grid role when the shell ships interactive controls.",
|
|
15
|
+
"given": "a datatable route that ships interactive per-row controls",
|
|
16
|
+
"when": "the shell renders",
|
|
17
|
+
"then": "the rendered table has `role=\"grid\"` and header cells scoped to `col`",
|
|
18
|
+
"testable": true,
|
|
19
|
+
"scope": "runtime"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"id": "AC-17107-2",
|
|
23
|
+
"description": "Given a rendered datatable, every per-row inline action (edit, delete, resend) has an accessible name that includes the acted-on row's identifier or a semantically equivalent noun (not `Edit` alone); the accessible name is readable by assistive tech per WCAG 4.1.2.",
|
|
24
|
+
"given": "a rendered datatable with per-row inline actions",
|
|
25
|
+
"when": "assistive tech reads the action controls",
|
|
26
|
+
"then": "each action's accessible name identifies the acted-on row",
|
|
27
|
+
"testable": true,
|
|
28
|
+
"scope": "runtime"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"id": "AC-17107-3",
|
|
32
|
+
"description": "Given a rendered datatable, the header row exposes each column's role (`<th scope=\"col\">` or `role=\"columnheader\"`) and every data cell resolves to a column header for row-and-column readouts on assistive tech (WCAG 1.3.1).",
|
|
33
|
+
"given": "a rendered datatable",
|
|
34
|
+
"when": "assistive tech traverses a data cell",
|
|
35
|
+
"then": "the announced context includes the column header the cell resolves to",
|
|
36
|
+
"testable": true,
|
|
37
|
+
"scope": "runtime"
|
|
38
|
+
}
|
|
39
|
+
],
|
|
40
|
+
"tacIds": ["TAC-1801-application-datatable-shell"],
|
|
41
|
+
"tags": ["blueprint:application-datatable"],
|
|
42
|
+
"createdAt": "2026-09-04T19:45:00Z",
|
|
43
|
+
"updatedAt": "2026-09-04T19:45:00Z"
|
|
44
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"usId": "application-datatable-US-17108",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"reqId": "application-datatable-REQ-002",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "approved",
|
|
7
|
+
"title": "URL state serialisation preserves sort, filter and page across reload and share",
|
|
8
|
+
"asA": "operator sharing a specific datatable view with a colleague",
|
|
9
|
+
"iWant": "the sort, filter and page state to serialise into the URL so a reload or a shared link lands on the same view",
|
|
10
|
+
"soThat": "the surface is deep-linkable and reload-stable (ADR-1802's recommended default)",
|
|
11
|
+
"acceptanceCriteria": [
|
|
12
|
+
{
|
|
13
|
+
"id": "AC-17108-1",
|
|
14
|
+
"description": "Given a rendered datatable where the operator applied a sort, a filter and advanced past page 1, the current URL carries the state as query parameters (`sort`, `q`, `page`) per ADR-1802's recommended default; reloading the URL rerenders the same view.",
|
|
15
|
+
"given": "a rendered datatable with an applied sort, filter and non-first page",
|
|
16
|
+
"when": "the operator reloads the URL",
|
|
17
|
+
"then": "the reloaded surface renders the same sort, filter and page",
|
|
18
|
+
"testable": true,
|
|
19
|
+
"scope": "runtime"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"id": "AC-17108-2",
|
|
23
|
+
"description": "Given the elicited client-side sort alternative (ADR-1802 elicited variant) applied to a small in-memory collection, the sort direction still writes to the URL so reload stability is preserved; the client-side branch never invents a URL state divergent from the server-side default.",
|
|
24
|
+
"given": "a rendered datatable applying the client-side sort alternative",
|
|
25
|
+
"when": "the operator activates a sort control",
|
|
26
|
+
"then": "the URL query parameters update with `sort=<column>:<direction>` in the same shape as the server-side default",
|
|
27
|
+
"testable": true,
|
|
28
|
+
"scope": "runtime"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"id": "AC-17108-3",
|
|
32
|
+
"description": "Given a rendered datatable, the default page size on the recommended default (ADR-1803) applies when no `pageSize` is present in the URL; the operator's elicited page-size override at apply time changes the default without changing the URL contract.",
|
|
33
|
+
"given": "a rendered datatable landed at the shell route without a `pageSize` query parameter",
|
|
34
|
+
"when": "the initial render fetches the first page",
|
|
35
|
+
"then": "the fetch carries `pageSize=<applied-default>` and the URL is left untouched",
|
|
36
|
+
"testable": true,
|
|
37
|
+
"scope": "runtime"
|
|
38
|
+
}
|
|
39
|
+
],
|
|
40
|
+
"tacIds": ["TAC-1801-application-datatable-shell", "TAC-1802-application-datatable-query-adapter"],
|
|
41
|
+
"tags": ["blueprint:application-datatable"],
|
|
42
|
+
"createdAt": "2026-09-04T19:45:00Z",
|
|
43
|
+
"updatedAt": "2026-09-04T19:45:00Z"
|
|
44
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"usId": "application-datatable-US-17109",
|
|
3
|
+
"prdId": "PRD-001",
|
|
4
|
+
"reqId": "application-datatable-REQ-004",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "approved",
|
|
7
|
+
"title": "Selection persistence across pages holds the elicited contract and announces the running count",
|
|
8
|
+
"asA": "operator selecting rows across several pages before running a bulk action",
|
|
9
|
+
"iWant": "the selection model to persist my row selections across pagination and announce the running count",
|
|
10
|
+
"soThat": "cross-page bulk operations are visible and reversible",
|
|
11
|
+
"acceptanceCriteria": [
|
|
12
|
+
{
|
|
13
|
+
"id": "AC-17109-1",
|
|
14
|
+
"description": "Given an operator elicited `selectionPersistence=cross-page` (ADR-1804), when the operator selects rows on page 1 and advances to page 2, the previously selected row ids remain in the selection model; a return to page 1 re-renders the checkboxes as checked. The check clicks a row checkbox, advances the page, returns, and asserts the checkbox is still checked.",
|
|
15
|
+
"given": "a rendered datatable with elicited cross-page selection persistence",
|
|
16
|
+
"when": "the operator selects rows on page 1 and paginates away and back",
|
|
17
|
+
"then": "the row checkboxes on page 1 remain in the selected state on return",
|
|
18
|
+
"testable": true,
|
|
19
|
+
"scope": "runtime"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"id": "AC-17109-2",
|
|
23
|
+
"description": "Given a running row selection, the surface renders the current count in an accessible location adjacent to the bulk action controls; the count updates when a row is toggled without a full re-render of the surface.",
|
|
24
|
+
"given": "a rendered datatable with at least one row selected",
|
|
25
|
+
"when": "the operator toggles a second row",
|
|
26
|
+
"then": "the accessible selection count updates by one without a full page re-render",
|
|
27
|
+
"testable": true,
|
|
28
|
+
"scope": "runtime"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"id": "AC-17109-3",
|
|
32
|
+
"description": "Given the operator did not elicit cross-page persistence (ADR-1804's non-elicited default), the selection resets on pagination; the surface names this behaviour in the accessible copy near the bulk action control so operators are not surprised on advance.",
|
|
33
|
+
"given": "a rendered datatable without cross-page persistence elicited",
|
|
34
|
+
"when": "the operator selects rows and paginates away",
|
|
35
|
+
"then": "the selection clears on advance and the accessible copy on the bulk-action region names the per-page-only behaviour",
|
|
36
|
+
"testable": true,
|
|
37
|
+
"scope": "runtime"
|
|
38
|
+
}
|
|
39
|
+
],
|
|
40
|
+
"tacIds": ["TAC-1803-application-datatable-selection-model"],
|
|
41
|
+
"tags": ["blueprint:application-datatable"],
|
|
42
|
+
"createdAt": "2026-09-04T19:45:00Z",
|
|
43
|
+
"updatedAt": "2026-09-04T19:45:00Z"
|
|
44
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# application-datatable: coordination vocabulary
|
|
2
|
+
|
|
3
|
+
## Global topics
|
|
4
|
+
|
|
5
|
+
The blueprint claims no new global topics at v1.0.0. The datatable shell is a general enterprise practice contract; every ADR (pattern choice, URL state, page size, selection persistence) is non-global.
|
|
6
|
+
|
|
7
|
+
## Deliberately unclaimed topics
|
|
8
|
+
|
|
9
|
+
- `dataGridEngine` (the chosen data-table library). Reserved for the applying project as an elicited choice, not a global topic; a second datatable-shaped blueprint that composes with a specific engine would either supersede this blueprint or share the shell TAC.
|
|
10
|
+
- `columnRegistry` (a shared column vocabulary across surfaces). No blueprint claims it today; a future admin-console blueprint (visual round T-5) may elicit column reuse without minting a global topic.
|
|
11
|
+
|
|
12
|
+
## Shelf id band and suffix block
|
|
13
|
+
|
|
14
|
+
| Blueprint | US band | ADR/TAC suffix block | Status | Global topics |
|
|
15
|
+
|---|---|---|---|---|
|
|
16
|
+
| application-datatable | 17101-17899 | 18xx | shipped v1.0.0 | none |
|
|
17
|
+
| application-charts | 18101-18899 | 19xx | shipped v1.0.0 | none |
|
|
18
|
+
| application-dashboard | 19101-19899 | 20xx | shipped v1.0.0 | none |
|
|
19
|
+
| application-notifications-in-app | 20101-20899 | 21xx | shipped v1.0.0 | none |
|
|
20
|
+
| application-admin-console | 21101-21899 | 22xx | shipped v1.0.0 | none |
|
|
21
|
+
|
|
22
|
+
The shelf-wide band registry lives in `packages/rcf-lite/docs/blueprint-authoring.md` section 5.
|
|
23
|
+
|
|
24
|
+
## Probe pack
|
|
25
|
+
|
|
26
|
+
`probe-packs/application-datatable.pack.mjs` ships six checks anchored to blueprint AC ids:
|
|
27
|
+
|
|
28
|
+
- `AC-17101-1` sort click reorders rows
|
|
29
|
+
- `AC-17102-1` filter text search issues q request
|
|
30
|
+
- `AC-17103-2` pagination announcement in aria-live region
|
|
31
|
+
- `AC-17104-3` bulk-action confirmation dialog returns focus to originating row
|
|
32
|
+
- `AC-17105-1` state distinctness (empty / loading / error / no-results)
|
|
33
|
+
- `AC-17106-1` column reorder keyboard alternative
|
|
34
|
+
|
|
35
|
+
The pack applies to any FBS binding `TAC-1801-application-datatable-shell` or whose navModel routes name a datatable path. See `packages/rcf-lite/docs/blueprint-authoring.md` section 8c for the pack authoring rules.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Guide: application-datatable (v1.0.0)
|
|
2
|
+
|
|
3
|
+
## What it is
|
|
4
|
+
|
|
5
|
+
A shipped, vendor-neutral datatable contract for a rcf-lite application. One shell (TAC-1801), one query adapter (TAC-1802), one selection model (TAC-1803), plus a shipped Playwright probe pack that gates ship on the six runtime-observable surfaces the shelf assures: sort activation reorders rendered rows, filter text search issues a `q` request, pagination announces `Page N of M` through an aria-live region, bulk actions open an APG dialog and return focus to the originating row, four states each render in their own region, and columns reorder without a drag.
|
|
6
|
+
|
|
7
|
+
## What it deliberately is not
|
|
8
|
+
|
|
9
|
+
- Not a data-table library. The shell is a contract; the applying project chooses TanStack Table, MUI DataGrid, AG Grid, a hand-rolled `<table>`, or any other realisation. The ACs are what ship must meet; the HOW is the project's decision.
|
|
10
|
+
- Not a data-source contract. The query adapter (TAC-1802) targets a REST endpoint on the applied `application-api-rest`, a GraphQL query, or an in-memory adapter for small collections; the adapter shape is one project decision above the data source.
|
|
11
|
+
- Not a row-level authorisation contract. The applied auth blueprint owns row-level visibility; the datatable reads the rows it is given.
|
|
12
|
+
|
|
13
|
+
## When to reach for it
|
|
14
|
+
|
|
15
|
+
- Any surface with tabular data the operator sorts, filters, paginates, or bulk-operates on. Users tables, orders, notifications, records, audit views. The dashboard blueprint (visual round T-3) consumes this shell for its `application-datatable` recent-items strip.
|
|
16
|
+
- Projects that want the ARIA APG discipline (table vs grid per interactivity) enforced at ship without hand-authoring the rule per surface.
|
|
17
|
+
|
|
18
|
+
## When it does not fit
|
|
19
|
+
|
|
20
|
+
- Read-only presentation of static data where sort, filter or pagination are not needed. A plain `<table>` inside a marketing surface does not need this shell.
|
|
21
|
+
- Highly bespoke tabular surfaces that render two-dimensional keyboard navigation over a non-table structure (a spreadsheet-shaped editor). Those supersede TAC-1801 with a project-authored shell.
|
|
22
|
+
|
|
23
|
+
## What a good outcome looks like
|
|
24
|
+
|
|
25
|
+
The rendered surface is a `<table role="grid">` when the shell ships interactive controls; sort activation reorders rows against the query adapter's response and announces the direction via `aria-sort`; the filter input carries `q` into the adapter; the pagination status region reads `Page N of M` and updates on advance; the bulk-action confirmation dialog opens as `role="dialog"` `aria-modal="true"` with `aria-labelledby` and `aria-describedby` set, initial focus lands on confirm, and cancel returns focus to the row control that opened the dialog; the four states each render inside their own `role="region"` with `aria-live="polite"`; column reorder has a paired left / right keyboard control per column; the shipped probe pack runs green on the delivery-ci-workflows gate.
|
|
26
|
+
|
|
27
|
+
## The operator decisions that remain open
|
|
28
|
+
|
|
29
|
+
- **The data-table realisation** (framework choice). TanStack Table, MUI DataGrid, AG Grid, hand-rolled `<table>`, or another. The ACs shape the outcome; the HOW is elicited at build time.
|
|
30
|
+
- **Server-side or client-side query adapter** (ADR-1802). Server-side default; client-side elicited alternative for small in-memory collections.
|
|
31
|
+
- **URL-state serialisation** (ADR-1802). Recommended default writes sort, filter and page into the URL; the session-scoped alternative is elicited for surfaces where deep-linking is undesirable.
|
|
32
|
+
- **Default page size** (ADR-1803). Default 25; elicit an override at apply.
|
|
33
|
+
- **Selection persistence across pages** (ADR-1804). Default `perPage`; `crossPage` elicited for high-cardinality bulk workflows.
|
|
34
|
+
- **Per-column filter dropdowns** (REQ-003). Which columns expose them, and what the value set is per column. Elicited at build.
|
|
35
|
+
|
|
36
|
+
## Cost-honesty
|
|
37
|
+
|
|
38
|
+
Adds six REQs, nine USs (with 27 runtime-observable ACs), three TACs, four ADRs, one shipped probe pack, and one sample-app fixture to the shipped shelf. The runtime cost is one probe-pack run per shell FBS on the delivery-ci-workflows gate (approximately 5 to 15 seconds per pack invocation against a live server). No runtime dependency added to the applying project's `package.json`; the probe pack drives the browser the runner provisions through the pinned Playwright MCP or the project's own `playwright` when installed. The elicited parameters (data source shape, page size, URL-state, selection persistence) shape the applying project's surface without expanding the shipped shelf.
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
// application-datatable probe pack (v1.0.0).
|
|
2
|
+
//
|
|
3
|
+
// Six runtime-observable checks anchored to the blueprint's ACs:
|
|
4
|
+
// AC-17101-1 sort click reorders rows (server-side sort)
|
|
5
|
+
// AC-17102-1 filter chrome text-search issues q=<value> request
|
|
6
|
+
// AC-17103-2 pagination announcement via aria-live "Page N of M"
|
|
7
|
+
// AC-17104-3 bulk-action confirmation focus return
|
|
8
|
+
// AC-17105-1 state region distinctness (empty / loading / error / no-results)
|
|
9
|
+
// AC-17106-1 column reorder keyboard alternative
|
|
10
|
+
//
|
|
11
|
+
// Every check drives the real Playwright browser the runner injects
|
|
12
|
+
// (see rcf-lite src/browser-verify/pack-browser.js). Runs against a
|
|
13
|
+
// server-side implementation of the shell: a keyboard-reachable sort
|
|
14
|
+
// control, a text filter that issues fetch('/api/rows?q=...'),
|
|
15
|
+
// pagination with an aria-live status region, row selection with a
|
|
16
|
+
// bulk action that opens an aria-modal dialog and returns focus on
|
|
17
|
+
// close, four distinct query-driven states, and a non-drag column
|
|
18
|
+
// reorder path.
|
|
19
|
+
|
|
20
|
+
export default {
|
|
21
|
+
packName: 'application-datatable',
|
|
22
|
+
version: '1.0.0',
|
|
23
|
+
blueprintSlug: 'application-datatable',
|
|
24
|
+
// Applies to any FBS that realises the datatable shell TAC or whose
|
|
25
|
+
// navModel routes name a datatable path. The source references both
|
|
26
|
+
// `tacIds` and `route` so the loader's applicability source-scan
|
|
27
|
+
// (route / tacIds / blueprint: tag) sees the two legal seams.
|
|
28
|
+
appliesTo: ({ fbs }) => {
|
|
29
|
+
const routes = fbs?.designStage?.navModel?.routes ?? [];
|
|
30
|
+
const tacIds = fbs?.contextRequirements?.tacIds ?? [];
|
|
31
|
+
if (tacIds.includes('TAC-1801-application-datatable-shell')) return true;
|
|
32
|
+
return routes.some((r) => typeof r?.path === 'string' && /datatable-shell|\/dt(\/|$)/.test(r.path));
|
|
33
|
+
},
|
|
34
|
+
boot: { bootCommand: null, waitForUrl: null, waitForSelector: null },
|
|
35
|
+
checks: [
|
|
36
|
+
{
|
|
37
|
+
id: 'AC-17101-1',
|
|
38
|
+
severity: 'block',
|
|
39
|
+
description: 'Sort click reorders rendered rows to match server sort order',
|
|
40
|
+
run: async ({ browser, fetch, runtimeUrl }) => {
|
|
41
|
+
if (!browser) return { verdict: 'fail', detail: 'no packBrowser wired' };
|
|
42
|
+
await browser.goto(runtimeUrl + '/');
|
|
43
|
+
const initialIds = await browser.evaluate(() =>
|
|
44
|
+
Array.from(document.querySelectorAll('table[role="grid"] tbody tr'))
|
|
45
|
+
.map((tr) => Number(tr.getAttribute('data-id'))));
|
|
46
|
+
if (!Array.isArray(initialIds) || initialIds.length === 0) {
|
|
47
|
+
return { verdict: 'fail', detail: 'no rows rendered: ' + JSON.stringify(initialIds) };
|
|
48
|
+
}
|
|
49
|
+
await browser.click('button.sortControl[data-column="score"]', 'score sort control');
|
|
50
|
+
// Give the client a beat to fetch and re-render.
|
|
51
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
52
|
+
const sortedIds = await browser.evaluate(() =>
|
|
53
|
+
Array.from(document.querySelectorAll('table[role="grid"] tbody tr'))
|
|
54
|
+
.map((tr) => Number(tr.getAttribute('data-id'))));
|
|
55
|
+
const apiRes = await fetch(runtimeUrl + '/api/rows?sort=score:asc&page=1&pageSize=3');
|
|
56
|
+
const apiPayload = await apiRes.json();
|
|
57
|
+
const apiIds = apiPayload.rows.map((r) => r.id);
|
|
58
|
+
if (JSON.stringify(sortedIds) === JSON.stringify(initialIds)) {
|
|
59
|
+
return { verdict: 'fail', detail: 'sort click did not change row order: initial=' + JSON.stringify(initialIds) };
|
|
60
|
+
}
|
|
61
|
+
if (JSON.stringify(sortedIds) !== JSON.stringify(apiIds)) {
|
|
62
|
+
return { verdict: 'fail', detail: 'rendered order ' + JSON.stringify(sortedIds) + ' does not match server sort ' + JSON.stringify(apiIds) };
|
|
63
|
+
}
|
|
64
|
+
return { verdict: 'pass', detail: 'initial=' + JSON.stringify(initialIds) + ' sorted=' + JSON.stringify(sortedIds) };
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
id: 'AC-17102-1',
|
|
69
|
+
severity: 'block',
|
|
70
|
+
description: 'Filter chrome text search issues q=<value> request and narrows rendered rows',
|
|
71
|
+
run: async ({ browser, fetch, runtimeUrl }) => {
|
|
72
|
+
if (!browser) return { verdict: 'fail', detail: 'no packBrowser wired' };
|
|
73
|
+
await browser.goto(runtimeUrl + '/');
|
|
74
|
+
await browser.type('input#filterInput', 'Alpha', 'filter input');
|
|
75
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
76
|
+
const names = await browser.evaluate(() =>
|
|
77
|
+
Array.from(document.querySelectorAll('table[role="grid"] tbody tr td:nth-child(3)'))
|
|
78
|
+
.map((td) => td.textContent.trim()));
|
|
79
|
+
const apiRes = await fetch(runtimeUrl + '/api/rows?q=Alpha&page=1&pageSize=3');
|
|
80
|
+
const apiPayload = await apiRes.json();
|
|
81
|
+
if (apiPayload.q !== 'Alpha') {
|
|
82
|
+
return { verdict: 'fail', detail: 'server did not read q parameter; payload.q=' + JSON.stringify(apiPayload.q) };
|
|
83
|
+
}
|
|
84
|
+
const expected = apiPayload.rows.map((r) => r.name);
|
|
85
|
+
if (JSON.stringify(names) !== JSON.stringify(expected)) {
|
|
86
|
+
return { verdict: 'fail', detail: 'filter did not narrow rows: rendered=' + JSON.stringify(names) + ' expected=' + JSON.stringify(expected) };
|
|
87
|
+
}
|
|
88
|
+
return { verdict: 'pass', detail: 'filter q=Alpha rendered ' + JSON.stringify(names) };
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
id: 'AC-17103-2',
|
|
93
|
+
severity: 'block',
|
|
94
|
+
description: 'Pagination announcement uses an aria-live region reading Page N of M',
|
|
95
|
+
run: async ({ browser, runtimeUrl }) => {
|
|
96
|
+
if (!browser) return { verdict: 'fail', detail: 'no packBrowser wired' };
|
|
97
|
+
await browser.goto(runtimeUrl + '/');
|
|
98
|
+
const initial = await browser.evaluate(() => {
|
|
99
|
+
const live = document.getElementById('paginationLive');
|
|
100
|
+
return { text: live?.textContent ?? '', ariaLive: live?.getAttribute('aria-live') ?? null };
|
|
101
|
+
});
|
|
102
|
+
if (initial.ariaLive !== 'polite') {
|
|
103
|
+
return { verdict: 'fail', detail: 'pagination status region missing aria-live=polite: ' + JSON.stringify(initial) };
|
|
104
|
+
}
|
|
105
|
+
if (!/^Page \d+ of \d+$/.test(initial.text)) {
|
|
106
|
+
return { verdict: 'fail', detail: 'initial pagination text does not match "Page N of M": ' + JSON.stringify(initial.text) };
|
|
107
|
+
}
|
|
108
|
+
await browser.click('button#pageNext', 'next page button');
|
|
109
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
110
|
+
const next = await browser.evaluate(() => document.getElementById('paginationLive')?.textContent ?? '');
|
|
111
|
+
if (!/^Page 2 of \d+$/.test(next)) {
|
|
112
|
+
return { verdict: 'fail', detail: 'next-page announcement did not update: ' + JSON.stringify(next) };
|
|
113
|
+
}
|
|
114
|
+
return { verdict: 'pass', detail: 'initial=' + JSON.stringify(initial.text) + ' next=' + JSON.stringify(next) };
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
id: 'AC-17104-3',
|
|
119
|
+
severity: 'block',
|
|
120
|
+
description: 'Bulk-action confirmation dialog opens as aria-modal and returns focus to the originating row on close',
|
|
121
|
+
run: async ({ browser, runtimeUrl }) => {
|
|
122
|
+
if (!browser) return { verdict: 'fail', detail: 'no packBrowser wired' };
|
|
123
|
+
await browser.goto(runtimeUrl + '/');
|
|
124
|
+
await browser.click('input.rowSelect[data-id="1"]', 'select row 1');
|
|
125
|
+
await browser.click('button#bulkAction', 'bulk action button');
|
|
126
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
127
|
+
const opened = await browser.evaluate(() => {
|
|
128
|
+
const dialog = document.getElementById('bulkDialog');
|
|
129
|
+
return {
|
|
130
|
+
hidden: dialog?.hidden ?? true,
|
|
131
|
+
role: dialog?.getAttribute('role') ?? null,
|
|
132
|
+
ariaModal: dialog?.getAttribute('aria-modal') ?? null,
|
|
133
|
+
ariaLabelledBy: dialog?.getAttribute('aria-labelledby') ?? null,
|
|
134
|
+
ariaDescribedBy: dialog?.getAttribute('aria-describedby') ?? null,
|
|
135
|
+
focused: document.activeElement?.id ?? null,
|
|
136
|
+
};
|
|
137
|
+
});
|
|
138
|
+
if (opened.hidden || opened.role !== 'dialog' || opened.ariaModal !== 'true') {
|
|
139
|
+
return { verdict: 'fail', detail: 'dialog did not open with role=dialog and aria-modal=true: ' + JSON.stringify(opened) };
|
|
140
|
+
}
|
|
141
|
+
if (!opened.ariaLabelledBy || !opened.ariaDescribedBy) {
|
|
142
|
+
return { verdict: 'fail', detail: 'dialog missing aria-labelledby / aria-describedby: ' + JSON.stringify(opened) };
|
|
143
|
+
}
|
|
144
|
+
if (opened.focused !== 'bulkConfirm') {
|
|
145
|
+
return { verdict: 'fail', detail: 'confirm control did not receive focus on open: ' + JSON.stringify(opened) };
|
|
146
|
+
}
|
|
147
|
+
await browser.click('button#bulkCancel', 'cancel bulk');
|
|
148
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
149
|
+
const closed = await browser.evaluate(() => ({
|
|
150
|
+
hidden: document.getElementById('bulkDialog')?.hidden ?? false,
|
|
151
|
+
focused: document.activeElement?.getAttribute?.('data-id') ?? document.activeElement?.id ?? null,
|
|
152
|
+
focusedTag: document.activeElement?.tagName ?? null,
|
|
153
|
+
focusedType: document.activeElement?.getAttribute?.('type') ?? null,
|
|
154
|
+
}));
|
|
155
|
+
if (!closed.hidden) {
|
|
156
|
+
return { verdict: 'fail', detail: 'dialog did not close: ' + JSON.stringify(closed) };
|
|
157
|
+
}
|
|
158
|
+
if (closed.focused !== '1' || closed.focusedType !== 'checkbox') {
|
|
159
|
+
return { verdict: 'fail', detail: 'focus did not return to row 1 checkbox: ' + JSON.stringify(closed) };
|
|
160
|
+
}
|
|
161
|
+
return { verdict: 'pass', detail: 'dialog open+close: opened=' + JSON.stringify(opened) + ' closed=' + JSON.stringify(closed) };
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
id: 'AC-17105-1',
|
|
166
|
+
severity: 'block',
|
|
167
|
+
description: 'Empty, loading, error and no-results states each render a distinct role=region with aria-live=polite',
|
|
168
|
+
run: async ({ browser, runtimeUrl }) => {
|
|
169
|
+
if (!browser) return { verdict: 'fail', detail: 'no packBrowser wired' };
|
|
170
|
+
const states = [
|
|
171
|
+
{ name: 'empty', url: runtimeUrl + '/?state=empty', expectId: 'emptyRegion' },
|
|
172
|
+
{ name: 'loading', url: runtimeUrl + '/?state=loading', expectId: 'loadingRegion' },
|
|
173
|
+
{ name: 'error', url: runtimeUrl + '/?state=error', expectId: 'errorRegion' },
|
|
174
|
+
];
|
|
175
|
+
const observed = [];
|
|
176
|
+
for (const state of states) {
|
|
177
|
+
await browser.goto(state.url);
|
|
178
|
+
const info = await browser.evaluate((id) => {
|
|
179
|
+
const el = document.getElementById(id);
|
|
180
|
+
if (!el) return { present: false };
|
|
181
|
+
return {
|
|
182
|
+
present: true,
|
|
183
|
+
role: el.getAttribute('role'),
|
|
184
|
+
ariaLive: el.getAttribute('aria-live'),
|
|
185
|
+
};
|
|
186
|
+
}, state.expectId);
|
|
187
|
+
if (!info.present || info.role !== 'region' || info.ariaLive !== 'polite') {
|
|
188
|
+
return { verdict: 'fail', detail: 'state ' + state.name + ' missing region+aria-live: ' + JSON.stringify(info) };
|
|
189
|
+
}
|
|
190
|
+
observed.push({ state: state.name, info });
|
|
191
|
+
}
|
|
192
|
+
await browser.goto(runtimeUrl + '/?q=ZZZ');
|
|
193
|
+
await new Promise((resolve) => setTimeout(resolve, 400));
|
|
194
|
+
const noResults = await browser.evaluate(() => {
|
|
195
|
+
const el = document.getElementById('noResultsRegion');
|
|
196
|
+
if (!el) return { present: false };
|
|
197
|
+
return {
|
|
198
|
+
present: true,
|
|
199
|
+
hidden: el.hidden,
|
|
200
|
+
role: el.getAttribute('role'),
|
|
201
|
+
ariaLive: el.getAttribute('aria-live'),
|
|
202
|
+
};
|
|
203
|
+
});
|
|
204
|
+
if (!noResults.present || noResults.role !== 'region' || noResults.ariaLive !== 'polite') {
|
|
205
|
+
return { verdict: 'fail', detail: 'no-results region shape wrong: ' + JSON.stringify(noResults) };
|
|
206
|
+
}
|
|
207
|
+
return { verdict: 'pass', detail: 'observed=' + JSON.stringify(observed) + ' noResults=' + JSON.stringify(noResults) };
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
id: 'AC-17106-1',
|
|
212
|
+
severity: 'block',
|
|
213
|
+
description: 'Column reorder has a non-drag keyboard-reachable path (WCAG 2.5.7)',
|
|
214
|
+
run: async ({ browser, runtimeUrl }) => {
|
|
215
|
+
if (!browser) return { verdict: 'fail', detail: 'no packBrowser wired' };
|
|
216
|
+
await browser.goto(runtimeUrl + '/');
|
|
217
|
+
const buttons = await browser.evaluate(() =>
|
|
218
|
+
Array.from(document.querySelectorAll('button.columnMove')).map((b) => ({
|
|
219
|
+
column: b.getAttribute('data-column'),
|
|
220
|
+
direction: b.getAttribute('data-direction'),
|
|
221
|
+
ariaLabel: b.getAttribute('aria-label'),
|
|
222
|
+
tag: b.tagName,
|
|
223
|
+
})));
|
|
224
|
+
if (buttons.length === 0) {
|
|
225
|
+
return { verdict: 'fail', detail: 'no keyboard column-move buttons found' };
|
|
226
|
+
}
|
|
227
|
+
const initialOrder = await browser.evaluate(() =>
|
|
228
|
+
Array.from(document.querySelectorAll('table[role="grid"] thead th[data-column]')).map((th) => th.getAttribute('data-column')));
|
|
229
|
+
await browser.click('button.columnMove[data-column="score"][data-direction="left"]', 'move score left');
|
|
230
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
231
|
+
const afterOrder = await browser.evaluate(() =>
|
|
232
|
+
Array.from(document.querySelectorAll('table[role="grid"] thead th[data-column]')).map((th) => th.getAttribute('data-column')));
|
|
233
|
+
if (JSON.stringify(initialOrder) === JSON.stringify(afterOrder)) {
|
|
234
|
+
return { verdict: 'fail', detail: 'column reorder button did not change header order: ' + JSON.stringify(initialOrder) };
|
|
235
|
+
}
|
|
236
|
+
return { verdict: 'pass', detail: 'initial=' + JSON.stringify(initialOrder) + ' after=' + JSON.stringify(afterOrder) + ' buttons=' + JSON.stringify(buttons.length) };
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
],
|
|
240
|
+
};
|
|
@@ -20,5 +20,10 @@
|
|
|
20
20
|
| Blueprint | US band | ADR/TAC suffix block | Status | Global topics |
|
|
21
21
|
|---|---|---|---|---|
|
|
22
22
|
| application-error-handling | 16101-16899 | 17xx | shipped v1.0.0 | `errorHandling` |
|
|
23
|
+
| application-datatable | 17101-17899 | 18xx | shipped v1.0.0 | none |
|
|
24
|
+
| application-charts | 18101-18899 | 19xx | shipped v1.0.0 | none |
|
|
25
|
+
| application-dashboard | 19101-19899 | 20xx | shipped v1.0.0 | none |
|
|
26
|
+
| application-notifications-in-app | 20101-20899 | 21xx | shipped v1.0.0 | none |
|
|
27
|
+
| application-admin-console | 21101-21899 | 22xx | shipped v1.0.0 | none |
|
|
23
28
|
|
|
24
29
|
The shelf-wide band registry lives in `packages/rcf-lite/docs/blueprint-authoring.md` section 5.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# application-notifications-in-app CHANGELOG
|
|
2
|
+
|
|
3
|
+
## 1.0.0 (visual round T-4, spec 2026-09-04)
|
|
4
|
+
|
|
5
|
+
- First ratified version of the shelf's application-notifications-in-app blueprint. Five REQs (live-region preseeding on every declared route; transient toast contract with priority-to-role mapping, one-shot announcement and timeout floor; notification centre inbox with retention and acknowledge round-trip; per-user preferences UI with category silence and sibling delegation; delivery-attempt log with operator-readable rows), eight USs binding runtime-observable ACs plus three cross-cutting cases (page load with backlog, background event, disjoint-content contract), three TACs (live-region wrappers with the toast factory; centre inbox with retention and acknowledge round-trip; preferences UI with sibling delegation), three ADRs (priority-to-role mapping polite/status vs assertive/alert per WCAG 4.1.3 and the ARIA APG alert pattern; six-second toast timeout floor per WCAG 2.2.1 with elicited overrides above the floor; thirty-day centre retention window with elicited overrides). No new global topics.
|
|
6
|
+
- Reserves the `application-notifications-` family prefix for the sibling channel blueprints the shelf will grow into (`-email`, `-push`, `-webhook`) as a doc-only reservation on the blueprint README and every applying blueprint's `docs/topics.md` shelf band registry per Baz decision 2026-09-04 ("we might support more types of notifications - be clear in the name what these ones are").
|
|
7
|
+
- Ships `probe-packs/application-notifications-in-app.pack.mjs`: three browser-verify checks anchored to blueprint AC ids, every check carrying a description field per spec section 9. `AC-20101-1` live-region preseeded on every declared route (wrappers present AND empty at load, enumerated by `[data-live-region]`). `AC-20102-1` transient toast contract with priority-to-role mapping and timeout measured against the ADR-2102 six-second floor via `data-shown-at`/`data-dismissed-at` timestamps (no six-second sleep in the pack; bounded polling). `AC-20103-1` centre acknowledge round-trip enumerated by `data-notification-id` (per-element attribute per T-3 gate discipline), reconciled through both `window.__notificationFetches` and the server-side request log. Fourth blueprint on the shelf that ships a Playwright probe pack under the T-0 runner extension.
|
|
8
|
+
- Ships a sample-app fixture at `packages/rcf-lite/test/fixtures/probe-pack-application-notifications-in-app/` (dependency-free Node HTTP server) so the pack can be probed at the shelf's own gate; the fixture is the golden the gate reviewer drives, with `?break=preseed`, `?break=role`, `?break=timeout` and `?break=ack` query switches for the negative runs. Three routes (`/`, `/notifications-centre`, `/notifications-preferences`); every route preseeds both live-region wrappers.
|
|
9
|
+
- Suggests the `logging` and `errorHandling` companions with the ratified spec's reasons. `providesRoles` absent, leaf blueprint per the loader contract (an empty array is refused, an omitted field marks the blueprint as a leaf).
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Notifications in-app blueprint (v1.0.0)
|
|
2
|
+
|
|
3
|
+
Vendor-neutral in-app-notifications contract for a rcf-lite application. Ships the live-region preseeding discipline (polite and assertive wrappers present in the DOM before any notification fires per the WAI-ARIA 1.2 normative reference), the transient toast contract with priority-to-role mapping (info to polite/status, error to assertive/alert per WCAG 4.1.3 and the ARIA APG alert pattern), the WCAG 2.2.1 six-second toast timeout floor with operator-elicited overrides above the floor, the notification centre inbox with a thirty-day retention window and a per-item acknowledge round-trip enumerated by `data-notification-id`, the per-user preferences UI with category silence and sibling-channel digest delegation, and the delivery-attempt log write path. Ships a Playwright probe pack under `probe-packs/application-notifications-in-app.pack.mjs` whose three checks are the runtime gate the delivery-ci-workflows runner drives (visual round spec 2026-09-04, section 5.4). No new global topics; suggests the `logging` and `errorHandling` companions. Fourth blueprint on the shelf that ships a Playwright probe pack under the T-0 runner extension.
|
|
4
|
+
|
|
5
|
+
## Apply
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
rcf define blueprint add <path-to>/blueprints/application-notifications-in-app
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Applies namespaced contributions into the project tree and records `manifest.blueprints[]`. Consumes the `logging` and `errorHandling` companions when they resolve to an applied provider or a registered library; falls back to the shelf providers otherwise.
|
|
12
|
+
|
|
13
|
+
## Anatomy
|
|
14
|
+
|
|
15
|
+
| Piece | Where | What |
|
|
16
|
+
|---|---|---|
|
|
17
|
+
| Metadata | `blueprint.json` | Slug, version 1.0.0, category `application`, `suggestedCompanions: [{ logging }, { errorHandling }]`, `providesRoles` absent (leaf blueprint), 19 contributions in the 20xxx US band and 21xx ADR/TAC block |
|
|
18
|
+
| Doc set | `contributions/` | 5 REQs, 8 USs, 3 TACs, 3 ADRs, schema-valid and namespaced |
|
|
19
|
+
| Probe pack | `probe-packs/application-notifications-in-app.pack.mjs` | Three browser-verify checks anchored to blueprint AC ids: `AC-20101-1` live-region preseeding on every declared route (wrappers present AND empty at load); `AC-20102-1` transient toast contract with priority-to-role mapping and timeout measured against the ADR-2102 floor via `data-shown-at`/`data-dismissed-at`; `AC-20103-1` centre acknowledge round-trip enumerated by `data-notification-id` |
|
|
20
|
+
| Guide | `guide/application-notifications-in-app.md` | Operator-facing: when to reach, when not, mechanism-reach gaps |
|
|
21
|
+
| Coordination vocabulary | `docs/topics.md` | Shelf id band registry update; no new global topics claimed; the family-prefix reservation row |
|
|
22
|
+
|
|
23
|
+
## What it contributes, and what it deliberately does not
|
|
24
|
+
|
|
25
|
+
Contributed: REQ, US (with inline ACs), TAC, ADR, plus one shipped probe pack. Adherence is expressed as ACs; the blueprint ships no notifications-framework source and no test files (the probe pack drives the real browser against the applying project's own runtime).
|
|
26
|
+
|
|
27
|
+
Deliberately not contributed: any transport (email, push, webhook). The in-app slug is the discriminator per Baz decision 2026-09-04: "we might support more types of notifications - be clear in the name what these ones are". Sibling channel blueprints ship their own transport contracts under the reserved `application-notifications-` family prefix.
|
|
28
|
+
|
|
29
|
+
## Family-prefix reservation
|
|
30
|
+
|
|
31
|
+
The `application-notifications-` prefix is reserved for the sibling in-app-adjacent channels the shelf will grow into:
|
|
32
|
+
|
|
33
|
+
- `application-notifications-email`: server-to-user notifications through the applied `email-smtp-resend` companion (or a paired email provider). Owns the email-transport dedupe semantics and the delivery-attempt log rows for the email channel.
|
|
34
|
+
- `application-notifications-push`: Web Push and platform APN/FCM notifications. Owns the subscription lifecycle and the platform-token store.
|
|
35
|
+
- `application-notifications-webhook`: outbound HTTP notifications to operator-configured endpoints. Owns the delivery-retry semantics and the endpoint registry.
|
|
36
|
+
|
|
37
|
+
The reservation is doc-only in v1.0.0 (per spec Q3 default): the family prefix is named in this README and in every shipped blueprint's `docs/topics.md` shelf band registry as a reserved-slot row. No sibling channel ships in this round. Any future PR that proposes a name outside the family (`application-alerts-email`, `application-messages-push`) reads against this reservation and stops at author-side review.
|
|
38
|
+
|
|
39
|
+
Digest opt-in on the preferences UI is elicited on the sibling channel, not here: the preferences UI carries a disabled section per sibling channel that is not yet applied, labelled `data-preference-status="sibling not applied"`. When the sibling ships and the applying project applies it, that sibling's own blueprint reads the operator's preference state and drives the digest transport.
|
|
40
|
+
|
|
41
|
+
## Quality bar
|
|
42
|
+
|
|
43
|
+
Every route the applying project ships renders with both live-region wrappers preseeded in the DOM before any notification fires (`[aria-live="polite"] [data-live-region="polite"]` and `[role="alert"] [data-live-region="assertive"]`), both empty at page load. Every toast writes into exactly one wrapper based on its priority (info to polite as `role="status"`, error to assertive as `role="alert"`) and records `data-shown-at` and `data-dismissed-at` timestamps a probe can measure the timeout against without sleeping in the pack. Every toast timeout is at or above the WCAG 2.2.1 six-second floor. The notification centre lists notifications inside the ADR-2103 retention window, every item enumerated by `data-notification-id`, every acknowledge control Tab-reachable and round-tripping to `POST /api/notifications/acknowledge` with the DOM updating on the response.
|
|
44
|
+
|
|
45
|
+
## Known mechanism-reach gaps
|
|
46
|
+
|
|
47
|
+
Every runtime-observable AC that is not bound to a pack check appears here individually per the T-1 gate discipline (`blueprint-authoring-checklist.md` section 6.g): categories are not enough. The pack has three checks; every other runtime-observable AC on this blueprint is a mechanism-reach gap named below.
|
|
48
|
+
|
|
49
|
+
- **AC-20101-2 live-region factory identity stable across route changes**. The pack asserts the wrappers are preseeded on every declared route (AC-20101-1); it does not assert the two wrappers are the same DOM nodes across route changes (a factory that recreates the wrappers on route change passes AC-20101-1 but fails AC-20101-2). A v1.1 minor bump could persist a `data-live-region-id` on each wrapper and assert identity across a `browser.click` on a nav link.
|
|
50
|
+
- **AC-20102-2 toast factory library-scope shape**. The pack drives the runtime toast surface (AC-20102-1); the library-scope AC on the factory's own signature is a project-side review concern.
|
|
51
|
+
- **AC-20103-2 centre factory reads through the delivery-log endpoint**. The pack drives the item enumeration and the acknowledge round-trip (AC-20103-1); the library-scope AC on the factory's own delivery-log read is a project-side review concern.
|
|
52
|
+
- **AC-20104-1 preferences category silence**. The preferences surface renders per-category toggles but the pack does not itself activate a silence toggle and assert the round-trip today. A v1.1 minor bump could add a preferences-round-trip check paralleling AC-20103-1.
|
|
53
|
+
- **AC-20104-2 sibling-channel digest section disabled when no sibling applied**. The fixture renders the disabled sections and the pack could inspect them, but the AC's real bite is when a sibling channel ships and the disabled state must lift; this class stays a v1.1 minor bump candidate for when the first sibling ships.
|
|
54
|
+
- **AC-20105-1 delivery-log endpoint shape**. The pack does not enumerate every row on the log (the delivery-log's persistence is delegated to the applied `logging` companion). A v1.1 minor bump could add a log-shape probe that reads `/api/delivery-log`, asserts the row shape and confirms append-only order.
|
|
55
|
+
- **AC-20105-2 delivery-log writes through the applied logging companion factory**. The pack does not inspect the companion's factory today. A v1.1 minor bump could add a companion-boundary check reading a marker the applying project stamps on companion-authored rows.
|
|
56
|
+
- **AC-20106-1 page load with backlog does not saturate the polite queue**. The pack does not itself count polite-queue emissions at load. A v1.1 minor bump could add a MutationObserver-based check that counts inserts into the polite wrapper during the first render tick.
|
|
57
|
+
- **AC-20107-1 background event indistinguishable from operator-driven event**. The pack fires the operator-driven variant (AC-20102-1); a background-event dispatch through `POST /__emit` on the fixture would exercise the same code path and reach the same DOM shape.
|
|
58
|
+
- **AC-20108-1 disjoint content between wrappers**. The pack asserts the disjoint-content rule at the moment it inspects the wrappers, not continuously across the toast lifetime. TAC-2101 notes name this residual; a v1.1 minor bump could add a MutationObserver-based check.
|
|
59
|
+
- **AC-2101-6 family-prefix reservation is documented on the shelf**. This is a doc-observable AC (the reservation paragraph exists in this README and the shelf registry rows). Not runtime-observable; not a mechanism-reach gap in the same sense but named for completeness.
|
|
60
|
+
|
|
61
|
+
## Elicited parameters (ADR-2101 through ADR-2103 and REQ notes)
|
|
62
|
+
|
|
63
|
+
The applying project elicits these at apply; the declarative ADR shape (`elicited: true`) records the intent on the manifest. The runner has no apply-time elicitation phase today (w-2026-09-04-dave-022, built in T-5); accept the declarative shape and gather the operator's answers by hand during the apply pass.
|
|
64
|
+
|
|
65
|
+
- **Toast timeout floor** (ADR-2102): six seconds baseline per WCAG 2.2.1; operator elicits an override above the floor (twelve seconds, thirty seconds); the elicited value lands on `manifest.blueprints[application-notifications-in-app].appliedParameters.toastTimeoutSeconds`. A value below six is refused at apply.
|
|
66
|
+
- **Notification categories** (REQ-004): the operator's category list (payment, security, product, and any project-specific categories). The preferences UI renders one section per elicited category.
|
|
67
|
+
- **Centre retention window** (ADR-2103): thirty days by default; operator elicits an override. Below one day refused at apply.
|
|
68
|
+
- **Notification centre route path** (REQ-003 note): `/notifications-centre` by default; operator elicits an override for a bespoke route.
|
|
69
|
+
- **Digest transports** (REQ-004 note): elicited on the sibling channel blueprint at its apply, not here. This blueprint ships the preferences UI's disabled sibling section only.
|
|
70
|
+
|
|
71
|
+
## Standards trace
|
|
72
|
+
|
|
73
|
+
WCAG 4.1.3 Status Messages on the live-region contract (REQ-001, ADR-2101). ARIA APG alert pattern on the assertive slot (ADR-2101). WCAG 2.2.1 Timing Adjustable on the toast timeout floor (ADR-2102). WAI-ARIA 1.2 live regions normative reference (Sara Soueidan's guidance is the shipped project-side citation on the preseeding contract; the standards trace holds against the WAI-ARIA specification directly). `standardsTraceClause` on each ADR carries the primary clause or pattern id.
|
|
74
|
+
|
|
75
|
+
## Consumers and dependencies
|
|
76
|
+
|
|
77
|
+
- Consumes the applied `logging` companion (or the shelf provider `observability-logging`) for the delivery-attempt log write path (REQ-005, TAC-2102) and every acknowledge round-trip record. A project without a `logging` companion applied sees the delivery-log endpoint returning an empty rows array, which fails project-side review.
|
|
78
|
+
- Consumes the applied `errorHandling` companion (or the shelf provider `application-error-handling`) for the assertive-slot alert's internal error record when an acknowledge round-trip fails at the server.
|
|
79
|
+
- Reserves the `application-notifications-` family prefix for sibling channel blueprints (see above).
|
|
80
|
+
- Reuses the T-3 pack-browser `resize(width, height)` seam only for future minor bumps; v1.0.0 does not exercise breakpoint reflow in the pack.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"slug": "application-notifications-in-app",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"category": "application",
|
|
5
|
+
"suggestedCompanions": [
|
|
6
|
+
{ "role": "logging", "reason": "Every acknowledge round-trip and every delivery-attempt row is written through the applied logger; a logging companion supplies the factory the notification centre, the toast surface and the delivery-attempt log write records against." },
|
|
7
|
+
{ "role": "errorHandling", "reason": "The assertive-slot alert routes an internal error record whose error envelope conforms to the applied error contract; an errorHandling companion supplies the record factory and the surface boundary the alert toast renders through." }
|
|
8
|
+
],
|
|
9
|
+
"contributions": [
|
|
10
|
+
{ "id": "application-notifications-in-app-REQ-001", "kind": "req", "path": "requirements/application-notifications-in-app-req-001.json" },
|
|
11
|
+
{ "id": "application-notifications-in-app-REQ-002", "kind": "req", "path": "requirements/application-notifications-in-app-req-002.json" },
|
|
12
|
+
{ "id": "application-notifications-in-app-REQ-003", "kind": "req", "path": "requirements/application-notifications-in-app-req-003.json" },
|
|
13
|
+
{ "id": "application-notifications-in-app-REQ-004", "kind": "req", "path": "requirements/application-notifications-in-app-req-004.json" },
|
|
14
|
+
{ "id": "application-notifications-in-app-REQ-005", "kind": "req", "path": "requirements/application-notifications-in-app-req-005.json" },
|
|
15
|
+
{ "id": "application-notifications-in-app-US-20101", "kind": "us", "path": "user-stories/application-notifications-in-app-us-20101.json" },
|
|
16
|
+
{ "id": "application-notifications-in-app-US-20102", "kind": "us", "path": "user-stories/application-notifications-in-app-us-20102.json" },
|
|
17
|
+
{ "id": "application-notifications-in-app-US-20103", "kind": "us", "path": "user-stories/application-notifications-in-app-us-20103.json" },
|
|
18
|
+
{ "id": "application-notifications-in-app-US-20104", "kind": "us", "path": "user-stories/application-notifications-in-app-us-20104.json" },
|
|
19
|
+
{ "id": "application-notifications-in-app-US-20105", "kind": "us", "path": "user-stories/application-notifications-in-app-us-20105.json" },
|
|
20
|
+
{ "id": "application-notifications-in-app-US-20106", "kind": "us", "path": "user-stories/application-notifications-in-app-us-20106.json" },
|
|
21
|
+
{ "id": "application-notifications-in-app-US-20107", "kind": "us", "path": "user-stories/application-notifications-in-app-us-20107.json" },
|
|
22
|
+
{ "id": "application-notifications-in-app-US-20108", "kind": "us", "path": "user-stories/application-notifications-in-app-us-20108.json" },
|
|
23
|
+
{ "id": "TAC-2101-application-notifications-in-app-live-region", "kind": "tac", "path": "tacs/tac-2101-application-notifications-in-app-live-region.json" },
|
|
24
|
+
{ "id": "TAC-2102-application-notifications-in-app-centre", "kind": "tac", "path": "tacs/tac-2102-application-notifications-in-app-centre.json" },
|
|
25
|
+
{ "id": "TAC-2103-application-notifications-in-app-preferences", "kind": "tac", "path": "tacs/tac-2103-application-notifications-in-app-preferences.json" },
|
|
26
|
+
{ "id": "ADR-2101-application-notifications-in-app-live-region-role-mapping", "kind": "adr", "path": "adrs/adr-2101-application-notifications-in-app-live-region-role-mapping.json", "recommendedDefault": true, "elicited": false, "standardsTraceClause": "WCAG 4.1.3 (Status Messages); ARIA APG alert pattern" },
|
|
27
|
+
{ "id": "ADR-2102-application-notifications-in-app-toast-timeout-floor", "kind": "adr", "path": "adrs/adr-2102-application-notifications-in-app-toast-timeout-floor.json", "recommendedDefault": true, "elicited": true, "standardsTraceClause": "WCAG 2.2.1 (Timing Adjustable)" },
|
|
28
|
+
{ "id": "ADR-2103-application-notifications-in-app-retention-window", "kind": "adr", "path": "adrs/adr-2103-application-notifications-in-app-retention-window.json", "recommendedDefault": true, "elicited": true, "standardsTraceClause": "generic enterprise practice" }
|
|
29
|
+
]
|
|
30
|
+
}
|