핵심 개념
theme와 harness의 차이, page recipe, state boundary, 비목표를 정리합니다.
reopt designUpdated
1. theme와 harness의 차이
Theme
color, radius, spacing token, primitive styling처럼 시각적 일관성을 해결합니다. 잘 써도 제품 화면의 정보 구조까지 자동으로 좋아지지는 않습니다.
Harness
페이지 폭, 섹션 리듬, state UX, toolbar/inspector/footer 배치처럼 제품 화면의 반복 규칙을 강제합니다.
2. manifest와 policy
harness의 기본 정책은 `density`, `contentWidth`, `navigationMode`, `motionPolicy`, `stateLabels`, `panelBehavior`로 구성됩니다. 즉, 페이지 컴포넌트마다 className으로 규칙을 흩뿌리는 대신 앱 단위 정책으로 고정하는 접근입니다.
`ShellProvider`는 manifest defaults와 화면별 override를 병합해 하위 트리에 전달합니다. 이 덕분에 Builder 같은 내부 앱은 넓은 화면과 reduced motion을 기본으로 두고, 필요할 때만 화면 단위 예외를 줄 수 있습니다.
3. managed harness lifecycle
정적 manifest만으로는 충분하지 않습니다. 실제 팀은 draft harness를 만들고, preview로 결과를 보고, current draft hash에 연결된 fresh PASS proof를 남기고, review note와 approval evidence를 남긴 뒤, 승인된 후보만 active runtime에 올려야 합니다. 패키지 API는normalizeManagedShellDefinition(), resolveManagedShellManifest() 같은 managed shell helper를 제공하고, Builder의 harness manager는 이 운영 개념을 사용자-facing 인터페이스로 올린 것입니다.
| 층위 | 값 | 의미 |
|---|---|---|
| Lifecycle | DRAFT, ACTIVE, ARCHIVED | 워크스페이스는 여러 draft를 유지하되 active harness는 하나만 가집니다. |
| Review | DRAFT, REVIEW_REQUESTED, APPROVED, CHANGES_REQUESTED | draft는 review 상태를 따로 가지며 APPROVED가 되기 전까지 activation 대상이 아닙니다. |
| Evidence | preview, design proof, review note, activity intelligence | candidate vs active 비교, current draft 기준 fresh proof, reviewer note, searchable timeline/learnings가 함께 남아야 운영 도구로 기능합니다. |
최근에는 여기서 한 걸음 더 나아가 append-only audit log 위에 searchable activity intelligence를 올렸습니다. 그래서 raw activity feed를 넘어서 timeline, learnings, exportable snapshot으로 운영 맥락을 다시 읽을 수 있습니다.
4. page recipe
`ShellPage`는 자유로운 div 조합을 막는 대신 명시적 슬롯을 제공합니다. 이 슬롯을 기준으로 페이지 리듬과 sticky aside 동작을 고정합니다. 다만 모든 recipe가 모든 슬롯을 쓰는 것은 아닙니다. `filters`는 list 전용이고, landing recipe는 aside를 갖지 않습니다.
| Slot | 용도 |
|---|---|
| header | 페이지 제목, 설명, 상위 상태 요약 |
| toolbar | 1차 액션과 페이지 레벨 명령 |
| filters | 검색, 필터, density 전환처럼 content 위에 오는 제어 UI |
| content / children | 핵심 도메인 콘텐츠 |
| aside | inspector, activity, secondary controls |
| footer | 보조 상태, last sync, bulk summary |
import {
DetailWorkspace,
ShellSection,
ShellStateBoundary,
} from "@reopt-ai/opt-shell";
export function ProjectScreen() {
return (
<DetailWorkspace
header={<div>Project Header</div>}
toolbar={<div>Toolbar</div>}
aside={<div>Sticky Inspector</div>}
footer={<div>Last synced 2m ago</div>}
>
<ShellStateBoundary
loading={false}
empty={{
title: "프로젝트가 없습니다",
description: "새 프로젝트를 만들거나 현재 필터를 조정해 보세요.",
}}
>
<ShellSection title="Projects" frame="card">
<div>content</div>
</ShellSection>
</ShellStateBoundary>
</DetailWorkspace>
);
}5. shared state boundary
`ShellStateBoundary`는 loading / empty / error를 공통 copy와 layout으로 렌더링합니다. 중요한 점은 상태를 "예쁘게 보여주는 컴포넌트"가 아니라 "제품 전반의 fallback 규칙"으로 취급한다는 점입니다. DataGrid나 Editor adapter도 이 boundary 위에서만 동작합니다.
6. 비목표
- 새로운 button, input, primitive를 다시 만드는 것
- opt-ui 전체를 re-export해서 또 다른 UI 라이브러리가 되는 것
- DataGrid나 Editor의 엔진 상태를 harness로 끌어오는 것
- 화면마다 임의의 chrome variation을 늘려 harness 경계를 무너뜨리는 것
- review와 approval evidence 없이 draft harness를 바로 active로 쓰는 것