뷰
List, Form, Kanban, Calendar, Gantt 등 — Console의 모든 오브젝트 표면을 선언하는 방법.
뷰
뷰는 사용자가 Console에서 레코드를 보고 편집하는 방식입니다. 뷰는 선언적 메타데이터이며 — 오브젝트와 동일한 라이프사이클을 가집니다. 한 번 선언하고, 패키지와 함께 배포하며, 어디서나 렌더링합니다.
두 가지 종류:
- List 뷰 — 여러 레코드를 시각화합니다 (grid, kanban, calendar 등)
- Form 뷰 — 단일 레코드를 보거나 편집합니다 (simple, tabbed, wizard 등)
스키마 소스:
packages/spec/src/ui/view.zod.ts.
가능한 가장 짧은 선언
모든 오브젝트는 뷰를 선언하지 않아도 기본 grid list와 simple form을
자동으로 가집니다. 재정의하거나 확장하려면 view를 추가하세요:
import { defineObject, F, P } from '@objectstack/spec'
export default defineObject({
name: 'support_ticket',
fields: [ /* ... */ ],
view: {
list: { type: 'grid', columns: ['subject', 'status', 'priority', 'assignee'] },
form: { sections: [ { label: 'Details', fields: ['subject','description','priority','status','assignee'] } ] }
}
})여러 뷰를 가진 오브젝트(예: 동일한 데이터에 대해 Kanban 과 calendar)의 경우 명명된 변형을 사용하세요:
view: {
listViews: {
by_status: { type: 'kanban', kanban: { groupByField: 'status' }, columns: ['subject','priority'] },
schedule: { type: 'calendar', calendar: { startDateField: 'due_at', titleField: 'subject' } },
by_owner: { type: 'grid', columns: ['subject','status','priority'], filterableFields: ['assignee'] }
},
formViews: {
quick: { type: 'modal', sections: [ /* ... */ ] },
full: { type: 'tabbed', sections: [ /* ... */ ] }
}
}List 뷰 타입
type | 렌더링 | 필수 설정 |
|---|---|---|
grid | 데이터 테이블 (기본값) | columns |
kanban | 컬럼이 있는 보드 | kanban: { groupByField } |
gallery | 카드 덱 | gallery: { coverField, titleField } |
calendar | 월 / 주 / 일 | calendar: { startDateField, titleField } |
timeline | 시간순 피드 | timeline: { startDateField, titleField } |
gantt | 프로젝트 타임라인 + 의존성 | gantt: { startDateField, endDateField, titleField } |
map | 지리공간 핀 | map: { locationField } |
chart | 임베드 차트 | chart: { chartType, xAxisField, yAxisFields } |
공통 list 옵션
{
type: 'grid',
columns: ['subject','status','priority','assignee','created_at'],
filter: [ { field: 'archived', operator: 'equals', value: false } ],
sort: [ { field: 'created_at', order: 'desc' } ],
pagination: { pageSize: 25 },
searchableFields: ['subject','description'],
filterableFields: ['status','priority','assignee'],
navigation: { mode: 'drawer' }, // 'page' | 'drawer' | 'modal' | 'split' | 'popover' | 'new_window' | 'none'
selection: { type: 'multiple' }, // 'none' | 'single' | 'multiple'
rowActions: ['close_ticket','assign_to_me'],
bulkActions: ['bulk_close','bulk_export'],
conditionalFormatting: [
{ condition: P`record.priority == 'urgent'`, style: { background: '#fef2f2', fontWeight: 600 } }
],
exportOptions: ['csv','xlsx'],
emptyState: { title: 'No tickets yet', message: 'Create one to get started', icon: 'inbox' }
}filter와 sort는 ObjectQL로 컴파일됩니다.
rowActions와 bulkActions는 actions를 이름으로 참조합니다.
Kanban
{
type: 'kanban',
kanban: {
groupByField: 'status', // discrete field — usually a select
summarizeField: 'amount', // optional total per column
columns: ['subject', 'priority', 'assignee'] // fields shown on each card
}
}보드의 컬럼은 groupByField의 값에서 가져오며, 그 순서와 색상은 해당
필드의 select 옵션 정의에서 가져옵니다.
컬럼 간 드래그 앤 드롭은 그룹화된 필드를 설정하는 업데이트를 발생시키며 — 수동 편집과 동일한 권한 규칙이 적용됩니다.
Calendar
{
type: 'calendar',
calendar: {
startDateField: 'start_at',
endDateField: 'end_at', // optional — single-point if omitted
titleField: 'subject',
colorField: 'priority' // optional — colours events by value
}
}Gantt
{
type: 'gantt',
gantt: {
startDateField: 'start_at',
endDateField: 'due_at',
titleField: 'name',
progressField: 'percent_complete', // optional, drives the progress bar
dependenciesField: 'depends_on' // optional — multiselect lookup to same object
}
}Chart (인라인)
{
type: 'chart',
chart: {
chartType: 'bar', // 'bar' | 'line' | 'pie' | 'area' | 'scatter'
xAxisField: 'created_at',
yAxisFields: ['amount'],
aggregation: 'sum',
groupByField: 'status'
}
}Chart 뷰는 단일 오브젝트의 인라인 대시보드를 위한 것입니다 — 더 풍부한 오브젝트 간 분석을 위해서는 전용 reports 표면을 사용하세요.
Form 뷰 타입
type | 레이아웃 |
|---|---|
simple | 단일 컬럼 또는 섹션 (기본값) |
tabbed | 탭 섹션 |
wizard | 단계별 플로우 |
split | 마스터-디테일 두 개 창 |
drawer | 측면 패널 폼 |
modal | 다이얼로그 폼 |
{
type: 'tabbed',
sections: [
{ label: 'Overview', fields: ['subject','status','priority','assignee'] },
{ label: 'Customer', fields: ['customer','contact','email','phone'] },
{ label: 'Resolution', fields: ['resolution_notes','resolved_at'] }
],
submitBehavior: { kind: 'next-record' } // 'thank-you' | 'redirect' | 'continue' | 'next-record'
}공개 폼
폼은 익명 접근이 가능하도록 만들 수 있습니다:
{
type: 'simple',
sections: [ { fields: ['name','email','message'] } ],
sharing: {
enabled: true,
publicLink: 'contact-us', // slug under /forms/
allowAnonymous: true
},
submitBehavior: { kind: 'thank-you' }
}이는 GET /api/v1/forms/contact-us와
POST /api/v1/forms/contact-us/submit를 자동으로 노출합니다 — 인증이
필요하지 않은 공개 폼 라우트입니다. REST API → Public forms를 참고하세요.
가시성, ARIA, 테마
visibleOn: P\...`` — form 섹션 및 필드에서, 사용자 / 레코드 / 환경에 따라 숨깁니다 (CEL 술어)aria: { label, description, ... }— 스크린 리더를 위한 ARIA 속성 (list 및 form 뷰)appearance: { showDescription, allowedVisualizations: [...] }— list 뷰에서, 최종 사용자가 전환할 수 있는 list 타입을 제한합니다
채팅으로 빌드하기
일반적으로 뷰 메타데이터를 직접 작성하지 않습니다. AI Builder에게 알려주세요:
"subject와 priority를 보여주는 카드와 함께 status별로 그룹화된 support_ticket 오브젝트의 kanban 뷰를 추가해줘. status에 따라 컬럼을 빨강 / 호박색 / 초록으로 색칠해줘."
AI Builder가 메타데이터 도구를 호출하고, diff를 큐에 넣으며, 승인하면 해당 뷰가 Console에 나타납니다. AI Builder를 참고하세요.
참고
- Data model — 뷰가 읽는 오브젝트
- Actions —
rowActions/bulkActions가 참조하는 것 - ObjectQL —
filter/sort가 컴파일되는 대상 - CEL —
conditionalFormatting,visibleOn @objectstack/spec/ui/view.zod.ts— 스키마