Skip to content

Commit db328b1

Browse files
committed
feat(docs): add Korean (ko) locale with full doc translations
Adds ko as the 7th supported locale, mirroring the ja/de/es/fr setup. - i18n: register 'ko'; LANGUAGE_NAMES '한국어'; nav labels (문서/다운로드/변경 내역) - middleware: map ko / ko-KR -> ko for browser language detection - 7 meta.ko.json sidebar files (구축/설정/권한/배포/운영/참조/리소스) - Full Korean translation of all 50 docs pages (*.ko.mdx) Translation prompt now enforces YAML-safe frontmatter (quote any title/ description containing a colon), preventing the build break fixed in 299b599. All 349 frontmatter blocks validate; type-check and docs build pass. UI strings in homepage-i18n/download-i18n fall back to English (same as ja/de/es/fr); legal pages (privacy/terms) fall back to English by design.
1 parent a4c100d commit db328b1

61 files changed

Lines changed: 6939 additions & 1 deletion

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/docs/app/[lang]/layout.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const LANGUAGE_NAMES: Record<string, string> = {
1010
de: 'Deutsch',
1111
es: 'Español',
1212
fr: 'Français',
13+
ko: '한국어',
1314
};
1415

1516
export default async function LanguageLayout({

apps/docs/lib/i18n.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@ import { defineI18n } from 'fumadocs-core/i18n';
1010
* - de: German (Deutsch)
1111
* - es: Spanish (Español)
1212
* - fr: French (Français)
13+
* - ko: Korean (한국어)
1314
*/
1415
export const i18n = defineI18n({
1516
defaultLanguage: 'en',
16-
languages: ['en', 'zh-Hans', 'ja', 'de', 'es', 'fr'],
17+
languages: ['en', 'zh-Hans', 'ja', 'de', 'es', 'fr', 'ko'],
1718
// Hide locale prefix for default language (e.g., /docs instead of /en/docs)
1819
hideLocale: 'default-locale',
1920
});

apps/docs/lib/layout.shared.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const NAV_LABELS: Record<string, { docs: string; download: string; changelog: st
1414
de: { docs: 'Dokumentation', download: 'Download', changelog: 'Änderungen' },
1515
es: { docs: 'Documentación', download: 'Descargar', changelog: 'Cambios' },
1616
fr: { docs: 'Documentation', download: 'Télécharger', changelog: 'Journal' },
17+
ko: { docs: '문서', download: '다운로드', changelog: '변경 내역' },
1718
};
1819

1920
const RELEASES_URL = 'https://github.com/objectstack-ai/objectos/releases';

apps/docs/middleware.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ const LANGUAGE_MAPPING: Record<string, string> = {
3131
// Traditional variants fall back to Simplified until zh-Hant ships
3232
'zh-TW': 'zh-Hans',
3333
'zh-HK': 'zh-Hans',
34+
'ko': 'ko', // Korean
35+
'ko-KR': 'ko', // Korean (Korea) -> Korean
3436
};
3537

3638
/**

content/docs/architecture.ko.mdx

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
---
2+
title: 아키텍처
3+
description: 실제로 무엇이 실행되는가 — 이 제품을 도입할지 평가하는 엔지니어를 위한 안내.
4+
---
5+
6+
# 아키텍처
7+
8+
ObjectOS를 배포할 때 여러분의 머신에서 무엇이 실행되는지, 어떤 데이터가
9+
네트워크 밖으로 나가고 어떤 데이터가 나가지 않는지에 대한 실용적인 관점입니다.
10+
11+
핵심 개념은 두 개의 얇은 계층입니다.
12+
13+
1. **메타데이터** — 객체 / 뷰 / 액션 / 플로우 / 에이전트의 패키지입니다.
14+
대부분은 샌드박스화된 도구 API를 대상으로 [AI Builder](/docs/build/ai-builder)
15+
작성하며, 때때로 직접 편집되기도 하지만 항상 버전 관리되고 감사됩니다.
16+
2. **단일 Node.js 런타임** — 이 메타데이터를 동작하는 애플리케이션으로
17+
해석합니다. REST API, Console UI, 권한, 작업, AI 도구가 모두 하나의
18+
프로세스 안에서 여러분의 데이터베이스와 통신합니다.
19+
20+
코드 생성 단계도, "사용자가 원하는 것을 설명함"과 "그것이 라이브로 동작함"
21+
사이의 배포 파이프라인도 없습니다. 런타임은 HITL 승인 이후 새 메타데이터를
22+
핫 로드합니다.
23+
24+
## 무엇을 배포하는가
25+
26+
ObjectOS 인스턴스당 하나의 Node.js 프로세스. 그것이 전부입니다.
27+
28+
```text
29+
┌─────────────────────────────────────────────────────┐
30+
│ ObjectOS process │
31+
│ ┌───────────────────────────────────────────────┐ │
32+
│ │ HTTP dispatcher (/ · /api · /_console …) │ │
33+
│ ├───────────────────────────────────────────────┤ │
34+
│ │ Per-project ObjectKernel (LRU cached) │ │
35+
│ │ ├─ Auth (Better Auth) │ │
36+
│ │ ├─ Security (RBAC + row-level + field) │ │
37+
│ │ ├─ ObjectQL (data engine, generates SQL) │ │
38+
│ │ ├─ REST API generator │ │
39+
│ │ └─ Capabilities loaded per artifact │ │
40+
│ │ (audit, storage, jobs, queue, AI …) │ │
41+
│ └───────────────────────────────────────────────┘ │
42+
└──────────┬──────────────────────────────────────────┘
43+
44+
45+
Your business database
46+
(Postgres / MySQL / SQLite / Turso / MongoDB)
47+
```
48+
49+
정적으로 링크된 단일 바이너리 수준의 복잡도입니다. 사이드카도, Kafka도,
50+
별도의 캐시 계층도 필요하지 않습니다. 필요할 때 추가하세요. 첫날부터 그
51+
비용을 치를 필요는 없습니다.
52+
53+
## 데이터는 어디에 있는가
54+
55+
| 데이터 | 저장 위치 | 네트워크 밖으로 나가는가? |
56+
|---|---|---|
57+
| 비즈니스 레코드 | 여러분의 데이터베이스 | **아니오** |
58+
| 사용자 계정, 세션, OAuth 토큰 | 여러분의 데이터베이스 | **아니오** |
59+
| 감사 로그 | 여러분의 데이터베이스 | **아니오** |
60+
| 설정, API 키, 시크릿 | 여러분의 데이터베이스 / 시크릿 매니저 | **아니오** |
61+
| 업로드된 파일 | 여러분의 디스크 또는 S3/R2 버킷 | **아니오** |
62+
| 컴파일된 앱 정의(`objectstack.json`) | 디스크의 파일 또는 컨트롤 플레인에서 가져옴 | 선택적 |
63+
64+
ObjectOS는 외부로 연결을 시도하지 않습니다. 텔레메트리도, 라이선스 검사도
65+
없습니다. 인터넷 접속을 완전히 차단해도 무기한 계속 실행됩니다.
66+
[에어갭](/docs/deploy/air-gapped)을 참고하세요.
67+
68+
## 요청이 처리되는 방식
69+
70+
```text
71+
1. Ingress / TLS termination (your load balancer)
72+
2. HTTP dispatcher (security headers, request id)
73+
3. Hostname → project resolution (cached, TTL configurable)
74+
4. Get or build per-project kernel from LRU
75+
5. AuthPlugin — session cookie, bearer token, or API key
76+
6. SecurityPlugin — RBAC + row-level + field-level checks
77+
7. Route handler — generated REST, declarative action, or custom
78+
8. Data driver — ObjectQL compiles to SQL / Mongo query
79+
9. Response with X-Request-Id propagated
80+
```
81+
82+
커널이 워밍업된 상태에서는 4~8단계가 일반적으로 5ms 미만으로 실행됩니다.
83+
84+
## 세 개의 계층 (통합할 때만 중요함)
85+
86+
대부분의 고객은 **ObjectOS**만 배포합니다. 나머지 두 계층은 아티팩트가
87+
어디에서 오는지 알고 싶을 때를 위해 존재합니다.
88+
89+
| 계층 | 무엇인가 | 어디에서 실행되는가 |
90+
|---|---|---|
91+
| **Framework**(`@objectstack/*`) | 오픈소스 커널, ObjectQL, 플러그인, 드라이버 | npm — 빌드 시점에 포함됨 |
92+
| **Control plane**(선택적) | 컴파일된 `objectstack.json` 아티팩트를 게시함. 호스팅되는 ObjectStack Cloud를 사용하거나, 직접 운영하거나, 완전히 생략할 수 있음 | 여러분의 CI, 우리 클라우드, 또는 여러분의 노트북 |
93+
| **ObjectOS** | 여러분이 운영하는 런타임 | **여러분의 인프라** |
94+
95+
단일 앱을 출시한다면 컨트롤 플레인이 필요하지 않습니다. CI에서
96+
`objectstack.config.ts → dist/objectstack.json`을 컴파일하고 그 JSON을
97+
이미지에 담아 출시하세요. 다수의 테넌트와 앱을 가진 내부 앱 마켓플레이스를
98+
운영한다면, 컨트롤 플레인이 카탈로그가 머무는 곳입니다.
99+
100+
## 부팅 모드
101+
102+
| 모드 | 언제 | 어떻게 |
103+
|---|---|---|
104+
| **Standalone** | 단일 앱, 개발, 평가, 에어갭, 대부분의 프로덕션 배포 | `pnpm dev` 또는 디스크에서 `dist/objectstack.json` 실행 |
105+
| **File-backed** | 외부에서 관리되는 아티팩트를 사용하는 프로덕션 | `OS_ARTIFACT_PATH=/path/to/objectstack.json` 설정 |
106+
| **Cloud-connected** | 컨트롤 플레인이 공급하는 멀티 테넌트 / 멀티 앱 배포 | `OS_CLOUD_URL` + `OS_CLOUD_API_KEY` 설정 |
107+
108+
모드는 환경 변수로부터 자동 감지됩니다.
109+
110+
## 성능 특성
111+
112+
| 지표 | 수치 |
113+
|---|---|
114+
| 콜드 스타트(프로세스 기동, 트래픽 수신 준비) | 약 1초 |
115+
| 커널당 워밍업(프로젝트로의 첫 요청) | 기능에 따라 50~300ms |
116+
| 워밍업된 요청 지연(REST를 통한 CRUD) | 일반적으로 10ms 미만 + 데이터베이스 지연 |
117+
| 메모리 사용량 | 기본 약 150MB, 활성 프로젝트 커널당 약 10~30MB |
118+
| 인스턴스당 동시 프로젝트 수 | `OS_KERNEL_CACHE_SIZE`로 제한됨(기본값 32) |
119+
120+
## 왜 이런 형태인가
121+
122+
- **사이드카 없는 단일 Node 프로세스**`docker run`에 들어맞고, systemd
123+
유닛에 들어맞고, Lambda 같은 환경에 들어맞습니다.
124+
- **프로젝트당 커널, LRU 캐시** → 하나의 인스턴스가 매 요청마다 워밍업
125+
비용을 치르지 않고도 많은 소규모 앱을 처리할 수 있습니다.
126+
- **선언된 메타데이터 위에 생성되는 API** → CI에 코드 생성 단계가 없고,
127+
게시할 클라이언트 SDK도 없습니다. API는 구조적으로 여러분의 데이터
128+
모델과 일치합니다.
129+
- **모든 기능은 선택적 플러그인** → 이미지 크기가 실제로 사용하는 것에
130+
맞춰 조정됩니다.
131+
132+
## 다음으로 갈 곳
133+
134+
- [프로덕션 준비성](/docs/operate/production) — 실제 트래픽에 노출하기 전의
135+
체크리스트.
136+
- [런타임 구성](/docs/configure/runtime) — 데이터베이스, 캐시, 시크릿
137+
연결하기.
138+
- [런타임 기능](/docs/reference/runtime-capabilities) — 어떤 선택적
139+
패키지가 존재하고 무엇을 활성화하는지.

content/docs/build/actions.ko.mdx

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
---
2+
title: 액션(Actions)
3+
description: 플랫폼이 REST 엔드포인트, Console 버튼, 플로우 단계, AI 도구로 노출하는 명명된 작업 — 단 하나의 선언으로 제공됩니다.
4+
---
5+
6+
# 액션(Actions)
7+
8+
**액션(Action)**은 객체에 대한 명명된 작업입니다. 한 번만 선언하면
9+
다음과 같이 나타납니다:
10+
11+
- `/api/v1/actions/<object>/<action>` 위치의 **REST 엔드포인트**
12+
- Console 레코드 상세 화면의 **버튼**
13+
- 자동화를 위한 **플로우 단계**(`type: 'action'`)
14+
- Agents와 AI Builder를 위한 **AI 도구**(`action_<name>`)
15+
16+
네 가지 표면에 걸쳐 같은 작업을 반복하지 않습니다. 하나의 선언으로 네 가지
17+
호출 방법을 제공합니다.
18+
19+
## 액션 선언하기
20+
21+
```ts
22+
// src/actions/approve_invoice.action.ts
23+
import { Action } from '@objectstack/spec';
24+
25+
export const approveInvoice = Action.create({
26+
name: 'approve_invoice', // lowercase snake_case (machine id)
27+
label: 'Approve Invoice',
28+
objectName: 'invoice', // attaches to the invoice object
29+
icon: 'check',
30+
variant: 'primary',
31+
locations: ['record_header'], // where the button shows
32+
confirmText: 'Approve this invoice?',
33+
successMessage: 'Invoice approved',
34+
refreshAfter: true,
35+
36+
// collect input before running
37+
params: [
38+
{ name: 'note', label: 'Approval note', type: 'textarea' },
39+
],
40+
41+
// only show the button when the record is still pending
42+
visible: 'record.status == "pending"',
43+
44+
// what it does — a sandboxed script body
45+
type: 'script',
46+
body: {
47+
language: 'js',
48+
source: `
49+
await ctx.data.update('invoice', input.id, {
50+
status: 'approved',
51+
approved_by: ctx.user.id,
52+
approved_at: now(),
53+
approval_note: input.note,
54+
});
55+
`,
56+
},
57+
});
58+
```
59+
60+
`os dev`가 재컴파일한 후:
61+
62+
- `POST /api/v1/actions/invoice/approve_invoice`가 동작합니다
63+
- Console의 Invoice 레코드 페이지에 **Approve Invoice** 버튼이 표시됩니다
64+
- 플로우에 `{ type: 'action', action: 'approve_invoice', inputs: { note: '…' } }`를 포함할 수 있습니다
65+
- 스킬이 허용하는 경우 AI 어시스턴트가 `action_approve_invoice`를 호출할 수 있습니다
66+
67+
## 액션 유형
68+
69+
`type` 필드가 액션이 수행할 작업을 결정합니다:
70+
71+
| `type` | 실행되는 것 | 사용 목적 |
72+
|---|---|---|
73+
| `script` | `body` — L1 formula 표현식 또는 샌드박스화된 L2 JavaScript | 대부분의 경우 — 서버 측 로직, 감사 가능 + AI 호출 가능 |
74+
| `api` | `target` 엔드포인트로의 HTTP 호출(`method`, `bodyExtra`) | 데이터 API 또는 플랫폼 엔드포인트 재사용 |
75+
| `flow` | `target`에 명명된 플로우를 실행 | 다단계 비즈니스 프로세스 |
76+
| `url` | `target` URL로 이동 | 딥 링크, 리디렉션 방식의 액션 |
77+
| `modal` | `target`에 명명된 페이지/모달을 열기 | 사용자 정의 대화 상자 |
78+
| `form` | `target`에 명명된 FormView를 열기 | 가이드 방식의 데이터 입력 |
79+
80+
```ts
81+
// api type — reuse a data-API endpoint
82+
Action.create({
83+
name: 'archive_order',
84+
objectName: 'order',
85+
label: 'Archive',
86+
locations: ['list_item'],
87+
type: 'api',
88+
method: 'PATCH',
89+
target: '/api/v1/data/order/{id}',
90+
bodyExtra: { archived: true },
91+
});
92+
```
93+
94+
`script`이 아닌 유형은 `target`이 필요합니다. 어떤 유형이든 액션은 모든
95+
표면에서 동일한 일급 시민입니다.
96+
97+
## 액션 호출하기
98+
99+
### REST
100+
101+
```bash
102+
# the record id can go in the body, or in the path
103+
curl -X POST https://app.example.com/api/v1/actions/invoice/approve_invoice/inv_123 \
104+
-H 'Authorization: Bearer <token>' \
105+
-H 'Content-Type: application/json' \
106+
-d '{"note": "LGTM"}'
107+
```
108+
109+
파라미터는 요청 본문에 평면 형태로 전송됩니다. 레코드 id는 후행 경로 세그먼트
110+
(`.../approve_invoice/:recordId`)로 제공하거나 본문에 포함할 수 있습니다. 응답은
111+
스크립트 본문의 반환 값(또는 `api` 유형 액션의 경우 호출 결과)입니다.
112+
113+
### Console
114+
115+
기본적으로 Console은 액션의 `visible` 조건으로 필터링하여 레코드 상세 페이지에
116+
버튼으로 액션을 표시합니다. 뷰 설정에서 배치를 재정의할 수 있습니다:
117+
118+
```ts
119+
defineView({
120+
name: 'invoice_detail',
121+
object: 'invoice',
122+
actions: ['approve_invoice', 'reject_invoice', 'send_to_customer'],
123+
});
124+
```
125+
126+
### 플로우에서
127+
128+
```ts
129+
{
130+
type: 'action',
131+
action: 'approve_invoice',
132+
inputs: { note: 'Auto-approved by SLA flow' },
133+
record: '{!trigger.record.id}',
134+
}
135+
```
136+
137+
### AI Agent에서
138+
139+
`approve_invoice`가 에이전트가 보유한 스킬에 포함되어 있으면 LLM이 이를
140+
호출할 수 있습니다. 입력은 대화에서 가져오며, 권한은 사용자가 직접 호출한
141+
것처럼 적용됩니다.
142+
143+
> *"인보이스 INV-2042를 '전화로 확인됨'이라는 메모와 함께 승인해줘."*
144+
145+
## 권한
146+
147+
액션은 호출하는 사용자의 권한으로 실행됩니다. 플랫폼은 다음을 확인합니다:
148+
149+
1. **객체 권한** — 사용자의 [권한 세트](/docs/configure/permissions/permission-sets)
150+
액션에 필요한 객체 수준 접근 권한(예: 업데이트)을 부여해야 합니다.
151+
2. **필드 권한** — 액션이 쓰는 모든 필드에 대해 사용자가 쓰기 접근 권한(FLS)을
152+
가지고 있어야 합니다.
153+
3. **UI 게이팅**`visible``disabled` 조건(CEL, `record`, `os.user`,
154+
파라미터에 대해 평가됨)이 Console에서 버튼이 렌더링될지 또는 회색 처리될지를
155+
제어합니다.
156+
157+
권한 확인에 실패하면 `PERMISSION_DENIED` 오류와 함께 `403`을 반환합니다.
158+
159+
## 내장 액션
160+
161+
모든 객체는 다음을 기본으로 제공받습니다:
162+
163+
| 액션 | 수행하는 작업 |
164+
|---|---|
165+
| `create` | 레코드 삽입 |
166+
| `update` | 레코드 업데이트 |
167+
| `delete` | 레코드 삭제(또는 소프트 삭제) |
168+
| `restore` | 소프트 삭제 취소 |
169+
| `clone` | 레코드 깊은 복사 |
170+
| `share` | 사용자 / 역할과 직접 공유 |
171+
172+
이러한 액션은 다시 선언하지 마세요 — 객체의 [라이프사이클 및 기능 플래그](/docs/build/data-model)를 따릅니다.
173+
174+
## 감사(Auditing)
175+
176+
플랫폼 이벤트는 다음 필드를 포함하는 불변 기록인 `sys_audit_log`에 기록됩니다:
177+
178+
- `user_id` — 작업을 시작한 사용자
179+
- `action` — 액션 이름
180+
- `object_name``record_id` — 변경된 대상
181+
- `old_value` / `new_value` — 변경 내용
182+
- `ip_address` / `user_agent` — 요청 출처
183+
- `created_at` — 발생 시점
184+
185+
이는 *"누가 버튼을 눌렀는가?"*라는 질문에 가장 먼저 확인할 곳입니다.
186+
187+
## AI Builder로 액션 생성하기
188+
189+
> *"`support_ticket`에 우선순위를 긴급으로 설정하고 온콜 엔지니어에게
190+
> 할당하는 액션 `escalate_ticket`을 만들어줘."*
191+
192+
[AI Builder](/docs/build/ai-builder)는 액션 메타데이터를 생성하고 변경 사항을
193+
승인 대기열에 넣습니다. 승인 후에는 REST, Console, 플로우, 그리고 — 재귀적으로 —
194+
AI 자체에서 액션을 호출할 수 있습니다.
195+
196+
## 다음으로 갈 곳
197+
198+
- [플로우](/docs/build/flows) — 여러 액션을 비즈니스 로직으로 구성하기
199+
- [Agents](/docs/build/agents) — 액션을 AI 도구로 노출하기
200+
- [API 접근](/docs/configure/api-access) — 외부 시스템에서 액션 호출하기
201+
- [권한](/docs/configure/permissions) — 누가 무엇을 호출할 수 있는지 제어하기

0 commit comments

Comments
 (0)