{"title":"다중 테넌시 및 격리","slug":"multi-tenancy","category":"concepts","summary":"Synapse가 사용자와 마인드 간에 데이터를 격리하는 방식 — 보안 경계 설명.","audience":["human","llm"],"tags":["concept","multi-tenancy","security","isolation"],"difficulty":"intermediate","updated":"2026-06-27","word_count":490,"read_minutes":2,"lang":"ko","translated":true,"requested_lang":"ko","content_markdown":"\n# 다중 테넌시 및 격리\n\nSynapse는 다중 테넌트입니다: 여러 사용자, 각각 여러 마인드를 가지며,\n서로 완전히 격리되어 있습니다. 이 페이지에서는 격리 모델을 설명합니다.\n\n## 테넌트 계층 구조\n\n```\nSynapse Instance\n  │\n  ├── User Account 1 (email: alice@example.com)\n  │   ├── Mind A (Mind Key mk_aaa...)\n  │   │   ├── Memories (only accessible via mk_aaa...)\n  │   │   ├── Tasks\n  │   │   └── Chat\n  │   └── Mind B (Mind Key mk_bbb...)\n  │       └── ... (isolated from Mind A)\n  │\n  ├── User Account 2 (email: bob@example.com)\n  │   └── Mind C (Mind Key mk_ccc...)\n  │       └── ... (isolated from Alice's minds)\n  │\n  └── ... (more users)\n```\n\n## 격리 수준\n\n### 수준 1: 사용자 격리\n\n각 사용자 계정은 격리되어 있습니다. Alice는 다음을 할 수 없습니다:\n\n- Bob의 마인드 보기\n- Bob의 메모리 접근 (그녀의 JWT로도)\n- Bob의 계정 정보 나열\n\n강제 방법: 모든 테이블의 `user_id` 컬럼, JWT에 `user_id` 포함, 모든\n쿼리는 `user_id`로 필터링.\n\n### 수준 2: 마인드 격리\n\n사용자 내에서 각 마인드는 격리되어 있습니다. Mind A는 다음을 할 수 없습니다:\n\n- Mind B의 메모리 보기\n- Mind B의 작업, 채팅, 스크립트 접근\n\n강제 방법: 모든 데이터 테이블의 `mind_id` 컬럼, Mind Key에 `mind_id` 포함,\n모든 쿼리는 `mind_id`로 필터링.\n\n> [!CRITICAL]\n> Mind Key 격리는 기본 보안 경계입니다. 유출된 Mind Key는 해당 마인드의\n> 데이터에 대한 전체 접근 권한을 부여합니다 — 하지만 해당 마인드에만.\n\n## 인증 토큰\n\n| 토큰 | 범위 | 접근 가능한 것 |\n|-------|-------|-------------------|\n| Mind Key | 단일 마인드 | 해당 마인드의 데이터만 |\n| JWT | 사용자 계정 | 계정 관리 (마인드 생성/나열/삭제) |\n| Computer Token | 단일 컴퓨터 | 해당 컴퓨터의 명령 |\n\n## 마인드 간 접근\n\n### 동일 사용자 내\n\n사용자는 JWT를 통해 모든 마인드에 접근할 수 있습니다 (예: `GET /minds`가\n모두 나열). 하지만 메모리 데이터를 읽고/쓰려면 특정 Mind Key가 필요합니다.\n\n### 사용자 간\n\n사용자는 서로의 데이터에 접근할 수 없습니다 — Sharing API를 통해 명시적으로\n마인드를 공유하지 않는 한:\n\n```bash\n# Alice shares Mind A with Bob\ncurl -X POST https://synapse.schaefer.zone/sharing \\\n  -H \"Authorization: Bearer ALICE_JWT\" \\\n  -d '{\"mind_id\": \"m_aaa\", \"email\": \"bob@example.com\", \"role\": \"read\"}'\n```\n\n공유 후, Bob은 자신의 JWT를 통해 Mind A에 접근할 수 있습니다 (`role=read`인\n경우 읽기 전용).\n\n## 보안 경계\n\n```\n┌─────────────────────────────────────────────────┐\n│              Synapse Instance                    │\n│  ┌─────────────────────────────────────────┐    │\n│  │         User Account Boundary           │    │\n│  │  ┌──────────────┐  ┌──────────────┐    │    │\n│  │  │  Mind Bound. │  │  Mind Bound. │    │    │\n│  │  │  (Mind Key)  │  │  (Mind Key)  │    │    │\n│  │  │              │  │              │    │    │\n│  │  │  Memories    │  │  Memories    │    │    │\n│  │  │  Tasks       │  │  Tasks       │    │    │\n│  │  │  Chat        │  │  Chat        │    │    │\n│  │  │  Scripts     │  │  Scripts     │    │    │\n│  │  └──────────────┘  └──────────────┘    │    │\n│  └─────────────────────────────────────────┘    │\n└─────────────────────────────────────────────────┘\n```\n\n## 일반적인 다중 테넌시 패턴\n\n### 패턴 1: 단일 사용자, 단일 마인드\n\n개별 LLM 에이전트 사용자에게 가장 일반적입니다.\n\n- 1개 사용자 계정\n- 1개 마인드\n- 1개 Mind Key\n- 모든 메모리가 하나의 범위에\n\n### 패턴 2: 단일 사용자, 다중 마인드\n\n여러 컨텍스트 (업무, 개인, 프로젝트)를 가진 사용자용.\n\n- 1개 사용자 계정\n- N개 마인드 (예: \"work\", \"personal\", \"project-x\")\n- N개 Mind Key\n- 각 LLM 세션은 하나의 Mind Key 사용\n\n### 패턴 3: 팀 공유 마인드\n\n프로젝트에서 협업하는 팀용.\n\n- 1명의 사용자가 마인드 생성 (Mind Key 획득)\n- 생성자가 JWT를 통해 팀원과 공유\n- 모든 팀원이 JWT (또는 공유 Mind Key)로 접근\n\n> [!WARNING]\n> Mind Key 공유는 전체 읽기/쓰기 권한을 부여합니다. 팀 협업의 경우,\n> Mind Key를 직접 공유하기보다 Sharing API (JWT 기반)를 선호하십시오.\n\n### 패턴 4: SaaS 제공자\n\nSynapse를 메모리 계층으로 내장하는 앱용.\n\n- 각 고객 = 1개 사용자 계정\n- 각 고객 프로젝트 = 1개 마인드\n- 앱이 고객/프로젝트별 Mind Key 저장\n- 고객 간 전체 격리\n\n## 격리 검증\n\n### 테스트: Mind Key는 다른 마인드에 접근할 수 없음\n\n```bash\n# Mind A's key cannot read Mind B's memories\ncurl -H \"Authorization: Bearer mk_aaa...\" \\\n     \"https://synapse.schaefer.zone/memory/search?q=test\"\n# Returns only Mind A's memories\n\ncurl -H \"Authorization: Bearer mk_bbb...\" \\\n     \"https://synapse.schaefer.zone/memory/search?q=test\"\n# Returns only Mind B's memories (different results)\n```\n\n### 테스트: JWT는 메모리 데이터를 직접 읽을 수 없음\n\n```bash\n# JWT can list minds\ncurl -H \"Authorization: Bearer YOUR_JWT\" \\\n     https://synapse.schaefer.zone/minds\n# Returns: list of minds\n\n# JWT CANNOT read memories (need Mind Key)\ncurl -H \"Authorization: Bearer YOUR_JWT\" \\\n     https://synapse.schaefer.zone/memory/recall\n# Returns: 401 Unauthorized\n```\n\n## 모범 사례\n\n> [!TIP]\n> - **프로젝트/컨텍스트당 하나의 마인드 사용** — 격리가 도움입니다\n> - **Mind Key 절대 공유하지 않기** — Sharing API를 대신 사용\n> - **노출 시 Mind Key 교체** (마인드 삭제, 새로 생성)\n> - **공유 마인드 감사** — 정기적으로 `GET /sharing` 검토\n> - **human UI에 JWT 사용** — 최종 사용자에게 Mind Key 노출 금지\n\n## 다음 단계\n\n- [Authentication](/docs/getting-started/authentication)\n- [Mind Key vs JWT](/docs/getting-started/mind-key-vs-jwt)\n- [아키텍처](/docs/concepts/architecture)\n","content_html":"<h1>다중 테넌시 및 격리</h1>\n<p>Synapse는 다중 테넌트입니다: 여러 사용자, 각각 여러 마인드를 가지며,\n서로 완전히 격리되어 있습니다. 이 페이지에서는 격리 모델을 설명합니다.</p>\n<h2>테넌트 계층 구조</h2>\n<pre><code class=\"hljs language-plaintext\">Synapse Instance\n  │\n  ├── User Account 1 (email: alice@example.com)\n  │   ├── Mind A (Mind Key mk_aaa...)\n  │   │   ├── Memories (only accessible via mk_aaa...)\n  │   │   ├── Tasks\n  │   │   └── Chat\n  │   └── Mind B (Mind Key mk_bbb...)\n  │       └── ... (isolated from Mind A)\n  │\n  ├── User Account 2 (email: bob@example.com)\n  │   └── Mind C (Mind Key mk_ccc...)\n  │       └── ... (isolated from Alice&#x27;s minds)\n  │\n  └── ... (more users)</code></pre><h2>격리 수준</h2>\n<h3>수준 1: 사용자 격리</h3>\n<p>각 사용자 계정은 격리되어 있습니다. Alice는 다음을 할 수 없습니다:</p>\n<ul>\n<li>Bob의 마인드 보기</li>\n<li>Bob의 메모리 접근 (그녀의 JWT로도)</li>\n<li>Bob의 계정 정보 나열</li>\n</ul>\n<p>강제 방법: 모든 테이블의 <code>user_id</code> 컬럼, JWT에 <code>user_id</code> 포함, 모든\n쿼리는 <code>user_id</code>로 필터링.</p>\n<h3>수준 2: 마인드 격리</h3>\n<p>사용자 내에서 각 마인드는 격리되어 있습니다. Mind A는 다음을 할 수 없습니다:</p>\n<ul>\n<li>Mind B의 메모리 보기</li>\n<li>Mind B의 작업, 채팅, 스크립트 접근</li>\n</ul>\n<p>강제 방법: 모든 데이터 테이블의 <code>mind_id</code> 컬럼, Mind Key에 <code>mind_id</code> 포함,\n모든 쿼리는 <code>mind_id</code>로 필터링.</p>\n<div class=\"callout callout-critical\">Mind Key 격리는 기본 보안 경계입니다. 유출된 Mind Key는 해당 마인드의\n데이터에 대한 전체 접근 권한을 부여합니다 — 하지만 해당 마인드에만.</div><h2>인증 토큰</h2>\n<table>\n<thead>\n<tr>\n<th>토큰</th>\n<th>범위</th>\n<th>접근 가능한 것</th>\n</tr>\n</thead>\n<tbody><tr>\n<td>Mind Key</td>\n<td>단일 마인드</td>\n<td>해당 마인드의 데이터만</td>\n</tr>\n<tr>\n<td>JWT</td>\n<td>사용자 계정</td>\n<td>계정 관리 (마인드 생성/나열/삭제)</td>\n</tr>\n<tr>\n<td>Computer Token</td>\n<td>단일 컴퓨터</td>\n<td>해당 컴퓨터의 명령</td>\n</tr>\n</tbody></table>\n<h2>마인드 간 접근</h2>\n<h3>동일 사용자 내</h3>\n<p>사용자는 JWT를 통해 모든 마인드에 접근할 수 있습니다 (예: <code>GET /minds</code>가\n모두 나열). 하지만 메모리 데이터를 읽고/쓰려면 특정 Mind Key가 필요합니다.</p>\n<h3>사용자 간</h3>\n<p>사용자는 서로의 데이터에 접근할 수 없습니다 — Sharing API를 통해 명시적으로\n마인드를 공유하지 않는 한:</p>\n<pre><code class=\"hljs language-bash\"><span class=\"hljs-comment\"># Alice shares Mind A with Bob</span>\ncurl -X POST https://synapse.schaefer.zone/sharing \\\n  -H <span class=\"hljs-string\">&quot;Authorization: Bearer ALICE_JWT&quot;</span> \\\n  -d <span class=\"hljs-string\">&#x27;{&quot;mind_id&quot;: &quot;m_aaa&quot;, &quot;email&quot;: &quot;bob@example.com&quot;, &quot;role&quot;: &quot;read&quot;}&#x27;</span></code></pre><p>공유 후, Bob은 자신의 JWT를 통해 Mind A에 접근할 수 있습니다 (<code>role=read</code>인\n경우 읽기 전용).</p>\n<h2>보안 경계</h2>\n<pre><code class=\"hljs language-plaintext\">┌─────────────────────────────────────────────────┐\n│              Synapse Instance                    │\n│  ┌─────────────────────────────────────────┐    │\n│  │         User Account Boundary           │    │\n│  │  ┌──────────────┐  ┌──────────────┐    │    │\n│  │  │  Mind Bound. │  │  Mind Bound. │    │    │\n│  │  │  (Mind Key)  │  │  (Mind Key)  │    │    │\n│  │  │              │  │              │    │    │\n│  │  │  Memories    │  │  Memories    │    │    │\n│  │  │  Tasks       │  │  Tasks       │    │    │\n│  │  │  Chat        │  │  Chat        │    │    │\n│  │  │  Scripts     │  │  Scripts     │    │    │\n│  │  └──────────────┘  └──────────────┘    │    │\n│  └─────────────────────────────────────────┘    │\n└─────────────────────────────────────────────────┘</code></pre><h2>일반적인 다중 테넌시 패턴</h2>\n<h3>패턴 1: 단일 사용자, 단일 마인드</h3>\n<p>개별 LLM 에이전트 사용자에게 가장 일반적입니다.</p>\n<ul>\n<li>1개 사용자 계정</li>\n<li>1개 마인드</li>\n<li>1개 Mind Key</li>\n<li>모든 메모리가 하나의 범위에</li>\n</ul>\n<h3>패턴 2: 단일 사용자, 다중 마인드</h3>\n<p>여러 컨텍스트 (업무, 개인, 프로젝트)를 가진 사용자용.</p>\n<ul>\n<li>1개 사용자 계정</li>\n<li>N개 마인드 (예: &quot;work&quot;, &quot;personal&quot;, &quot;project-x&quot;)</li>\n<li>N개 Mind Key</li>\n<li>각 LLM 세션은 하나의 Mind Key 사용</li>\n</ul>\n<h3>패턴 3: 팀 공유 마인드</h3>\n<p>프로젝트에서 협업하는 팀용.</p>\n<ul>\n<li>1명의 사용자가 마인드 생성 (Mind Key 획득)</li>\n<li>생성자가 JWT를 통해 팀원과 공유</li>\n<li>모든 팀원이 JWT (또는 공유 Mind Key)로 접근</li>\n</ul>\n<div class=\"callout callout-warn\">Mind Key 공유는 전체 읽기/쓰기 권한을 부여합니다. 팀 협업의 경우,\nMind Key를 직접 공유하기보다 Sharing API (JWT 기반)를 선호하십시오.</div><h3>패턴 4: SaaS 제공자</h3>\n<p>Synapse를 메모리 계층으로 내장하는 앱용.</p>\n<ul>\n<li>각 고객 = 1개 사용자 계정</li>\n<li>각 고객 프로젝트 = 1개 마인드</li>\n<li>앱이 고객/프로젝트별 Mind Key 저장</li>\n<li>고객 간 전체 격리</li>\n</ul>\n<h2>격리 검증</h2>\n<h3>테스트: Mind Key는 다른 마인드에 접근할 수 없음</h3>\n<pre><code class=\"hljs language-bash\"><span class=\"hljs-comment\"># Mind A&#x27;s key cannot read Mind B&#x27;s memories</span>\ncurl -H <span class=\"hljs-string\">&quot;Authorization: Bearer mk_aaa...&quot;</span> \\\n     <span class=\"hljs-string\">&quot;https://synapse.schaefer.zone/memory/search?q=test&quot;</span>\n<span class=\"hljs-comment\"># Returns only Mind A&#x27;s memories</span>\n\ncurl -H <span class=\"hljs-string\">&quot;Authorization: Bearer mk_bbb...&quot;</span> \\\n     <span class=\"hljs-string\">&quot;https://synapse.schaefer.zone/memory/search?q=test&quot;</span>\n<span class=\"hljs-comment\"># Returns only Mind B&#x27;s memories (different results)</span></code></pre><h3>테스트: JWT는 메모리 데이터를 직접 읽을 수 없음</h3>\n<pre><code class=\"hljs language-bash\"><span class=\"hljs-comment\"># JWT can list minds</span>\ncurl -H <span class=\"hljs-string\">&quot;Authorization: Bearer YOUR_JWT&quot;</span> \\\n     https://synapse.schaefer.zone/minds\n<span class=\"hljs-comment\"># Returns: list of minds</span>\n\n<span class=\"hljs-comment\"># JWT CANNOT read memories (need Mind Key)</span>\ncurl -H <span class=\"hljs-string\">&quot;Authorization: Bearer YOUR_JWT&quot;</span> \\\n     https://synapse.schaefer.zone/memory/recall\n<span class=\"hljs-comment\"># Returns: 401 Unauthorized</span></code></pre><h2>모범 사례</h2>\n<div class=\"callout callout-ok\"></div><h2>다음 단계</h2>\n<ul>\n<li><a href=\"/docs/getting-started/authentication\">Authentication</a></li>\n<li><a href=\"/docs/getting-started/mind-key-vs-jwt\">Mind Key vs JWT</a></li>\n<li><a href=\"/docs/concepts/architecture\">아키텍처</a></li>\n</ul>\n","urls":{"html":"/docs/concepts/multi-tenancy","text":"/docs/concepts/multi-tenancy?format=text","json":"/docs/concepts/multi-tenancy?format=json","llm":"/docs/concepts/multi-tenancy?format=llm"},"translations_available":["en","zh","hi","es","fr","ar","pt","ru","ja","de","it","ko","nl","pl","tr","sv","vi","th","id","uk"]}