Core Concepts
핵심 개념
brandapp-ui는 런타임 UI 라이브러리가 아니라 BrandApp 기능을 제품에 빠르게 붙이는 copy-paste source package입니다.
reopt designUpdated
1. Copy-paste package
package.json의 공개 export는 metadata뿐입니다. 실제 Surface는 opt-cli registry에 들어가고, 소비자는 opt surface add로 파일을 복사합니다. 복사된 뒤에는 SemVer upgrade 대상이 아니라 consumer app 코드입니다.
text
@reopt-ai/brandapp-ui
├─ src/surfaces
│ ├─ sign-in-with-reopt-button.tsx
│ ├─ reopt-user-menu.tsx
│ ├─ sign-in-gate.tsx
│ ├─ session-expired-dialog.tsx
│ ├─ reopt-ai-chat.tsx
│ ├─ reopt-ai-image-studio.tsx
│ └─ reopt-record-table.tsx
├─ src/surfaces/_meta.ts
└─ src/meta.ts2. 책임 경계
brandapp-ui가 SDK와 UI를 모두 대신 소유하지 않습니다. secret, API route, 제품 정책은 consumer app에 남기고, Surface는 검증된 출발점을 제공합니다.
text
Consumer app
owns env, server routes, auth route, product copy, final UX policy
@reopt-ai/brandapp-sdk
owns OAuth, sessions, EAV, AI provider, typed SDK errors
@reopt-ai/brandapp-ui
owns copy-paste source templates and registry metadata
@reopt-ai/opt-ui / opt-chat
owns primitives, DataTable, Conversation, PromptInput3. Import boundary
Surface source는 소비자 프로젝트로 복사되므로 내부 monorepo 경로나 app-specific API에 의존하면 안 됩니다. 인증 Surface는 반드시 consumer app의 @/lib/auth-client를 사용합니다.
tsx
// Surface source 안에서는 consumer project 경로를 사용합니다.
import { authClient } from "@/lib/auth-client";
import { SignInWithReoptButton } from "./sign-in-with-reopt-button";
// OK: public package API
import { Button, Avatar, DataTable } from "@reopt-ai/opt-ui";
import { Conversation, useChatSession } from "@reopt-ai/opt-chat";
// 금지: opt-ui 내부 파일 경로, app-specific router, secret SDK client
// import { Button } from "@reopt-ai/opt-ui/src/core/button";
// import { useRouter } from "next/navigation";
// import { createReoptSDK } from "@reopt-ai/brandapp-sdk";4. Client/server split
| Surface | Client side | Server side |
|---|---|---|
| Auth surfaces | @/lib/auth-client, authClient.useSession(), signInWithReopt | Better Auth route and createReoptBetterAuth live in consumer app |
| AI surfaces | ReoptAiChat, ReoptAiImageStudio receive endpoint props | createBrandappProvider/createReoptSDK and typed error mapping live in route handlers |
| EAV surfaces | ReoptRecordTable fetches recordsEndpoint and renders DataTable | sdk.eav.records(entityId).list() proxy keeps clientSecret off the browser |