Skip to content

Research: UI Empty State & Submit Entry Point

Branch: 004-ui-empty-state-submit | Date: 2026-06-11

Summary

No technical unknowns exist for this feature. All decisions are grounded in existing codebase patterns and confirmed Onyx component APIs. This document records the key findings for traceability.


Decision 1 — Auth group check mechanism

Decision: Use useAuthStore().isInGroup(group) to test whether the user belongs to the initiator group.

Rationale: isInGroup is already implemented in ui/src/stores/auth.ts:38 and used by SubmitFlowView.vue for the same guard. No new mechanism needed.

Alternatives considered: Direct user.value?.groups.includes(group) — identical semantics; isInGroup is the preferred encapsulated form already in use.


Decision 2 — Definitions source

Decision: Import AVAILABLE_DEFINITIONS from ui/src/api/definitions.ts to determine whether any definitions are available and which definitionId to navigate to.

Rationale: AVAILABLE_DEFINITIONS is already exported and contains DOCUMENT_APPROVAL_DEFINITION with initiatorGroup: 'initiators'. The single-definition assumption is documented in the spec Assumptions section; no picker screen is needed.

Alternatives considered: Fetching from a backend GET /definitions endpoint — deferred by the spec (hardcoded fallback is intentional until the endpoint ships).


Decision 3 — Onyx component selection

Decision: Use OnyxButton for the header CTA and OnyxEmpty for the empty state.

Rationale: Both are present in sit-onyx@^1.14.0 (confirmed via ui/node_modules/sit-onyx/dist/components/). OnyxButton accepts a link prop that renders it as a router-aware anchor — avoiding a manual RouterLink wrapper. OnyxEmpty provides default (headline), description, and buttons slots that map directly to FR-004 and FR-005.

OnyxButton key props: label (required), color (primary | neutral | danger), mode (default | outline | plain), link (renders as link).

OnyxEmpty key slots: default (headline text), description (explanatory paragraph), buttons (CTA button area).

Alternatives considered: Plain <button> + <RouterLink> — already in use for other elements; Onyx components give consistent visual language with the rest of the design system.


Decision 4 — Onyx registration

Decision: Import OnyxButton and OnyxEmpty directly from sit-onyx inside the SFC <script setup> block.

Rationale: Onyx is not globally registered in ui/src/main.ts (no createOnyx() call). All existing components import Vue primitives directly. The same pattern applies here.

Alternatives considered: Global app.use(createOnyx()) registration — would require changing main.ts and is beyond the scope of this feature.


Decision 5 — Navigation target

Decision: Navigate to { name: 'submit-flow', params: { definitionId: definition.definitionId } } using Vue Router's named route.

Rationale: The submit-flow route (/submit/:definitionId) is registered in ui/src/router/index.ts:28. Using the named route avoids hard-coding the path string.

Alternatives considered: Hard-coding /submit/document-approval — fragile; named routes survive path restructuring.