나만의 업무 시스템 만들기
SetFN 워크스페이스에서 그룹웨어나 ERP 같은 사내 시스템을 직접 만들 수 있습니다. 데이터베이스 구조와 화면은 AI에게 만들게 하고, 결과 파일을 워크스페이스에 올려 배포합니다. 이 문서에서는 제조 현장의 재고 관리 프로그램을 예로 듭니다.
완성된 파일을 바로 쓰려면 전체 샘플 ZIP 다운로드에서 스키마, index.html, mock-db-upload.html, README를 받습니다.
1. 스키마 파일(.sfn) 만들기
SetFN에서는 .sfn 스키마 파일로 DB를 만듭니다. Claude, ChatGPT, Gemini 같은 AI에게 .sfn 예시와 함께 "부품과 제품 재고 관리를 하고 싶어"처럼 요구사항을 전달하면 AI가 스키마 파일을 만들어 줍니다.
다음 프롬프트를 복사하고, 아래쪽 요구사항을 필요에 맞게 바꿔 AI에게 전달합니다.
너는 SetFN이라는 노코드 백엔드 플랫폼의 스키마 파일(.sfn)을 설계하는 엔지니어야.
.sfn은 아래 구조를 가진 JSON 파일이야.
{
"content-type": "application/setfn-schema",
"dbType": "sqlite3",
"apiBuild": {
"dbName": "영문_소문자_밑줄_db이름",
"dbEngine": "sqlite",
"includeClient": false,
"features": {
"realtime": { "enabled": false },
"upload": { "enabled": false },
"ai-chat": { "enabled": false }
}
},
"data": [
{
"table": { "name": "테이블명", "cmt": "이 테이블 설명" },
"columns": [
{ "name": "id", "type": "serial4", "primary": true, "default": "auto_increment" },
{ "name": "컬럼명", "type": "text", "notnull": true, "cmt": "컬럼 설명" },
{ "name": "숫자컬럼", "type": "int4", "notnull": true, "default": "0" },
{ "name": "_created_at", "type": "timestamp", "default": "now()" }
],
"permissions": {
"security": { "login": true },
"ops": {
"list": { "login": true },
"view": { "login": true },
"create": { "login": true },
"update": { "login": true },
"delete": { "login": true, "roles": ["admin"] }
}
}
}
]
}
컬럼 type은 serial4(자동증가 PK) / text / int4(정수) / timestamp만 사용해.
컬럼에는 notnull, default, unique, index, cmt를 필요에 맞게 붙여.
이제 이 형식으로, 제조업체가 쓸 "재고관리 시스템" DB를 설계해줘. 요구사항은 다음과 같아.
- 부품을 등록하고, 부품별 현재 재고 수량을 관리한다.
- 제품을 등록하고, 제품별 현재 재고 수량을 관리한다.
- 제품 하나는 여러 부품으로 조립되어 만들어진다. 어떤 제품에 어떤 부품이 몇 개씩 필요한지(BOM, 자재명세서)를 관리한다.
- 부품/제품의 입고·출고 이력을 남긴다. 특히 "부품을 조립해서 제품을 생산"하는 이벤트가 발생하면, 그 순간 사용된 부품들과 생산된 제품 수량이 하나의 사건으로 함께 추적되어야 한다(나중에 "이 제품을 만드는데 부품이 얼마나 들어갔는지" 조회할 수 있어야 함).
DB 이름(dbName)은 "inventory_management"로 해줘.
테이블 4개 이내로, 실무에서 바로 쓸 수 있을 만큼 실용적으로 설계해줘.
다른 설명 없이 완성된 .sfn JSON 코드만 출력해줘.
다음은 AI 응답 예시입니다. 결과는 AI와 실행 시점에 따라 조금씩 다르며, 구조가 비슷하면 됩니다. 응답이 설명 없이 {로 시작해 }로 끝나야 에디터에 그대로 붙여넣을 수 있습니다.
{
"content-type": "application/setfn-schema",
"dbType": "sqlite3",
"apiBuild": {
"dbName": "inventory_management",
"dbEngine": "sqlite",
"includeClient": false,
"features": {
"realtime": { "enabled": false },
"upload": { "enabled": false },
"ai-chat": { "enabled": false }
}
},
"data": [
{
"table": { "name": "parts", "cmt": "부품 마스터. 조회/등록/수정은 회원 누구나, 삭제는 관리자만" },
"columns": [
{ "name": "id", "type": "serial4", "primary": true, "default": "auto_increment" },
{ "name": "part_code", "type": "text", "notnull": true, "unique": true, "cmt": "부품 코드" },
{ "name": "name", "type": "text", "notnull": true, "cmt": "부품명" },
{ "name": "spec", "type": "text", "cmt": "규격 (예: M2, 220V/50Hz). 같은 이름이라도 규격이 다르면 별도 part_code로 등록" },
{ "name": "category", "type": "text", "cmt": "부품 분류 (전자부품/기구부품/포장재 등)" },
{ "name": "unit", "type": "text", "notnull": true, "default": "EA", "cmt": "단위" },
{ "name": "unit_cost", "type": "int4", "notnull": true, "default": "0", "cmt": "단가" },
{ "name": "current_stock", "type": "int4", "notnull": true, "default": "0", "cmt": "현재고" },
{ "name": "safety_stock", "type": "int4", "notnull": true, "default": "0", "cmt": "안전재고(재주문점)" },
{ "name": "supplier", "type": "text", "cmt": "공급업체" },
{ "name": "_user_id", "type": "int4", "notnull": true, "index": true },
{ "name": "_nick", "type": "text", "cmt": "최종 등록/수정한 회원 표시 이름" },
{ "name": "_created_at", "type": "timestamp", "default": "now()" }
],
"permissions": {
"security": { "login": true, "ownerColumn": "_user_id" },
"ops": {
"list": { "login": true },
"view": { "login": true },
"create": { "login": true },
"update": { "login": true },
"delete": { "login": true, "roles": ["admin"] }
}
}
},
{
"table": { "name": "products", "cmt": "제품 마스터. 조회/등록/수정은 회원 누구나, 삭제는 관리자만" },
"columns": [
{ "name": "id", "type": "serial4", "primary": true, "default": "auto_increment" },
{ "name": "product_code", "type": "text", "notnull": true, "unique": true, "cmt": "제품 코드" },
{ "name": "name", "type": "text", "notnull": true, "cmt": "제품명" },
{ "name": "category", "type": "text", "cmt": "제품 분류" },
{ "name": "unit", "type": "text", "notnull": true, "default": "EA", "cmt": "단위" },
{ "name": "price", "type": "int4", "notnull": true, "default": "0", "cmt": "판매가" },
{ "name": "current_stock", "type": "int4", "notnull": true, "default": "0", "cmt": "현재고" },
{ "name": "_user_id", "type": "int4", "notnull": true, "index": true },
{ "name": "_nick", "type": "text", "cmt": "최종 등록/수정한 회원 표시 이름" },
{ "name": "_created_at", "type": "timestamp", "default": "now()" }
],
"permissions": {
"security": { "login": true, "ownerColumn": "_user_id" },
"ops": {
"list": { "login": true },
"view": { "login": true },
"create": { "login": true },
"update": { "login": true },
"delete": { "login": true, "roles": ["admin"] }
}
}
},
{
"table": { "name": "bom", "cmt": "제품별 부품 구성표(단일 단계). bom_key(product_id:part_id)에 unique 제약을 걸어 같은 제품에 같은 부품이 중복 등록되지 않게 함" },
"columns": [
{ "name": "id", "type": "serial4", "primary": true, "default": "auto_increment" },
{ "name": "product_id", "type": "int4", "notnull": true, "index": true },
{ "name": "part_id", "type": "int4", "notnull": true, "index": true },
{ "name": "qty_per_unit", "type": "int4", "notnull": true, "default": "1", "cmt": "제품 1개를 만드는 데 필요한 부품 수량" },
{ "name": "bom_key", "type": "text", "notnull": true, "unique": true, "cmt": "product_id:part_id 조합. 중복 등록 방지용" },
{ "name": "_user_id", "type": "int4", "notnull": true, "index": true },
{ "name": "_nick", "type": "text", "cmt": "등록한 회원 표시 이름" },
{ "name": "_created_at", "type": "timestamp", "default": "now()" }
],
"permissions": {
"security": { "login": true, "ownerColumn": "_user_id" },
"ops": {
"list": { "login": true },
"view": { "login": true },
"create": { "login": true },
"update": { "login": true },
"delete": { "login": true, "roles": ["admin"] }
}
}
},
{
"table": { "name": "stock_transactions", "cmt": "입출고/조립 통합 이력. item_type=part|product, tx_type=입고|출고|조립사용|조립생산. 하나의 조립생산 이벤트는 같은 batch_id를 공유하는 조립사용(부품 소모) 여러 건 + 조립생산(제품 증가) 1건으로 구성되어, 제품에 어떤 부품이 얼마나 쓰였는지 추적할 수 있음" },
"columns": [
{ "name": "id", "type": "serial4", "primary": true, "default": "auto_increment" },
{ "name": "item_type", "type": "text", "notnull": true, "cmt": "part | product" },
{ "name": "item_id", "type": "int4", "notnull": true, "index": true, "cmt": "parts.id 또는 products.id" },
{ "name": "item_name", "type": "text", "notnull": true, "cmt": "등록 시점 품목명 스냅샷" },
{ "name": "tx_type", "type": "text", "notnull": true, "cmt": "입고 | 출고 | 조립사용 | 조립생산" },
{ "name": "reason", "type": "text", "cmt": "입출고 사유. 조립사용/조립생산은 tx_type 자체가 사유이므로 비워둠" },
{ "name": "qty", "type": "int4", "notnull": true, "cmt": "항상 양수. 방향은 tx_type으로 판단" },
{ "name": "batch_id", "type": "text", "index": true, "cmt": "조립생산 이벤트 묶음 id. 단순 입출고는 비어 있음" },
{ "name": "note", "type": "text", "cmt": "메모" },
{ "name": "_user_id", "type": "int4", "notnull": true, "index": true },
{ "name": "_nick", "type": "text", "cmt": "등록한 회원 표시 이름" },
{ "name": "_created_at", "type": "timestamp", "default": "now()" }
],
"permissions": {
"security": { "login": true, "ownerColumn": "_user_id" },
"ops": {
"list": { "login": true },
"view": { "login": true },
"create": { "login": true },
"update": { "login": true, "roles": ["admin"] },
"delete": { "login": true, "roles": ["admin"] }
}
}
}
]
}
워크스페이스에서 만들기 > 템플릿 파일 > 새 스키마 (DB)를 선택해 빈 스키마 파일을 만듭니다.

파일 이름을 입력하고 저장하면 빈 스키마 파일이 만들어집니다.

오른쪽 위의 에디터 탭을 선택하고 AI 응답을 붙여넣습니다.

파일을 저장하고 API빌드 탭을 선택하면 테이블별로 자동 생성된 API 목록이 표시됩니다.

배포하기를 선택해 설정을 펼치고 데이터베이스 식별자를 확인한 뒤 배포하기를 다시 선택합니다. 몇 초 뒤 배포 완료! 메시지가 표시되면 상단의 저장 버튼으로 파일을 저장합니다.
이제 부품, 제품, 구성표, 입출고 이력 4개 테이블과 이를 다루는 REST API를 사용할 수 있습니다.
2. 화면 파일(.html) 만들기
화면도 AI에게 요청합니다. 만들 기능을 정리하고, 1번에서 만든 .sfn 내용을 함께 전달합니다. 이 예제의 화면 기능은 다음과 같습니다.
- 부품·제품을 등록하는 입력 폼
- 입고·출고를 등록하는 폼
- "이 제품을 몇 개 생산했다"고 등록하면 필요한 부품 수량을 자동으로 계산해서 재고를 반영
- 현재 재고 현황을 표로 보여주고, 표에서 바로 값을 고쳐서 저장
다음 프롬프트를 AI 채팅에 붙여넣습니다. 맨 위에는 1번 결과를 넣습니다.
[여기에 1번 결과를 붙여넣기]
위 스키마가 이미 배포되어 있어. 이 스키마를 사용하는 웹 화면(index.html) 하나를 만들어줘.
화면에서 데이터를 불러오고 저장할 때는 아래 규칙으로 서버에 요청해.
1. 로그인한 사용자의 API 토큰을 얻으려면:
POST /api/auth/bootstrap (credentials: "include")
응답: { data: { access_token, user: { id, nick } } }
2. 이후 모든 요청은 이 헤더를 붙인다: Authorization: Bearer <access_token>
3. 테이블 CRUD:
조회 GET /api/web/{dbName}/{table}/list?컬럼=값 → 응답 { rows: [...] } (rows는 결과가 없으면 null일 수 있으니 항상 rows || [] 로 처리)
생성 POST /api/web/{dbName}/{table}/create → body: JSON, 응답 { lastInsertId }
수정 PUT /api/web/{dbName}/{table}/update/{id} → body: JSON (바뀐 컬럼만 보내도 됨)
삭제 DELETE /api/web/{dbName}/{table}/delete/{id}
화면에 필요한 기능은 다음과 같아.
- 부품과 제품을 신규 등록할 수 있는 입력 폼
- 부품/제품의 입고·출고를 등록할 수 있는 폼 (등록하면 현재 재고 수량도 같이 갱신)
- "이 제품을 몇 개 생산했다"를 등록하면, 등록된 구성표에 따라 필요한 부품 수량을 자동으로 계산해서 부품 재고를 차감하고 제품 재고를 늘리는 기능. 부품 재고가 모자라면 등록을 막고 알려줘.
- 현재 부품/제품 재고 현황을 표로 보여주는 화면. 표의 칸을 클릭하면 그 자리에서 바로 값을 수정하고 저장할 수 있게.
- 입고/출고/조립 이력을 시간순으로 보여주는 목록.
HTML/CSS/JS 한 파일에 전부 담아줘. 깔끔한 흰 배경에 카드형 레이아웃으로 만들어줘.
다른 설명 없이 완성된 index.html 코드만 출력해줘.
다음은 이렇게 만든 index.html 예시입니다. 결과는 AI에 따라 조금씩 다릅니다.
이 파일을 워크스페이스에 올리면 팀원이 이 화면을 사용할 수 있습니다.
3. 테스트 데이터 채우기
동작을 확인하려면 데이터가 필요합니다. 버튼 하나로 예시 데이터를 채우는 화면도 AI에게 요청해 만들 수 있습니다.
[여기에 1번 결과를 붙여넣기]
위 스키마가 이미 배포되어 있고, 이 스키마를 쓰는 index.html도 이미 만들어져 있어.
버튼 하나를 누르면 테스트용 데이터를 자동으로 채워 넣는 화면(mock-db-upload.html)을 만들어줘.
데이터는 2번 화면과 같은 방식(POST /api/auth/bootstrap으로 토큰을 받고, POST /api/web/{dbName}/{table}/create로 생성)으로 실제 서버에 넣어줘.
- 부품 10~15개, 제품 3~5개, 각 제품의 부품 구성, 입출고 이력 몇 건을 실제로 만들어 넣어줘.
- 부품/제품 이름과 수량은 제조업 현장에서 실제로 쓸 법한 값으로 채워줘.
- 이미 같은 코드의 데이터가 있으면 그 항목만 건너뛰고 계속 진행해줘.
- 진행 상황을 화면에 한 줄씩 로그로 보여주고, 끝나면 "완료"를 표시해줘.
다른 설명 없이 완성된 mock-db-upload.html 코드만 출력해줘.
다음은 mock-db-upload.html 예시입니다. 이 화면은 배포하지 않고 데모를 준비할 때만 엽니다.
데이터를 넣은 뒤의 화면은 다음과 같습니다.




4. 반복해서 수정하기
화면을 쓰면서 고칠 부분이 생기면 AI에게 이어서 요청합니다. 수정 범위에 따라 다음 작업이 다릅니다.
- DB 구조(테이블·컬럼)를 바꾸는 수정(예: 컬럼이나 테이블 추가): 수정된
.sfn을에디터에 붙여넣고API빌드에서 다시 배포합니다. - 화면만 고치는 수정(예: 디자인, 문구, 버튼 위치):
index.html만 새 파일로 덮어씁니다. API는 다시 배포하지 않아도 됩니다. - 데이터가 있는 테이블의 구조를 바꿀 때는 배포 설정의
기존 데이터 덮어쓰기여부를 확인합니다. 덮어쓰기를 켜면 기존 데이터가 영구 삭제됩니다.