업무 지표 (metrics:) 와 업무 용어 (@terms)
"매출이 무엇인가", "주문 수에 취소도 세나" 는 핵심 도메인 정보인데, 코드·SQL·BI 도구마다 따로 정의되면 서로 다른
숫자가 나옵니다. DSL 에 한 번 적으면 Apache Ossie 내보내기가 Ossie 의 metrics
로 BI·AI 도구에 전합니다. 애플리케이션 코드나 조회 API 는 생성하지 않습니다.
metrics:
revenue: sum(PurchaseOrder.total) where status != CANCELLED @terms(sales, 매출액) -- 매출 (취소 제외, VAT 포함·할인 후 금액)
orderCount: count(PurchaseOrder) where status != CANCELLED @terms(orders, 주문 건수) -- 주문 수 (취소 제외)
averageOrder: revenue / orderCount @terms(AOV, 객단가) -- 주문 1건 평균 금액
shippedOrders: count(PurchaseOrder) where status = SHIPPED -- 배송된 주문 수
cancelledOrders: count(PurchaseOrder) where status = CANCELLED -- 취소된 주문 수
customerCount: count(Customer) where role = USER @terms(members, 회원 수) -- 고객 수 (관리자 제외)
metrics: 는 도메인의 어느 모델 파일에나 두는 최상위 섹션입니다. 지표 하나가 한 줄:
이름: 식 [@terms(...)] [-- 설명].
문법
| 쓰는 법 | 뜻 | 내보내는 SQL (OSSIE_SQL_2026) |
|---|---|---|
sum(엔티티.필드) / avg / min / max | 한 엔티티의 필드 집계 | SUM(PurchaseOrder.total) |
count(엔티티) | 행 수 | COUNT(PurchaseOrder.order_id) - 키 컬럼을 세어 BI 도구가 어느 dataset 인지 알게 |
count(엔티티.필드) | 값이 있는 행 수 | COUNT(PurchaseOrder.total) |
… where 필드 != 값 and 필드 >= 값 | 조건: =, !=, <, <=, >, >=, and | SUM(CASE WHEN … THEN … END) |
| 값 | 숫자, '글자'(안의 ' 는 ''), true/false, enum 상수 이름 | 저장된 값: @db 코드('CAN'), @jpa:Enumerated(STRING) 면 이름, 둘 다 없으면 순번 |
지표A / 지표B (+ - * /) | 앞에서 선언한 지표끼리 | (…) / NULLIF((…), 0) - 0 으로 나누지 않고, 개수 / 개수는 소수 |
@terms(sales, 매출액) | 업무 용어·동의어 | ai_context.synonyms |
-- 매출 | 설명 | description |
데이터 타입: count 는 Integer, sum·min·max 는 그 필드의 타입, avg 와 나누기는 Decimal(Float 필드면
Float), + - * 는 둘 다 Integer 면 Integer, 아니면 Decimal. sum·avg 는 숫자 필드에만 씁니다.
revenue 를 내보낸 결과:
metrics:
- name: revenue
expression:
dialects:
- dialect: OSSIE_SQL_2026
expression: "SUM(CASE WHEN PurchaseOrder.status <> 'CAN' THEN PurchaseOrder.total END)"
description: "매출 (취소 제외, VAT 포함·할인 후 금액)"
datatype: Decimal
ai_context:
synonyms: ["sales", "매출액"]
한계
- 한 엔티티 안에서만 셉니다. 다른 엔티티의 조건이 필요한 지표("취소되지 않은 주문의 팔린 수량" - 주문 줄과 그 주문의 상태)는 아직 쓸 수 없습니다. 억지로 쓰면 취소분까지 세게 되므로 넣지 마세요.
- 기간은 지표에 넣지 않습니다. 월별 매출은 BI 도구가 날짜 필드(
orderDate, Ossie 의 time dimension)로 나눕니다. - 못 읽는 줄(없는 엔티티·필드, enum 에 없는 상수, 뒤에 선언된 지표, enum 이 아닌 필드에 따옴 표 없는 값)은
[ossie] [도메인] metric 이름: … ; it is left out.경고 후 빠집니다. 추측해서 내보내지 않습니다. - 줄에
#나:가 들어가면 YAML 이 줄을 자르거나 파일을 못 읽으므로 줄 전체를 따옴표로 감쌉니다:ratio: "shippedOrders / orderCount -- 배송 비율: 배송 / 전체".
@terms - 사람들이 부르는 말
@terms 는 엔티티 meta: 줄, 필드, 지표에 붙여 업무에서 부르는 이름과 동의어를 적습니다. 생성 코드에는 영향이 없고
Ossie 의 ai_context.synonyms 로 나갑니다 - "지난달 구매 금액" 이라고 물으면 AI 가 PurchaseOrder 와 revenue 를
찾도록.
PurchaseOrder:
meta: entity @root @expose(20) @terms(order, purchase, 구매) -- 주문
Item:
meta: entity @root @editable @terms(pet, 반려동물) -- 판매 품목
fields:
unitCost: money(10.2)! @terms(price, 가격)
지표를 답하는 API
지표는 엔드포인트를 만들지 않습니다. 관리자 매출 요약은 개발자 소유 서비스의 메서드로
ACCESS.require(currentUser, "report") 뒤에 둡니다 - 직접 쓰는 로직
의 상점 레시피 보고서를 보세요.
확인: Pet Store 의 MetricsTest 가 주문을 접수·배송·취소한 뒤, 내보낸 지표 SQL 을 실제 DB 에서 실행한 값과 엔티티로
직접 계산한 값이 같은지 봅니다.