[{"data":1,"prerenderedAt":1555},["ShallowReactive",2],{"nav-docs":3,"page-/ko/docs/webspace/examples/realtime-gomoku":885,"surround-/ko/docs/webspace/examples/realtime-gomoku":1549,"raw-/ko/docs/webspace/examples/realtime-gomoku":1552},[4,56,226,546,638,778,811,868],{"title":5,"path":6,"stem":7,"children":8,"page":55},"스페이스빌더 시작하기","/getting-started","00.getting-started",[9,13,17,23,29,33,38,42,46,50],{"title":10,"path":11,"stem":12,"children":-1},"스페이스빌더 소개","/getting-started/overview","00.getting-started/00.overview",{"title":14,"path":15,"stem":16,"children":-1},"SetFN 계정 생성","/getting-started/create-setfn-account","00.getting-started/05.create-setfn-account",{"title":18,"path":19,"stem":20,"tags":21,"children":-1},"Linux에 설치하기","/getting-started/install-linux","00.getting-started/10.install-linux",[22],"recommended",{"title":24,"path":25,"stem":26,"tags":27,"children":-1},"Docker로 설치하기","/getting-started/install-docker","00.getting-started/12.install-docker",[28],"preparing",{"title":30,"path":31,"stem":32,"children":-1},"Windows에 설치하기","/getting-started/install-windows","00.getting-started/14.install-windows",{"title":34,"path":35,"stem":36,"tags":37,"children":-1},"macOS에 설치하기","/getting-started/install-macos","00.getting-started/16.install-macos",[28],{"title":39,"path":40,"stem":41,"children":-1},"초기 설정","/getting-started/initial-setup","00.getting-started/20.initial-setup",{"title":43,"path":44,"stem":45,"children":-1},"라이선스 활성화","/getting-started/license-activation","00.getting-started/30.license-activation",{"title":47,"path":48,"stem":49,"children":-1},"접속 주소 확인 (로컬/내부망)","/getting-started/access-url","00.getting-started/35.access-url",{"title":51,"path":52,"stem":53,"tags":54,"children":-1},"외부 접속 방식 선택","/getting-started/access-domain","00.getting-started/40.access-domain",[22],false,{"title":57,"path":58,"stem":59,"children":60,"page":55},"스페이스 관리하기","/admin","10.admin",[61,74,107,136,171,184,209],{"title":62,"path":63,"stem":64,"children":65,"page":55},"관리자 홈","/admin/home","10.admin/00.home",[66,70],{"title":67,"path":68,"stem":69,"children":-1},"관리자 페이지 접속","/admin/home/admin-page-access","10.admin/00.home/00.admin-page-access",{"title":71,"path":72,"stem":73,"children":-1},"라이선스 관리","/admin/home/license","10.admin/00.home/20.license",{"title":75,"path":76,"stem":77,"children":78,"page":55},"사용자 관리","/admin/user-management","10.admin/10.user-management",[79,83,87,91,95,99,103],{"title":80,"path":81,"stem":82,"children":-1},"가입 정책 및 기본 권한 설정하기","/admin/user-management/signup-policy","10.admin/10.user-management/02.signup-policy",{"title":84,"path":85,"stem":86,"children":-1},"사용자 계정 만들기","/admin/user-management/invite-new-member","10.admin/10.user-management/10.invite-new-member",{"title":88,"path":89,"stem":90,"children":-1},"사용자 계정 수정하기","/admin/user-management/edit-member","10.admin/10.user-management/11.edit-member",{"title":92,"path":93,"stem":94,"children":-1},"관리자 추가하기","/admin/user-management/add-new-admin","10.admin/10.user-management/12.add-new-admin",{"title":96,"path":97,"stem":98,"children":-1},"팀 관리","/admin/user-management/team","10.admin/10.user-management/22.team",{"title":100,"path":101,"stem":102,"children":-1},"레벨 관리","/admin/user-management/level","10.admin/10.user-management/24.level",{"title":104,"path":105,"stem":106,"children":-1},"접속 기록 확인하기","/admin/user-management/access-log","10.admin/10.user-management/30.access-log",{"title":108,"path":109,"stem":110,"children":111,"page":55},"서비스 구성","/admin/service-config","10.admin/20.service-config",[112,116,120,124,128,132],{"title":113,"path":114,"stem":115,"children":-1},"파일 영역 설정","/admin/service-config/file-area","10.admin/20.service-config/10.file-area",{"title":117,"path":118,"stem":119,"children":-1},"웹훅 설정","/admin/service-config/webhook-settings","10.admin/20.service-config/16.webhook-settings",{"title":121,"path":122,"stem":123,"children":-1},"커뮤니티 설정","/admin/service-config/community-space","10.admin/20.service-config/22.community-space",{"title":125,"path":126,"stem":127,"children":-1},"AI 챗봇 정책 설정","/admin/service-config/community-ai-chatbot","10.admin/20.service-config/24.community-ai-chatbot",{"title":129,"path":130,"stem":131,"children":-1},"메일 설정","/admin/service-config/email-settings","10.admin/20.service-config/30.email-settings",{"title":133,"path":134,"stem":135,"children":-1},"브랜딩 설정","/admin/service-config/brand","10.admin/20.service-config/40.brand",{"title":137,"path":138,"stem":139,"children":140,"page":55},"지능형 서비스 (AI)","/admin/ai","10.admin/30.ai",[141,145,149,153,159,163,167],{"title":142,"path":143,"stem":144,"children":-1},"AI 모델 설정","/admin/ai/ai-model-setting","10.admin/30.ai/10.ai-model-setting",{"title":146,"path":147,"stem":148,"children":-1},"AI DB 설정","/admin/ai/ai-db-setting","10.admin/30.ai/20.ai-db-setting",{"title":150,"path":151,"stem":152,"children":-1},"Qdrant 서버 준비하기","/admin/ai/qdrant-server-setup","10.admin/30.ai/25.qdrant-server-setup",{"title":154,"path":155,"stem":156,"children":157},"지식 인덱싱","/admin/ai/knowledge-indexing","10.admin/30.ai/30.knowledge-indexing",[158],{"title":154,"path":155,"stem":156,"children":-1},{"title":160,"path":161,"stem":162,"children":-1},"AI 연동 및 정책 설정","/admin/ai/ai-link","10.admin/30.ai/40.ai-link",{"title":164,"path":165,"stem":166,"children":-1},"MCP 서버 관리","/admin/ai/mcp-server","10.admin/30.ai/50.mcp-server",{"title":168,"path":169,"stem":170,"children":-1},"검색 관리","/admin/ai/search-management","10.admin/30.ai/60.search-management",{"title":172,"path":173,"stem":174,"children":175,"page":55},"플러그인","/admin/plugin","10.admin/40.plugin",[176,180],{"title":177,"path":178,"stem":179,"children":-1},"플러그인 관리하기","/admin/plugin/overview","10.admin/40.plugin/00.overview",{"title":181,"path":182,"stem":183,"children":-1},"확장 플러그인 설정","/admin/plugin/settings","10.admin/40.plugin/10.settings",{"title":185,"path":186,"stem":187,"children":188,"page":55},"보안 관리","/admin/security","10.admin/50.security",[189,193,197,201,205],{"title":190,"path":191,"stem":192,"children":-1},"보안 개요","/admin/security/overview","10.admin/50.security/00.overview",{"title":194,"path":195,"stem":196,"children":-1},"감사 로그 확인하기","/admin/security/audit-log","10.admin/50.security/05.audit-log",{"title":198,"path":199,"stem":200,"children":-1},"차단 관리","/admin/security/block-management","10.admin/50.security/10.block-management",{"title":202,"path":203,"stem":204,"children":-1},"보안 설정","/admin/security/security-setting","10.admin/50.security/12.security-setting",{"title":206,"path":207,"stem":208,"children":-1},"IP 접근 제한","/admin/security/ip-restriction","10.admin/50.security/16.ip-restriction",{"title":210,"path":211,"stem":212,"children":213,"page":55},"시스템 관리","/admin/system-admin","10.admin/60.system-admin",[214,218,222],{"title":215,"path":216,"stem":217,"children":-1},"디바이스 정보","/admin/system-admin/device-info","10.admin/60.system-admin/10.device-info",{"title":219,"path":220,"stem":221,"children":-1},"서버 재시작 및 시스템 유지보수","/admin/system-admin/server-restart","10.admin/60.system-admin/12.server-restart",{"title":223,"path":224,"stem":225,"children":-1},"백그라운드 서비스","/admin/system-admin/background-service","10.admin/60.system-admin/14.background-service",{"title":227,"path":228,"stem":229,"children":230,"page":55},"워크스페이스 사용하기","/workspace","20.workspace",[231,264,281,337,448,495,527],{"title":232,"path":233,"stem":234,"children":235,"page":55},"메뉴","/workspace/menu","20.workspace/05.menu",[236,240,244,248,252,256,260],{"title":237,"path":238,"stem":239,"children":-1},"워크스페이스 소개","/workspace/menu/overview","20.workspace/05.menu/00.overview",{"title":241,"path":242,"stem":243,"children":-1},"팀 스페이스","/workspace/menu/team-space","20.workspace/05.menu/05.team-space",{"title":245,"path":246,"stem":247,"children":-1},"클라이언트 스페이스","/workspace/menu/client-space","20.workspace/05.menu/06.client-space",{"title":249,"path":250,"stem":251,"children":-1},"즐겨찾기","/workspace/menu/favorites","20.workspace/05.menu/10.favorites",{"title":253,"path":254,"stem":255,"children":-1},"최근 문서","/workspace/menu/recent","20.workspace/05.menu/20.recent",{"title":257,"path":258,"stem":259,"children":-1},"외부 공유","/workspace/menu/external-share","20.workspace/05.menu/30.external-share",{"title":261,"path":262,"stem":263,"children":-1},"휴지통","/workspace/menu/trash","20.workspace/05.menu/40.trash",{"title":265,"path":266,"stem":267,"children":268,"page":55},"계정","/workspace/account","20.workspace/10.account",[269,273,277],{"title":270,"path":271,"stem":272,"children":-1},"회원가입 및 로그인","/workspace/account/signup","20.workspace/10.account/10.signup",{"title":274,"path":275,"stem":276,"children":-1},"비밀번호 재설정","/workspace/account/reset-password","20.workspace/10.account/20.reset-password",{"title":278,"path":279,"stem":280,"children":-1},"계정 설정","/workspace/account/account-settings","20.workspace/10.account/30.account-settings",{"title":282,"path":283,"stem":284,"children":285,"page":55},"폴더","/workspace/folder","20.workspace/20.folder",[286,290,294,298,302,308,312,316,321,325,329,333],{"title":287,"path":288,"stem":289,"children":-1},"폴더 기본 기능","/workspace/folder/basic","20.workspace/20.folder/10.basic",{"title":291,"path":292,"stem":293,"children":-1},"여러 폴더 한꺼번에 만들기","/workspace/folder/bulk-folder-creation","20.workspace/20.folder/12.bulk-folder-creation",{"title":295,"path":296,"stem":297,"children":-1},"필터","/workspace/folder/filter","20.workspace/20.folder/13.filter",{"title":299,"path":300,"stem":301,"children":-1},"폴더 보기 옵션 설정","/workspace/folder/folder-view-options","20.workspace/20.folder/14.folder-view-options",{"title":303,"path":304,"stem":305,"tags":306,"children":-1},"폴더 웹 보기","/workspace/folder/folder-web-view","20.workspace/20.folder/16.folder-web-view",[307],"hot",{"title":309,"path":310,"stem":311,"children":-1},"폴더 정리","/workspace/folder/folder-organize","20.workspace/20.folder/17.folder-organize",{"title":313,"path":314,"stem":315,"children":-1},"폴더 공지 (README)","/workspace/folder/folder-readme","20.workspace/20.folder/18.folder-readme",{"title":317,"path":318,"stem":319,"tags":320,"children":-1},"폴더/파일 목록 내보내기","/workspace/folder/folder-export","20.workspace/20.folder/20.folder-export",[307],{"title":322,"path":323,"stem":324,"children":-1},"레벨별 접근 권한 설정","/workspace/folder/level-access-permissions","20.workspace/20.folder/24.level-access-permissions",{"title":326,"path":327,"stem":328,"children":-1},"팀별 접근 권한 설정","/workspace/folder/team-access-permissions","20.workspace/20.folder/26.team-access-permissions",{"title":330,"path":331,"stem":332,"children":-1},"폴더 웹훅","/workspace/folder/webhook","20.workspace/20.folder/30.webhook",{"title":334,"path":335,"stem":336,"children":-1},"업무 자동화 폴더","/workspace/folder/automation","20.workspace/20.folder/40.automation",{"title":338,"path":339,"stem":340,"children":341,"page":55},"파일","/workspace/file","20.workspace/30.file",[342,346,351,355,359,363,367,371,375,379,384,388,392,396,400,404,408,412,416,420,424,428,432,436,440,444],{"title":343,"path":344,"stem":345,"children":-1},"파일 관리 기본 기능","/workspace/file/overview","20.workspace/30.file/00.overview",{"title":347,"path":348,"stem":349,"tags":350,"children":-1},"파일 보면서 목록 확인하기","/workspace/file/list-in-file","20.workspace/30.file/05.list-in-file",[307],{"title":352,"path":353,"stem":354,"children":-1},"디스크 파일 등록","/workspace/file/disk-file-registration","20.workspace/30.file/06.disk-file-registration",{"title":356,"path":357,"stem":358,"children":-1},"텍스트 파일 보기 및 편집","/workspace/file/text-file-viewer","20.workspace/30.file/10.text-file-viewer",{"title":360,"path":361,"stem":362,"children":-1},"HTML 파일 보기","/workspace/file/html-viewer","20.workspace/30.file/11.html-viewer",{"title":364,"path":365,"stem":366,"children":-1},"CSV 파일 보기 및 편집","/workspace/file/csv-viewer","20.workspace/30.file/12.csv-viewer",{"title":368,"path":369,"stem":370,"children":-1},"이미지/동영상 파일 보기","/workspace/file/image-file-viewer","20.workspace/30.file/13.image-file-viewer",{"title":372,"path":373,"stem":374,"children":-1},"오피스/PDF 파일 보기","/workspace/file/office-viewer","20.workspace/30.file/14.office-viewer",{"title":376,"path":377,"stem":378,"children":-1},"웹페이지 붙여넣기 (HTML)","/workspace/file/paste-html","20.workspace/30.file/20.paste-html",{"title":380,"path":381,"stem":382,"tags":383,"children":-1},"스크린샷 붙여넣기","/workspace/file/paste-screenshot","20.workspace/30.file/21.paste-screenshot",[307],{"title":385,"path":386,"stem":387,"children":-1},"마크다운 붙여넣기 (MD)","/workspace/file/paste-md","20.workspace/30.file/22.paste-md",{"title":389,"path":390,"stem":391,"children":-1},"스크린 녹화하기","/workspace/file/screen-recording","20.workspace/30.file/23.screen-recording",{"title":393,"path":394,"stem":395,"children":-1},"파일 태그","/workspace/file/file-tag","20.workspace/30.file/33.file-tag",{"title":397,"path":398,"stem":399,"children":-1},"파일 이름 일괄 변경","/workspace/file/bulk-name-revise","20.workspace/30.file/34.bulk-name-revise",{"title":401,"path":402,"stem":403,"children":-1},"파일 변환","/workspace/file/file-convert-overview","20.workspace/30.file/40.file-convert-overview",{"title":405,"path":406,"stem":407,"children":-1},"템플릿 파일","/workspace/file/templates","20.workspace/30.file/41.templates",{"title":409,"path":410,"stem":411,"children":-1},"할일 목록 (Todo)","/workspace/file/template-todo","20.workspace/30.file/42.template-todo",{"title":413,"path":414,"stem":415,"children":-1},"결재 서식","/workspace/file/template-approval","20.workspace/30.file/43.template-approval",{"title":417,"path":418,"stem":419,"children":-1},"칸반 보드","/workspace/file/template-kanban","20.workspace/30.file/44.template-kanban",{"title":421,"path":422,"stem":423,"children":-1},"타임라인","/workspace/file/template-timeline","20.workspace/30.file/45.template-timeline",{"title":425,"path":426,"stem":427,"children":-1},"메모장","/workspace/file/template-memo","20.workspace/30.file/46.template-memo",{"title":429,"path":430,"stem":431,"children":-1},"AI 채팅 파일","/workspace/file/ai-chat-file","20.workspace/30.file/47.ai-chat-file",{"title":433,"path":434,"stem":435,"children":-1},"파일 변경 기록 확인","/workspace/file/audit-trail","20.workspace/30.file/50.audit-trail",{"title":437,"path":438,"stem":439,"children":-1},"파일 버전 관리","/workspace/file/version-trail","20.workspace/30.file/51.version-trail",{"title":441,"path":442,"stem":443,"children":-1},"편집 잠금","/workspace/file/file-lock","20.workspace/30.file/52.file-lock",{"title":445,"path":446,"stem":447,"children":-1},"파일 암호화","/workspace/file/file-encrypt","20.workspace/30.file/53.file-encrypt",{"title":449,"path":450,"stem":451,"children":452,"page":55},"협업","/workspace/cooperation","20.workspace/35.cooperation",[453,457,461,465,470,474,478,482,487,491],{"title":454,"path":455,"stem":456,"children":-1},"파일·폴더 댓글","/workspace/cooperation/file-comments","20.workspace/35.cooperation/00.file-comments",{"title":458,"path":459,"stem":460,"children":-1},"채팅","/workspace/cooperation/chat","20.workspace/35.cooperation/10.chat",{"title":462,"path":463,"stem":464,"children":-1},"협업 채팅 및 편집 잠금","/workspace/cooperation/collaboration-chat","20.workspace/35.cooperation/11.collaboration-chat",{"title":466,"path":467,"stem":468,"tags":469,"children":-1},"팀원 작업 위치 따라가기","/workspace/cooperation/follow-team-location","20.workspace/35.cooperation/12.follow-team-location",[307],{"title":471,"path":472,"stem":473,"children":-1},"멘션","/workspace/cooperation/mention","20.workspace/35.cooperation/14.mention",{"title":475,"path":476,"stem":477,"children":-1},"쪽지","/workspace/cooperation/dm","20.workspace/35.cooperation/16.dm",{"title":479,"path":480,"stem":481,"children":-1},"알림 보관함","/workspace/cooperation/notification-inbox","20.workspace/35.cooperation/18.notification-inbox",{"title":483,"path":484,"stem":485,"tags":486,"children":-1},"팀 활동 확인하기","/workspace/cooperation/file-activity","20.workspace/35.cooperation/30.file-activity",[307],{"title":488,"path":489,"stem":490,"children":-1},"외부 공유 링크 만들기","/workspace/cooperation/share-link-creation","20.workspace/35.cooperation/40.share-link-creation",{"title":492,"path":493,"stem":494,"children":-1},"외부 공유 이메일 전송","/workspace/cooperation/share-link-email","20.workspace/35.cooperation/42.share-link-email",{"title":496,"path":497,"stem":498,"children":499,"page":55},"검색","/workspace/search","20.workspace/40.search",[500,504,509,515,519,523],{"title":501,"path":502,"stem":503,"children":-1},"파일 검색","/workspace/search/search","20.workspace/40.search/00.search",{"title":505,"path":506,"stem":507,"tags":508,"children":-1},"문맥 검색 (AI 검색)","/workspace/search/context-search","20.workspace/40.search/10.context-search",[307],{"title":510,"path":511,"stem":512,"tags":513,"children":-1},"이미지 검색","/workspace/search/image-search","20.workspace/40.search/20.image-search",[514],"new",{"title":516,"path":517,"stem":518,"children":-1},"채팅 검색","/workspace/search/chat-search","20.workspace/40.search/30.chat-search",{"title":520,"path":521,"stem":522,"children":-1},"댓글 검색","/workspace/search/comment-search","20.workspace/40.search/40.comment-search",{"title":524,"path":525,"stem":526,"children":-1},"유의어 검색","/workspace/search/synonym-search","20.workspace/40.search/50.synonym-search",{"title":528,"path":529,"stem":530,"children":531,"page":55},"AI","/workspace/ai","20.workspace/50.ai",[532,536,541],{"title":533,"path":534,"stem":535,"children":-1},"AI 기능 요약","/workspace/ai/overview","20.workspace/50.ai/00.overview",{"title":537,"path":538,"stem":539,"tags":540,"children":-1},"로컬 AI에게 업무 요청하기","/workspace/ai/ai-work","20.workspace/50.ai/10.ai-work",[307],{"title":542,"path":543,"stem":544,"tags":545,"children":-1},"외부 AI 활용하기","/workspace/ai/external-ai","20.workspace/50.ai/20.external-ai",[514],{"title":547,"path":548,"stem":549,"children":550,"page":55},"웹스페이스","/webspace","40.webspace",[551,555,559,563,567,571,576,580,584,588,592,621],{"title":552,"path":553,"stem":554,"children":-1},"웹스페이스(Webspace)란?","/webspace/overview","40.webspace/00.overview",{"title":556,"path":557,"stem":558,"children":-1},"웹사이트 배포하기","/webspace/website-release","40.webspace/10.website-release",{"title":560,"path":561,"stem":562,"children":-1},"스키마 파일(.sfn) 만들기","/webspace/create-database","40.webspace/20.create-database",{"title":564,"path":565,"stem":566,"children":-1},"API 빌드 및 데이터베이스 배포하기","/webspace/api-overview","40.webspace/24.api-overview",{"title":568,"path":569,"stem":570,"children":-1},"프론트엔드 샘플 확인하기","/webspace/frontend-example","40.webspace/26.frontend-example",{"title":572,"path":573,"stem":574,"tags":575,"children":-1},"팀 내부용 웹서비스 만들기","/webspace/internal-webservice","40.webspace/32.internal-webservice",[307],{"title":577,"path":578,"stem":579,"children":-1},"외부 공개용 웹서비스 만들기","/webspace/external-webservice","40.webspace/34.external-webservice",{"title":581,"path":582,"stem":583,"children":-1},"SQL 가져오기와 내보내기","/webspace/sql-converter","40.webspace/42.sql-converter",{"title":585,"path":586,"stem":587,"children":-1},"개발자 팁 2: Code 컨버터","/webspace/code-converter","40.webspace/44.code-converter",{"title":589,"path":590,"stem":591,"children":-1},"성능과 확장","/webspace/performance","40.webspace/48.performance",{"title":593,"path":594,"stem":595,"children":596,"page":55},"웹스페이스 관리","/webspace/admin","40.webspace/50.admin",[597,601,605,609,613,617],{"title":598,"path":599,"stem":600,"children":-1},"웹스페이스 관리 시작하기","/webspace/admin/overview","40.webspace/50.admin/00.overview",{"title":602,"path":603,"stem":604,"children":-1},"운영 현황","/webspace/admin/operations","40.webspace/50.admin/10.operations",{"title":606,"path":607,"stem":608,"children":-1},"워크스페이스 접근","/webspace/admin/workspace-access","40.webspace/50.admin/20.workspace-access",{"title":610,"path":611,"stem":612,"children":-1},"API · 사이트 보안","/webspace/admin/api-site-security","40.webspace/50.admin/30.api-site-security",{"title":614,"path":615,"stem":616,"children":-1},"서비스 및 용량","/webspace/admin/service-capacity","40.webspace/50.admin/40.service-capacity",{"title":618,"path":619,"stem":620,"children":-1},"배포 관리와 프론트엔드 릴리스","/webspace/admin/deployments","40.webspace/50.admin/50.deployments",{"title":622,"path":623,"stem":624,"children":625,"page":55},"웹스페이스 따라해보기","/webspace/examples","40.webspace/60.examples",[626,630,634],{"title":627,"path":628,"stem":629,"children":-1},"웹스페이스 응용편","/webspace/examples/overview","40.webspace/60.examples/00.overview",{"title":631,"path":632,"stem":633,"children":-1},"나만의 업무 시스템 만들기","/webspace/examples/my-own-system","40.webspace/60.examples/10.my-own-system",{"title":635,"path":636,"stem":637,"children":-1},"실시간 오목 게임 만들기","/webspace/examples/realtime-gomoku","40.webspace/60.examples/20.realtime-gomoku",{"title":639,"path":640,"stem":641,"children":642,"page":55},"플러그인 사용하기","/plugin","50.plugin",[643,647,664,709,727,757],{"title":644,"path":645,"stem":646,"children":-1},"플러그인 개요","/plugin/overview","50.plugin/00.overview",{"title":648,"path":649,"stem":650,"children":651,"page":55},"캘린더","/plugin/calendar","50.plugin/10.calendar",[652,656,660],{"title":653,"path":654,"stem":655,"children":-1},"캘린더 소개","/plugin/calendar/overview","50.plugin/10.calendar/00.overview",{"title":657,"path":658,"stem":659,"children":-1},"일정 생성, 수정 및 삭제하기","/plugin/calendar/create-event","50.plugin/10.calendar/10.create-event",{"title":661,"path":662,"stem":663,"children":-1},"활동 기록 확인하기","/plugin/calendar/file-activity","50.plugin/10.calendar/40.file-activity",{"title":665,"path":666,"stem":667,"children":668,"page":55},"이메일","/plugin/email","50.plugin/20.email",[669,673,677,681,685,689,693,697,701,705],{"title":670,"path":671,"stem":672,"children":-1},"이메일 소개","/plugin/email/overview","50.plugin/20.email/00.overview",{"title":674,"path":675,"stem":676,"children":-1},"이메일 설정","/plugin/email/setfn-email-setting","50.plugin/20.email/05.setfn-email-setting",{"title":678,"path":679,"stem":680,"children":-1},"외부 이메일 연결","/plugin/email/external-email","50.plugin/20.email/07.external-email",{"title":682,"path":683,"stem":684,"children":-1},"이메일 기본 기능","/plugin/email/email-basic","50.plugin/20.email/10.email-basic",{"title":686,"path":687,"stem":688,"children":-1},"이메일 작성 및 전송","/plugin/email/email-compose","50.plugin/20.email/20.email-compose",{"title":690,"path":691,"stem":692,"children":-1},"파일 첨부하기","/plugin/email/email-attachment","50.plugin/20.email/30.email-attachment",{"title":694,"path":695,"stem":696,"children":-1},"이메일 폴더 관리","/plugin/email/email-folders","50.plugin/20.email/40.email-folders",{"title":698,"path":699,"stem":700,"children":-1},"이메일 자동 분류하기","/plugin/email/email-auto-classify","50.plugin/20.email/50.email-auto-classify",{"title":702,"path":703,"stem":704,"children":-1},"이메일 파일 보관 및 공유","/plugin/email/email-open-in-space","50.plugin/20.email/60.email-open-in-space",{"title":706,"path":707,"stem":708,"children":-1},"이메일 보안","/plugin/email/email-security","50.plugin/20.email/70.email-security",{"title":710,"path":711,"stem":712,"children":713,"page":55},"워크플로우 (업무자동화)","/plugin/workflow","50.plugin/30.workflow",[714,718,723],{"title":715,"path":716,"stem":717,"children":-1},"워크플로우 소개","/plugin/workflow/overview","50.plugin/30.workflow/00.overview",{"title":719,"path":720,"stem":721,"tags":722,"children":-1},"새 워크플로우 만들기","/plugin/workflow/new-workflow","50.plugin/30.workflow/10.new-workflow",[307],{"title":724,"path":725,"stem":726,"children":-1},"실행 기록 확인하기","/plugin/workflow/execution-history","50.plugin/30.workflow/20.execution-history",{"title":728,"path":729,"stem":730,"children":731,"page":55},"파인튜닝 (AI 학습)","/plugin/fine-tuning","50.plugin/40.fine-tuning",[732,737,741,745,749,753],{"title":733,"path":734,"stem":735,"tags":736,"children":-1},"파인튜닝 소개","/plugin/fine-tuning/overview","50.plugin/40.fine-tuning/00.overview",[307],{"title":738,"path":739,"stem":740,"children":-1},"학습 데이터 전처리","/plugin/fine-tuning/pre-processing","50.plugin/40.fine-tuning/10.pre-processing",{"title":742,"path":743,"stem":744,"children":-1},"학습","/plugin/fine-tuning/training","50.plugin/40.fine-tuning/20.training",{"title":746,"path":747,"stem":748,"children":-1},"평가","/plugin/fine-tuning/evaluation","50.plugin/40.fine-tuning/30.evaluation",{"title":750,"path":751,"stem":752,"children":-1},"채팅 테스트","/plugin/fine-tuning/chat-test","50.plugin/40.fine-tuning/40.chat-test",{"title":754,"path":755,"stem":756,"children":-1},"내보내기","/plugin/fine-tuning/export","50.plugin/40.fine-tuning/50.export",{"title":758,"path":759,"stem":760,"children":761,"page":55},"EDC (데이터 수집)","/plugin/edc","50.plugin/50.edc",[762,766,770,774],{"title":763,"path":764,"stem":765,"children":-1},"EDC 소개","/plugin/edc/overview","50.plugin/50.edc/00.overview",{"title":767,"path":768,"stem":769,"children":-1},"데이터 입력, Audit Trail","/plugin/edc/data-entry","50.plugin/50.edc/10.data-entry",{"title":771,"path":772,"stem":773,"children":-1},"빌더","/plugin/edc/builder","50.plugin/50.edc/20.builder",{"title":775,"path":776,"stem":777,"children":-1},"사용자/기관 설정","/plugin/edc/account","50.plugin/50.edc/30.account",{"title":779,"path":780,"stem":781,"children":782,"page":55},"FAQ","/faq","99.FAQ",[783,787,791,795,799,803,807],{"title":784,"path":785,"stem":786,"children":-1},"SetFN vs 클라우드 서비스 비교","/faq/comparison-cloud","99.FAQ/10.comparison-cloud",{"title":788,"path":789,"stem":790,"children":-1},"SetFN vs NAS 비교","/faq/comparison-nas","99.FAQ/20.comparison-nas",{"title":792,"path":793,"stem":794,"children":-1},"보안 정책","/faq/security-policy","99.FAQ/30.security-policy",{"title":796,"path":797,"stem":798,"children":-1},"SetFN은 왜 빠른가요","/faq/why-fast","99.FAQ/40.why-fast",{"title":800,"path":801,"stem":802,"children":-1},"라이선스 FAQ","/faq/license-faq","99.FAQ/50.license-faq",{"title":804,"path":805,"stem":806,"children":-1},"AI 기능 FAQ","/faq/ai-faq","99.FAQ/60.ai-faq",{"title":808,"path":809,"stem":810,"children":-1},"문제 해결 가이드","/faq/troubleshooting","99.FAQ/70.troubleshooting",{"title":812,"path":813,"stem":814,"children":815,"page":55},"응용편(초안)","/draft","draft",[816,820,824,828,832,836,840,844,848,852,856,860,864],{"title":817,"path":818,"stem":819,"children":-1},"예시 1. 소개 페이지 만들기","/draft/static-intro","draft/05.static-intro",{"title":821,"path":822,"stem":823,"children":-1},"예시 2. 공지 게시판 만들기","/draft/public-notice-board","draft/07.public-notice-board",{"title":825,"path":826,"stem":827,"children":-1},"예시 3. 커피챗 예약 시스템 만들기","/draft/coffee-chat-booking","draft/08.coffee-chat-booking",{"title":829,"path":830,"stem":831,"children":-1},"예시 4. 휴가 신청 시스템 만들기","/draft/leave-request","draft/09.leave-request",{"title":833,"path":834,"stem":835,"children":-1},"예시 5. 실시간 팀 채팅 만들기","/draft/team-chat","draft/10.team-chat",{"title":837,"path":838,"stem":839,"children":-1},"예시 6. 채용 지원 서류 제출함 만들기","/draft/client-submission","draft/11.client-submission",{"title":841,"path":842,"stem":843,"children":-1},"예시 7. 팀과 레벨에 따른 이슈 트래커 만들기","/draft/crm-basic","draft/12.crm-basic",{"title":845,"path":846,"stem":847,"children":-1},"예시 8. 이슈 상태별 필터와 통계 요약 화면 만들기","/draft/crm-search-filter","draft/13.crm-search-filter",{"title":849,"path":850,"stem":851,"children":-1},"예시 9. 실시간 커뮤니티 채팅과 운영 기능 만들기","/draft/community-moderation","draft/14.community-moderation",{"title":853,"path":854,"stem":855,"children":-1},"예시 10. 실시간 출석체크·투표 만들기","/draft/attendance-poll","draft/15.attendance-poll",{"title":857,"path":858,"stem":859,"children":-1},"예시 11. 찬반 논쟁 배틀 만들기","/draft/debate-battle","draft/16.debate-battle",{"title":861,"path":862,"stem":863,"children":-1},"예시 13. 공지사항 읽음 확인 만들기","/draft/announcement-read","draft/18.announcement-read",{"title":865,"path":866,"stem":867,"children":-1},"예시 14. 재고 관리 시스템 만들기","/draft/inventory-management","draft/19.inventory-management",{"title":869,"path":870,"stem":871,"children":872,"page":55},"SJAUTO","/sjauto","sjauto",[873,876,879,882],{"title":67,"path":874,"stem":875,"children":-1},"/sjauto/admin-page-access","sjauto/00.admin-page-access",{"title":270,"path":877,"stem":878,"children":-1},"/sjauto/signup","sjauto/10.signup",{"title":429,"path":880,"stem":881,"children":-1},"/sjauto/ai-chat-file","sjauto/ai-chat-file",{"title":631,"path":883,"stem":884,"children":-1},"/sjauto/webspace-schema-example","sjauto/webspace-schema-example",{"id":886,"title":635,"body":887,"cover":1530,"description":1531,"extension":1532,"image":1530,"meta":1533,"navigation":1535,"path":636,"seo":1536,"stem":637,"tags":1530,"thumbnail":1530,"__hash__":1548},"docs_ko/40.webspace/60.examples/20.realtime-gomoku.md",{"type":888,"value":889,"toc":1514},"minimal",[890,894,898,901,908,911,916,924,955,958,975,978,982,985,1053,1056,1060,1063,1073,1080,1124,1127,1131,1138,1169,1172,1176,1183,1189,1192,1198,1205,1209,1219,1229,1242,1246,1276,1279,1285,1289,1292,1298,1305,1309,1314,1410,1413,1416,1420,1486,1489,1492,1496],[891,892,635],"h1",{"id":893},"실시간-오목-게임-만들기",[895,896,897],"p",{},"파일을 올리고 스키마를 배포한 다음 브라우저 두 개를 열어 보세요. 한쪽에서 만든 방에 친구가 참가하고, 돌을 놓는 순간 다른 화면에도 같은 수가 나타납니다. 승패와 순위는 서버가 알아서 기록합니다.",[895,899,900],{},"별도의 프론트엔드 빌드 도구는 필요하지 않습니다. 완성된 샘플로 한 판을 먼저 실행한 뒤 데이터 구조, 실시간 기능과 게임 규칙을 하나씩 바꿔볼 수 있습니다.",[895,902,903],{},[904,905],"img",{"alt":906,"src":907},"19×19 바둑판과 실시간 중계 및 플레이어 순위","/img/docs/webspace/gomoku/realtime-gomoku-board.png",[909,910],"hr",{},[912,913,915],"h2",{"id":914},"_1-먼저-한-판-실행해-보기","1. 먼저 한 판 실행해 보기",[895,917,918,919,923],{},"처음에는 ",[920,921,922],"strong",{},"전체 샘플 ZIP","으로 시작하는 편이 가장 빠릅니다. 스키마와 화면 파일을 같은 폴더에 올리고 스키마를 배포하면 바로 대국을 열 수 있습니다.",[925,926,927,948],"ul",{},[928,929,930,935,936,940,941,940,944,947],"li",{},[931,932,934],"a",{"href":933},"/examples/webspace/gomoku/setfn-realtime-gomoku-sample.zip","실시간 오목 전체 샘플 ZIP 다운로드",": 스키마와 ",[937,938,939],"code",{},"index.html",", ",[937,942,943],{},"style.css",[937,945,946],{},"app.js",", README 포함",[928,949,950,954],{},[931,951,953],{"href":952},"/examples/webspace/gomoku/gomoku-realtime.sfn","오목 스키마 파일(.sfn) 다운로드",": 백엔드 구조만 살펴보거나 직접 만든 화면과 연결할 때",[895,956,957],{},"샘플을 실행하면 다음 장면을 직접 확인할 수 있습니다.",[925,959,960,963,966,969,972],{},[928,961,962],{},"방 코드를 이용한 두 사용자 대국",[928,964,965],{},"마지막 수, 내 돌과 현재 차례 표시",[928,967,968],{},"한 수마다 다시 시작되는 3분 제한시간",[928,970,971],{},"진행 상황을 알려 주는 실시간 경기 중계",[928,973,974],{},"승리·패배 표시와 최근 대국, 플레이어 순위 자동 갱신",[895,976,977],{},"스키마에는 19×19 보드와 다섯 돌 승리, 승 3점·무승부 1점·패 0점 규칙이 미리 들어 있습니다. 사용자당 최대 3개의 대기방을 만들 수 있고, 30분 동안 참가자가 없는 대기방은 정리 대상으로 처리됩니다.",[912,979,981],{"id":980},"게임-안에서-작동하는-기능","게임 안에서 작동하는 기능",[895,983,984],{},"오목 한 판에는 WebSpace의 주요 기능이 자연스럽게 들어 있습니다.",[986,987,988,1001],"table",{},[989,990,991],"thead",{},[992,993,994,998],"tr",{},[995,996,997],"th",{},"기능",[995,999,1000],{},"오목에서 하는 일",[1002,1003,1004,1013,1021,1029,1037,1045],"tbody",{},[992,1005,1006,1010],{},[1007,1008,1009],"td",{},"스키마 파일",[1007,1011,1012],{},"대국, 착수 기록과 사용자 전적 구조 정의",[992,1014,1015,1018],{},[1007,1016,1017],{},"REST API",[1007,1019,1020],{},"최근 대국과 플레이어 순위 조회",[992,1022,1023,1026],{},[1007,1024,1025],{},"WebSocket",[1007,1027,1028],{},"방 생성·참가와 착수 결과를 실시간 전달",[992,1030,1031,1034],{},[1007,1032,1033],{},"이벤트 처리기",[1007,1035,1036],{},"차례, 좌표, 승리 조건과 제한시간을 서버에서 판정",[992,1038,1039,1042],{},[1007,1040,1041],{},"회원 권한",[1007,1043,1044],{},"로그인한 사용자만 대국에 참여",[992,1046,1047,1050],{},[1007,1048,1049],{},"협업 기능",[1007,1051,1052],{},"같은 화면에서 참가자와 대화",[895,1054,1055],{},"중요한 점은 브라우저가 승리를 선언하거나 점수를 직접 쓰지 않는다는 것입니다. 서버가 현재 판과 차례를 확인하고 정상적인 착수만 저장한 뒤 두 사용자에게 같은 결과를 보냅니다.",[912,1057,1059],{"id":1058},"_2-워크스페이스에-올리기","2. 워크스페이스에 올리기",[895,1061,1062],{},"스키마 파일만 내려받았다면 팀 또는 개인 워크스페이스의 프로젝트 폴더에 업로드합니다. 전체 샘플 ZIP을 내려받았다면 폴더 업로드나 압축 파일 업로드로 다섯 파일을 같은 폴더에 둡니다.",[1064,1065,1071],"pre",{"className":1066,"code":1068,"language":1069,"meta":1070},[1067],"language-text","오목대국장/\n├── gomoku-realtime.sfn\n├── index.html\n├── style.css\n├── app.js\n└── README.md\n","text","",[937,1072,1068],{"__ignoreMap":1070},[895,1074,1075,1076,1079],{},"스키마 파일을 열고 ",[937,1077,1078],{},"DB구조","에서 세 개의 테이블을 확인합니다.",[986,1081,1082,1092],{},[989,1083,1084],{},[992,1085,1086,1089],{},[995,1087,1088],{},"테이블",[995,1090,1091],{},"저장 내용",[1002,1093,1094,1104,1114],{},[992,1095,1096,1101],{},[1007,1097,1098],{},[937,1099,1100],{},"gomoku_games",[1007,1102,1103],{},"방 코드, 참가자, 현재 차례, 제한시간과 최종 결과",[992,1105,1106,1111],{},[1007,1107,1108],{},[937,1109,1110],{},"gomoku_moves",[1007,1112,1113],{},"몇 번째 수인지, 돌 색상, 좌표와 사용자",[992,1115,1116,1121],{},[1007,1117,1118],{},[937,1119,1120],{},"gomoku_players",[1007,1122,1123],{},"사용자별 승·패·무, 누적 점수와 최근 경기",[895,1125,1126],{},"대국과 전적을 나눠 저장하기 때문에 화면을 새로 열어도 최근 기록과 순위를 다시 불러올 수 있습니다.",[912,1128,1130],{"id":1129},"_3-api와-실시간-기능-확인하기","3. API와 실시간 기능 확인하기",[895,1132,1133,1134,1137],{},"상단의 ",[937,1135,1136],{},"API빌드","를 열고 다음 항목을 확인합니다.",[1139,1140,1141,1148,1154,1160,1166],"ol",{},[928,1142,1143,1144,1147],{},"데이터베이스 이름이 ",[937,1145,1146],{},"gomoku","인지 확인합니다.",[928,1149,1150,1153],{},[937,1151,1152],{},"기능 연결","에서 실시간 소켓이 켜져 있는지 확인합니다.",[928,1155,1156,1157,1147],{},"이벤트 처리기가 ",[937,1158,1159],{},"turn-based-board",[928,1161,1162,1163,1147],{},"실시간 송신과 수신 권한이 ",[937,1164,1165],{},"회원",[928,1167,1168],{},"세 테이블의 등록과 수정 API가 비활성화되어 있는지 확인합니다.",[895,1170,1171],{},"등록과 수정 API를 끄는 이유가 있습니다. 참가자가 REST API로 승리 횟수나 착수 기록을 직접 바꾸지 못하게 하고, 모든 게임 상태 변경을 서버의 이벤트 처리기로 통과시키기 위해서입니다.",[912,1173,1175],{"id":1174},"_4-sqlite3로-배포하기","4. SQLite3로 배포하기",[895,1177,1178,1179,1182],{},"처음 실행할 때는 ",[937,1180,1181],{},"스토리지","에서 SQLite3를 선택합니다. 별도의 데이터베이스 주소나 계정을 준비하지 않아도 되므로 예제를 확인하기에 가장 간단합니다.",[895,1184,1185,1188],{},[937,1186,1187],{},"배포하기","를 누르기 전에 화면에 표시되는 변경 내용과 권한 요약을 확인합니다. 이미 같은 이름의 데이터베이스에 기록이 있다면 서버의 덮어쓰기 정책에 따라 관리자 또는 배포 담당자의 승인이 필요할 수 있습니다.",[895,1190,1191],{},"배포가 끝나면 다음 주소 형식의 REST API와 WebSocket이 준비됩니다.",[1064,1193,1196],{"className":1194,"code":1195,"language":1069,"meta":1070},[1067],"GET /api/web/gomoku/gomoku_games/list\nGET /api/web/gomoku/gomoku_players/list\nWS  /api/web/gomoku/realtime-ws\n",[937,1197,1195],{"__ignoreMap":1070},[895,1199,1200,1201,1204],{},"운영 서버가 HTTPS라면 브라우저는 같은 도메인의 안전한 ",[937,1202,1203],{},"wss://"," 연결을 사용해야 합니다. 주소를 특정 개발 도메인으로 코드에 고정하지 않고 현재 페이지의 호스트를 기준으로 만드는 것이 좋습니다.",[912,1206,1208],{"id":1207},"_5-오목-화면-열기","5. 오목 화면 열기",[895,1210,1211,1212,940,1214,940,1216,1218],{},"스키마 파일은 게임의 데이터베이스와 백엔드를 만들고, ",[937,1213,939],{},[937,1215,943],{},[937,1217,946],{},"는 바둑판과 사용자 경험을 담당합니다. 두 부분을 나눠 두면 대국 기록을 유지하면서 화면만 새롭게 바꿀 수 있습니다.",[895,1220,1221,1222,1224,1225,1228],{},"전체 샘플을 올렸다면 ",[937,1223,939],{},"을 선택하고 ",[937,1226,1227],{},"미리보기","를 엽니다. 스키마 파일만 사용한다면 직접 만든 HTML에서 위의 REST API와 WebSocket을 연결합니다.",[895,1230,1231,1232,940,1235,940,1238,1241],{},"클라이언트는 ",[937,1233,1234],{},"board-game.create",[937,1236,1237],{},"board-game.join",[937,1239,1240],{},"board-game.move"," 같은 동작을 WebSocket으로 보냅니다. 돌과 점수는 서버에서 돌아온 확정 이벤트를 기준으로 표시합니다.",[912,1243,1245],{"id":1244},"_6-두-명이-실제로-대국하기","6. 두 명이 실제로 대국하기",[1139,1247,1248,1254,1261,1264,1270,1273],{},[928,1249,1250,1251,1253],{},"서로 다른 회원 계정으로 같은 ",[937,1252,939],{},"을 엽니다.",[928,1255,1256,1257,1260],{},"첫 번째 계정에서 ",[937,1258,1259],{},"새 대국 만들기","를 누릅니다.",[928,1262,1263],{},"만들어진 방 코드를 두 번째 계정에 전달합니다.",[928,1265,1266,1267,1260],{},"두 번째 계정에서 코드를 입력하고 ",[937,1268,1269],{},"참가하기",[928,1271,1272],{},"번갈아 돌을 놓고 두 화면에 같은 수가 표시되는지 확인합니다.",[928,1274,1275],{},"다섯 돌이 이어진 뒤 승리 표시, 최근 대국과 순위가 갱신되는지 확인합니다.",[895,1277,1278],{},"일반 창과 시크릿 창처럼 로그인 세션이 분리된 브라우저를 사용하면 한 컴퓨터에서도 테스트하기 편합니다.",[895,1280,1281],{},[904,1282],{"alt":1283,"src":1284},"협업 채팅을 함께 연 실시간 오목 화면","/img/docs/webspace/gomoku/realtime-gomoku-collaboration.png",[912,1286,1288],{"id":1287},"결과는-서버가-기록합니다","결과는 서버가 기록합니다",[895,1290,1291],{},"가로, 세로 또는 대각선으로 다섯 돌이 이어지면 서버가 대국을 끝내고 승자와 점수를 저장합니다. 한 수의 제한시간이 지나도 서버 시각을 기준으로 시간패가 결정됩니다.",[895,1293,1294],{},[904,1295],{"alt":1296,"src":1297},"오목 승리 결과와 자동 집계된 플레이어 순위","/img/docs/webspace/gomoku/realtime-gomoku-result.png",[895,1299,1300,1301,1304],{},"최근 대국과 순위가 즉시 바뀌지 않는다면 버튼을 다시 누르기보다 WebSocket의 종료 이벤트를 받은 뒤 목록을 다시 조회하는 흐름인지 확인하세요. 화면의 ",[937,1302,1303],{},"개발 정보","를 펼치면 송수신 JSON과 서버 처리시간도 확인할 수 있습니다.",[912,1306,1308],{"id":1307},"여기서부터-내-게임-만들기","여기서부터 내 게임 만들기",[895,1310,1311,1313],{},[937,1312,1159],{},"는 오목이라는 이름에 고정된 처리기가 아닙니다. 스키마 파일의 처리기 설정에서 다음 값을 바꿔 다른 턴 기반 게임의 출발점으로 사용할 수 있습니다.",[986,1315,1316,1330],{},[989,1317,1318],{},[992,1319,1320,1323,1327],{},[995,1321,1322],{},"설정",[995,1324,1326],{"align":1325},"right","현재 값",[995,1328,1329],{},"의미",[1002,1331,1332,1345,1358,1371,1384,1397],{},[992,1333,1334,1339,1342],{},[1007,1335,1336],{},[937,1337,1338],{},"boardSize",[1007,1340,1341],{"align":1325},"19",[1007,1343,1344],{},"보드 한 변의 칸 수",[992,1346,1347,1352,1355],{},[1007,1348,1349],{},[937,1350,1351],{},"winLength",[1007,1353,1354],{"align":1325},"5",[1007,1356,1357],{},"승리에 필요한 연속 돌 수",[992,1359,1360,1365,1368],{},[1007,1361,1362],{},[937,1363,1364],{},"turnTimeSeconds",[1007,1366,1367],{"align":1325},"180",[1007,1369,1370],{},"한 수의 제한시간",[992,1372,1373,1378,1381],{},[1007,1374,1375],{},[937,1376,1377],{},"winScore",[1007,1379,1380],{"align":1325},"3",[1007,1382,1383],{},"승리 점수",[992,1385,1386,1391,1394],{},[1007,1387,1388],{},[937,1389,1390],{},"drawScore",[1007,1392,1393],{"align":1325},"1",[1007,1395,1396],{},"무승부 점수",[992,1398,1399,1404,1407],{},[1007,1400,1401],{},[937,1402,1403],{},"lossScore",[1007,1405,1406],{"align":1325},"0",[1007,1408,1409],{},"패배 점수",[895,1411,1412],{},"작은 보드의 빠른 게임으로 바꾸거나 점수 규칙을 조직 행사에 맞게 조정해 보세요. 같은 실시간 기반 위에 관전 화면, 시즌 순위와 팀 대전을 추가하는 것도 가능합니다.",[895,1414,1415],{},"오목은 완성된 예제이면서 새 게임의 출발점입니다. 돌 대신 몬스터와 아이템을 표시하면 턴제 전투가 되고, 칸 대신 문제와 선택지를 보여 주면 실시간 퀴즈가 됩니다. 데이터와 규칙은 스키마에 두고, 화면에는 만들고 싶은 게임의 재미를 더해 보세요.",[912,1417,1419],{"id":1418},"문제가-생겼을-때","문제가 생겼을 때",[986,1421,1422,1432],{},[989,1423,1424],{},[992,1425,1426,1429],{},[995,1427,1428],{},"증상",[995,1430,1431],{},"확인할 항목",[1002,1433,1434,1445,1453,1463,1478],{},[992,1435,1436,1439],{},[1007,1437,1438],{},"실시간 이벤트 처리기를 사용할 수 없음",[1007,1440,1441,1442,1444],{},"서버가 현재 스키마의 ",[937,1443,1159],{}," 처리기를 지원하는 버전인지 확인",[992,1446,1447,1450],{},[1007,1448,1449],{},"새 대국이나 참가 버튼이 동작하지 않음",[1007,1451,1452],{},"DB 배포 상태, 실시간 기능, 로그인과 송수신 권한 확인",[992,1454,1455,1460],{},[1007,1456,1457],{},[937,1458,1459],{},"401 Unauthorized",[1007,1461,1462],{},"로그인 세션이 유효한지 확인하고 URL 쿼리에 토큰을 직접 넣지 않았는지 확인",[992,1464,1465,1468],{},[1007,1466,1467],{},"운영 서버에서 WebSocket이 차단됨",[1007,1469,1470,1471,1473,1474,1477],{},"HTTPS 페이지가 ",[937,1472,1203],{},"를 사용하고 CSP의 ",[937,1475,1476],{},"connect-src","가 허용됐는지 확인",[992,1479,1480,1483],{},[1007,1481,1482],{},"수정한 화면이 이전 모습으로 보임",[1007,1484,1485],{},"미리보기를 다시 열고 정적 파일의 최신 버전이 응답되는지 확인",[912,1487,1488],{"id":1488},"마치며",[895,1490,1491],{},"정적 페이지 하나였던 첫 예제에서 시작해, 데이터베이스, 테이블 간 관계, 역할별 권한, 조직 밖에서 들어오는 파일 제출, 그리고 서버가 직접 판정하는 실시간 게임 상태까지 이어왔습니다. 각 예제는 이전 예제 위에 개념을 하나씩만 더하는 방식으로 구성했습니다. 필요한 기능에 따라 이 중 몇 가지를 조합하면, 대부분의 사내·대고객 도구를 WebSpace만으로 만들 수 있습니다.",[912,1493,1495],{"id":1494},"다음에-해볼-것","다음에 해볼 것",[925,1497,1498,1504,1509],{},[928,1499,1500],{},[931,1501,1503],{"href":1502},"../api-overview","API 빌드 및 데이터베이스 배포",[928,1505,1506],{},[931,1507,589],{"href":1508},"../performance",[928,1510,1511],{},[931,1512,614],{"href":1513},"../admin/service-capacity",{"title":1070,"searchDepth":1515,"depth":1516,"links":1517},2,3,[1518,1519,1520,1521,1522,1523,1524,1525,1526,1527,1528,1529],{"id":914,"depth":1515,"text":915},{"id":980,"depth":1515,"text":981},{"id":1058,"depth":1515,"text":1059},{"id":1129,"depth":1515,"text":1130},{"id":1174,"depth":1515,"text":1175},{"id":1207,"depth":1515,"text":1208},{"id":1244,"depth":1515,"text":1245},{"id":1287,"depth":1515,"text":1288},{"id":1307,"depth":1515,"text":1308},{"id":1418,"depth":1515,"text":1419},{"id":1488,"depth":1515,"text":1488},{"id":1494,"depth":1515,"text":1495},null,"오목 스키마 파일(.sfn)을 내려받아 SQLite3 데이터베이스, REST API와 WebSocket 게임 백엔드로 배포합니다.","md",{"slug":1534},"/webspace/examples/realtime-gomoku/",true,{"title":1537,"description":1538,"ogType":1539,"twitterCard":1540,"keywords":1541},"실시간 오목 게임 만들기 | WebSocket 게임 서버 예제","SetFN WebSpace에서 오목 스키마 파일을 배포하고 방 참가, 실시간 착수, 승패 판정과 순위 저장까지 확인합니다.","article","summary_large_image",[635,1542,1543,1544,1545,1546,1547],"웹소켓 게임 서버","WebSocket 예제","SQLite 게임","노코드 백엔드","스키마 파일 다운로드","SetFN WebSpace","WGhwW39jJ2ZbpW3u-TfnY5fLxdbwK9VuFGUtYkuGppU",[1550,1551],{"title":631,"path":632,"stem":633,"children":-1},{"title":644,"path":645,"stem":646,"children":-1},{"title":635,"filename":1553,"content":1554},"realtime-gomoku","# 실시간 오목 게임 만들기\n\n파일을 올리고 스키마를 배포한 다음 브라우저 두 개를 열어 보세요. 한쪽에서 만든 방에 친구가 참가하고, 돌을 놓는 순간 다른 화면에도 같은 수가 나타납니다. 승패와 순위는 서버가 알아서 기록합니다.\n\n별도의 프론트엔드 빌드 도구는 필요하지 않습니다. 완성된 샘플로 한 판을 먼저 실행한 뒤 데이터 구조, 실시간 기능과 게임 규칙을 하나씩 바꿔볼 수 있습니다.\n\n![19×19 바둑판과 실시간 중계 및 플레이어 순위](/img/docs/webspace/gomoku/realtime-gomoku-board.png)\n\n---\n\n## 1. 먼저 한 판 실행해 보기\n\n처음에는 **전체 샘플 ZIP**으로 시작하는 편이 가장 빠릅니다. 스키마와 화면 파일을 같은 폴더에 올리고 스키마를 배포하면 바로 대국을 열 수 있습니다.\n\n- [실시간 오목 전체 샘플 ZIP 다운로드](/examples/webspace/gomoku/setfn-realtime-gomoku-sample.zip): 스키마와 `index.html`, `style.css`, `app.js`, README 포함\n- [오목 스키마 파일(.sfn) 다운로드](/examples/webspace/gomoku/gomoku-realtime.sfn): 백엔드 구조만 살펴보거나 직접 만든 화면과 연결할 때\n\n샘플을 실행하면 다음 장면을 직접 확인할 수 있습니다.\n\n- 방 코드를 이용한 두 사용자 대국\n- 마지막 수, 내 돌과 현재 차례 표시\n- 한 수마다 다시 시작되는 3분 제한시간\n- 진행 상황을 알려 주는 실시간 경기 중계\n- 승리·패배 표시와 최근 대국, 플레이어 순위 자동 갱신\n\n스키마에는 19×19 보드와 다섯 돌 승리, 승 3점·무승부 1점·패 0점 규칙이 미리 들어 있습니다. 사용자당 최대 3개의 대기방을 만들 수 있고, 30분 동안 참가자가 없는 대기방은 정리 대상으로 처리됩니다.\n\n## 게임 안에서 작동하는 기능\n\n오목 한 판에는 WebSpace의 주요 기능이 자연스럽게 들어 있습니다.\n\n| 기능          | 오목에서 하는 일                                 |\n| ------------- | ------------------------------------------------ |\n| 스키마 파일   | 대국, 착수 기록과 사용자 전적 구조 정의          |\n| REST API      | 최근 대국과 플레이어 순위 조회                   |\n| WebSocket     | 방 생성·참가와 착수 결과를 실시간 전달           |\n| 이벤트 처리기 | 차례, 좌표, 승리 조건과 제한시간을 서버에서 판정 |\n| 회원 권한     | 로그인한 사용자만 대국에 참여                    |\n| 협업 기능     | 같은 화면에서 참가자와 대화                      |\n\n중요한 점은 브라우저가 승리를 선언하거나 점수를 직접 쓰지 않는다는 것입니다. 서버가 현재 판과 차례를 확인하고 정상적인 착수만 저장한 뒤 두 사용자에게 같은 결과를 보냅니다.\n\n## 2. 워크스페이스에 올리기\n\n스키마 파일만 내려받았다면 팀 또는 개인 워크스페이스의 프로젝트 폴더에 업로드합니다. 전체 샘플 ZIP을 내려받았다면 폴더 업로드나 압축 파일 업로드로 다섯 파일을 같은 폴더에 둡니다.\n\n```text\n오목대국장/\n├── gomoku-realtime.sfn\n├── index.html\n├── style.css\n├── app.js\n└── README.md\n```\n\n스키마 파일을 열고 `DB구조`에서 세 개의 테이블을 확인합니다.\n\n| 테이블           | 저장 내용                                        |\n| ---------------- | ------------------------------------------------ |\n| `gomoku_games`   | 방 코드, 참가자, 현재 차례, 제한시간과 최종 결과 |\n| `gomoku_moves`   | 몇 번째 수인지, 돌 색상, 좌표와 사용자           |\n| `gomoku_players` | 사용자별 승·패·무, 누적 점수와 최근 경기         |\n\n대국과 전적을 나눠 저장하기 때문에 화면을 새로 열어도 최근 기록과 순위를 다시 불러올 수 있습니다.\n\n## 3. API와 실시간 기능 확인하기\n\n상단의 `API빌드`를 열고 다음 항목을 확인합니다.\n\n1. 데이터베이스 이름이 `gomoku`인지 확인합니다.\n2. `기능 연결`에서 실시간 소켓이 켜져 있는지 확인합니다.\n3. 이벤트 처리기가 `turn-based-board`인지 확인합니다.\n4. 실시간 송신과 수신 권한이 `회원`인지 확인합니다.\n5. 세 테이블의 등록과 수정 API가 비활성화되어 있는지 확인합니다.\n\n등록과 수정 API를 끄는 이유가 있습니다. 참가자가 REST API로 승리 횟수나 착수 기록을 직접 바꾸지 못하게 하고, 모든 게임 상태 변경을 서버의 이벤트 처리기로 통과시키기 위해서입니다.\n\n## 4. SQLite3로 배포하기\n\n처음 실행할 때는 `스토리지`에서 SQLite3를 선택합니다. 별도의 데이터베이스 주소나 계정을 준비하지 않아도 되므로 예제를 확인하기에 가장 간단합니다.\n\n`배포하기`를 누르기 전에 화면에 표시되는 변경 내용과 권한 요약을 확인합니다. 이미 같은 이름의 데이터베이스에 기록이 있다면 서버의 덮어쓰기 정책에 따라 관리자 또는 배포 담당자의 승인이 필요할 수 있습니다.\n\n배포가 끝나면 다음 주소 형식의 REST API와 WebSocket이 준비됩니다.\n\n```text\nGET /api/web/gomoku/gomoku_games/list\nGET /api/web/gomoku/gomoku_players/list\nWS  /api/web/gomoku/realtime-ws\n```\n\n운영 서버가 HTTPS라면 브라우저는 같은 도메인의 안전한 `wss://` 연결을 사용해야 합니다. 주소를 특정 개발 도메인으로 코드에 고정하지 않고 현재 페이지의 호스트를 기준으로 만드는 것이 좋습니다.\n\n## 5. 오목 화면 열기\n\n스키마 파일은 게임의 데이터베이스와 백엔드를 만들고, `index.html`, `style.css`, `app.js`는 바둑판과 사용자 경험을 담당합니다. 두 부분을 나눠 두면 대국 기록을 유지하면서 화면만 새롭게 바꿀 수 있습니다.\n\n전체 샘플을 올렸다면 `index.html`을 선택하고 `미리보기`를 엽니다. 스키마 파일만 사용한다면 직접 만든 HTML에서 위의 REST API와 WebSocket을 연결합니다.\n\n클라이언트는 `board-game.create`, `board-game.join`, `board-game.move` 같은 동작을 WebSocket으로 보냅니다. 돌과 점수는 서버에서 돌아온 확정 이벤트를 기준으로 표시합니다.\n\n## 6. 두 명이 실제로 대국하기\n\n1. 서로 다른 회원 계정으로 같은 `index.html`을 엽니다.\n2. 첫 번째 계정에서 `새 대국 만들기`를 누릅니다.\n3. 만들어진 방 코드를 두 번째 계정에 전달합니다.\n4. 두 번째 계정에서 코드를 입력하고 `참가하기`를 누릅니다.\n5. 번갈아 돌을 놓고 두 화면에 같은 수가 표시되는지 확인합니다.\n6. 다섯 돌이 이어진 뒤 승리 표시, 최근 대국과 순위가 갱신되는지 확인합니다.\n\n일반 창과 시크릿 창처럼 로그인 세션이 분리된 브라우저를 사용하면 한 컴퓨터에서도 테스트하기 편합니다.\n\n![협업 채팅을 함께 연 실시간 오목 화면](/img/docs/webspace/gomoku/realtime-gomoku-collaboration.png)\n\n## 결과는 서버가 기록합니다\n\n가로, 세로 또는 대각선으로 다섯 돌이 이어지면 서버가 대국을 끝내고 승자와 점수를 저장합니다. 한 수의 제한시간이 지나도 서버 시각을 기준으로 시간패가 결정됩니다.\n\n![오목 승리 결과와 자동 집계된 플레이어 순위](/img/docs/webspace/gomoku/realtime-gomoku-result.png)\n\n최근 대국과 순위가 즉시 바뀌지 않는다면 버튼을 다시 누르기보다 WebSocket의 종료 이벤트를 받은 뒤 목록을 다시 조회하는 흐름인지 확인하세요. 화면의 `개발 정보`를 펼치면 송수신 JSON과 서버 처리시간도 확인할 수 있습니다.\n\n## 여기서부터 내 게임 만들기\n\n`turn-based-board`는 오목이라는 이름에 고정된 처리기가 아닙니다. 스키마 파일의 처리기 설정에서 다음 값을 바꿔 다른 턴 기반 게임의 출발점으로 사용할 수 있습니다.\n\n| 설정              | 현재 값 | 의미                     |\n| ----------------- | ------: | ------------------------ |\n| `boardSize`       |      19 | 보드 한 변의 칸 수       |\n| `winLength`       |       5 | 승리에 필요한 연속 돌 수 |\n| `turnTimeSeconds` |     180 | 한 수의 제한시간         |\n| `winScore`        |       3 | 승리 점수                |\n| `drawScore`       |       1 | 무승부 점수              |\n| `lossScore`       |       0 | 패배 점수                |\n\n작은 보드의 빠른 게임으로 바꾸거나 점수 규칙을 조직 행사에 맞게 조정해 보세요. 같은 실시간 기반 위에 관전 화면, 시즌 순위와 팀 대전을 추가하는 것도 가능합니다.\n\n오목은 완성된 예제이면서 새 게임의 출발점입니다. 돌 대신 몬스터와 아이템을 표시하면 턴제 전투가 되고, 칸 대신 문제와 선택지를 보여 주면 실시간 퀴즈가 됩니다. 데이터와 규칙은 스키마에 두고, 화면에는 만들고 싶은 게임의 재미를 더해 보세요.\n\n## 문제가 생겼을 때\n\n| 증상                                  | 확인할 항목                                                               |\n| ------------------------------------- | ------------------------------------------------------------------------- |\n| 실시간 이벤트 처리기를 사용할 수 없음 | 서버가 현재 스키마의 `turn-based-board` 처리기를 지원하는 버전인지 확인   |\n| 새 대국이나 참가 버튼이 동작하지 않음 | DB 배포 상태, 실시간 기능, 로그인과 송수신 권한 확인                      |\n| `401 Unauthorized`                    | 로그인 세션이 유효한지 확인하고 URL 쿼리에 토큰을 직접 넣지 않았는지 확인 |\n| 운영 서버에서 WebSocket이 차단됨      | HTTPS 페이지가 `wss://`를 사용하고 CSP의 `connect-src`가 허용됐는지 확인  |\n| 수정한 화면이 이전 모습으로 보임      | 미리보기를 다시 열고 정적 파일의 최신 버전이 응답되는지 확인              |\n\n## 마치며\n\n정적 페이지 하나였던 첫 예제에서 시작해, 데이터베이스, 테이블 간 관계, 역할별 권한, 조직 밖에서 들어오는 파일 제출, 그리고 서버가 직접 판정하는 실시간 게임 상태까지 이어왔습니다. 각 예제는 이전 예제 위에 개념을 하나씩만 더하는 방식으로 구성했습니다. 필요한 기능에 따라 이 중 몇 가지를 조합하면, 대부분의 사내·대고객 도구를 WebSpace만으로 만들 수 있습니다.\n\n## 다음에 해볼 것\n\n- [API 빌드 및 데이터베이스 배포](../24.api-overview.md)\n- [성능과 확장](../48.performance.md)\n- [서비스 및 용량](../50.admin/40.service-capacity.md)\n",1789664768331]