실제 제품을 적절한 조작 환경에서 실행해 변경 사항을 검증하고, 사용자가 확인할 수 있는 증거를 모아 인수 보고서로 게시합니다. 기존 검증 계획을 확인하거나 점검 항목을 만들고, `lh` CLI로 결과를 게시할 수 있습니다.
- 변경된 제품 동작을 실제로 확인하기
- 스크린샷 등 검증 증거 수집하기
- 검증 계획과 보고서 작성하기
Zustand 상태 유형, 선택자, 별도 액션 클래스의 구성을 안내합니다. `local-replica`로 서버 기반 목록과 상세 데이터를 동기화하고, 낙관적 업데이트 및 실패 시 롤백을 구현하는 방법과 기존 스토어 관례도 다룹니다.
Use for Zustand stores: state shapes and type sources, state-only stores with xActions classes, replica-backed list/detail data (local-replica), selectors, optimistic writes, and legacy slice/internal_* action composition.
실행 점수 미검증
설치 방법 보기이 가이드는 Zustand 스토어의 상태, 유형, 선택자, 액션을 구성하는 방법을 설명합니다. 새로 만들거나 마이그레이션하는 스토어에서는 상태와 액션을 분리하고, 액션은 전용 클래스에 둡니다. 컴포넌트는 선택자로 상태를 읽고 액션 클래스를 직접 호출합니다. 공유 스토어 유형은 @lobechat/types에서 가져오며, 목록 항목 유형은 상세 유형과 분리합니다.
서버에서 제공하는 목록과 상세 데이터에는 local-replica를 사용합니다. 로컬 복원, 재검증, 페이지 처리, 낙관적 업데이트와 실패 시 롤백, 사용자 및 워크스페이스 범위 격리를 다룹니다. 리소스 정의, replica 슬라이스 연결, 선택자를 통한 읽기, 화면이 연결되지 않은 상태에서의 가져오기, replica API를 통한 쓰기 방법도 안내합니다. slice나 internal_* 액션을 사용하는 기존 스토어는 해당 형식을 수정할 때 참고할 별도 지침을 제공합니다.
스토어를 새로 만들거나 마이그레이션할 때, 목록과 상세 데이터 유형을 정할 때, 서버 데이터를 동기화하거나 낙관적 업데이트를 구현할 때 유용합니다. 기존 레거시 스토어를 수정하면서 적용할 규칙을 확인할 때도 참고할 수 있습니다.
local-replica로 목록 데이터를 읽고 쓰는 방법을 설명해 주세요.”특별한 주의 사항은 없습니다.
이 소개문은 공개된 SKILL.md를 바탕으로 AI(OpenAI Codex)가 작성했습니다. 정확한 사양은 아래 원문을 확인하세요.
AI가 SKILL.md의 내용에서 주의가 필요한 작업과 도입 전제를 확인했습니다. 점수는 실제로 실행한 결과(실행 검증)만으로 매깁니다.
점수에는 넣지 않았습니다. 2026년 10월 26일 기준으로 AI(OpenAI Codex)가 판정했습니다. 참고용이므로 설치 전에 원문도 확인해 주세요.
설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.
@lobechat/types, not @lobechat/database.xxxDetailMap: Record<string, Detail>); never hold a single currentDetail object.xxxSelectors aggregates (selectors.ts), not ad-hoc lambdas repeated across components.Actions stay out of the Zustand state. Reference: src/store/page.
| File | Owns |
|---|---|
store.ts | useXStore = createWithEqualityFn<XState>()(devtools(() => initialState), shallow): state only, no methods |
privateAction.ts | XPrivateAction: replica slices, entity links, and write helpers shared by public actions. Not exported from index.ts |
action.ts | XActionImpl (the public API) and the singleton xActions = new XActionImpl(setState, getState, new XPrivateAction(…)) |
useXStore(selector) and call xActions.foo() directly. Never select an action out of the store.xActions.useFetchX(params).this.foo(). Private helpers are reached through this.#private. Do not add internal_* methods to the store to share logic between classes.this.#set(partial, false, n('actionName')) with const n = setNamespace('x').reset() on the public class and register xActions in resetableActions in src/store/utils/userDataStores.ts.xActions and assert on useXStore.getState(). To mock in component tests: vi.mock('@/store/x', () => ({ xActions: { foo: vi.fn() }, useXStore: … })).Server lists and details the UI paints go through @/libs/replica, not a hand-written SWR onSuccess + reducer. The engine owns hydration from IndexedDB, head revalidation, paging, optimistic overlays with rollback, and scope (user + workspace) isolation. API reference: the local-replica README. The engine is maintained in lobehub/local-replica: fix it there, publish, then bump the dependency here.
defineReplica / definePagedReplica) in the store's projection.ts, converting server rows at the boundary.xxxMap: Record<key, TData>) and its bookkeeping (xxxReplica: createReplicaState()).createReplicaSlice(resource, { get, set, stateKey: 'xxxReplica', view: recordLens('xxxMap'), … }). When the same entity lives in several replicas (list row + detail), link them with linkReplicaEntity([list, detail]).slice.useSync(params) returns only fetch flags (isHydrated, isValidating, error, revalidate). Data comes from selectors over xxxMap. "Entry is undefined" is the loading signal — do not add xxxInit flags or loadingXxxIds.await slice.fetch(params) ({ fresh: true } after a write). Never call the service and slice.replace(...) by hand, because that skips the scope, removal, clear and superseded-request guards. Side effects of every response (not-found maps, seeding another store) go in the slice effects (onApplied / onMissing / onPurge / onError) with isMissing, not in one hook's onSuccess.useSync hydrates only after the component mounts. For a list that must paint from the local copy, add a preHydrate action (ensureScope + hydrate) and call it from the route's loader through a lazy wrapper (src/spa/router/pageListLoader.ts, agentChatTopicListLoader.ts) bounded by settleWithin(…, PRE_PAINT_HYDRATE_TIMEOUT) from @/libs/replica/prePaint. @/libs/replica presets the cache scope, IndexedDB / localStorage storage (AppIndexedDBStorage / AppLocalStorage in @/libs/replica/storage) and the app's SWR driver; the package README stays app-agnostic.slice.optimistic(key, apply, serverCall) or entity.optimistic(id, fn | 'remove', serverCall). A failed call rolls back to the confirmed value, so deletes are optimistic too. Rows that exist only on the client (temp ids) are declared with isClientOnly and seeded with update(key, fn, { persist: false }).Outside test seeding, write a replica's view only through its slice. A plain set bypasses the engine's bookkeeping (persistence, rollback base, entity links).
Stores that still flatten action classes into state (flattenActions, create*Slice, internal_*, internal_dispatch* + reducers, SWR onSuccess syncing) follow Legacy slices. Use that layout only when editing one of those stores; migrate to the layouts above when moving its data onto a replica.
아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.
로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.
아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.
실제 제품을 적절한 조작 환경에서 실행해 변경 사항을 검증하고, 사용자가 확인할 수 있는 증거를 모아 인수 보고서로 게시합니다. 기존 검증 계획을 확인하거나 점검 항목을 만들고, `lh` CLI로 결과를 게시할 수 있습니다.
LobeHub에 AI 모델 제공자를 추가하는 과정을 안내합니다. 런타임 연동, 모델 정보와 설정, 브랜드 표시, 문서화 및 인수 확인을 다루며, 기존 제공자에 모델만 추가하는 경우와 새 연동이 필요한 경우를 구분합니다.
서버 환경 변수로 사용자 설정의 기본값을 지정하도록 구현하는 절차를 안내합니다. 변수 검증, 서버 설정 구성, 사용자 저장소 반영부터 예시 환경 파일과 셀프 호스팅 문서 갱신까지 다룹니다.
에이전트 실행 단계, 도구 호출, 사람의 승인, 컨텍스트 압축, 하위 에이전트 호출에 훅을 등록하는 방법을 안내합니다. 이벤트를 관찰하고 로컬 도구 결과를 모의하거나 설정에 따라 웹훅으로 도구 호출을 허용 또는 거부할 수 있습니다.
에이전트의 이벤트 기반 백그라운드 작업을 설계하고 구현하도록 돕습니다. 소스, 시그널, 액션, 정책의 역할을 나누고 비동기 처리, 중복 실행 방지, 완료 기록과 관측 기능을 다룹니다.
실제 데스크톱 채팅 앱에서 봇 채널의 인수 테스트를 진행합니다. Discord, Slack, Telegram, WeChat, Lark, QQ에서 메시지를 보내고 응답을 기다린 뒤 결과 화면을 캡처합니다. iMessage는 BlueBubbles 브리지를 사용합니다.