작업 목록 앱의 아키텍처와 설정
앱은 데이터 서비스 훅과 화면 컴포넌트를 분리합니다. 훅은 OSDK 조회, 사용자 정보와 미디어 처리를 담당하고, SWR은 데이터를 캐시하며 재검증 상태를 제공합니다. 컴포넌트는 필요한 훅을 호출하여 해당 화면의 데이터를 받습니다.
예제 설치
Code Workspaces에서 + New Workspace를 선택하고 VS Code > Applications의 예제 목록에서 고급 작업 목록 앱을 찾습니다. 플랫폼의 Examples (Build with AIP)나 Developer Console의 OSDK 예제 검색에서도 찾을 수 있습니다.
설치한 예제의 생성 SDK와 의존성을 사용합니다. 훅은 TypeScript OSDK 2.x와 SWR 2의 API를 사용합니다. @osdk/react의 Provider와 클라이언트는 호환 버전 설정을 따르며, 생성 SDK와 런타임 패키지의 버전을 함께 맞춥니다.
데이터 모델
예제가 사용하는 API 이름은 다음과 같습니다. 실제 SDK에서 이름을 변경하면 import, 링크와 속성 참조도 함께 바꿉니다.
| 유형 | 역할과 사용 항목 |
|---|---|
AdvanceTodoProject | 프로젝트 이름과 codingTasks, learningTasks 링크를 제공합니다. |
OsdkITask | 두 작업 유형의 공통 인터페이스입니다. projectId, title, status, dueDate, createdBy, assignedTo를 사용합니다. |
osdkCodingTask | 코딩 작업의 구체 유형이며 language, codeSnippet을 표시합니다. |
osdkLearningTask | 학습 작업의 구체 유형이며 description, mediaReference, contentUrl을 사용합니다. |
작업 상세 화면은 task.osdkTask.$objectType이 osdkCodingTask인지 osdkLearningTask인지에 따라 해당 컴포넌트를 선택합니다. 코딩 작업은 $as로 기반 속성을 사용하고, 학습 작업은 구체 유형의 객체를 다시 조회합니다.
라우팅과 Provider
React Router의 createBrowserRouter로 두 경로를 구성합니다.
| 경로 | 컴포넌트의 역할 |
|---|---|
/ | 프로젝트와 작업을 표시하는 Home 화면 |
/auth/callback | OAuth 인증 뒤 돌아온 요청을 처리하는 AuthCallback 화면 |
basename은 import.meta.env.BASE_URL을 사용하여 앱이 하위 경로에 호스팅되는 경우를 반영합니다. 루트의 OsdkProvider 아래에 RouterProvider를 두면 화면과 데이터 훅이 같은 클라이언트를 사용합니다.
다음 함수는 설치한 예제의 Home과 AuthCallback 요소, 인증 설정을 마친 클라이언트와 실제 루트 DOM 요소를 입력으로 받습니다. 앱 시작 시 한 번 호출하며, 라우터와 React 루트는 페이지 수명 동안 유지합니다. 두 화면의 업무 로직이나 OAuth 처리는 이 함수의 입력을 제공하는 예제 앱이 담당합니다.
import { StrictMode, type ReactElement } from "react";
import { createRoot } from "react-dom/client";
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import { OsdkProvider } from "@osdk/react";
import type { Client } from "@osdk/client";
export function mountTodoApplication(
element: HTMLElement,
client: Client,
home: ReactElement,
authCallback: ReactElement,
) {
const router = createBrowserRouter([
{ path: "/", element: home },
{ path: "/auth/callback", element: authCallback },
], { basename: import.meta.env.BASE_URL });
const root = createRoot(element);
root.render(
<StrictMode>
<OsdkProvider client={client}>
<RouterProvider router={router} />
</OsdkProvider>
</StrictMode>,
);
}
OAuth 클라이언트
client.ts는 Foundry URL, 공개 client ID, 리다이렉트 URL과 온톨로지 RID를 읽고 OAuth 클라이언트와 OSDK 클라이언트를 준비합니다. OAuth 클라이언트가 인증 리다이렉트, 토큰 취득과 갱신, 사용자 세션을 처리합니다. OsdkProvider는 이 클라이언트를 컴포넌트에 제공하며, Provider 자체가 사용자에게 데이터 권한을 부여하지는 않습니다.
컴포넌트의 useOsdkClient()는 같은 클라이언트를 반환합니다. useTasks는 이를 사용해 프로젝트 ID를 필터링하고 작업을 정렬하여 조회합니다. 요청은 인증한 사용자가 접근할 수 있는 데이터 범위를 따릅니다.
앱에 필요한 OAuth 범위와 API 접근은 Developer Console 권한에서 구성합니다. 기존 API 보안 모델과 신규 또는 이전된 고급 API 보안 모델은 요구하는 범위가 다를 수 있으므로 앱의 등록 상태에 맞춰 설정합니다. 공개 client ID와 비밀 client secret을 구분하며, 브라우저 앱에 client secret을 넣지 않습니다.
환경 파일과 meta 설정
| 파일 | 적용 범위 |
|---|---|
.env | 공통 설정 |
.env.development | npm run dev의 개발 설정 |
.env.production | npm run build의 운영 빌드 설정 |
모드별 값은 공통 파일의 같은 이름을 덮어씁니다. Vite를 시작할 때 이미 제공한 환경 변수는 파일보다 우선합니다. 환경 파일을 바꿨다면 개발 서버를 다시 시작해야 합니다.
index.html에는 네 개의 meta 태그를 둡니다. Vite가 %...% 값을 치환하고 client.ts가 이를 읽습니다.
<meta name="osdk-clientId" content="%VITE_FOUNDRY_CLIENT_ID%" />
<meta name="osdk-redirectUrl" content="%VITE_FOUNDRY_REDIRECT_URL%" />
<meta name="osdk-foundryUrl" content="%VITE_FOUNDRY_API_URL%" />
<meta name="osdk-ontologyRid" content="%VITE_FOUNDRY_ONTOLOGY_RID%" />
| 변수 | 의미 |
|---|---|
VITE_FOUNDRY_CLIENT_ID | 공개 OAuth client ID |
VITE_FOUNDRY_REDIRECT_URL | 인증 뒤 돌아올 앱 URL |
VITE_FOUNDRY_API_URL | Foundry API의 기준 URL |
VITE_FOUNDRY_ONTOLOGY_RID | 앱이 사용하는 온톨로지 RID |
VITE_ 값과 HTML meta 내용은 브라우저에서 볼 수 있는 공개 구성입니다. 토큰이나 client secret을 이 변수에 넣지 않습니다.
다음 도메인, client ID와 RID는 가상 설정 예입니다. 실제 값으로 바꾸고 리다이렉트 URL을 Developer Console에 등록해야 합니다. 위 라우터의 callback 경로와 호스팅의 base 경로를 모두 반영합니다.
개발용 .env.development:
VITE_FOUNDRY_CLIENT_ID=example-development-client
VITE_FOUNDRY_REDIRECT_URL=http://localhost:3000/auth/callback
VITE_FOUNDRY_API_URL=https://foundry-dev.example.com
VITE_FOUNDRY_ONTOLOGY_RID=ri.ontology.main.ontology.12345678-abcd-1234-abcd-1234567890ab
운영용 .env.production:
VITE_FOUNDRY_CLIENT_ID=example-production-client
VITE_FOUNDRY_REDIRECT_URL=https://tasks.example.com/auth/callback
VITE_FOUNDRY_API_URL=https://foundry-prod.example.com
VITE_FOUNDRY_ONTOLOGY_RID=ri.ontology.main.ontology.87654321-abcd-1234-abcd-1234567890ab
개발 서버는 HMR로 편집 내용을 반영하며 개발 또는 스테이징 플랫폼 인스턴스에 연결할 수 있습니다. 운영 빌드는 운영 인스턴스와 배포 주소를 사용하고 코드를 최적화합니다. CSP와 호스팅 설정은 배포 대상에 맞게 별도로 적용합니다.
기능별 데이터 처리
인터페이스와 상세 화면
OsdkITask로 공통 속성을 읽고 실제 객체 유형에 맞는 상세 화면을 선택합니다. 코딩 작업의 $as는 부모가 읽어 둔 기반 속성을 사용합니다. 생성 SDK의 스키마와 메타데이터를 사용하므로 지원되지 않는 다른 객체 유형으로 임의 변환하지 않습니다.
미디어 내용
학습 작업은 미디어 참조의 fetchContents()로 내용과 Blob을 얻고, fetchMetadata()로 MIME 유형을 판별합니다. PDF, 이미지, 비디오 또는 링크를 선택하여 표시합니다. URL의 생성과 해제는 표시하는 화면의 수명에 맞춥니다.
서버 통계
프로젝트는 withProperties, pivotTo, where, aggregate를 조합해 작업 개수를 계산합니다. 서버에서 종류별 통계를 받고 클라이언트에서 합산하므로 통계를 위해 모든 작업 본문을 전송하지 않습니다.
표시 메타데이터
client.fetchMetadata로 인터페이스나 객체 유형의 표시 이름, 속성 표시 이름과 설명을 읽습니다. 이 정보를 사용하는 UI 문구는 온톨로지 메타데이터 변경을 반영할 수 있습니다. API 이름이나 스키마가 바뀌면 생성 SDK와 코드도 해당 계약에 맞춰야 합니다.
변경 통지
작업 목록은 프로젝트 조건의 객체 집합을 구독하고 변경 통지에 따라 SWR 키를 재검증합니다. 구독이 오래되었다는 통지도 재조회로 처리하고, 컴포넌트가 해제되면 구독을 종료합니다.
사용자 정보
사용자 훅은 ID별 캐시를 먼저 확인하고 필요한 사용자만 한 번에 최대 500개씩 요청합니다. 요청한 사용자가 없으면 그 ID의 값은 undefined일 수 있습니다. 프로필 이미지는 사용자 정보와 별도이며 각 Blob URL의 소유자가 해제합니다.
이 예제의 키는 한 앱, 온톨로지와 인증 세션의 캐시 범위를 전제로 합니다. 같은 페이지에서 클라이언트나 인증 사용자를 교체하는 앱은 캐시도 분리하거나 초기화해야 합니다.