diff --git a/AGENTS.md b/AGENTS.md index d4bde23f..32cdb672 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -234,6 +234,75 @@ pnpm dev **URL:** http://localhost:5174 +### Frontend Layout & Responsive Design Standards (v16.0) + +**CRITICAL:** Responsive web design is MANDATORY for all layouts, not optional. + +#### CSS Variable Standards (base.css) +```css +:root { + --ks-sidebar-width: 16rem; /* Navigation sidebars */ + --ks-aside-width: 22rem; /* Side panels */ + --ks-preview-width: 24rem; /* Preview/summary panels */ + --ks-detail-width: 28rem; /* Detail panels */ + --ks-content-max: 1400px; /* Max content width (prevent excessive expansion) */ +} +``` + +#### Layout Rules (Non-Negotiable) +1. **NO hardcoded pixel/rem widths in minmax.** Always use CSS variables: `minmax(0, 1fr) var(--ks-aside-width)` ✅, NOT `minmax(18rem, 26rem)` ❌ +2. **Unified breakpoints (all layouts must use same):** + - **Desktop:** Default (no constraint) + - **Tablet:** `@media (max-width: 1100px) { grid-template-columns: 1fr; }` (2-col → 1-col) + - **Mobile:** `@media (max-width: 768px) { /* adjust padding, font sizes */ }` +3. **All flex children:** `flex: 1; min-height: 0;` required (prevents overflow squashing) +4. **Scrollable containers:** `overflow-y: auto; min-height: 0;` (enables internal scroll without page scroll) +5. **Grid layouts:** `align-items: start;` (NOT center/stretch) to prevent column stretching at different heights +6. **Max-width constraint:** Wrap pages in `.page-wrapper { max-width: var(--ks-content-max); margin: 0 auto; }` to prevent 2560px+ distortion + +#### Height Propagation Chain (Single-Screen Principle) +``` +PageLayout (.ks-page__content) + ├─ height: 100%; min-height: 0; display: flex; + ↓ +QueryStateBoundary (.ks-query-boundary) + ├─ flex: 1; height: 100%; min-height: 0; display: flex; + ↓ +Content Container (KsSplitter, .ks-stack, FormPageLayout) + ├─ flex: 1; min-height: 0; height: 100%; + ├─ display: flex/grid; + ↓ +Internal Panes (.request-list, .detail-panel, .items) + ├─ flex: 1; min-height: 0; overflow-y: auto; +``` + +#### Banned Patterns +- ❌ `grid-template-columns: minmax(18rem, 26rem)` (hardcoded min/max) +- ❌ `calc(100vh - Xpx)` (brittle, changes with header size) +- ❌ `max-width: 600px` on full-page containers (prevents responsiveness) +- ❌ `align-items: center` in grid layouts (prevents height-based alignment) +- ❌ `position: fixed` sidebars without mobile fallback +- ❌ Multiple different breakpoints across layouts (950px, 900px, 1000px, 1200px all mixed) + +#### Verification Checklist +For every layout change: +- [ ] Uses CSS variables, not hardcoded rem/px +- [ ] Breakpoints are 1100px (tablet) and 768px (mobile) +- [ ] All flex children have `flex: 1; min-height: 0` +- [ ] All scrollable panes have `overflow-y: auto; min-height: 0` +- [ ] Tested at 768px (mobile), 1100px (tablet breakpoint), 1512px (current test), 1920px (fullHD), 2560px (4K) +- [ ] No page-level scroll on first load (only internal pane scroll if needed) +- [ ] Content max-width prevents distortion on ultra-wide (>1400px) + +#### Affected Layouts (Status) +| Layout | Issue | Status | Reason | +|--------|-------|--------|--------| +| PageLayout | None | ✅ COMPLIANT | Uses CSS variables | +| CrudWorkspaceLayout | None | ✅ COMPLIANT | Uses CSS variables | +| FormPageLayout | Hardcoded `minmax(18rem, 26rem)` | 🔴 FIX REQUIRED | Session 2026-08-16 | +| ReviewWorkbenchLayout | Mixed hardcoded widths | 🔴 FIX REQUIRED | Session 2026-08-16 | +| OperationsConsoleLayout | Hardcoded `minmax(18rem, 28rem)` | 🔴 FIX REQUIRED | Session 2026-08-16 | + ### Authentication for Testing Development mode uses `DevelopmentHeaderAuthenticationHandler`. Test requests with: diff --git a/docs/FRONTEND-RESPONSIVE-DESIGN-STANDARD.md b/docs/FRONTEND-RESPONSIVE-DESIGN-STANDARD.md new file mode 100644 index 00000000..742ccb2a --- /dev/null +++ b/docs/FRONTEND-RESPONSIVE-DESIGN-STANDARD.md @@ -0,0 +1,202 @@ +# Frontend Responsive Design Standard v1.0 + +**Status:** ACTIVE +**Authority:** AGENTS.md v16.0 +**Last Updated:** 2026-08-16 + +--- + +## 📌 Core Principle + +**Responsive web design is MANDATORY for all layouts, not optional.** + +All layouts must support mobile (768px), tablet (1100px), and desktop (1400px+) seamlessly. + +**Reference:** AGENTS.md § "Frontend Layout & Responsive Design Standards" + +--- + +## 🎯 Quick Rules + +| Rule | ❌ DON'T | ✅ DO | +|------|---------|--------| +| Width | `minmax(18rem, 26rem)` | `var(--ks-preview-width)` | +| Breakpoint | 950px, 900px, 1000px, 1200px (mixed) | 1100px (tablet), 768px (mobile) | +| Flex Child | `flex: 1` only | `flex: 1; min-height: 0;` | +| Scroll | `height: calc(100vh - 220px)` | `flex: 1; min-height: 0; overflow-y: auto;` | +| Grid Align | `align-items: center` | `align-items: start` | +| Max Width | None (distorts at 2560px+) | `max-width: 1400px; margin: 0 auto;` | + +--- + +## 📐 CSS Variable Standards + +**Location:** `frontend/src/design-system/base.css` + +**Standard widths (ALWAYS use these, NEVER hardcode):** +```css +:root { + --ks-sidebar-width: 16rem; /* Navigation sidebars */ + --ks-aside-width: 22rem; /* Side panels (PageLayout) */ + --ks-preview-width: 24rem; /* Preview/summary panels (FormPageLayout) */ + --ks-detail-width: 28rem; /* Detail panels (ReviewWorkbenchLayout) */ + --ks-content-max: 1400px; /* Max page width (prevent 2560px+ distortion) */ +} +``` + +**Standard breakpoints (ALWAYS use these, NEVER create new breakpoints):** +```css +/* Tablet: 2-col → 1-col */ +@media (max-width: 1100px) { + .layout { grid-template-columns: 1fr; } +} + +/* Mobile: adjust spacing */ +@media (max-width: 768px) { + .layout { padding: 0.75rem; } + .layout h1 { font-size: 1.25rem; } +} +``` + +--- + +## 🔗 Layout Examples + +### ✅ Correct: CSS Variable Based + +```css +/* FormPageLayout (correct) */ +.ks-form-layout { + display: grid; + grid-template-columns: minmax(0, 1fr) var(--ks-preview-width); + gap: var(--ks-space-4); + flex: 1; + min-height: 0; + height: 100%; +} + +@media (max-width: 1100px) { + .ks-form-layout { grid-template-columns: 1fr; } +} +``` + +### ❌ Wrong: Hardcoded Widths + +```css +/* FormPageLayout (WRONG - current) */ +.ks-form-layout { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(18rem, 26rem); + /* Problems: + - 1950px+: right column = 26rem (hardcoded), left = excessive + - Not maintainable: width is hard to find/change + - Not scalable: doesn't adapt to design changes + */ +} + +@media (max-width: 950px) { + /* Wrong: 950px is arbitrary, not shared with other layouts */ + .ks-form-layout { grid-template-columns: 1fr; } +} +``` + +--- + +## 🏗️ Height Propagation Chain (Non-Negotiable) + +Every page MUST follow this chain. Each level must propagate height to the next. + +``` +1. PageLayout (.ks-page__content) + └─ height: 100%; min-height: 0; display: flex; flex-direction: column; + +2. QueryStateBoundary (.ks-query-boundary) + └─ flex: 1; height: 100%; min-height: 0; display: flex; flex-direction: column; + +3. Content Container (KsSplitter / .ks-stack / FormPageLayout / etc) + ├─ flex: 1; min-height: 0; height: 100%; + ├─ display: flex/grid; + └─ overflow: hidden; + +4. Internal Panes (.request-list, .detail-panel, .items, etc) + └─ flex: 1; min-height: 0; overflow-y: auto; (enables internal scroll) +``` + +**Result:** Page fits single viewport. Only internal panes scroll. + +--- + +## ✅ Verification Checklist + +For EVERY layout change, verify: + +- [ ] **Variables:** Uses `var(--ks-*-width)`, not hardcoded `18rem` / `26rem` / `28rem` +- [ ] **Breakpoints:** Uses standard 1100px (tablet) and 768px (mobile) +- [ ] **Flex children:** All have `flex: 1; min-height: 0;` +- [ ] **Scrollable panes:** Have `overflow-y: auto; min-height: 0;` +- [ ] **Max-width:** Wraps content in `max-width: 1400px; margin: 0 auto;` to prevent 2560px+ distortion +- [ ] **Tested:** + - [ ] 768px (mobile) + - [ ] 1100px (tablet breakpoint) + - [ ] 1512px (current test resolution) + - [ ] 1920px (fullHD) + - [ ] 2560px (4K) +- [ ] **Result:** No page-level scroll on first load; only internal panes scroll if content exceeds height +- [ ] **Grid align:** Uses `align-items: start` (not center/stretch) + +--- + +## 🔴 Critical Issues to Fix (Session 2026-08-16) + +### 1. FormPageLayout +**File:** `frontend/src/shared/ui/layouts/FormPageLayout.vue` +**Current:** `grid-template-columns: minmax(0, 1fr) minmax(18rem, 26rem);` +**Fix:** `grid-template-columns: minmax(0, 1fr) var(--ks-preview-width);` +**Breakpoint:** Change from 950px to 1100px +**Pages Affected:** MarketDataIngestion, EditFormPage, etc. + +### 2. ReviewWorkbenchLayout +**File:** `frontend/src/shared/ui/layouts/ReviewWorkbenchLayout.vue` +**Current:** `grid-template-columns: minmax(18rem, 28rem) minmax(24rem, 1fr) minmax(18rem, 24rem);` +**Fix:** `grid-template-columns: var(--ks-sidebar-width) minmax(0, 1fr) var(--ks-aside-width);` +**Breakpoint:** Change from 1200px to 1100px +**Pages Affected:** ApprovalQueue (master-detail), review screens + +### 3. OperationsConsoleLayout +**File:** `frontend/src/shared/ui/layouts/OperationsConsoleLayout.vue` +**Current:** `grid-template-columns: minmax(18rem, 28rem) minmax(0, 1fr);` +**Fix:** `grid-template-columns: var(--ks-detail-width) minmax(0, 1fr);` +**Breakpoint:** Standardize to 1100px +**Pages Affected:** Operations console + +--- + +## 📚 Related Documents + +- **AGENTS.md v16.0:** Authoritative source for all engineering rules + - § "Frontend Layout & Responsive Design Standards" +- **ADR-LAYOUT-HEIGHT-PROPAGATION:** Height propagation principles +- **CLAUDE.md:** Project context (architecture overview, navigation) + +--- + +## 🎓 For AI Agents / LLMs + +**When implementing any layout:** + +1. **Check AGENTS.md first** (source of truth) +2. **Consult this document** for standard variables and breakpoints +3. **Verify against checklist** before committing +4. **Reference variables in CSS:** Always use `var(--ks-*-width)` for width constraints +5. **Uniform breakpoints:** Use ONLY 1100px (tablet) and 768px (mobile) +6. **Height chain:** Ensure flex: 1 / min-height: 0 propagates through all levels + +**BANNED:** Hardcoded pixel/rem widths in grid-template-columns. Always use CSS variables. + +--- + +## Version History + +| Version | Date | Change | +|---------|------|--------| +| v1.0 | 2026-08-16 | Initial standard; fixes 3 layouts; establishes CSS variable system | diff --git a/frontend/current_screen.png b/frontend/current_screen.png index 9d0536bc..391954cc 100644 Binary files a/frontend/current_screen.png and b/frontend/current_screen.png differ diff --git a/frontend/src/shared/ui/layouts/FormPageLayout.vue b/frontend/src/shared/ui/layouts/FormPageLayout.vue index e2a31e63..fa7f00f0 100644 --- a/frontend/src/shared/ui/layouts/FormPageLayout.vue +++ b/frontend/src/shared/ui/layouts/FormPageLayout.vue @@ -5,4 +5,4 @@ - + diff --git a/frontend/src/shared/ui/layouts/OperationsConsoleLayout.vue b/frontend/src/shared/ui/layouts/OperationsConsoleLayout.vue index 3324ef96..85f6e432 100644 --- a/frontend/src/shared/ui/layouts/OperationsConsoleLayout.vue +++ b/frontend/src/shared/ui/layouts/OperationsConsoleLayout.vue @@ -1,3 +1,3 @@ {{ title }}상태 {{ runStatus ?? '-' }} · Watermark {{ watermark ?? '-' }} · Owner {{ owner ?? '-' }} - + diff --git a/frontend/src/shared/ui/layouts/PageLayout.vue b/frontend/src/shared/ui/layouts/PageLayout.vue index 62501c3d..678117c4 100644 --- a/frontend/src/shared/ui/layouts/PageLayout.vue +++ b/frontend/src/shared/ui/layouts/PageLayout.vue @@ -109,6 +109,6 @@ const showHelp = ref(false) .ks-page__workspace { min-width: 0; flex: 1; display: grid; min-height: 0; gap: var(--ks-space-4); } .ks-page__workspace.has-aside { grid-template-columns: minmax(0, 1fr) var(--ks-aside-width); } .ks-page__content, .ks-page__aside { min-width: 0; min-height: 0; height: 100%; display: flex; flex-direction: column; } -.ks-page__footer { position: sticky; bottom: 0; z-index: 2; display: flex; justify-content: flex-end; gap: var(--ks-space-2); padding: var(--ks-space-3); border: 1px solid var(--ks-color-neutral-200); background: rgb(255 255 255 / 96%); } +.ks-page__footer { flex: 0 0 auto; display: flex; justify-content: flex-end; gap: var(--ks-space-2); padding: var(--ks-space-3); border: 1px solid var(--ks-color-neutral-200); background: rgb(255 255 255 / 96%); } @media (max-width: 1100px) { .ks-page__workspace.has-aside { grid-template-columns: 1fr; } } diff --git a/frontend/src/shared/ui/layouts/ReviewWorkbenchLayout.vue b/frontend/src/shared/ui/layouts/ReviewWorkbenchLayout.vue index cd4cc966..b061f37c 100644 --- a/frontend/src/shared/ui/layouts/ReviewWorkbenchLayout.vue +++ b/frontend/src/shared/ui/layouts/ReviewWorkbenchLayout.vue @@ -6,7 +6,7 @@
상태 {{ runStatus ?? '-' }} · Watermark {{ watermark ?? '-' }} · Owner {{ owner ?? '-' }}