You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Status: pending — groomed and ready for implementation
Tags: bug, portal, frontend, testing, design, P0
Parent: #148
Depends on: None
Blocks: final deployed acceptance in #155 and closure of #148
Next owner: Software Engineer
Scope
Correct the post-cutover canonical UI in top-level frontend/ at current main 36d446c. Complete the existing hash-route adapter, entity loading/history behavior, mobile Inbox triage, and the small missing operator controls below. Use the existing authenticated work APIs and shared browser-cookie login/logout flow; this is not a new router, shell, data model, or information-architecture project.
Deployment blockers #136/#143 do not block local implementation, review, merge, or source CI. After this source fix is integrated, #155 owns normal deployed verification at the corrected SHA.
Supported route matrix
These are the only supported workspace hash paths. Entity parameters are optional; without one, the route opens its list/surface.
Task queue; date sets the date, bundleId filters the queue, taskId opens the exact task, and contextBundleId shows the independent return/workflow context; preserve valid combinations
#/bundles?bundleId=<id>&taskId=<id>
Exact workflow; optional exact task within that workflow
Use URLSearchParams/encoded values and safe text rendering. A single trailing slash may normalize to the table form. Unsupported query keys are discarded. Empty hash, unknown paths, malformed path/query encoding, invalid dates, and structurally invalid parameter combinations normalize with replaceState to /#/ without adding a history entry, losing the authenticated session, or rendering route input as HTML.
Acceptance Criteria
Routes, entities, and browser history
Fresh navigation, refresh, hashchange, Back, and Forward resolve every row and valid parameter combination in the matrix inside the one canonical shell; UI state and URL never diverge or create navigation loops.
Operator-initiated list selection, close/back, notification launch, search result, and task/workflow/intake/assistant/template/sponsor relationship navigation write the canonical URL with pushState; normalization alone uses replaceState.
Entity context is applied only after its required data resolves. A requested intake outside the active filter still opens that exact item.
A stale or 404 intakeId, taskId, bundleId, assistantJobId, templateId, or bookingId shows an entity-specific, focusable not-found state with the requested ID as text plus Retry and Return-to-list actions. It never selects the first row, opens another record, leaves a generic loading panel, or reports a non-404 API failure as “not found.”
Combined task/workflow links preserve date, queue bundleId, and independent contextBundleId; #/bundles?...&taskId=... reports a task/workflow mismatch instead of silently substituting context.
Signed-out page navigation and visible Sign out use the shared browser-cookie /login and /logout flow. /api/* and /work/api/* continue to return JSON 401, never SPA HTML or a browser bearer-token path.
Mobile Inbox and readable history
Inbox has one visible page heading. At 390x844 it shows item status/context and one state-appropriate primary action before secondary controls; choosing an action reveals only its required fields, while secondary and destructive actions live in labelled keyboard-operable disclosures.
State behavior is explicit: new/triaged items prioritize Convert or Attach; blocked items prioritize due Follow-up sent or Response received; attached/converted/assistant-ready items prioritize their linked task/workflow/assistant continuation; duplicate/ignored/archived items are a read-only resolution summary. Invalid backend transitions are not presented as available actions.
Mutation controls prevent double submission, keep inline validation/API/conflict errors with the selected item, move focus to the error/status, and retain entered values for retry.
History uses operator language instead of raw action codes, renders parseable absolute Europe/Berlin date/time in a <time datetime> (relative copy may supplement it), and includes useful actor/reason/waiting/follow-up/relationship context without dumping raw metadata. Order is labelled and deterministic.
At 1440x900 and 390x844, Inbox queue/detail, disclosures, history, route not-found states, panels/dialogs, and close/back controls have no horizontal overflow, overlap, clipping, or unreachable keyboard action.
Small operator parity controls
Sign out is visible and keyboard accessible in desktop and mobile Settings, identifies the current action clearly, and invokes /logout without exposing session material.
Each notification has a labelled Dismiss action using the existing authenticated API. Success removes only that item and updates both bell counts; failure remains visible/retryable; activating Dismiss never also opens the linked task.
Recurring rows clearly distinguish Pause/Resume from Delete. Delete requires a labelled confirmation explaining that it removes only the schedule, not generated tasks; a successful unreferenced delete refreshes the list, while the existing 409 generated-history response tells the operator to Pause instead and preserves the row.
Changed states have correct heading order, names/roles, aria-current/expanded/live semantics, modal focus trap/restore, visible focus, and keyboard operation, with zero critical/serious WCAG A/AA violations in the automated affected-state scan.
Test Scenarios
Scenario: Complete route and history matrix
Given: deterministic real-API fixtures for every entity parameter
When: each route/combination is opened fresh and the operator follows relationships, closes detail, and uses Back/Forward/hash changes
Then: the exact entity, visible context, URL, focus, and history entry are synchronized
Scenario: Invalid route and stale entities
Given: unknown/malformed routes plus stale, filtered-out, mismatched, and non-404-failing entity requests
When: routing/data loading finishes
Then: malformed routes replace-normalize to Home, the filtered-out item opens exactly, and stale/mismatch/failure states stay honest and recoverable without fallback selection
Scenario: State-based mobile Inbox
Given: new, triaged, blocked-due, blocked-future, attached, converted, assistant-ready, and resolved fixtures at 390x844
When: the operator performs each available next action by keyboard and touch-sized controls
Then: only valid state-based actions/fields are exposed, mutations use the real API once, and humanized history/state remain readable without overflow
Scenario: Operator controls
Given: an authenticated session, task-linked notifications, and referenced/unreferenced recurring configs
When: the operator signs out, dismisses a notification, and attempts both recurring deletions
Then: shared logout is used, dismissal/counts are correct, unreferenced deletion succeeds, and referenced deletion explains Pause without data loss
Required Verification
Use the normal test server/in-memory DynamoDB path; request interception, mocked route payloads, source-string markers, and screenshots without behavior assertions do not count.
Focused route-normalization/entity/history tests plus Playwright assertions for every matrix row and valid combination.
Real API/browser coverage for stale 404 versus other failures, filtered Inbox selection, notification dismissal, recurring DELETE 204/409, and shared logout/auth JSON semantics.
Automated accessibility scan plus keyboard/focus assertions for route not-found, Inbox disclosures/actions/history, Settings, Notifications, and recurring confirmation/error.
A new framework, third frontend, broad navigation/IA redesign, or general visual redesign.
New API/data-model behavior beyond consuming the existing auth, entity, notification, and recurring contracts; any discovered contract defect requires a PM amendment.
Complete canonical deep-link and operator parity
Status: pending — groomed and ready for implementation
Tags:
bug,portal,frontend,testing,design,P0Parent: #148
Depends on: None
Blocks: final deployed acceptance in #155 and closure of #148
Next owner: Software Engineer
Scope
Correct the post-cutover canonical UI in top-level
frontend/at current main36d446c. Complete the existing hash-route adapter, entity loading/history behavior, mobile Inbox triage, and the small missing operator controls below. Use the existing authenticated work APIs and shared browser-cookie login/logout flow; this is not a new router, shell, data model, or information-architecture project.Deployment blockers #136/#143 do not block local implementation, review, merge, or source CI. After this source fix is integrated, #155 owns normal deployed verification at the corrected SHA.
Supported route matrix
These are the only supported workspace hash paths. Entity parameters are optional; without one, the route opens its list/surface.
#/#/inbox?intakeId=<id>#/tasks?taskId=<id>&date=<YYYY-MM-DD>&bundleId=<id>&contextBundleId=<id>datesets the date,bundleIdfilters the queue,taskIdopens the exact task, andcontextBundleIdshows the independent return/workflow context; preserve valid combinations#/bundles?bundleId=<id>&taskId=<id>#/assistants?assistantJobId=<id>#/templates?templateId=<id>#/recurring#/artifacts#/notifications#/bookkeeping#/sponsors?bookingId=<id>#/newsletter#/calendar#/mailing-exports#/processes#/admin#/usersUse
URLSearchParams/encoded values and safe text rendering. A single trailing slash may normalize to the table form. Unsupported query keys are discarded. Empty hash, unknown paths, malformed path/query encoding, invalid dates, and structurally invalid parameter combinations normalize withreplaceStateto/#/without adding a history entry, losing the authenticated session, or rendering route input as HTML.Acceptance Criteria
Routes, entities, and browser history
hashchange, Back, and Forward resolve every row and valid parameter combination in the matrix inside the one canonical shell; UI state and URL never diverge or create navigation loops.pushState; normalization alone usesreplaceState.intakeId,taskId,bundleId,assistantJobId,templateId, orbookingIdshows an entity-specific, focusable not-found state with the requested ID as text plus Retry and Return-to-list actions. It never selects the first row, opens another record, leaves a generic loading panel, or reports a non-404 API failure as “not found.”date, queuebundleId, and independentcontextBundleId;#/bundles?...&taskId=...reports a task/workflow mismatch instead of silently substituting context./loginand/logoutflow./api/*and/work/api/*continue to return JSON 401, never SPA HTML or a browser bearer-token path.Mobile Inbox and readable history
<time datetime>(relative copy may supplement it), and includes useful actor/reason/waiting/follow-up/relationship context without dumping raw metadata. Order is labelled and deterministic.Small operator parity controls
/logoutwithout exposing session material.aria-current/expanded/live semantics, modal focus trap/restore, visible focus, and keyboard operation, with zero critical/serious WCAG A/AA violations in the automated affected-state scan.Test Scenarios
Scenario: Complete route and history matrix
Given: deterministic real-API fixtures for every entity parameter
When: each route/combination is opened fresh and the operator follows relationships, closes detail, and uses Back/Forward/hash changes
Then: the exact entity, visible context, URL, focus, and history entry are synchronized
Scenario: Invalid route and stale entities
Given: unknown/malformed routes plus stale, filtered-out, mismatched, and non-404-failing entity requests
When: routing/data loading finishes
Then: malformed routes replace-normalize to Home, the filtered-out item opens exactly, and stale/mismatch/failure states stay honest and recoverable without fallback selection
Scenario: State-based mobile Inbox
Given: new, triaged, blocked-due, blocked-future, attached, converted, assistant-ready, and resolved fixtures at 390x844
When: the operator performs each available next action by keyboard and touch-sized controls
Then: only valid state-based actions/fields are exposed, mutations use the real API once, and humanized history/state remain readable without overflow
Scenario: Operator controls
Given: an authenticated session, task-linked notifications, and referenced/unreferenced recurring configs
When: the operator signs out, dismisses a notification, and attempts both recurring deletions
Then: shared logout is used, dismissal/counts are correct, unreferenced deletion succeeds, and referenced deletion explains Pause without data loss
Required Verification
Use the normal test server/in-memory DynamoDB path; request interception, mocked route payloads, source-string markers, and screenshots without behavior assertions do not count.
npm --prefix backend testnpm --prefix backend run typechecknpm --prefix backend run buildnpm --prefix backend run test:e2euv run --project lambda-functions --extra search --with pytest python -m pytest tests/docs_appTester captures and reads these exact sanitized viewport screenshots under
.tmp/screenshots/issue-156/:desktop-task-combined-context-1440x900.pngdesktop-entity-not-found-1440x900.pngdesktop-inbox-blocked-actions-history-1440x900.pngdesktop-settings-sign-out-1440x900.pngdesktop-notification-dismiss-1440x900.pngdesktop-recurring-delete-guidance-1440x900.pngmobile-task-combined-context-390x844.pngmobile-entity-not-found-390x844.pngmobile-inbox-new-primary-390x844.pngmobile-inbox-blocked-follow-up-history-390x844.pngmobile-settings-sign-out-390x844.pngmobile-notification-dismiss-390x844.pngmobile-recurring-delete-guidance-390x844.pngArchitect reviews route/auth/history boundaries; Designer reviews both viewport sets and progressive disclosure; then Tester and PM gates run.
Lifecycle Gates
Closes #156Out of Scope
../dtc-operations,../datatasks,../podcast-assistant, or operational/private knowledge.