- Created useAuthApi composable for JWT token lifecycle management
- Implemented setupAuthInterceptor for automatic Authorization header injection
- Added LoginPage.vue with username/password form
- Configured router to redirect to /login for unauthenticated access
- Token stored in localStorage with expiration tracking
- Automatic token validation and cleanup on expiration
- All fetch requests automatically include Bearer token
- Unit tests for login, logout, token validation flows
This enables frontend to authenticate via JWT tokens in production mode.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Cleaned up development debugging output for production deployment.
Core form field navigation behavior (Enter key → next field, Ctrl+Enter in textarea → newline) verified and stable.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- KsNumberField: Enter -> next field
- KsMoneyField: Enter -> next field
- KsMultiSelect: Enter (when closed) -> next field
- Complete Tab-like Enter key behavior across all form inputs
- Enables seamless form navigation with Enter key (matching grid behavior)
- Create useFormFieldNavigation composable for Tab-like Enter behavior
- KsTextField: Enter -> next field
- KsTextArea: Ctrl+Enter for newline, Enter -> next field
- KsSelect: Enter -> next field after selection
- Implements standard form navigation pattern across input components
- Use exact focusRow pattern: ensureIndexVisible + setFocusedCell + startEditingCell
- Apply retry logic to all three operations
- Ensures next cell gets full focus + edit mode like focusRow
- Apply same ensureEditMode retry pattern to onCellKeyDown
- Retry startEditingCell at 0ms, 10ms, 50ms after tabToNextCell
- Ensures next cell enters edit mode reliably after Enter key
- Remove redundant startEditingCell calls that override AG Grid native behavior
- Use only stopEditing + tabToNextCell with setTimeout
- Let AG Grid handle edit mode auto-start for next cell
- Use multiple setTimeout attempts to ensure startEditingCell succeeds
- Retry at 10ms and 50ms intervals for DOM/Grid stability
- Addresses issue where keyboard input not available after focusRow
- Add setTimeout in focusRow to ensure DOM updates before startEditingCell
- Add startEditingCell after tabToNextCell in Enter key handler
- Ensures smooth edit mode transition: focus → edit mode immediately
- Remove invalid onCellKeyDown from colDef
- Add onCellKeyDown handler to AgGridVue component
- Enter key now properly triggers tabToNextCell for editable columns
- Implement onCellKeyDown callback for editable columns
- Enter key now calls tabToNextCell() like Tab key
- Addresses user request: 넥스트 셀을 네가 찾지말고 tab key와 같은 기능이 동작하면 됀다
Problem: onCellFocused was auto-starting edit mode on every focus,
preventing AG Grid's native Enter-key navigation from working.
Solution: Remove onCellFocused function and @cell-focused event handler.
Now Enter key can properly navigate to next cell (Tab behavior).
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Removed custom navigateToNextCell function and binding.
Now relies on AG Grid's native :enter-navigates-to-next-cell setting.
This allows Enter key to properly use Tab navigation as intended.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Simplified navigateToNextCell to let Enter key use default AG Grid Tab behavior.
Previous: Custom Enter navigation (next editable column only)
New: Return suggestedNextCell for Enter, which is Tab's default behavior
This makes Enter and Tab fully equivalent, consistent with user expectation.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Changed Enter key behavior to move only to next editable column within same row
(no row change, just like Tab key).
Previous: Enter → next column OR next row (if last column)
New: Enter → next column only (last column does nothing)
This makes data entry more predictable and consistent with Tab behavior.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Problem: DataGridShell expects gridRef to have redrawRows() method
but KsDataGrid.vue only exposed focusRow and gridApi
Fixed:
1. Added redrawRows() function that calls gridApi.redrawRows()
2. Updated defineExpose to include redrawRows
3. Removed unused CellEditingStoppedEvent import
Result: CommonCodeManagementPage.redrawRows() calls now work
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Improved onCellFocused to check if already editing same cell before starting edit mode.
Problem: Enter key moves to next cell + startEditingCell(), then onCellFocused fires
and tries to startEditingCell() again on same cell, causing timing issues.
Solution: Check getEditingCell() to see if we're already editing the focused cell
- If same cell: skip (already editing)
- If different cell: enter edit mode
Result: Enter key → next cell → auto edit mode (no duplication)
Tab/Click/Arrow → auto edit mode (only once)
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Added onCellFocused handler to automatically enter edit mode when a cell receives focus.
- Listen to @cell-focused event
- Check if column is editable
- Call startEditingCell() on focus
- Result: Tab key, arrow keys, or any navigation auto-enters edit mode
Affects: All pages using KsDataGrid with editable cells
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Fixed 3 critical bugs in grid editing:
1. onCellValueChanged redrawRows() removal
- Removed event.api.redrawRows() that was resetting cell input
- Issue: redrawRows() triggered computed property re-evaluation
- Result: Array reference changed, grid lost input value
2. ScrollApiModule registration
- Added ScrollApiModule to ModuleRegistry
- Issue: focusRow() called ensureIndexVisible without module
- Result: AG Grid #200 error, page hung
3. onCellEditingStopped removal
- Removed auto-restart of edit mode on cell exit
- Issue: Prevented navigateToNextCell from working on Enter key
- Result: Enter key now properly moves focus to next cell
4. CommonCodeManagementPage focusRow safety
- Wrapped focusRow() in try-catch
- Issue: focusRow may not be available, causing errors
- Result: Grid continues even if focusRow unavailable
Affects: /system/common-codes grid editing and all pages using KsDataGrid
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Problem: Adding a group row then typing in cells caused continuous reset
Root Cause: Vue reactivity lost when assigning new array to reactive object
Solution: Use Object.assign() to maintain reactivity tracking
- Changed: mockChildCodesMap[key] = list
- To: Object.assign(mockChildCodesMap, { [key]: list })
- Result: Cell input now persists without reset
Affects: /system/common-codes grid editing
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Migrate from PageLayout to EditFormPage (standard form pattern)
- Add state management (PROCESSING/ERROR/READY)
- Separate form input and result preview sections
- Use #preview slot for policy evaluation results
- Add evidence tracking (asOf, version)
- Add dirty state (form has potential changes)
- Improve result display: semantic HTML (dl/dt/dd)
- Add CSS styles for result presentation
Result: Consistent form pattern across all research tools
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Add EMPTY state to StandardScreenState when portfolio has no positions
- Condition all template slots on dashboard data presence
- Validate dashboard.healthScore, riskMetrics, portfolio, stressResults
- Update empty message: '보유 종목이 없습니다' → '포트폴리오 보유 종목이 없습니다'
- Display 'EMPTY' state instead of blank screen when no data
- Improve state computation: LOADING → ERROR/WARN → EMPTY → READY
Result: Better UX for empty/error states, clearer data validation
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Restructure detail panel as approval form (EditFormPage pattern)
- Separate concerns: Header (read-only) + Content (form) + Footer (actions)
- Use form/fieldset semantics for read-only vs editable sections
- Request Details and Metrics as disabled fieldsets (read-only)
- Review Comment as textarea form input
- Footer buttons (Approve/Reject) with validation
- CSS refactor: approval-form, form-header/content/footer structure
- Improved accessibility and semantic HTML
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Root cause: CSS Grid with optional (v-if) children caused inconsistent row counts.
Grid-template-rows: auto auto auto auto 1fr auto auto (7 rows) didn't match
actual child count (5-6 rows), causing 1fr collapse to 3px.
Solution: Revert to flexbox (proven stable).
- .ks-page: display: grid → display: flex; flex-direction: column
- .ks-page__workspace: add flex: 1 (replaces 1fr grid expansion)
- All flex children have min-height: 0 (height propagation chain)
Result: ShadowRunQueue grid now expands to full viewport height.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Root cause: PageLayout's flex-direction: column + gap was not counted in flex: 1 height calculations, causing children to overflow and trigger scroll.
Solution: Convert PageLayout from flexbox to CSS Grid with explicit grid-template-rows. Grid automatically accounts for gaps in row sizing.
Changes:
- PageLayout.vue: display: flex → display: grid
- grid-template-rows: auto auto auto auto 1fr auto auto
- .ks-page__content/.ks-page__aside: height: 100% → flex: 1
- .ks-page__workspace: removed flex: 1 (grid cell, not flex)
Impact:
- models-master fits viewport without page-level scroll ✓
- All screen-types layouts auto-fit with correct height propagation
- Fix applies to all pages using PageLayout
AGENTS.md v16.0: Added Layout Rule #7 (PageLayout grid requirement)
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Display app version (v0.1.0 or VITE_APP_VERSION) in sidebar footer
- Hidden when sidebar is collapsed
- Positioned above Help/Settings buttons
This provides system version visibility without requiring footer.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Changes:
• base.css: Add global footer hiding rule (applies to all .ks-page__footer, .ks-shell__footer, footer[class*=ks-])
• PageLayout: Remove individual footer CSS (use global rule)
• AppShellLayout: Remove individual footer CSS (use global rule)
Benefits:
✓ Single source of truth (base.css)
✓ Easier to maintain and update globally
✓ Consistent behavior across all layouts
✓ Can enable/disable with one change if needed
✓ Structure preserved (v-if, grid-areas intact)
Design principle: Single-screen + content-first
• All controls in header/command-bar/summary
• Recover ~48-64px per page for content
• Mobile-friendly (no hard-to-reach footer)
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Replace custom grid layout with KsSplitter component
- Add storageKey to prevent ratio conflicts with other pages
- Remove dead .content CSS class
- Update .request-list height constraint (flex: 1 → height: 100%)
- Maintain overflow-y: auto for scrollable panes
- Simplifies code by ~50 lines, adds drag-to-resize functionality