워크스루: 업무를 설명하면, 표준을 따르는 스키마가 나온다
갱신
아무 챗봇에나 게시판 스키마를 달라고 하면 하나 나옵니다. 문제는 어떤 스키마를 얻는 게 아니라 팀이 이미 합의한 스키마를 얻는 것입니다: 같은 약어, 같은 접미사, 같은 개념에 같은 단어 — 첫 번째 테이블과 열 번째 테이블에서 똑같이.
이 워크스루는 빈 프로젝트에서 표준을 준수하는 DDL까지 에이전트를 떠나지 않고 갑니다. 예제는 스레드형 게시판입니다 — 따라갈 만큼 작고, 대부분의 도구를 넘어뜨리는 한 가지 경우를 강제합니다: 다른 글에 답하는 글.
아래 출력은 전부 실제 실행에서 복사했습니다.
시작하기 전에
- Node.js 22 이상,
sqemo-mcp2.2.0 이상 - 에이전트에 MCP 서버가 등록돼 있고
npx sqemo-mcp login을 마친 상태 — AI 연동(MCP) 참고 - 팀 표준이 있는 워크스페이스. 이 워크스루는 단어사전에 이미 Customer, Order, Number, Content, Flag 등 십여 개가 들어 있는 것을 씁니다
1. 표준 위에서 프로젝트 시작
새 ERD는 단어사전이 비어 있어 물리명이 논리명 그대로 나옵니다. 생성 시점에 프로젝트를 표준에 묶으면 단어사전·명명 규칙·도메인이 함께 옵니다:
list_workspaces
// → [{ workspaceId: "…", name: "Engineering", role: "owner",
// glossary: { version: 4, … } }]
create_erd {
name: "Threaded Discussion Board",
workspaceId: "…",
target: { server: true }
}
get_erd_overview
// → { glossaryLinked: true, dictionaryEntryCount: 28, domainCount: 15, … }
저 glossaryLinked: true가 핵심입니다. 이제부터 에이전트가 만드는 모든 이름은
지어내는 게 아니라 표준을 통해 풀립니다.
2. 업무 용어로 일을 설명
이제 동료에게 말하듯 에이전트에게 말합니다:
회원이 글을 올리고, 글은 다른 글에 대한 답글일 수 있고, 회원이 글에 댓글을 다는 게시판을 모델링해 줘.
에이전트는 논리명으로 upsert_entity와 upsert_attribute를 호출합니다. 컬럼명은
한 번도 치지 않습니다:
upsert_entity { logicalName: "Post" }
// → { physicalName: "POST" }
upsert_attribute { logicalName: "Post Content", domain: "Content" }
// → { physicalName: "POST_CNTS" }
upsert_attribute { logicalName: "Delete Flag", domain: "Flag" }
// → { physicalName: "DELETE_YN" }
Content → CNTS, Flag → YN은 에이전트의 취향이 아닙니다. 팀 단어사전의
약어이고, 팀이 모델링한 다른 모든 테이블에 적용된 것과 같은 방식으로 적용됐습니다.
도메인이 데이터 타입을 실어 나르므로 Content는 나타나는 모든 곳에서
varchar(1000)입니다 — 테이블마다 컬럼 폭을 정하는 사람은 없습니다.
3. 글에 답하는 글
자기참조 외래키는 기본키의 이름을 그대로 쓸 수 없어 역할 접두사(role prefix) 를 받습니다. 접두사는 명명 규칙이고 — 다른 모든 단어처럼 — 단어사전을 통해 풀립니다:
upsert_relationship {
sourceEntityId: "<Post>", targetEntityId: "<Post>",
cardinality: "1:N", relationshipType: "nonIdentifying",
constraintName: "FK_POST_PARENT"
}
`PARENT_POST_NO` varchar(20) COMMENT 'Parent Post Number'
접두사 기본값은 Parent라 위 FK는 설정 없이 PARENT_POST_NO로 나옵니다. 표준에서
한 번 바꾸면 — 앱에서 명명(Naming) 탭 → 편집(Edit) → 자기참조 접두사(Self-reference
prefix) — 연결된 모든 프로젝트의 모든 자기참조 FK가 따릅니다.
바꾸기 전에 알아 둘 두 가지:
- 접두사를 줄이고 싶으면 먼저 단어로 등록하세요(
Parent→PRNT이면PARENT_POST_NO대신PRNT_POST_NO). - 보통 컬럼명과 달리 기존 자기참조 FK는 다음 편집 때 이름이 바뀝니다. 이름이 저장된 것이 아니라 파생되기 때문입니다. 나머지는 이미 가진 이름을 유지합니다.
이 기본값이 바뀌기 전에 만든 프로젝트는 발밑에서 움직이지 않습니다. 불러올 때 미설정
접두사가 명명 규칙에 기록됩니다: 이미 자기참조 관계가 있으면 상위(그래서 그 컬럼명이
그대로 유지됨), 없으면 Parent.
4. 표준에 아직 없는 단어
실제 모델링은 아무도 등록하지 않은 단어에 부딪힙니다. Sqemo는 조용히 약어를 지어내지 않고 표시합니다:
lint_erd
// → { code: "unknown-word", severity: "warning",
// objectName: "Delete Flag",
// message: "'Delete Flag' contains words not registered in the word list." }
Delete가 없어서 DELETE_YN이 줄여지지 않고 나왔습니다. 고치는 방법은 이름을
하드코딩하는 게 아니라 단어를 제안하는 것입니다:
propose_dictionary_word {
logicalWord: "Delete", physicalWord: "DELETE", abbreviation: "DEL",
note: "Found while modelling the discussion board"
}
// → { proposalId: "…", status: "pending", baseVersion: 4 }
표준 소유자가 앱에서 승인하면 약어가 연결된 모든 프로젝트로 전파됩니다. 챗봇이 할 수 없는 부분이 이것입니다: 에이전트는 제안자이지 권한자가 아닙니다.
5. 준수 검사
check_naming은 이미 있는 물리명을 표준이 생성했을 이름과 비교합니다:
check_naming {
logicalName: "Customer Phone Number",
physicalName: "CUSTOMER_PHONE_NUMBER"
}
// → { generatedPhysicalName: "CUST_TEL_NO",
// compliant: false, providedMatches: false }
CI에 넣을 검사가 이것입니다. 에이전트 없이 프로젝트 파일에서 동작합니다:
npx sqemo-mcp lint schema.erd.json # 위반이 있으면 종료 코드 1
6. 내보내기
export_sql { dialect: "mysql" }
CREATE TABLE `POST` (
`POST_NO` varchar(20) NOT NULL COMMENT 'Post Number',
`POST_CNTS` varchar(1000) NOT NULL COMMENT 'Post Content',
`DELETE_YN` char(1) NOT NULL DEFAULT 'N' COMMENT 'Delete Flag',
`PARENT_POST_NO` varchar(20) COMMENT 'Parent Post Number',
PRIMARY KEY (`POST_NO`)
) COMMENT='An article on a board; may reply to another post';
ALTER TABLE `POST` ADD CONSTRAINT `FK_POST_PARENT`
FOREIGN KEY (`PARENT_POST_NO`) REFERENCES `POST` (`POST_NO`);
논리명이 컬럼 코멘트로 살아남아, 업무 의미가 다이어그램에서 죽지 않고 데이터베이스까지 갑니다.
함정 하나
defaultValue는 원시 SQL이며 DEFAULT 뒤에 그대로 나갑니다. 문자열 리터럴은 직접
따옴표로 감싸세요:
upsert_attribute { logicalName: "Delete Flag", defaultValue: "'N'" } // ✅
upsert_attribute { logicalName: "Delete Flag", defaultValue: "N" } // ❌ DEFAULT N
따옴표 없는 값은 표현식으로 취급됩니다. 0이나 CURRENT_TIMESTAMP에는 원하는
동작이고 — N에는 원하지 않는 동작입니다.
실제로 일어난 일
에이전트는 타이핑을 했습니다. 중요한 것은 아무것도 결정하지 않았습니다:
| 결정 | 결정한 쪽 |
|---|---|
| 어떤 테이블과 관계가 존재하는가 | 당신, 업무 용어로 |
| 약어·구분자·대소문자 | 팀 표준 |
| 데이터 타입 | 도메인 |
| 표준에 들어가는 새 단어 | 표준 소유자, 승인으로 |
스키마를 생성하는 것과 팀이 유지할 수 있는 스키마를 키우는 것의 차이가 그것입니다. 다음은: 단어사전과 규칙의 동작은 명명 표준, 제안 목록과 역할은 공유와 협업 — 제안 목록은 2분 영상으로도 있으니, 단어가 승인되는 과정을 읽기보다 보고 싶다면 그쪽으로.