Wave 0 item W0-9 of the dashboard fix plan. The EDI home now shows business work only (DASHBOARD-STANDARD P0.4, A-0).
System widgets leave the EDI home.edi_home_system, edi_home_dead, edi_home_certificates and edi_home_setup (all integration configuration: identities, transports, certificates, guides, and the host's EdiRuntime.initialize() step) are no longer in the app's widget list. They stay defined and are exposed as EdiHome.ADMIN_WIDGET_NAMES (same pattern as SlackApp.ADMIN_WIDGETS) for a host to place on its Admin home. They are gated to edi.admin.hasAccess (EdiHome.ADMIN_PERMISSION_BASE_NAME, the permission the admin processes already use), DenyBehavior.HIDDEN, and are all full width (gridColumns 12). That fixes the narrow side-by-side certificates tile.
One business item replaces them. A new edi_home_delayed alert, first on the home, says "Inbound documents are delayed" with the count, the threshold and the oldest document's age. It links to /app/edi_inbox?filter=... (the same filter-link form the EDI tiles use: unprocessed statuses with receivedAt before the cutoff). It renders nothing (hideWidget) when nothing is delayed or when the viewer cannot read the inbox. The threshold is the new config value inboundDelayedAfterMinutes, default 60. No new required config.
No unprotected widgets. Every home widget (EdiHome.HOME_WIDGET_NAMES) now needs edi.hasAccess (the EDI app permission) and is hidden without it. Before, all were NOT_PROTECTED.
No silent -1. A failed Setup count is now null. It renders as "Unavailable" and is logged (EDI setup count unavailable, with the table), never as -1.
Docs: README, UPGRADE and CHANGELOG, plus a help entry for the new widget.
The "KoF22 Demo Partner" seeding is untouched (open owner decision, W0-12).
Rubric item moved
A1 0 -> 1 on EDI (edi); A10 narrow certificates widget fixed in its Admin placement; A7 no silent -1.
Audit row fixed
EDI (edi), Content app home:
A1 (0): "edi_home_system is a component/queue health table, edi_home_dead and edi_home_certificates are system tiles, and edi_home_setup is transport/certificate configuration. All are shown to business users (A-0). No purpose line or table action". The system widgets are now admin-only and off the home. A purpose line and table action are still missing, so A1 moves to 1, not 2.
A7 (0): "Differing implicit ranges: today, 24 h, 7 d, 30 d, all-open; no shared scope; no as-of; safeCount turns failures into -1 silently inside Setup". The silent -1 is fixed. The shared scope and as-of are later plan items.
Tests
New EdiHomeAudienceTest:
The app widget list equals HOME_WIDGET_NAMES and excludes every ADMIN_WIDGET_NAMES entry. The delayed alert is first. Admin widgets are gated to edi.admin, hidden and full width. Every edi_home_* widget is HAS_ACCESS_PERMISSION and HIDDEN.
A business EDI user (edi.hasAccess plus table reads, no edi.admin.hasAccess) does not get the system widgets in MetaDataAction output, and RenderWidgetAction with ENFORCE throws QPermissionDeniedException for each one. An EDI admin gets and renders them. A user without edi.hasAccess gets no edi_home_* widget.
The delayed alert is hidden with no backlog and hidden at 30 m. At 95 m it shows "Inbound documents are delayed ... 1 h ... 1 h 35 m" with href="/app/edi_inbox?filter=...", and the decoded filter has the receivedAt cutoff and the statuses. It is hidden again at a 120 m threshold, and hidden for a viewer without inbox read.
Setup with transport read denied shows "5. Transport | Unavailable", and no cell contains -1.
Updated EdiSetupStatusTest (null counts, setup is in the admin list), PhiCanaryTest (the viewer now holds the widget permissions) and EdiDemoServerTest (new config property).
Widget-level preview, attached locally (not committed). Each page uses the real EdiHome.render output for every widget, rendered from a unit test with synthetic data into a minimal standalone page and shot with Playwright at 390, 768, 1024, 1440, 1920 and 3200 px. No width has horizontal scroll.
before\<width>.png: the old 12-widget home that every edi.hasAccess user saw, with the narrow Dead letters and Certificates tiles and the Setup and System tables.
after\<width>.png: the business home with the "Inbound documents are delayed" alert first (two synthetic inbox rows, oldest 2 h 15 m), then 4 tiles, then the queues.
admin\<width>.png: EdiHome.ADMIN_WIDGET_NAMES at full width, as a host would place them on its Admin home.
Full-page shots come when kof22 pins the release.
Release
A qbit-edi release is needed: the next RC after what kof22 pins. Website-Backend origin/main pins qbit-edi.version0.1.0-RC.9, so this ships in 0.1.0-RC.10 (or later). Cut it with the release-rc.yml workflow after merge.
Follow-up kof22 (Website-Backend) PR, described here and not done in this PR:
Bump qbit-edi.version to the new RC.
Place EdiHome.ADMIN_WIDGET_NAMES on the Admin home's widget list (system audience).
Confirm the kof22-admins grant covers edi.admin.hasAccess. WebsiteEdiMetaData.adminPermissions already derives each edi_ widget's base name plus .hasAccess, so it should pick it up without code changes.
Business EDI users keep edi.hasAccess and need edi.inbox.read to see the delayed alert.
## Summary
Wave 0 item W0-9 of the dashboard fix plan. The EDI home now shows business work only (DASHBOARD-STANDARD P0.4, A-0).
- **System widgets leave the EDI home.** `edi_home_system`, `edi_home_dead`, `edi_home_certificates` and `edi_home_setup` (all integration configuration: identities, transports, certificates, guides, and the host's `EdiRuntime.initialize()` step) are no longer in the app's widget list. They stay defined and are exposed as `EdiHome.ADMIN_WIDGET_NAMES` (same pattern as `SlackApp.ADMIN_WIDGETS`) for a host to place on its Admin home. They are gated to `edi.admin.hasAccess` (`EdiHome.ADMIN_PERMISSION_BASE_NAME`, the permission the admin processes already use), `DenyBehavior.HIDDEN`, and are all full width (`gridColumns` 12). That fixes the narrow side-by-side certificates tile.
- **One business item replaces them.** A new `edi_home_delayed` alert, first on the home, says "Inbound documents are delayed" with the count, the threshold and the oldest document's age. It links to `/app/edi_inbox?filter=...` (the same filter-link form the EDI tiles use: unprocessed statuses with `receivedAt` before the cutoff). It renders nothing (`hideWidget`) when nothing is delayed or when the viewer cannot read the inbox. The threshold is the new config value `inboundDelayedAfterMinutes`, default 60. No new required config.
- **No unprotected widgets.** Every home widget (`EdiHome.HOME_WIDGET_NAMES`) now needs `edi.hasAccess` (the EDI app permission) and is hidden without it. Before, all were `NOT_PROTECTED`.
- **No silent -1.** A failed Setup count is now `null`. It renders as "Unavailable" and is logged (`EDI setup count unavailable`, with the table), never as -1.
- Docs: README, UPGRADE and CHANGELOG, plus a help entry for the new widget.
The "KoF22 Demo Partner" seeding is untouched (open owner decision, W0-12).
## Rubric item moved
A1 0 -> 1 on EDI (`edi`); A10 narrow certificates widget fixed in its Admin placement; A7 no silent -1.
## Audit row fixed
EDI (`edi`), Content app home:
- **A1 (0):** "`edi_home_system` is a component/queue health table, `edi_home_dead` and `edi_home_certificates` are system tiles, and `edi_home_setup` is transport/certificate configuration. All are shown to business users (A-0). No purpose line or table action". The system widgets are now admin-only and off the home. A purpose line and table action are still missing, so A1 moves to 1, not 2.
- **A7 (0):** "Differing implicit ranges: today, 24 h, 7 d, 30 d, all-open; no shared scope; no as-of; `safeCount` turns failures into -1 silently inside Setup". The silent -1 is fixed. The shared scope and as-of are later plan items.
## Tests
- New `EdiHomeAudienceTest`:
- The app widget list equals `HOME_WIDGET_NAMES` and excludes every `ADMIN_WIDGET_NAMES` entry. The delayed alert is first. Admin widgets are gated to `edi.admin`, hidden and full width. Every `edi_home_*` widget is `HAS_ACCESS_PERMISSION` and `HIDDEN`.
- A business EDI user (`edi.hasAccess` plus table reads, no `edi.admin.hasAccess`) does not get the system widgets in `MetaDataAction` output, and `RenderWidgetAction` with `ENFORCE` throws `QPermissionDeniedException` for each one. An EDI admin gets and renders them. A user without `edi.hasAccess` gets no `edi_home_*` widget.
- The delayed alert is hidden with no backlog and hidden at 30 m. At 95 m it shows "Inbound documents are delayed ... 1 h ... 1 h 35 m" with `href="/app/edi_inbox?filter=..."`, and the decoded filter has the `receivedAt` cutoff and the statuses. It is hidden again at a 120 m threshold, and hidden for a viewer without inbox read.
- Setup with transport read denied shows "5. Transport | Unavailable", and no cell contains -1.
- Updated `EdiSetupStatusTest` (null counts, setup is in the admin list), `PhiCanaryTest` (the viewer now holds the widget permissions) and `EdiDemoServerTest` (new config property).
- `./mvnw verify`: 266 tests, 0 failures, Checkstyle and JaCoCo checks met.
## Screenshots
Widget-level preview, attached locally (not committed). Each page uses the real `EdiHome.render` output for every widget, rendered from a unit test with synthetic data into a minimal standalone page and shot with Playwright at 390, 768, 1024, 1440, 1920 and 3200 px. No width has horizontal scroll.
Folder: `C:\Users\james\AppData\Local\Temp\claude\R--Git-Local-KofTwentyTwo-Praetor\83da0ae2-628c-4edb-9fd7-a93d49e86d27\scratchpad\dashboard-standard\pr-shots\qbit-edi-edi-home\`
- `before\<width>.png`: the old 12-widget home that every `edi.hasAccess` user saw, with the narrow Dead letters and Certificates tiles and the Setup and System tables.
- `after\<width>.png`: the business home with the "Inbound documents are delayed" alert first (two synthetic inbox rows, oldest 2 h 15 m), then 4 tiles, then the queues.
- `admin\<width>.png`: `EdiHome.ADMIN_WIDGET_NAMES` at full width, as a host would place them on its Admin home.
Full-page shots come when kof22 pins the release.
## Release
A qbit-edi release is needed: the next RC after what kof22 pins. Website-Backend `origin/main` pins `qbit-edi.version` `0.1.0-RC.9`, so this ships in `0.1.0-RC.10` (or later). Cut it with the `release-rc.yml` workflow after merge.
Follow-up kof22 (Website-Backend) PR, described here and not done in this PR:
1. Bump `qbit-edi.version` to the new RC.
2. Place `EdiHome.ADMIN_WIDGET_NAMES` on the Admin home's widget list (system audience).
3. Confirm the kof22-admins grant covers `edi.admin.hasAccess`. `WebsiteEdiMetaData.adminPermissions` already derives each `edi_` widget's base name plus `.hasAccess`, so it should pick it up without code changes.
4. Business EDI users keep `edi.hasAccess` and need `edi.inbox.read` to see the delayed alert.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Wave 0 item W0-9 of the dashboard fix plan. The EDI home now shows business work only (DASHBOARD-STANDARD P0.4, A-0).
edi_home_system,edi_home_dead,edi_home_certificatesandedi_home_setup(all integration configuration: identities, transports, certificates, guides, and the host'sEdiRuntime.initialize()step) are no longer in the app's widget list. They stay defined and are exposed asEdiHome.ADMIN_WIDGET_NAMES(same pattern asSlackApp.ADMIN_WIDGETS) for a host to place on its Admin home. They are gated toedi.admin.hasAccess(EdiHome.ADMIN_PERMISSION_BASE_NAME, the permission the admin processes already use),DenyBehavior.HIDDEN, and are all full width (gridColumns12). That fixes the narrow side-by-side certificates tile.edi_home_delayedalert, first on the home, says "Inbound documents are delayed" with the count, the threshold and the oldest document's age. It links to/app/edi_inbox?filter=...(the same filter-link form the EDI tiles use: unprocessed statuses withreceivedAtbefore the cutoff). It renders nothing (hideWidget) when nothing is delayed or when the viewer cannot read the inbox. The threshold is the new config valueinboundDelayedAfterMinutes, default 60. No new required config.EdiHome.HOME_WIDGET_NAMES) now needsedi.hasAccess(the EDI app permission) and is hidden without it. Before, all wereNOT_PROTECTED.null. It renders as "Unavailable" and is logged (EDI setup count unavailable, with the table), never as -1.The "KoF22 Demo Partner" seeding is untouched (open owner decision, W0-12).
Rubric item moved
A1 0 -> 1 on EDI (
edi); A10 narrow certificates widget fixed in its Admin placement; A7 no silent -1.Audit row fixed
EDI (
edi), Content app home:edi_home_systemis a component/queue health table,edi_home_deadandedi_home_certificatesare system tiles, andedi_home_setupis transport/certificate configuration. All are shown to business users (A-0). No purpose line or table action". The system widgets are now admin-only and off the home. A purpose line and table action are still missing, so A1 moves to 1, not 2.safeCountturns failures into -1 silently inside Setup". The silent -1 is fixed. The shared scope and as-of are later plan items.Tests
EdiHomeAudienceTest:HOME_WIDGET_NAMESand excludes everyADMIN_WIDGET_NAMESentry. The delayed alert is first. Admin widgets are gated toedi.admin, hidden and full width. Everyedi_home_*widget isHAS_ACCESS_PERMISSIONandHIDDEN.edi.hasAccessplus table reads, noedi.admin.hasAccess) does not get the system widgets inMetaDataActionoutput, andRenderWidgetActionwithENFORCEthrowsQPermissionDeniedExceptionfor each one. An EDI admin gets and renders them. A user withoutedi.hasAccessgets noedi_home_*widget.href="/app/edi_inbox?filter=...", and the decoded filter has thereceivedAtcutoff and the statuses. It is hidden again at a 120 m threshold, and hidden for a viewer without inbox read.EdiSetupStatusTest(null counts, setup is in the admin list),PhiCanaryTest(the viewer now holds the widget permissions) andEdiDemoServerTest(new config property)../mvnw verify: 266 tests, 0 failures, Checkstyle and JaCoCo checks met.Screenshots
Widget-level preview, attached locally (not committed). Each page uses the real
EdiHome.renderoutput for every widget, rendered from a unit test with synthetic data into a minimal standalone page and shot with Playwright at 390, 768, 1024, 1440, 1920 and 3200 px. No width has horizontal scroll.Folder:
C:\Users\james\AppData\Local\Temp\claude\R--Git-Local-KofTwentyTwo-Praetor\83da0ae2-628c-4edb-9fd7-a93d49e86d27\scratchpad\dashboard-standard\pr-shots\qbit-edi-edi-home\before\<width>.png: the old 12-widget home that everyedi.hasAccessuser saw, with the narrow Dead letters and Certificates tiles and the Setup and System tables.after\<width>.png: the business home with the "Inbound documents are delayed" alert first (two synthetic inbox rows, oldest 2 h 15 m), then 4 tiles, then the queues.admin\<width>.png:EdiHome.ADMIN_WIDGET_NAMESat full width, as a host would place them on its Admin home.Full-page shots come when kof22 pins the release.
Release
A qbit-edi release is needed: the next RC after what kof22 pins. Website-Backend
origin/mainpinsqbit-edi.version0.1.0-RC.9, so this ships in0.1.0-RC.10(or later). Cut it with therelease-rc.ymlworkflow after merge.Follow-up kof22 (Website-Backend) PR, described here and not done in this PR:
qbit-edi.versionto the new RC.EdiHome.ADMIN_WIDGET_NAMESon the Admin home's widget list (system audience).edi.admin.hasAccess.WebsiteEdiMetaData.adminPermissionsalready derives eachedi_widget's base name plus.hasAccess, so it should pick it up without code changes.edi.hasAccessand neededi.inbox.readto see the delayed alert.🤖 Generated with Claude Code