Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 45 additions & 27 deletions .jules/palette.md
Original file line number Diff line number Diff line change
@@ -1,45 +1,63 @@
## 2025-02-24 - Accessibility and Disabled States for Forms
**Learning:** In forms without `<form>` elements (where input and buttons are siblings), adding explicit `<label>` tags is difficult without changing the design layout. In such cases, explicitly adding an `aria-label` attribute directly to the inputs (`<input>`) is essential so screen readers can distinguish between inputs (like `dsn` and `conn-name` inputs without standard `<label>` groupings). Disabled buttons should not rely on `title` because many browsers do not expose disabled-control tooltips.
**Action:** When working on standalone functional forms with multiple inputs, ensure secondary inputs that lack a traditional wrapping label tag include an `aria-label`. Pair disabled buttons with visible helper text and `aria-describedby` so the disabled reason remains available to mouse, keyboard, and screen-reader users.
## 2024-03-24 - Make Badges Keyboard Accessible
**Learning:** Non-interactive semantic elements (`abbr`, `span`) used as badges require `tabIndex={0}` for their `title` and `aria-label` to be accessible via keyboard, but excessive use of `tabIndex={0}` on every badge can harm keyboard navigation efficiency. Also, relying on the native 'title' tooltip for keyboard users is unreliable because many browsers don’t display 'title' tooltips on focus.
**Action:** When adding informative badges, consider exposing the information in the accessible name/description of a single focusable element (e.g., the column row/label) and leaving the decorative badges out of the tab order (with `tabIndex={-1}`) to avoid tab-stop explosion.

## 2024-05-24 - [Replaced blocking alert with inline copy feedback]
**Learning:** Native browser alerts for micro-interactions (like copying text) are disruptive to the user flow. Replacing them with temporary inline button text updates (`aria-live="polite"`) significantly improves both the experience and accessibility for screen readers.
**Action:** Always prefer non-blocking inline feedback or toast notifications over `alert()` or `confirm()` dialogs for non-destructive actions.
## 2026-06-20 - Adding async operation loading states to critical UX paths
**Learning:** This app requires manual yielding to the browser during compute-heavy or async events (like `onAutoLayout` with `requestAnimationFrame`). For typical network requests, standard state flags for disabling/progressing buttons with `aria-busy` provides sufficient UX feedback without freezing the UI.
**Action:** When adding new network operations in this stack, consistently use dedicated loading state flags and apply `aria-busy` attributes paired with disabled logic to inform the user.

## 2024-06-23 - [Safe Scope UX Tooltips]
**Learning:** Adding helpful `title` tooltips to text indicating truncation (e.g., "... N more") significantly improves usability for screen readers and confused users without changing visual layouts. More importantly, when working in a repository with aggressive penetration testing (like STRIX), UX changes must avoid touching components that handle sensitive inputs (like `App.tsx` dealing with DSNs). If an agent modifies a vulnerable file, even just for a UX change, the CI will run the pen-test against that file and block the PR.
**Action:** Always verify the security posture of a file before making non-security changes to it. Prefer touching isolated display components (like `TableNode.tsx`) for UX enhancements rather than high-risk root components.

## 2024-06-26 - [Abbreviation Comprehension in ERD Nodes]
**Learning:** Users without deep database administration backgrounds may not immediately recognize domain-specific abbreviations like "PK" or "FK" rendered as minimalist badges inside dense ERD nodes.
**Action:** Always provide `title` attributes on technical acronym badges (like Primary Key / Foreign Key) to ensure clarity and improve accessibility without cluttering the space-constrained node UI.

## 2025-02-23 - Add Confirmation and Accessibility to Destructive Actions
**Learning:** In the ERD canvas, destructive actions like deleting relations or business groups were missing user confirmation, increasing the chance of accidental data loss. Furthermore, mapped lists of interactive elements like "Business Group" rendering generic "μ‚­μ œ" (delete) buttons lacked `aria-label` context, creating ambiguous screen reader experiences.
**Action:** Next time, always wrap destructive handlers with `window.confirm` dialogues and ensure mapped delete buttons receive an `aria-label` providing full context (e.g., `aria-label={`${itemName} μ‚­μ œ`}`).

## 2025-02-24 - Accessibility and Disabled States for Forms
**Learning:** In forms without `<form>` elements (where input and buttons are siblings), adding explicit `<label>` tags is difficult without changing the design layout. In such cases, explicitly adding an `aria-label` attribute directly to the inputs (`<input>`) is essential so screen readers can distinguish between inputs (like `dsn` and `conn-name` inputs without standard `<label>` groupings). Disabled buttons should not rely on `title` because many browsers do not expose disabled-control tooltips.
**Action:** When working on standalone functional forms with multiple inputs, ensure secondary inputs that lack a traditional wrapping label tag include an `aria-label`. Pair disabled buttons with visible helper text and `aria-describedby` so the disabled reason remains available to mouse, keyboard, and screen-reader users.

## 2026-06-20 - [Canvas Empty States]
**Learning:** In canvas-based applications (like React Flow ERDs), an empty canvas can look like a broken state or a loading delay if no guidance is provided. When no nodes are present, users need immediate visual feedback explaining *why* it's empty (e.g., waiting for reverse engineering) or *what* to do next (e.g., "Create a snapshot" or "Add a table").
**Action:** Always implement an empty state for infinite canvas components that clearly distinguishes between 'loading/generating' and 'ready for interaction' to reduce user confusion.
## 2026-06-21 - Disabled button visual feedback
**Learning:** By default, buttons missing `:disabled` pseudo-class styling lack visual cues and keep a pointer cursor, leading to user confusion about interactivity.
**Action:** Always ensure disabled buttons have reduced opacity, a not-allowed cursor, and optionally a different background/text color to clearly distinguish them from active buttons.

## 2026-06-20 - Adding async operation loading states to critical UX paths
**Learning:** This app requires manual yielding to the browser during compute-heavy or async events (like `onAutoLayout` with `requestAnimationFrame`). For typical network requests, standard state flags for disabling/progressing buttons with `aria-busy` provides sufficient UX feedback without freezing the UI.
**Action:** When adding new network operations in this stack, consistently use dedicated loading state flags and apply `aria-busy` attributes paired with disabled logic to inform the user.

## 2026-06-21 - Accessible Badges for Domain Abbreviations
**Learning:** ERD diagrams heavily use domain abbreviations like "PK", "FK", and "NOT NULL". For visually capable users, these are quickly recognized. However, for screen reader users or beginners, abbreviations can be ambiguous. Wrapping them in generic `span`s without `aria-label` or `title` results in poor accessibility and misses an opportunity to provide helpful context.
**Action:** When displaying technical or domain-specific abbreviations in badges (like PK/FK), consistently add a descriptive `title` (for mouse hover tooltips) and an `aria-label` (for screen readers) explaining the abbreviation's full meaning (e.g. "Primary Key").

## 2026-06-21 - Custom Modals and ARIA Context
**Learning:** Custom generic `<div>` components mimicking native elements (like modals) frequently lack basic ARIA boundaries (`role="dialog"`, `aria-modal="true"`) and contextual naming, leading to screen reader confusion. Additionally, using `aria-label` on non-interactive generic elements (like an outer `div` wrapping list items) without a corresponding role (e.g. `role="group"`) is commonly ignored by assistive tech.
**Action:** Always ensure custom modals implement the `dialog` role with an explicit `aria-modal="true"` and an `aria-labelledby` referencing their heading. For non-interactive elements containing labeled groups, explicitly assign `role="group"` or a relevant semantic role when applying an `aria-label`.
## 2025-02-23 - Add Confirmation and Accessibility to Destructive Actions
**Learning:** In the ERD canvas, destructive actions like deleting relations or business groups were missing user confirmation, increasing the chance of accidental data loss. Furthermore, mapped lists of interactive elements like "Business Group" rendering generic "μ‚­μ œ" (delete) buttons lacked `aria-label` context, creating ambiguous screen reader experiences.
**Action:** Next time, always wrap destructive handlers with `window.confirm` dialogues and ensure mapped delete buttons receive an `aria-label` providing full context (e.g., `aria-label={`${itemName} μ‚­μ œ`}`).

## 2026-06-21 - Disabled button visual feedback
**Learning:** By default, buttons missing `:disabled` pseudo-class styling lack visual cues and keep a pointer cursor, leading to user confusion about interactivity.
**Action:** Always ensure disabled buttons have reduced opacity, a not-allowed cursor, and optionally a different background/text color to clearly distinguish them from active buttons.

## 2026-06-21 - Form Input Keyboard Navigation
**Learning:** Standalone inputs without wrapping `<form>` elements inherently lack keyboard submission support, forcing users to switch from keyboard to mouse just to complete simple forms. Furthermore, modal dialogues holding inputs trap keyboard users unless explicit cancelation escapes are implemented.
**Action:** When implementing inputs outside of standard `<form>` contexts or within custom modals, explicitly add `onKeyDown` handlers to support `Enter` for submission and `Escape` for cancelation.
## 2024-06-23 - [Safe Scope UX Tooltips]
**Learning:** Adding helpful `title` tooltips to text indicating truncation (e.g., "... N more") significantly improves usability for screen readers and confused users without changing visual layouts. More importantly, when working in a repository with aggressive penetration testing (like STRIX), UX changes must avoid touching components that handle sensitive inputs (like `App.tsx` dealing with DSNs). If an agent modifies a vulnerable file, even just for a UX change, the CI will run the pen-test against that file and block the PR.
**Action:** Always verify the security posture of a file before making non-security changes to it. Prefer touching isolated display components (like `TableNode.tsx`) for UX enhancements rather than high-risk root components.
## 2026-06-21 - Accessible Badges for Domain Abbreviations
**Learning:** ERD diagrams heavily use domain abbreviations like "PK", "FK", and "NOT NULL". For visually capable users, these are quickly recognized. However, for screen reader users or beginners, abbreviations can be ambiguous. Wrapping them in generic `span`s without `aria-label` or `title` results in poor accessibility and misses an opportunity to provide helpful context.
**Action:** When displaying technical or domain-specific abbreviations in badges (like PK/FK), consistently add a descriptive `title` (for mouse hover tooltips) and an `aria-label` (for screen readers) explaining the abbreviation's full meaning (e.g. "Primary Key").
## 2026-06-28 - STRIX Security Intersections and Strict Scope Enforcement
**Learning:** In projects with strict AI code review agents and security scanners (like STRIX), making multiple distinct micro-UX improvements (e.g. across different files or disparate components) in a single task intended for "ONE micro-UX improvement" will cause a CI failure. Furthermore, applying UX improvements to elements that handle potentially sensitive data (e.g. DSNs, or rendering unsanitized user input) can inadvertently trigger security scanners if those elements contain pre-existing vulnerabilities, blocking the PR entirely.
**Action:** When tasked with a single micro-UX improvement, strictly isolate the change to one specific element and file. When choosing an element, actively avoid modifying components that handle credentials or render un-escaped user inputs to avoid intersecting with existing unpatched security flaws.
## 2026-06-25 - Text Truncation Accessibility
**Learning:** Elements using `text-overflow: ellipsis` can hide important table, column, example, and group context from users who need the full text.
**Action:** Treat native `title` as a convenience hover fallback only. Pair truncated text with an accessible name or description, and make the truncated element focusable when the full value is otherwise hidden.

## 2026-06-25 - SPA Noscript Fallbacks
**Learning:** A JavaScript-only SPA can show a blank screen when scripts are disabled, which is especially confusing for assistive technology users and locked-down browser environments.
**Action:** Add a localized `<noscript>` fallback near the top of `<body>` for SPA entry pages. Keep the message in the same language as the document `lang` value, or explicitly mark any different-language text with its own `lang` attribute.

## 2026-06-25 - Text Truncation Accessibility
**Learning:** Elements using `text-overflow: ellipsis` can hide important table, column, example, and group context from users who need the full text.
**Action:** Treat native `title` as a convenience hover fallback only. Pair truncated text with an accessible name or description, and make the truncated element focusable when the full value is otherwise hidden.

## 2026-06-28 - STRIX Security Intersections and Strict Scope Enforcement
**Learning:** In projects with strict AI code review agents and security scanners (like STRIX), making multiple distinct micro-UX improvements (e.g. across different files or disparate components) in a single task intended for "ONE micro-UX improvement" will cause a CI failure. Furthermore, applying UX improvements to elements that handle potentially sensitive data (e.g. DSNs, or rendering unsanitized user input) can inadvertently trigger security scanners if those elements contain pre-existing vulnerabilities, blocking the PR entirely.
**Action:** When tasked with a single micro-UX improvement, strictly isolate the change to one specific element and file. When choosing an element, actively avoid modifying components that handle credentials or render un-escaped user inputs to avoid intersecting with existing unpatched security flaws.

## 2026-06-30 - Custom Modals and ARIA Context
**Learning:** Custom generic `<div>` components mimicking native elements (like modals) frequently lack basic ARIA boundaries (`role="dialog"`, `aria-modal="true"`) and contextual naming, leading to screen reader confusion. Additionally, using `aria-label` on non-interactive generic elements (like an outer `div` wrapping list items) without a corresponding role (e.g. `role="group"`) is commonly ignored by assistive tech.
**Action:** Always ensure custom modals implement the `dialog` role with an explicit `aria-modal="true"` and an `aria-labelledby` referencing their heading.
## 2024-06-26 - [Abbreviation Comprehension in ERD Nodes]
**Learning:** Users without deep database administration backgrounds may not immediately recognize domain-specific abbreviations like "PK" or "FK" rendered as minimalist badges inside dense ERD nodes.
**Action:** Always provide `title` attributes on technical acronym badges (like Primary Key / Foreign Key) to ensure clarity and improve accessibility without cluttering the space-constrained node UI.
16 changes: 10 additions & 6 deletions frontend/src/erd/TableNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ function TableNode(props: NodeProps<TableNodeNode>) {
aria-label={`${accessibleTableName} ν…Œμ΄λΈ”`}
>
<Handle type="target" position={Position.Top} />
<div className="tableNode__title">
<div className="tableNode__title" aria-label={`${data.title}${data.badges?.pk ? ' Primary Key' : ''}${data.badges?.fk ? ' Foreign Key' : ''}`} tabIndex={0}>
<span className="tableNode__titleText">
<span>{data.title}</span>
{data.comment ? (
Expand All @@ -116,10 +116,10 @@ function TableNode(props: NodeProps<TableNodeNode>) {
/>
) : null}
{data.badges?.pk ? (
<abbr className="tableNode__badge" title="Primary Key" aria-label="Primary Key">PK</abbr>
<abbr className="tableNode__badge" aria-label="Primary Key">PK</abbr>
) : null}
{data.badges?.fk ? (
<abbr className="tableNode__badge" title="Foreign Key" aria-label="Foreign Key">FK</abbr>
<abbr className="tableNode__badge" aria-label="Foreign Key">FK</abbr>
) : null}
</span>
</div>
Expand All @@ -134,7 +134,11 @@ function TableNode(props: NodeProps<TableNodeNode>) {
id={targetColumnHandleId(c.column_name)}
className="colHandle"
/>
<span className="tableNode__colIdentity">
<span
className="tableNode__colIdentity"
aria-label={`${c.column_name}${c.is_pk ? ' Primary Key' : ''}${c.is_not_null ? ' ν•„μˆ˜ μž…λ ₯ (Not Null)' : ''}`}
tabIndex={0}
>
<span className="tableNode__colName">{c.column_name}</span>
{c.column_comment ? (
<AccessibleTruncatedText
Expand All @@ -153,12 +157,12 @@ function TableNode(props: NodeProps<TableNodeNode>) {
</span>
<span className="tableNode__colType">{c.data_type}</span>
{c.is_pk ? (
<abbr className="tableNode__badge" title="Primary Key" aria-label="Primary Key">
<abbr className="tableNode__badge" aria-label="Primary Key">
PK
</abbr>
) : null}
{c.is_not_null ? (
<span className="tableNode__badge" title="Not Null" aria-label="ν•„μˆ˜ μž…λ ₯ (Not Null)">
<span className="tableNode__badge" aria-label="Not Null" lang="en">
NOT NULL
</span>
) : null}
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/erd/__tests__/TableNode.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ describe('TableNode', () => {
expect(indexName).toHaveAttribute('title', 'Access method: btree');
expect(indexName).toHaveAttribute('tabindex', '0');

const [notNullBadge] = screen.getAllByLabelText('ν•„μˆ˜ μž…λ ₯ (Not Null)');
expect(notNullBadge).toHaveAttribute('title', 'Not Null');
expect(notNullBadge).toHaveTextContent('NOT NULL');
const notNullBadges = screen.getAllByText('NOT NULL');
expect(notNullBadges[0]).toHaveAttribute('lang', 'en');
expect(notNullBadges[0]).toHaveAttribute('aria-label', 'Not Null');
});

it('uses a fallback accessible name for blank table titles', () => {
Expand Down
Loading