Files
AIclinicalresearch/docs/03-业务模块/ADMIN-运营管理端/00-系统设计/00-权限与角色体系梳理报告_v1.0.md
HaHafeng 1b53ab9d52 feat(aia): Complete AIA V2.0 with universal streaming capabilities
Major Changes:
- Add StreamingService with OpenAI Compatible format
- Upgrade Chat component V2 with Ant Design X integration
- Implement AIA module with 12 intelligent agents
- Update API routes to unified /api/v1 prefix
- Update system documentation

Backend (~1300 lines):
- common/streaming: OpenAI Compatible adapter
- modules/aia: 12 agents, conversation service, streaming integration
- Update route versions (RVW, PKB to v1)

Frontend (~3500 lines):
- modules/aia: AgentHub + ChatWorkspace (100% prototype restoration)
- shared/Chat: AIStreamChat, ThinkingBlock, useAIStream Hook
- Update API endpoints to v1

Documentation:
- AIA module status guide
- Universal capabilities catalog
- System overview updates
- All module documentation sync

Tested: Stream response verified, authentication working
Status: AIA V2.0 core completed (85%)
2026-01-14 19:15:01 +08:00

1383 lines
40 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# **AIclinicalresearch 譚<>剞荳手ァ定牡菴鍋ウサ譴ウ逅<EFBDB3>冠蜻?*
> **譁<>。」迚域悽<E59F9F>?* v1.1<EFBFBD>域紛蜷<EFBFBD>rompt邂。逅<EFBFBD>怙豎ゑシ<EFBFBD>
> **蛻帛サコ譌・譛滂シ?* 2026-01-11
> **譛€蜷取峩譁ー<E8AD81><EFBDB0>** 2026-01-11
> **菴懆€<E68786><EFBFBD>** AI譫カ譫<EFBDB6>ク?
> **逶ョ逧<EFBDAE>シ?* 邉サ扈滓€ァ譴ウ逅<EFBDB3>ス灘燕譚<E78795>剞螳樒鴫迥カ蜀オ<E89C80>御クコ霑占是邂。逅<EFBDA1>ォッ蜥梧惻譫<E683BB>ョ。逅<EFBDA1>ォッ蠑€蜿大★蜃<E29885><EFBFBD>
> **蜿俶峩隸エ譏趣シ?* 謨エ蜷亥渚鬥亥サコ隶ョ + Prompt邂。逅<EFBDA1>ウサ扈滄怙豎?
---
## <20>搭 逶ョ蠖<EFBDAE>
1. [蠖灘燕邉サ扈溽憾諤∝<E8ABA4>譫疹(#1-蠖灘燕邉サ扈溽憾諤∝<E8ABA4>譫?
2. [謨ー謐ョ蠎灘アる擇譴ウ逅<EFBDB3>(#2-謨ー謐ョ蠎灘アる擇譴ウ逅?
3. [蜷守ォッ譚<EFBDAF>剞螳樒鴫譴ウ逅<EFBDB3>(#3-蜷守ォッ譚<EFBDAF>剞螳樒鴫譴ウ逅<EFBDB3>)
4. [蜑咲ォッ譚<EFBDAF>剞螳樒鴫譴ウ逅<EFBDB3>(#4-蜑咲ォッ譚<EFBDAF>剞螳樒鴫譴ウ逅<EFBDB3>)
5. [蟾ョ霍晏<E99C8D>譫疹(#5-蟾ョ霍晏<E99C8D><EFBFBD>)
6. [譁ーPRD髴€豎りァ」隸サ](#6-譁ーprd髴€豎りァ」隸?
7. [譫カ譫<EFBFBD>ョセ隶。蟒コ隶ョ](#7-譫カ譫<EFBDB6>ョセ隶。蟒コ隶ョ)
8. [螳樊命霍ッ郤ソ蝗セ](#8-螳樊命霍ッ郤ソ蝗?
9. [<5B><> Prompt邂。逅<EFBDA1>ウサ扈滓紛蜷<E7B49B>(#9-prompt邂。逅<EFBDA1>ウサ扈滓紛蜷<E7B49B>)
10. [<5B><> 蜿埼ヲ磯㊦郤ウ隸エ譏讃(#10-蜿埼ヲ磯㊦郤ウ隸エ譏<EFBDB4>)
---
## 1. 蠖灘燕邉サ扈溽憾諤∝<E8ABA4>譫?
### 1.1 譬ク蠢<EFBDB8>書邇ー <20>
**笨?蟾イ譛牙渕遑€**<EFBFBD>?
- 謨ー謐ョ蠎捺怏蝓コ遑€逧Фser陦ィ<E999A6><EFBDA8>platform_schema.users` 蜥?`public.users`荳、荳ェ迚域悽<E59F9F>?
- 譛牙渕譛ャ逧вole蟄玲ョオ<EFBDAE>磯サ倩ョ、蛟シ<E89B9F><EFBDBC>"user"<22>?
- 蜑咲ォッ譛画揀髯先。<E58588><EFBFBD><E6A594>PermissionContext`<60>会シ御ス?*莉<>ock謨ー謐ョ**
- 蜷守ォッ**螳悟<E89EB3>豐。譛芽ョ、隸<EFBDA4>/謗域揀邉サ扈<EFBDBB>**
**笶?郛コ螟ア蜈ウ髞ョ閭ス蜉<EFBDBD>**<EFBFBD>?
1. **豐。譛臥匳蠖<E58CB3>/豕ィ蜀窟PI**
2. **豐。譛雨WT隶、隸∽クュ髣エ莉?*
3. **豐。譛臥ァ滓姐(Tenant)菴鍋ウサ**
4. **豐。譛芽ァ定牡譚<E789A1>剞邉サ扈<EFBDBB>(RBAC)**
5. **豐。譛宇eature Flag謗ァ蛻カ**
6. **豐。譛牙ョ。隶。譌・蠢礼ウサ扈<EFBDBB>**
**<EFBFBD>識 蠖灘燕迥カ諤?*<2A>?
- 邉サ扈溷、<E6BAB7><EFBFBD>**蜊墓オ玖ッ戊エヲ蜿?*髦カ谿オ
-€譛陰PI驛ス譏ッ**譌<>隶、隸√€∵裏驩エ譚<EFBDB4>**迥カ諤?
- 蜑咲ォッ譚<EFBDAF>剞謗ァ蛻カ譏?*郤ッ螻慕、コ諤?*逧<>ock螳樒鴫
---
## 2. 謨ー謐ョ蠎灘アる擇譴ウ逅?
### 2.1 蠖灘燕User陦ィ扈捺<E68988>?
#### **platform_schema.users** 笨?譁ー譫カ譫<EFBDB6><EFBFBD>risma螳壻ケ会シ?
```prisma
model User {
id String @id @default(uuid())
email String @unique
password String
name String?
avatarUrl String? @map("avatar_url")
role String @default("user") // 笞<><E7AC9E><EFBFBD>€蜊募ュ礼ャヲ荳イ<E88DB3>御ク榊、溽畑
status String @default("active")
kbQuota Int @default(3)
kbUsed Int @default(0)
trialEndsAt DateTime? @map("trial_ends_at")
isTrial Boolean @default(true)
lastLoginAt DateTime? @map("last_login_at")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@schema("platform_schema")
}
```
#### **public.users** 笶?譌ァ陦ィ<E999A6>亥紙蜿イ驕礼蕗<E7A4BC><E89597>
```prisma
model users {
id String
email String @unique
password String
name String?
avatar_url String?
role String @default("user") // 笞<><E7AC9E><EFBFBD> 蜷梧<E89CB7>キ邂€蜊?
status String @default("active")
kb_quota Int @default(3)
kb_used Int @default(0)
// ... 蜈カ莉門ュ玲ョオ
@@schema("public")
}
```
**笞<><E7AC9E><EFBFBD> 髣ョ鬚假シ?*
- 荳、荳ェUser陦ィ蟷カ蟄假シ悟多蜷堺ク堺ク€閾エ<E996BE><EFBDB4>sers vs User<65>?
- `role`蟄玲ョオ莉<EFBFBD>クコ蟄礼ャヲ荳イ<EFBFBD>梧裏enum郤ヲ譚<EFBFBD>
- **豐。譛臥ァ滓姐蜈ウ閨泌ュ玲ョオ<EFBDAE><EFBDB5>enantId<49>?*
- **豐。譛蛾Κ髣ィ蟄玲ョオ<EFBDAE><EFBDB5>epartment<6E>?*
- **豐。譛画揀髯宣<E9ABAF>鄂ョ蟄玲ョオ**
### 2.2 郛コ螟ア逧<EFBDB1><E980A7>ク蠢<EFBDB8>。ィ
譬ケ謐ョPRD髴€豎ゑシ碁怙隕∵眠蠅樔サ・荳玖。ィ<EFBFBD>?
| 陦ィ蜷<EFBDA8> | Schema菴咲スョ | 逕ィ騾?| 莨伜<E88EA8>郤?|
|------|-----------|------|--------|
| **tenants** | platform_schema | 遘滓姐荳サ陦ィ<E999A6>亥現髯「縲∬艮莨√€∵悄蛻奇シ<E5A587> | P0 |
| **tenant_users** | platform_schema | 遘滓姐-逕ィ謌キ蜈ウ閨碑。?| P0 |
| **departments** | platform_schema | 驛ィ髣ィ/遘大ョ、陦?| P1 |
| **feature_flags** | platform_schema | Feature Flag驟咲スョ | P0 |
| **tenant_modules** | platform_schema | 遘滓姐隶「髦<EFBDA2>ィ。蝮鈴<E89DAE>鄂ョ | P0 |
| **tenant_quotas** | platform_schema | 遘滓姐驟埼「晉ョ。逅<EFBDA1> | P1 |
| **admin_operation_logs** | admin_schema | 霑占是謫堺ス懈律蠢<E5BE8B> | P1 |
**豕ィ諢擾シ?* 蠖灘燕譛我ク€荳ェ`AdminLog`陦ィ蝨ィ`public`schema<EFBFBD>御ス<EFBFBD>ク榊ョ梧紛縲?
### 2.3 蟾イ譛臥噪螳。隶。譌・蠢?
**IIT讓。蝮礼噪螳。隶。譌・蠢?* 笨?<3F>亥庄蜿り€<E3828A>シ会シ?
```prisma
model IitAuditLog {
id String @id @default(uuid())
projectId String
userId String
actionType String
entityType String
entityId String
details Json?
traceId String
createdAt DateTime @default(now())
@@schema("iit_schema")
}
```
**蜿ッ螟咲畑諤ァ<E8ABA4><EFBDA7>** 笨?譫カ譫<EFBDB6>ョセ隶。莨倡ァ€<EFBDA7>悟庄菴應クコ蜈ィ螻€螳。隶。譌・蠢礼噪蜿り€<E3828A>€?
---
## 3. 蜷守ォッ譚<EFBDAF>剞螳樒鴫譴ウ逅<EFBDB3>
### 3.1 隶、隸∫ウサ扈溽憾諤?笶?**譛ェ螳樒<E89EB3>?*
**謳懃エ「扈捺棡<E68DBA>?*
- 笶?豐。譛画伽蛻ー `/api/auth/login` 謌?`/api/auth/register`
- 笶?豐。譛雨WT逕滓<E98095>/鬪瑚ッ∝キ・蜈キ
- 笶?豐。譛芽ョ、隸∽クュ髣エ莉カ<E88E89>亥ヲ?`requireAuth`<EFBFBD>?
**蟇ケ豈泌<E8B188>莉夜。ケ逶ョ**<EFBFBD>井サ残odebase_search扈捺棡<EFBFBD>会シ<EFBFBD>
- ODJ鬘ケ逶ョ譛牙ョ梧紛逧Пassport JWT隶、隸<EFBDA4> 笨?
- BYSY鬘ケ逶ョ譛雨WT隶、隸∽クュ髣エ莉?笨?
- **譛ャ鬘ケ逶ョ<E980B6>壼ョ悟<EFBDAE>遨コ逋ス** 笶?
### 3.2 謗域揀邉サ扈溽憾諤?笶?**譛ェ螳樒<E89EB3>?*
**郛コ螟ア蜀<EFBDB1>ョケ<EFBDAE>?*
- 笶?豐。譛芽ァ定牡譽€譟・荳ュ髣エ莉カ<E88E89>亥ヲ<E4BAA5> `requireRole(['admin'])`<EFBFBD>?
- 笶?豐。譛画揀髯先丐蟆<E4B890>。ィ<EFBDA1><EFBDA8>OLE_PERMISSIONS<4E>?
- 笶?豐。譛宇eature Flag譽€譟・騾サ霎<EFBDBB>
**蠖ア蜩搾シ?*
-€譛陰PI遶ッ轤ケ驛ス譏ッ蜈ャ蠑€<C280>シ梧裏譚<E8A38F>剞菫晄<E88FAB>?
-<>豕募玄蛻<E78E84>ョ。逅<EFBDA1>遭蜥梧勸騾夂畑謌?
-<>豕募ョ樒鴫螟夂ァ滓姐謨ー謐ョ髫皮ヲ?
### 3.3 蠖灘燕API扈捺桷
**Legacy Routes** (譌<>隶、隸?<3F>?
```
/api/v1/aia/* - AI譎コ閭ス髣ョ遲費シ域裏譚<E8A38F>剞譽€譟・<E8AD9F><EFBDA5>
/api/v1/pkb/* - 荳ェ莠コ遏・隸<EFBDA5>コ難シ域裏譚<E8A38F>剞譽€譟・<E8AD9F><EFBDA5>
/api/v1/rvw/* - 遞ソ莉カ螳。譟・<E8AD9F>域裏譚<E8A38F>剞譽€譟・<E8AD9F><EFBDA5>
```
**髣ョ鬚假シ?*
- 莉サ菴穂ココ驛ス蜿ッ莉・隶ソ髣ョ莉サ菴慕畑謌キ逧<EFBDB7>焚謐?
- 豐。譛<EFBDA1> `userId` 驩エ譚<EFBDB4>€サ霎<EFBDBB>
- 豐。譛臥ァ滓姐謨ー謐ョ髫皮ヲサ
---
## 4. 蜑咲ォッ譚<EFBDAF>剞螳樒鴫譴ウ逅<EFBDB3>
### 4.1 譚<>剞譯<E5899E>楔蟄伜惠 笨?菴<><EFBFBD>クコMock
**譁<>サカ菴咲スョ<EFBDBD>?* `frontend-v2/src/framework/permission/PermissionContext.tsx`
**譬ク蠢<EFBDB8>サ」遐<EFBDA3>シ?*
```typescript
// 笞<><E7AC9E><EFBFBD> 遑ャ郛也<E9839B>∽クコ譛€鬮俶揀髯撰シ御サ<E5BEA1>セ帛シ€蜿第オ玖ッ?
const MOCK_USER: UserInfo = {
id: 'test-user-001',
name: '豬玖ッ慕<EFBDAF>皮ゥカ蜻?,
email: 'test@example.com',
version: 'premium', // <20>争 遑ャ郛也<E9839B>?
avatar: null,
isTrial: false,
}
// 譚<>剞譽€譟・蜃ス謨ー<E8ACA8>亥渕莠散serVersion遲臥コァ<EFBDBA>?
const checkModulePermission = (requiredVersion?: UserVersion): boolean => {
if (!user) return false
if (!requiredVersion) return true
return checkVersionLevel(user.version, requiredVersion)
}
```
**UserVersion螳壻ケ会シ?*
```typescript
// framework/permission/types.ts
export type UserVersion = 'free' | 'basic' | 'professional' | 'premium'
```
### 4.2 譚<>剞譽€譟・騾サ霎<EFBDBB> 笨?譫カ譫<EFBDB6>ョ梧紛
**讓。蝮玲ウィ蜀梧慮逧<E685AE>揀髯仙」ー譏趣シ?*
```typescript
// 讓。蝮怜ョ壻ケ画磁蜿」
interface ModuleDefinition {
id: string
name: string
path: string
requiredVersion?: UserVersion // <20>識 譚<>剞隕∵ア<E288B5>
// ...
}
```
**霍ッ逕ア螳亥梱<E4BAA5>?*
```typescript
// RouteGuard.tsx
if (module.requiredVersion && !checkModulePermission(module.requiredVersion)) {
return <PermissionDenied />
}
```
**笨?莨倡せ<E580A1>?*
-<>剞譯<E5899E>楔隶セ隶。螳悟埋
- 譏謎コ取黄螻募芦逵溷ョ櫁ョ、隸?
**笶?郛コ轤ケ<E8BDA4>?*
- 逕ィ謌キ菫。諱ッ螳悟<E89EB3>hardcode
- 豐。譛牙ッケ謗・蜷守ォッAPI
- 豐。譛臥匳蠖<E58CB3>/逋サ蜃コUI
---
## 5. 蟾ョ霍晏<E99C8D><EFBFBD>
### 5.1 荳傘RD髴€豎ら噪蟾ョ霍<EFBDAE>
| PRD髴€豎?| 蠖灘燕迥カ諤?| 蟾ョ霍<EFBDAE> | 莨伜<E88EA8>郤?|
|---------|---------|------|--------|
| **遘滓姐邂。逅<EFBDA1>** | 笶?譌?| 髴€螳梧紛螳樒鴫Tenant菴鍋ウサ | P0 |
| **4遘崎ァ定<EFBDA7>?* (SUPER_ADMIN/HOSPITAL_ADMIN/PHARMA_ADMIN/USER) | 笶?蜿ェ譛臥ョ€蜊瓶ole蟄礼ャヲ荳?| 髴€RBAC菴鍋ウサ | P0 |
| **蜩∫煙螳壼宛** (Logo/逋サ蠖暮。? | 笶?譌?| 髴€tenant.config JSONB蟄玲ョオ | P0 |
| **逋サ蠖慕ウサ扈<EFBDBB>** | 笶?譌?| 髴€JWT隶、隸∫ウサ扈<EFBDBB> | P0 |
| **譚<>剞謗ァ蛻カ** | 笨?蜑咲ォッMock / 笶?蜷守ォッ譌?| 髴€蜷守ォッ荳ュ髣エ莉?| P0 |
| **Feature Flag** | 笶?譌?| 髴€驟咲スョ陦?譽€譟・騾サ霎<EFBDBB> | P0 |
| **霑占是遶?* (/admin/*) | 笶?譌?| 髴€蜈ィ譁ー蠑€蜿?| P0 |
| **譛コ譫<EFBDBA>ォ?* (/org/hospital/*, /org/pharma/*) | 笶?譌?| 髴€蜈ィ譁ー蠑€蜿?| P1 |
| **螳。隶。譌・蠢<EFBDA5>** | 笞<><E7AC9E><EFBFBD><>IT讓。蝮<EFBDA1> | 髴€蜈ィ螻€螳。隶。邉サ扈<EFBDBB> | P1 |
### 5.2 譫カ譫<EFBDB6>アる擇蟾ョ霍<EFBDAE>
**蠖灘燕譫カ譫<EFBDB6>シ?* 蜊慕畑謌キ縲∵裏遘滓姐縲∵裏譚<E8A38F>
```
User (蜊戊。ィ)
竊?
Projects/KnowledgeBases/... (逶エ謗・蜈ウ閨<EFBDB3> userId)
```
**逶ョ譬<EFBDAE>楔譫<E6A594>シ?* 螟夂ァ滓姐縲ヽBAC縲∵焚謐ョ髫皮ヲ?
```
Tenant (遘滓姐)
竊?
Department (驛ィ髣ィ/遘大ョ、)
竊?
User (逕ィ謌キ) + Role (隗定牡)
竊?
Projects/KnowledgeBases/... (tenant_id + user_id)
```
---
## 6. 譁ーPRD髴€豎りァ」隸?
### 6.1 譬ク蠢<EFBDB8>ァ定牡螳壻ケ会シ域擂閾ェPRD v2.1<EFBFBD>?
| 隗定牡Code | 蠖貞ア<E8B29E> | 譚<>剞闌<E5899E>峩 | URL蜑咲シ€ | 譬ク蠢<EFBDB8>雍」 |
|---------|------|---------|---------|---------|
| **SUPER_ADMIN** | 蟷ウ蜿ー | 蜈ィ螻€謨ー謐ョ | /admin | 遘滓姐蠑€騾壹€∝刀迚碁<E8BF9A>鄂ョ縲 ̄rompt隹<74><EFBFBD> |
| **HOSPITAL_ADMIN** | 蛹サ髯「遘滓姐 | 譛ャ髯「謨ー謐ョ | /org/hospital | 遘大ョ、邂。逅<EFBDA1>€<EFBFBD><C280>鬚晏<E9AC9A>驟?|
| **PHARMA_ADMIN** | 闕ッ莨∫ァ滓姐 | 譛ャ莨<EFBDAC>。ケ逶ョ | /org/pharma | 鬘ケ逶ョ逶第而縲RO邂。逅<EFBDA1>€∝ョ。隶?|
| **USER** | 莉サ諢冗ァ滓姐 | 荳ェ莠コ/陲ォ謗域揀謨ー謐?| /app | 遘醍<E98198>比ク壼苅謫堺ス<E5A0BA> |
### 6.2 遘滓姐邀サ蝙具シ<E585B7>enant Type<70>?
```typescript
enum TenantType {
HOSPITAL = 'HOSPITAL', // 蛹サ髯「螳「謌キ
PHARMA = 'PHARMA', // 闕ッ莨∝ョ「謌キ
JOURNAL = 'JOURNAL', // 譛溷<E8AD9B>螳「謌キ
}
```
### 6.3 蜩∫煙螳壼宛髴€豎?<3F><>
**URL遲也払<E4B99F>?*
```
騾夂畑逋サ蠖包シ喇ttps://app.yizhengxun.com/auth/login
荳灘ア樒匳蠖包シ喇ttps://app.yizhengxun.com/t/{tenant_code}/login
```
**遘滓姐驟咲スョ<EFBDBD><EFBDAE>SONB<4E>会シ<E4BC9A>**
```json
{
"branding": {
"logoUrl": "https://oss.../jst_logo.png",
"loginBackgroundUrl": "https://oss.../jst_bldg.jpg",
"primaryColor": "#0056b3",
"welcomeTitle": "蛹嶺コャ遘ッ豌エ貎ュ蛹サ髯?AI 荳エ蠎顔ァ醍<EFBDA7>泌ケウ蜿ー",
"welcomeSubTitle": "? <EFBFBD>? ?
}
}
```
### 6.4 譎コ閭ス霍ッ逕ア蛻<EFBDB1><EFBFBD>育匳蠖募錘霍ウ霓ャ<E99C93>?
```typescript
function getRedirectPath(user, tenant) {
if (user.role === 'SUPER_ADMIN') return '/admin/dashboard';
if (user.role === 'TENANT_ADMIN') {
if (tenant.type === 'HOSPITAL') return '/org/hospital/dashboard';
if (tenant.type === 'PHARMA') return '/org/pharma/dashboard';
}
if (tenant.type === 'JOURNAL') return '/app/rvw/dashboard';
return '/app/dashboard'; // 鮟倩ョ、<EFBDAE>壽勸騾夂畑謌?
}
```
---
## 7. 譫カ譫<EFBDB6>ョセ隶。蟒コ隶ョ
### 7.1 謨ー謐ョ蠎鉄chema隶セ隶。
#### **7.1.1 platform_schema<6D>亥ケウ蜿ー譬ク蠢<EFBDB8>。ィ<EFBDA1>?*
**A. tenants 陦?* <20><>0<EFBFBD>?
```prisma
model Tenant {
id String @id @default(uuid())
name String // 遘滓姐蜷咲ァー<EFBDA7>亥ヲゑシ壼圏莠ャ遘ッ豌エ貎ュ蛹サ髯「<E9ABAF>?
code String @unique // 遘滓姐莉」遐<EFBDA3>シ亥ヲゑシ嗚st-hospital<61>檎畑莠散RL<52>?
type TenantType // 遘滓姐邀サ蝙具シ唏OSPITAL/PHARMA/JOURNAL
status String @default("active") // active/suspended/expired
// 蜩∫煙驟咲スョ<EFBDBD><EFBDAE>SONB<4E>?
config Json @default("{}") // branding驟咲スョ縲∵ィ。蝮苓ョ「髦<EFBDA2><EFBFBD>
// 驟埼「晉ョ。逅<EFBDA1>
tokenQuota Int? // 諤サToken鬚晏コヲ
tokenUsed Int @default(0) // 蟾イ菴ソ逕ィToken
// 譌カ髣エ謌?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
expiresAt DateTime? // 隶「髦<EFBDA2>芦譛滓慮髣エ
// 蜈ウ邉サ
users TenantUser[]
departments Department[]
modules TenantModule[]
@@index([code])
@@index([type])
@@index([status])
@@map("tenants")
@@schema("platform_schema")
}
enum TenantType {
HOSPITAL
PHARMA
JOURNAL
@@schema("platform_schema")
}
```
**B. users 陦ィ謇ゥ螻?* <20><>0<EFBFBD>?
```prisma
model User {
id String @id @default(uuid())
email String @unique
password String
name String?
avatarUrl String? @map("avatar_url")
// <20><> 螟夂ァ滓姐謾ッ謖?
tenantId String? @map("tenant_id") // 謇€螻樒ァ滓姐<E6BB93><E5A790>ULL=蟷ウ蜿ー邂。逅<EFBDA1><EFBFBD><E981AD>
departmentId String? @map("department_id") // 謇€螻樣Κ髣?遘大ョ、
// <20><> 隗定牡邉サ扈<EFBDBB>
role UserRole // SUPER_ADMIN/TENANT_ADMIN/USER
// 蜈カ莉門ュ玲ョオ菫晄戟荳榊序...
status String @default("active")
kbQuota Int @default(3)
trialEndsAt DateTime?
lastLoginAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// 蜈ウ邉サ
tenant Tenant? @relation(fields: [tenantId], references: [id])
department Department? @relation(fields: [departmentId], references: [id])
@@index([tenantId])
@@index([departmentId])
@@index([role])
@@map("users")
@@schema("platform_schema")
}
enum UserRole {
SUPER_ADMIN // 蟷ウ蜿ー雜<EFBDB0>コァ邂。逅<EFBDA1><E98085>?
TENANT_ADMIN // 遘滓姐邂。逅<EFBDA1><EFBFBD>亥現髯「/闕ッ莨<EFBDAF>シ?
USER // 譎ョ騾夂畑謌キ<E8AC8C>亥現逕<E78FBE>/遐皮ゥカ蜻假シ<E58187>
@@schema("platform_schema")
}
```
**C. tenant_members 陦?* <20><>0<EFBFBD>俄恟<E4BF84>?驥<>コウ蜿埼ヲ茨シ壽隼蜷堺クコTenantMember
```prisma
model TenantMember {
id String @id @default(uuid())
tenantId String @map("tenant_id")
userId String @map("user_id")
role String // 蝨ィ隸・遘滓姐荳ュ逧<EFBDAD>ァ定牡
joinedAt DateTime @default(now()) @map("joined_at")
tenant Tenant @relation(fields: [tenantId], references: [id])
@@unique([tenantId, userId])
@@map("tenant_members") // 隸ュ荵画峩貂<E5B3A9><E8B282>?
@@schema("platform_schema")
}
```
**D. departments 陦?* <20><>1<EFBFBD>?
```prisma
model Department {
id String @id @default(uuid())
tenantId String @map("tenant_id")
name String // 遘大ョ、蜷咲ァー<EFBDA7>亥ヲゑシ壼ソ<E5A3BC><EFBDBF>遘托シ?
parentId String? @map("parent_id") // 荳顔コァ遘大ョ、<EFBDAE>域髪謖∵<E8AC96>大ス「扈捺桷<E68DBA><E6A1B7>
tokenQuota Int? @map("token_quota") // 遘大ョ、Token鬚晏コヲ
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
tenant Tenant @relation(fields: [tenantId], references: [id])
users User[]
parent Department? @relation("DepartmentHierarchy", fields: [parentId], references: [id])
children Department[] @relation("DepartmentHierarchy")
@@index([tenantId])
@@map("departments")
@@schema("platform_schema")
}
```
**E. feature_flags 陦?* <20><>0<EFBFBD>?
```prisma
model FeatureFlag {
id String @id @default(uuid())
featureKey String @unique @map("feature_key") // 蜉溯<E89C89><EFBFBD><EFBFBD>シ亥ヲゑシ嗽se_gpt_5<5F>?
displayName String @map("display_name")
description String?
isEnabled Boolean @default(false) @map("is_enabled")
targetRoles String[] @map("target_roles") // 蜈∬ョク逧<EFBDB8>ァ定牡蛻苓。?
targetTenants String[] @default([]) @map("target_tenants") // 蜈∬ョク逧<EFBDB8>ァ滓姐ID蛻苓。ィ
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("feature_flags")
@@schema("platform_schema")
}
```
**F. tenant_modules 陦?* <20><>0<EFBFBD>?
```prisma
model TenantModule {
id String @id @default(uuid())
tenantId String @map("tenant_id")
moduleCode String @map("module_code") // 讓。蝮嶺サ」遐<EFBDA3><EFBFBD>SL/DC/IIT遲会シ<E4BC9A>
isEnabled Boolean @default(true) @map("is_enabled")
expiresAt DateTime? @map("expires_at") // 讓。蝮苓ョ「髦<EFBDA2>芦譛滓慮髣エ
createdAt DateTime @default(now())
tenant Tenant @relation(fields: [tenantId], references: [id])
@@unique([tenantId, moduleCode])
@@map("tenant_modules")
@@schema("platform_schema")
}
```
**G. tenant_quota_allocations 陦?* <20><>0<EFBFBD>解氣?驥<>コウ蜿埼ヲ茨シ夂イセ扈<EFBDBE>喧驟埼「晏<EFBDA2><EFBFBD>
```prisma
model TenantQuotaAllocation {
id Int @id @default(autoincrement())
tenantId String @map("tenant_id")
targetType String @map("target_type") // 'DEPARTMENT' | 'USER'
targetKey String @map("target_key") // DepartmentID 謌?UserID
limitAmount BigInt @map("limit_amount") // 蛻<><E89BBB>Уoken鬚晏コヲ
usedAmount BigInt @default(0) @map("used_amount") // 蟾イ菴ソ逕?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([tenantId, targetType, targetKey])
@@index([tenantId])
@@index([targetType, targetKey])
@@map("tenant_quota_allocations")
@@schema("platform_schema")
}
```
**逕ィ騾費シ<E8B2BB>** 蛹サ髯「遶ッ蜿ッ莉・蟆<EFBDA5>€サToken鬚晏コヲ蛻<EFBDA6><E89BBB>扈?蠢<><E8A0A2>遘?<3F><>epartment<6E><EFBFBD>"蠑<>蛹サ逕?<3F><>ser<65>?
#### **7.1.2 admin_schema<6D>郁ソ占是邂。逅<EFBDA1><EFBFBD>**
**H. admin_operation_logs 陦?* <20><>1<EFBFBD>俄恟<E4BF84>?驥<>コウ蜿埼ヲ茨シ壼「槫刈module蟄玲ョオ
```prisma
model AdminOperationLog {
id Int @id @default(autoincrement())
adminId String @map("admin_id")
operationType String @map("operation_type") // CREATE_TENANT/UPDATE_FEATURE_FLAG遲?
targetType String @map("target_type") // tenant/user/config
targetId String @map("target_id")
module String? @map("module") // <20><>€螻樊ィ。蝮暦シ<E69AA6>IT/ASL/邉サ扈滄<E68988>鄂ョ遲会シ<E4BC9A>
beforeData Json? @map("before_data")
afterData Json? @map("after_data")
ipAddress String? @map("ip_address")
userAgent String? @map("user_agent")
createdAt DateTime @default(now())
@@index([adminId])
@@index([operationType])
@@index([module]) // <20><> 闕ッ莨∫ォッ謖画ィ。蝮玲衍隸「
@@index([createdAt])
@@map("admin_operation_logs")
@@schema("admin_schema")
}
```
### 7.2 蜷守ォッAPI譫カ譫<EFBDB6>ョセ隶。
#### **A. 隶、隸∫ウサ扈<EFBDBB>** <20><>0<EFBFBD>?
**霍ッ逕ア<E98095>?* `/api/v1/auth/*`
```typescript
// backend/src/platform/auth/routes.ts
POST /api/v1/auth/register // 逕ィ謌キ豕ィ蜀<EFBDA8>
POST /api/v1/auth/login // 逋サ蠖包シ郁ソ泌屓JWT<57>?
POST /api/v1/auth/logout // 逋サ蜃コ
POST /api/v1/auth/refresh // 蛻キ譁ーToken
GET /api/v1/auth/me // 闔キ蜿門ス灘燕逕ィ謌キ菫。諱ッ
```
**JWT Payload扈捺桷<E68DBA>?*
```typescript
interface JWTPayload {
userId: string
email: string
role: UserRole
tenantId?: string
tenantType?: TenantType
exp: number // 霑<>悄譌カ髣エ
}
```
#### **B. 隶、隸∽クュ髣エ莉?* <20><>0<EFBFBD>?
```typescript
// backend/src/common/middleware/auth.ts
/**
* JWT隶、隸∽クュ髣エ莉?
* 鬪瑚ッゝoken蟷カ蟆<EFBDB6>畑謌キ菫。諱ッ謖りスス蛻?req.user
*/
export const requireAuth = async (req, res, next) => {
const token = extractToken(req)
if (!token) return res.status(401).send({ error: 'Unauthorized' })
try {
const payload = verifyJWT(token)
req.user = await prisma.user.findUnique({ where: { id: payload.userId } })
if (!req.user) return res.status(401).send({ error: 'User not found' })
next()
} catch (error) {
return res.status(401).send({ error: 'Invalid token' })
}
}
/**
* 隗定牡譚<E789A1>剞荳ュ髣エ莉?
* 譽€譟・逕ィ謌キ譏ッ蜷ヲ蜈キ譛画欠螳夊ァ定<EFBDA7>?
*/
export const requireRole = (...allowedRoles: UserRole[]) => {
return (req, res, next) => {
if (!req.user) return res.status(401).send({ error: 'Unauthorized' })
if (!allowedRoles.includes(req.user.role)) {
return res.status(403).send({ error: 'Forbidden' })
}
next()
}
}
/**
* 遘滓姐謨ー謐ョ髫皮ヲサ荳ュ髣エ莉?
* 遑ョ菫晉畑謌キ蜿ェ閭ス隶ソ髣ョ閾ェ蟾ア遘滓姐逧<E5A790>焚謐?
*/
export const requireTenantAccess = (req, res, next) => {
if (!req.user) return res.status(401).send({ error: 'Unauthorized' })
// SUPER_ADMIN蜿ッ莉・隶ソ髣ョ謇€譛臥ァ滓姐謨ー謐?
if (req.user.role === 'SUPER_ADMIN') return next()
// 蜈カ莉也畑謌キ蜿ェ閭ス隶ソ髣ョ閾ェ蟾ア遘滓姐逧<E5A790>焚謐?
req.tenantId = req.user.tenantId
next()
}
```
#### **C. 霑占是邂。逅<EFBDA1>ォッAPI** <20><>0<EFBFBD>?
**霍ッ逕ア<E98095>?* `/api/v1/admin/*`
```typescript
// 遘滓姐邂。逅<EFBDA1>
POST /api/v1/admin/tenants // 蛻帛サコ遘滓姐
GET /api/v1/admin/tenants // 遘滓姐蛻苓。ィ
GET /api/v1/admin/tenants/:id // 遘滓姐隸ヲ諠<EFBDA6>
PUT /api/v1/admin/tenants/:id // 譖エ譁ー遘滓姐
DELETE /api/v1/admin/tenants/:id // 蛻<>髯、遘滓姐
// Feature Flag邂。逅<EFBDA1>
GET /api/v1/admin/feature-flags // 闔キ蜿匁園譛宇eature Flag
PUT /api/v1/admin/feature-flags/:key // 譖エ譁ーFeature Flag
// 逕ィ謌キ邂。逅<EFBDA1>
GET /api/v1/admin/users // 蜈ィ螻€逕ィ謌キ蛻苓。ィ
POST /api/v1/admin/users/:id/assign-tenant // 蛻<><E89BBB>遘滓姐
```
**譚<>剞隕∵アゑシ?* 蜈ィ驛ィ髴€隕?`requireRole('SUPER_ADMIN')`
#### **D. 譛コ譫<EFBDBA>ョ。逅<EFBDA1>ォッAPI** <20><>1<EFBFBD>?
**霍ッ逕ア<E98095>?* `/api/v1/org/*`
```typescript
// 蛹サ髯「邂。逅<EFBDA1>ォ?
GET /api/v1/org/hospital/departments // 遘大ョ、蛻苓。ィ
POST /api/v1/org/hospital/departments // 蛻帛サコ遘大ョ、
GET /api/v1/org/hospital/members // 謌仙遭蛻苓。ィ
POST /api/v1/org/hospital/members/import // 謇ケ驥丞ッシ蜈・謌仙遭
// 闕ッ莨∫ョ。逅<EFBDA1>ォ?
GET /api/v1/org/pharma/projects // 鬘ケ逶ョ蛻苓。ィ
GET /api/v1/org/pharma/audit-logs // 螳。隶。譌・蠢<EFBDA5>
```
**譚<>剞隕∵アゑシ?* `requireRole('TENANT_ADMIN')` + `requireTenantAccess`
#### **E. 蜈ャ蠑€API** <20><>0<EFBFBD>?
**霍ッ逕ア<E98095>?* `/api/public/*`
```typescript
// 遘滓姐蜩∫煙驟咲スョ<EFBDBD>域裏髴€逋サ蠖包シ?
GET /api/public/tenant-config?code={code} // 闔キ蜿也ァ滓姐蜩∫煙驟咲スョ
```
### 7.3 蜑咲ォッ譫カ譫<EFBDB6>ョセ隶。
#### **A. 隶、隸∵ィ。蝮<EFBDA1>** <20><>0<EFBFBD>?
**逶ョ蠖慕サ捺桷<E68DBA>?*
```
frontend-v2/src/modules/auth/
笏懌楳笏€ pages/
笏? 笏懌楳笏€ LoginPage.tsx # 騾夂畑逋サ蠖暮。?
笏? 笏懌楳笏€ TenantLoginPage.tsx # 遘滓姐荳灘ア樒匳蠖暮。オ<EFBDA1>亥勘諤∝刀迚鯉シ<E9AF89>
笏? 笏披楳笏€ RegisterPage.tsx # 豕ィ蜀碁。?
笏懌楳笏€ api/
笏? 笏披楳笏€ authApi.ts # 隶、隸、PI隹<49>
笏懌楳笏€ hooks/
笏? 笏披楳笏€ useAuth.ts # 隶、隸ook
笏披楳笏€ routes.tsx # 隶、隸∬キッ逕ア
```
#### **B. 霑占是邂。逅<EFBDA1>ォッ讓。蝮?* <20><>0<EFBFBD>?
**逶ョ蠖慕サ捺桷<E68DBA>?*
```
frontend-v2/src/modules/admin/
笏懌楳笏€ pages/
笏? 笏懌楳笏€ Dashboard.tsx # 霑占是莉ェ陦ィ逶?
笏? 笏懌楳笏€ TenantManagement/ # 遘滓姐邂。逅<EFBDA1>
笏? 笏? 笏懌楳笏€ TenantList.tsx
笏? 笏? 笏懌楳笏€ TenantCreate.tsx
笏? 笏? 笏懌楳笏€ TenantEdit.tsx
笏? 笏? 笏披楳笏€ BrandingConfig.tsx # 蜩∫煙驟咲スョ
笏? 笏懌楳笏€ FeatureFlagManagement.tsx # Feature Flag邂。逅<EFBDA1>
笏? 笏披楳笏€ UserManagement.tsx # 逕ィ謌キ邂。逅<EFBDA1>
笏懌楳笏€ api/
笏? 笏披楳笏€ adminApi.ts
笏披楳笏€ index.tsx # 讓。蝮怜ョ壻ケ<E5A3BB>
```
**讓。蝮玲ウィ蜀鯉シ?*
```typescript
const AdminModule: ModuleDefinition = {
id: 'admin',
name: '霑占是邂。逅<EFBDA1>',
path: '/admin',
requiredVersion: undefined, // 荳榊渕莠思ersion譽€譟?
requireRole: ['SUPER_ADMIN'], // <20><> 蝓コ莠手ァ定牡譽€譟?
component: lazy(() => import('./layouts/AdminLayout')),
}
```
#### **C. 譛コ譫<EFBDBA>ョ。逅<EFBDA1>ォッ讓。蝮?* <20><>1<EFBFBD>?
**逶ョ蠖慕サ捺桷<E68DBA>?*
```
frontend-v2/src/modules/org/
笏懌楳笏€ hospital/ # 蛹サ髯「邂。逅<EFBDA1>ォ?
笏? 笏懌楳笏€ pages/
笏? 笏? 笏懌楳笏€ Dashboard.tsx
笏? 笏? 笏懌楳笏€ DepartmentManagement.tsx
笏? 笏? 笏披楳笏€ MemberManagement.tsx
笏? 笏披楳笏€ index.tsx
笏披楳笏€ pharma/ # 闕ッ莨∫ョ。逅<EFBDA1>ォ?
笏懌楳笏€ pages/
笏? 笏懌楳笏€ Dashboard.tsx
笏? 笏懌楳笏€ ProjectManagement.tsx
笏? 笏披楳笏€ AuditLogs.tsx
笏披楳笏€ index.tsx
```
---
## 8. 螳樊命霍ッ郤ソ蝗?
### 8.1 Phase 0<>壼㊥螟<E38AA5>キ・菴懶シ<E687B6>1螟ゥ<E89E9F><EFBDA9>
**逶ョ譬<EFBDAE>シ?* 扈滉ク€謨ー謐ョ蠎楢。ィ扈捺桷<E68DBA>梧ク<E6A2A7>炊蜴<E7828A>彰驕礼<E9A995>?
- [ ] **莉サ蜉。1<EFBDA1>?* 蜀ウ遲紋ソ晉蕗 `platform_schema.users` 霑俶弍 `public.users`
- 蟒コ隶ョ<E99AB6>壻ソ晉<EFBDBF>?`platform_schema.users`<EFBFBD>域眠譫カ譫<EFBFBD>シ?
- 霑∫ァサ `public.users`<>紙蜿イ謨ー謐ョ蛻ー `platform_schema.users`
-<>髯、 `public.users` 陦?
- [ ] **莉サ蜉。2<EFBDA1>?* 蛻帛サコ霑∫ァサ譁<EFBDBB>。」
- 譴ウ逅<EFBDB3>園譛我ク壼苅讓。蝮怜ッケ User 陦ィ逧<EFBDA8>シ慕畑
- 蛻カ螳壽焚謐ョ霑∫ァサ閼壽悽
### 8.2 Phase 1<>壽焚謐ョ蠎鉄chema隶セ隶。<E99AB6>?螟ゥ<E89E9F><EFBDA9>
**P0 譬ク蠢<EFBDB8>。ィ<EFBDA1><EFBDA8>**
- [ ] **Day 1荳雁壕<E99B81>?* 隶セ隶。蟷カ蛻帛サ?`tenants` 陦?
- [ ] **Day 1荳句壕<E58FA5>?* 謇ゥ螻<EFBDA9> `users` 陦ィ<E999A6>亥「槫刈 tenantId, departmentId, role enum<75>?
- [ ] **Day 2荳雁壕<E99B81>?* 蛻帛サコ `tenant_users`, `feature_flags`, `tenant_modules` 陦?
- [ ] **Day 2荳句壕<E58FA5>?* 蛻帛サコ Prisma Schema 蟷カ霑占。瑚ソ∫ァ?
**莠、莉倡黄<E580A1><E9BB84>**
- 笨?Prisma Schema螳梧紛螳壻ケ<E5A3BB>
- 笨?霑∫ァサ閼壽悽霑占。碁€夊ソ<E5A48A>
- 笨?豬玖ッ墓焚謐ョ謠貞<E8ACA0>鬪瑚ッ<E7919A>
### 8.3 Phase 2<>壼錘遶ッ隶、隸∫ウサ扈滂シ<E6BB82>3螟ゥ<E89E9F><EFBDA9>
- [ ] **Day 1<>?* 螳樒鴫JWT蟾・蜈キ邀?
- `generateToken()`
- `verifyToken()`
- `refreshToken()`
- [ ] **Day 2<>?* 螳樒鴫隶、隸、PI
- POST `/api/v1/auth/register`
- POST `/api/v1/auth/login`
- GET `/api/v1/auth/me`
- [ ] **Day 3<>?* 螳樒鴫隶、隸∽クュ髣エ莉?
- `requireAuth`
- `requireRole`
- `requireTenantAccess`
- 蠎皮畑蛻ー邇ー譛鵜egacy API
**莠、莉倡黄<E580A1><E9BB84>**
- 笨?螳梧紛逧<E7B49B>ョ、隸∫ウサ扈?
- 笨?謇€譛陰PI蜉<49>荳願ョ、隸∽ソ晄侃
- 笨?Postman豬玖ッ暮€夊ソ<E5A48A>
### 8.4 Phase 3<>壼燕遶ッ隶、隸∝ッケ謗・<E8AC97><EFBDA5>2螟ゥ<E89E9F><EFBDA9>
- [ ] **Day 1<>?* 螳樒鴫逋サ蠖暮。オ髱「
- LoginPage.tsx
- useAuth Hook
- Token蟄伜お<E4BC9C><E3818A>ocalStorage<67>?
- [ ] **Day 2<>?* 蟇ケ謗・譚<EFBDA5>剞譯<E5899E>
- 譖ソ謐「PermissionContext荳ュ逧<EFBDAD>ock謨ー謐ョ
- 螳樒鴫莉主錘遶ッ闔キ蜿也畑謌キ菫。諱?
- 螳樒鴫逋サ蜃コ蜉溯<E89C89>
**莠、莉倡黄<E580A1><E9BB84>**
- 笨?蜿ッ逕ィ逧<EFBDA8>匳蠖?逋サ蜃コ豬∫ィ<E288AB>
- 笨?蜑咲ォッ譚<EFBDAF>剞謗ァ蛻カ逕滓譜
### 8.5 Phase 4<>夊ソ占是邂。逅<EFBDA1>ォッMVP<56>?螟ゥ<E89E9F><EFBDA9>
**P0 譬ク蠢<EFBDB8>粥閭ス<E996AD>?*
- [ ] **Day 1-2<>?* 遘滓姐邂。逅<EFBDA1>
- 遘滓姐蛻苓。ィ鬘?
- 蛻帛サコ遘滓姐陦ィ蜊包シ亥渕譛ャ菫。諱?遘滓姐邀サ蝙具シ?
- 遘滓姐隸ヲ諠<EFBDA6>。?
- [ ] **Day 3<>?* 蜩∫煙驟咲スョ
- Logo荳贋シ<E8B48B>蛻ーOSS
- 逋サ蠖暮。オ閭梧勹蝗セ荳贋シ<E8B48B>
- 驟咲スョ鬚<EFBDAE><EFBFBD>
- [ ] **Day 4<>?* Feature Flag邂。逅<EFBDA1>
- Feature Flag蛻苓。ィ
-€蜈ウ蛻<EFBDB3><E89BBB>?
- 逶ョ譬<EFBDAE>ァ滓姐驟咲スョ
- [ ] **Day 5<>?* 髮<><E9ABAE>豬玖ッ<E78E96>
- 霑占是遶ッ螳梧紛豬∫ィ区オ玖ッ?
-<>剞謗ァ蛻カ豬玖ッ<E78E96>
**莠、莉倡黄<E580A1><E9BB84>**
- 笨?霑占是邂。逅<EFBDA1>ォッMVP蜿ッ逕ィ
- 笨?蜿ッ莉・蛻帛サコ遘滓姐
- 笨?蜿ッ莉・驟咲スョ蜩∫煙
- 笨?蜿ッ莉・邂。逅<EFBDA1>eature Flag
### 8.6 Phase 5<>夂ァ滓姐荳灘ア樒匳蠖包シ<E58C85>2螟ゥ<E89E9F><EFBDA9>
- [ ] **Day 1<>?* 螳樒鴫TenantLoginPage
- 蜉ィ諤∝刈霓ス遘滓姐蜩∫煙驟咲ス?
- 譖ソ謐「Logo蜥瑚レ譎ッ蝗セ
- 蜉ィ諤∽クサ鬚倩牡
- [ ] **Day 2<>?* 螳樒鴫譎コ閭ス霍ッ逕ア蛻<EFBDB1>
- 逋サ蠖募錘譬ケ謐ョrole+tenantType霍ウ霓ャ
- 豬玖ッ穂ク榊酔隗定牡逧<E789A1>キウ霓ャ騾サ霎<EFBDBB>
**莠、莉倡黄<E580A1><E9BB84>**
- 笨?遘滓姐荳灘ア樒匳蠖暮。オ蜿ッ逕?
- 笨?URL<52>啻/t/{code}/login` 逕滓譜
### 8.7 Phase 6<>壽惻譫<E683BB>ョ。逅<EFBDA1>ォッ<EFBDAB>域潔髴€€蜿托シ<E68998>
**P1 蜉溯<E89C89><E6BAAF>亥錘扈ュ謗呈悄<E59188>会シ?*
- [ ] 蛹サ髯「邂。逅<EFBDA1>ォッ<EFBDAB>夂ァ大ョ、邂。逅<EFBDA1>€<C280>蜻倡ョ。逅<EFBDA1>€<EFBFBD><C280>鬚晏<E9AC9A>驟?
- [ ] 闕ッ莨∫ョ。逅<EFBDA1>ォッ<EFBDAB>夐。ケ逶ョ逶第而縲∝ョ。隶。譌・蠢?
---
## 9. 蜈ウ髞ョ蜀ウ遲也<E981B2>?
### 9.1 謚€譛ッ蜀ウ遲?
| 蜀ウ遲也<E981B2>?| 騾蛾。ケ | 蟒コ隶ョ | 逅<>罰 |
|--------|------|------|------|
| **User陦ィ騾画叫** | platform_schema.users vs public.users | 笨?platform_schema.users | 隨ヲ蜷域眠譫カ譫<EFBDB6>シ郡chema髫皮ヲサ貂<EFBDBB>匆 |
| **JWT蠎馴€画叫** | jsonwebtoken vs jose | 笨?jsonwebtoken | 謌千<E8AC8C>遞ウ螳夲シ檎、セ蛹コ豢サ霍?|
| **蟇<><E89F87>∝刈蟇<E58888>** | bcrypt vs argon2 | 笨?bcrypt | 鬘ケ逶ョ蟾イ譛我セ晁オ厄シ郁ァIT讓。蝮暦シ?|
| **Token蟄伜お** | localStorage vs httpOnly Cookie | 笨?localStorage | 蜑榊錘遶ッ蛻<EFBDAF>ヲサ<EFBDA6>瑚キィ蝓溷暑螂ス |
| **隗定牡螳壻ケ画婿蠑<E5A9BF>** | 蟄礼ャヲ荳?vs Enum | 笨?Prisma Enum | 邀サ蝙句ョ牙<EFBDAE><E78999>碁∩蜈肴蕎蜀咎漠隸?|
### 9.2 荳壼苅蜀ウ遲<EFBDB3>
| 蜀ウ遲也<E981B2>?| 騾蛾。ケ | 蟒コ隶ョ | 逅<>罰 |
|--------|------|------|------|
| **遘滓姐莉」遐∝髪荳€諤?* | 蜈ィ螻€蜚ッ荳€ vs 邀サ蝙句<E89D99>蜚ッ荳€ | 笨?蜈ィ螻€蜚ッ荳€ | URL `/t/{code}` 髴€蜈ィ螻€蜚ッ荳€ |
| **驛ィ髣ィ譬大アらコ?* | 蝗コ螳<EFBDBA>2螻?vs 譌<>髯仙アらコァ | 笨?譌<>髯仙アらコァ | 謾ッ謖∝、肴揩扈<E68FA9><EFBFBD>楔譫<E6A594> |
| **Feature Flag邊貞コヲ** | 遘滓姐郤?vs 逕ィ謌キ郤?| 笨?遘滓姐郤?| 隨ヲ蜷亥膚荳壽ィ。蠑擾シ檎ョ。逅<EFBDA1>€蜊?|
---
## 10. 鬟朱勦荳取倦謌?
### 10.1 謚€譛ッ鬟朱<E9AC9F>?
| 鬟朱勦 | 蠖ア蜩<EFBDB1> | 郛楢ァ」謗ェ譁ス |
|------|------|---------|
| **邇ー譛陰PI譌<49>隶、隸?* | 髴€隕∝<E99A95>髱「謾ケ騾?| 貂占ソ帛シ丞刈蜈・隶、隸<EFBDA4>シ御シ伜<EFBDBC>菫晄侃謨乗─API |
| **荳、荳ェUser陦?* | 謨ー謐ョ荳堺ク€閾?| 蟆ス蠢ォ扈滉ク€<EFBDB8>檎シ門<EFBDBC>霑∫ァサ閼壽<E996BC>?|
| **遘滓姐謨ー謐ョ髫皮ヲサ** | 蜿ッ閭ス豕<EFBDBD>愆謨ー謐ョ | 荳・譬シ豬玖ッ<E78E96> `requireTenantAccess` 荳ュ髣エ莉?|
### 10.2 蠑€蜿第倦謌?
| 謖第<E8AC96> | 髫セ蠎ヲ | 蠎泌ッケ譁ケ譯<EFBDB9> |
|------|------|---------|
| **JWT隶、隸∫ウサ扈<EFBDBB>** | 荳ュ遲<EFBDAD> | 蜿り€グDJ/BYSY鬘ケ逶ョ螳樒鴫 |
| **蜩∫煙蜉ィ諤∝刈霓?* | 荳ュ遲<EFBDAD> | 菴ソ逕ィCSS蜿倬㍼+OSS蝗セ迚ⅡRL |
| **譎コ閭ス霍ッ逕ア蛻<EFBDB1>** | 邂€蜊?| 蝓コ莠屍ole+tenantType逧<65>f-else |
---
## 11. 蠑€蜿題オ<E9A18C>コ宣怙豎?
### 11.1 莠コ蜉幃怙豎?
- **蜷守ォッ蠑€蜿托シ<E68998>** 1莠?テ<> 10螟ゥ<E89E9F><EFBDA9>hase 0-3<>?
- **蜑咲ォッ蠑€蜿托シ<E68998>** 1莠?テ<> 7螟ゥ<E89E9F><EFBDA9>hase 3-5<>?
- **豬玖ッ包シ?* 0.5莠?テ<> 3螟ゥ<E89E9F>磯寔謌先オ玖ッ包シ?
**諤サ隶。<E99AB6>?* 郤?0莠コ螟ゥ<E89E9F>育コヲ3蜻ィ<E89CBB><EFBDA8>
### 11.2 謚€譛ッ萓晁オ?
**譁ー蠅柤pm蛹<6D><EFBFBD>**
```json
{
"dependencies": {
"jsonwebtoken": "^9.0.0",
"bcryptjs": "^2.4.3"
},
"devDependencies": {
"@types/jsonwebtoken": "^9.0.0",
"@types/bcryptjs": "^2.4.2"
}
}
```
---
## 12. 諤サ扈<EFBDBB>
### 12.1 譬ク蠢<EFBDB8>サ楢ョコ
1. **蠖灘燕邉サ扈溷ョ悟<EFBDAE>豐。譛芽ョ、隸<EFBDA4>/謗域揀邉サ扈<EFBDBB>** 笶?
2. **謨ー謐ョ蠎捺怏荳、荳ェUser陦ィ<E999A6>碁怙扈滉ク€**<><E7AC9E><EFBFBD>
3. **蜑咲ォッ譚<EFBDAF>剞譯<E5899E>楔隶セ隶。螳悟埋<E6829F>御ス<E5BEA1><EFBFBD>クコmock**<><E7AC9E><EFBFBD>
4. **遘滓姐菴鍋ウサ螳悟<E89EB3>郛コ螟ア<E89E9F>碁怙莉朱峺蠑€蜿?* 笶?
### 12.2 莨伜<E88EA8>郤ァ蟒コ隶?
**P0<50><30>eek 1-2<>会シ<E4BC9A>** 謳ュ蟒コ蝓コ遑€譫カ譫<EFBDB6>
- 謨ー謐ョ蠎鉄chema隶セ隶。 + 霑∫ァサ
- JWT隶、隸∫ウサ扈<EFBDBB>
- 隶、隸∽クュ髣エ莉?
- 逋サ蠖<EFBDBB>/逋サ蜃コ蜉溯<E89C89>
- 霑占是邂。逅<EFBDA1>ォッMVP<56>育ァ滓姐邂。逅?蜩∫煙驟咲スョ<EFBDBD>?
**P1<50><31>eek 3-4<>会シ<E4BC9A>** 螳悟埋譬ク蠢<EFBDB8>粥閭ス
- Feature Flag邂。逅<EFBDA1>
- 遘滓姐荳灘ア樒匳蠖暮。?
- 譛コ譫<EFBDBA>ョ。逅<EFBDA1>ォッ<EFBDAB>亥現髯「迚茨シ<E88CA8>
**P2<50><32>eek 5+<2B>会シ<E4BC9A>** 謇ゥ螻募粥閭ス
- 譛コ譫<EFBDBA>ョ。逅<EFBDA1>ォッ<EFBDAB>郁艮莨∫沿<E288AB><E6B2BF>
- 鬮倡コァ螳。隶。譌・蠢<EFBDA5>
-<>剞扈<E5899E>イ貞コヲ謗ァ蛻?
### 12.3 荳倶ク€豁・陦悟<E999A6>?
1. 笨?**Review譛ャ謚・蜻?*<2A>檎。ョ隶、謚€譛ッ譁ケ譯?
2. 笨?**遑ョ螳壼シ€蜿第賜譛?*<2A>亥サコ隶?蜻ィ蜀イ蛻コ<E89BBB><EFBDBA>
3. 笨?**蜷ッ蜉ィPhase 0**<2A>壽焚謐ョ蠎楢。ィ扈滉ク€蜥郡chema隶セ隶。
4. 笨?**蟷カ陦悟星蜉ィ蜑咲ォッ逋サ蠖暮。オ隶セ隶?*<2A><>I隶セ隶。蟶茨シ<E88CA8>
---
## 9. <20><> Prompt邂。逅<EFBDA1>ウサ扈滓紛蜷<E7B49B>
### 9.1 荳コ莉€<C280>rompt邂。逅<EFBDA1>弍霑占是邂。逅<EFBDA1>ォッ逧<EFBDAF><E980A7>鬲?
譬ケ謐ョ縲?2-騾夂畑閭ス蜉帛ア<E5B89B>03-Prompt邂。逅<EFBDA1>ウサ扈滉ク守<EFBDB8>蠎ヲ鬚<EFBDA6>ァ郁ョセ隶。譁ケ譯?md縲具シ<E585B7>**Prompt邂。逅<EFBDA1>ク肴弍蜿ッ騾牙粥閭ス<E996AD>€梧弍霑占是邂。逅<EFBDA1>ォッ蟄伜惠逧<E683A0><E980A7>ク蠢<EFBDB8>炊逕ア荵倶ク€**縲?
#### **荳壼苅逞帷せ<E5B8B7>?*
1. **豬玖ッ慕識蠅<E8AD98>裏豕墓ィ。諡溽悄螳樊焚謐ョ**
- ASL逧<4C>枚迪ョ遲幃€蛾怙隕?0遽<30>悄螳槫現蟄ヲ隶コ譁<EFBDBA>ェ瑚ッ∝㊥遑ョ邇<EFBDAE>
- DC逧<43>焚謐ョ貂<EFBDAE>エ鈴怙隕∫悄螳樒羅蜴<E7BE85>焚謐ョ鬪瑚ッ∵歓蜿匁譜譫?
- 豬玖ッ慕識蠅<E8AD98>噪蛛<E599AA>焚謐ョ螳悟<E89EB3><EFBFBD>豕墓垓髴イPrompt逧<74>悄螳樣琉鬚?
2. **蠖灘燕蠑€蜿第オ∫ィ区譜邇<E8AD9C>栫菴?*
- 豈乗ャ。隹<EFBDA1>紛Prompt髴€<C280>シ壽隼莉」遐?竊?commit 竊?驛ィ鄂イ 竊?遲牙セ<E78999>AE驥榊星<E6A68A>育コヲ5蛻<35><EFBFBD>?
- 荳エ蠎贋ク灘ョカ譌<EFBDB6>豕募盾荳手ー<E6898B>ッ包シ井サ紋サャ荳堺シ壼<EFBDBC>莉」遐<EFBDA3>シ?
-<>豕募ソォ騾溯ソュ莉」<E88E89>御ク€螟ゥ蜿ェ閭ス蟆晁ッ募<EFBDAF>谺?
3. **逕滉コァ莠区腐鬟朱勦鬮?*
-€譌ヲPrompt蜿醍沿<E9868D>梧園譛臥畑謌キ遶句叉蜿怜スア蜩<EFBDB1>
- 豐。譛臥<E8AD9B>蠎ヲ譛コ蛻カ<E89BBB>梧裏豕募ー剰激蝗エ鬪瑚ッ<E7919A>
#### **隗」蜀ウ譁ケ譯茨シ夂函莠ァ邇ッ蠅<EFBDAF><E8A085>蠎ヲ鬚<EFBDA6>ァ?*
<EFBFBD>ッ戊€<EFBFBD>€蜷ッDebug讓。蠑丞錘<EFBFBD><EFBFBD>蜉ィ霍ッ逕ア蛻ーDRAFT迚<EFBFBD>rompt<EFBFBD>碁ェ瑚ッ<EFBFBD>€夊ソ<EFBFBD>錘荳€髞ョ蜿大ク<EFBFBD>クコACTIVE迚医€?
### 9.2 Prompt邂。逅<EFBDA1>ウサ扈滓楔譫<E6A594>
#### **9.2.1 謨ー謐ョ蠎楢ョセ隶。<E99AB6><EFBDA1>apability_schema<6D>?*
```prisma
// --- Prompt Management System ---
model PromptTemplate {
id Int @id @default(autoincrement())
code String @unique // 蜚ッ荳€<C280><EFBFBD>: 'ASL_SCREENING_TitleAbstract'
name String // 莠コ邀サ蜿ッ隸サ蜷咲ァー
module String // 謇€螻樊ィ。蝮? ASL, DC, AIA, IIT
description String?
variables Json? // 鬚<>悄蜿倬㍼: ["title", "abstract"]
versions PromptVersion[]
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("prompt_templates")
@@schema("capability_schema")
}
model PromptVersion {
id Int @id @default(autoincrement())
templateId Int @map("template_id")
version Int // 迚域悽蜿?1, 2, 3...
content String @db.Text // Prompt蜀<74>ョケ<EFBDAE>域髪謖andlebars讓。譚ソ<E8AD9A>?
modelConfig Json? // {"temperature": 0.1, "model": "deepseek-chat"}
status PromptStatus @default(DRAFT)
changelog String? // 菫ョ謾ケ隸エ譏<EFBDB4>
createdBy String? @map("created_by") // <20>剥 螳。隶。<E99AB6>夊ー∽ソョ謾ケ逧?
template PromptTemplate @relation(fields: [templateId], references: [id])
createdAt DateTime @default(now()) @map("created_at")
@@map("prompt_versions")
@@schema("capability_schema")
@@index([templateId, status]) // 鬮倬「第衍隸「莨伜喧
}
enum PromptStatus {
DRAFT // 闕臥ィソ<EFBDA8>井サ<E4BA95>ebug讓。蠑丞庄隗<E5BA84>シ?
ACTIVE // 郤ソ荳顔函謨茨シ磯サ倩ョ、<EFBDAE><EFBDA4>
ARCHIVED // 蠖呈。」
@@schema("capability_schema")
}
```
#### **9.2.2 譁ー蠅櫁ァ定牡荳取揀髯?*
| 隗定牡 | 譚<>剞 Code | 隸エ譏<EFBDB4> |
|------|-----------|------|
| **SUPER_ADMIN** | prompt:\* | 雜<>コァ邂。逅<EFBDA1>遭諡・譛画園譛画揀髯?|
| **PROMPT_ENGINEER** <20><> | prompt:view<br>prompt:edit<br>prompt:debug<br>prompt:publish | <20>**譬ク蠢<EFBDB8>ァ定牡**<EFBFBD>壻ク謎ク啀rompt蟾・遞句ク域<EFBFBD>荳エ蠎贋ク灘ョカ |
| HOSPITAL_ADMIN | - | 譛コ譫<EFBDBA>ョ。逅<EFBDA1>遭譌<E981AD>Prompt譚<74>剞 |
| PHARMA_ADMIN | - | 闕ッ莨∫ョ。逅<EFBDA1>遭譌<E981AD>Prompt譚<74>剞 |
**譚<>剞隸ヲ隗」<E99A97>?*
- `prompt:view` - 譟・逵輝rompt蛻苓。ィ蜥悟紙蜿イ迚域<E8BF9A>?
- `prompt:edit` - 蛻帛サコ/菫ョ謾ケDRAFT迚域悽
- `prompt:debug` - 箝?譬ク蠢<EFBDB8>シ壼シ€蜷ッ隹<EFBDAF>ッ墓ィ。蠑?
- `prompt:publish` - 蜿大クゥRAFT荳コACTIVE
#### **9.2.3 譬ク蠢<EFBDB8>橿譛ッ螳樒<E89EB3>?*
**A. PromptService<63>亥錘遶ッ<E981B6><EFBDAF>**
```typescript
// backend/src/common/capabilities/prompt/prompt.service.ts
export class PromptService {
private debugUsers = new Set<string>(); // 蜀<>ュ伜ュ伜お隹<E3818A>ッ慕畑謌キ
private activeCache = new Map<string, string>(); // ACTIVE迚域悽郛灘ュ<E78198>
/**
* 隶セ鄂ョ隹<EFBDAE>ッ墓ィ。蠑<EFBDA1>
* @requires Permission: prompt:debug
*/
async setDebugMode(userId: string, enabled: boolean) {
if (enabled) {
this.debugUsers.add(userId);
} else {
this.debugUsers.delete(userId);
}
}
/**
* 闔キ蜿鳳rompt<70><EFBFBD>ク蠢<EFBDB8><E8A0A2>蠎ヲ騾サ霎托シ?
*/
async get(code: string, variables: any, userId: string): Promise<string> {
// 1. 譽€譟・譏ッ蜷ヲ荳コ隹<EFBDBA>ッ戊€?
if (this.debugUsers.has(userId)) {
// 莨伜<E88EA8>闔キ蜿縫RAFT迚域悽
const draft = await this.getDraftVersion(code);
if (draft) {
return this.render(draft.content, variables);
}
}
// 2. 譎ョ騾夂畑謌キ謌匁裏DRAFT譌カ<E8AD8C>瑚執蜿泡CTIVE迚域悽
let active = this.activeCache.get(code);
if (!active) {
const version = await prisma.promptVersion.findFirst({
where: {
template: { code },
status: 'ACTIVE'
},
orderBy: { version: 'desc' }
});
active = version?.content || this.getFallback(code);
this.activeCache.set(code, active);
}
return this.render(active, variables);
}
/**
* Postgres LISTEN/NOTIFY 辜ュ譖エ譁?
*/
async initHotReload() {
const client = await pool.connect();
await client.query('LISTEN prompt_update');
client.on('notification', (msg) => {
console.log('[PromptService] Received update:', msg.payload);
this.activeCache.clear(); // 貂<>ゥコ郛灘ュ<E78198>
});
}
}
```
**B. API遶ッ轤ケ隶セ隶。**
| 譁ケ豕<EFBDB9> | 霍ッ蠕<EFBDAF> | 譚<>剞 | 謠剰ソー |
|------|------|------|------|
| GET | /api/admin/prompts | prompt:view | 闔キ蜿匁園譛臼rompt讓。譚ソ蛻苓。ィ |
| GET | /api/admin/prompts/:id | prompt:view | 闔キ蜿冶ッヲ諠<EFBDA6>シ亥性蜴<E680A7>彰迚域悽<E59F9F>?|
| POST | /api/admin/prompts/draft | prompt:edit | 菫晏ュ倩拷遞ソ<E9819E>育函謌先眠迚域悽<E59F9F>茎tatus=DRAFT<46>?|
| POST | /api/admin/prompts/publish | prompt:publish | 蜿大ク<E5A4A7>沿譛ャ<E8AD9B><EFBDAC>RAFT竊但CTIVE<56>瑚ァヲ蜿鮮OTIFY<46>?|
| POST | /api/admin/prompts/debug | **prompt:debug** | **蠑€蜈ウ隹<EFBDB3>ッ墓ィ。蠑?* |
**C. 蜑咲ォッ蜈ィ螻€<C280>ッ募シ€蜈?*
```tsx
// frontend-v2/src/modules/admin/components/PromptDebugSwitch.tsx
export const PromptDebugSwitch = () => {
const { hasPermission } = usePermission();
const [debugMode, setDebugMode] = useState(false);
// <20>白 譚<>剞謗ァ蛻カ<E89BBB>壻サ<E5A3BB>rompt:debug譚<67>剞逕ィ謌キ蜿ッ隗<EFBDAF>
if (!hasPermission('prompt:debug')) {
return null;
}
const handleToggle = async (enabled: boolean) => {
await api.post('/api/admin/prompts/debug', { enabled });
setDebugMode(enabled);
};
return (
<>
<Switch
checked={debugMode}
onChange={handleToggle}
checkedChildren="<22>菅 隹<>ッ墓ィ。蠑<EFBDA1>"
unCheckedChildren="逕滉コァ讓。蠑<EFBDA1>"
/>
{debugMode && (
<Alert
type="warning"
message="笞<><E7AC9E><EFBFBD><>ッ墓ィ。蠑丞キイ蠑€蜷ッ<E89CB7>壽お蠖灘燕豁」蝨ィ菴ソ逕ィ闕臥ィソ迚茨シ<E88CA8>RAFT<46>画署遉コ隸<EFBDBA>"
banner
closable={false}
/>
)}
</>
);
};
```
### 9.3 豸牙所逧<E68980>園譛我ク壼苅讓。蝮?
譬ケ謐ョ譁<EFBFBD>。」隨?闃ゑシ碁怙隕 ̄rompt邂。逅<EFBDA1>噪讓。蝮暦シ<E69AA6>
| 讓。蝮<EFBDA1> | 譬ク蠢<EFBDB8>惻譎ッ | Prompt螟肴揩蠎?| 莨伜<E88EA8>郤?|
|------|---------|-------------|--------|
| **ASL** | 譬<>「俶遭隕∝<E99A95>遲帙€<C280><EFBFBD>、咲ュ帙€∬ッ∵紺蜷域<E89CB7>?| 箝絶ュ絶ュ絶ュ絶ュ?| P0 |
| **DC** | Tool B謠仙叙縲ゝool C貂<43>エ励€<C280>遯∵」€豬?| 箝絶ュ絶ュ絶ュ絶ュ?| P0 |
| **IIT** | 雍ィ謗ァ譽€譟・縲∵э蝗セ隸<EFBDBE>悪縲∵衍隸「逕滓<E98095>?| 箝絶ュ絶ュ絶ュ絶ュ?| P1 |
| **PKB** | RAG髣ョ遲斐€∵音螟<E99FB3>炊髦<E7828A>ッサ | 箝絶ュ絶ュ絶ュ<E7B5B6> | P1 |
| **AIA** | 10+譎コ閭ス菴薙€∵э蝗セ隸<EFBDBE><E99AB8>?| 箝絶ュ絶ュ?| P2 |
| **RVW** | 隗<>激諤ァ譽€譟?| 箝絶ュ絶ュ?| P2 |
### 9.4 Prompt邂。逅<EFBDA1>€蜿題ョ。蛻?
#### **Phase 0: 蝓コ遑€隶セ譁ス<E8AD81>?螟ゥ<E89E9F><EFBDA9>**
1. 蛻帛サコ`capability_schema`逧Пrompt逶ク蜈ウ陦?
2. 豺サ蜉<EFBDBB>`prompt:*`<EFBFBD>剞蛻ー`platform_schema.permissions`
3. 蛻帛サコ`PROMPT_ENGINEER`隗定牡
4. 螳樒鴫`PromptService`譬ク蠢<EFBFBD>€サ霎<EFBFBD>
#### **Phase 1: 霑占是遶ッMVP<56>?螟ゥ<E89E9F><EFBDA9>**
1. 蜑咲ォッ邂。逅<EFBDA1>阜髱「<E9ABB1><EFBFBD>陦ィ縲∫シ冶セ大勣縲∫沿譛ャ蜴<EFBDAC><EFBFBD><E5BDB0>
2. 蜈ィ螻€<C280>ッ募シ€蜈ウ扈<EFBDB3>サ?
3. 闕臥ィソ菫晏ュ<E6998F>/蜿大ク<E5A4A7>粥閭ス
#### **Phase 2: 荳壼苅讓。蝮玲磁蜈・<E89C88>磯囂荳壼苅蠑€蜿托シ<E68998>**
- ASL遲幃€画ィ。蝮苓ー<E88B93>`promptService.get()`
- DC謨ー謐ョ貂<EFBDAE>エ玲ィ。蝮苓ー<E88B93>`promptService.get()`
- 蜈カ莉匁ィ。蝮玲潔髴€謗・蜈・
### 9.5 螳牙<E89EB3>荳朱」取<EFBDA3>?
1. **譚<>剞髫皮ヲサ**
- 荳・譬シ譽€譟・`prompt:debug`<EFBFBD><EFBFBD>碁亟豁「譎ョ騾夂畑謌キ隸ッ蜈・隹<EFBFBD>ッ墓ィ。蠑?
-<>ッ墓ィ。蠑冗憾諤∝ュ伜お蝨ィ蜀<EFBDA8>ュ假シ育畑謌キ逋サ蜃コ閾ェ蜉ィ螟ア謨茨シ<E88CA8>
2. **螳。隶。譌・蠢<EFBDA5>**
- `PromptVersion.createdBy`隶ー蠖穂ソョ謾ケ莠?
- `AdminOperationLog`隶ー蠖募書蟶<EFBFBD>。御クコ
3. **蜈懷コ墓惻蛻カ**
- 莉」遐∽クュ菫晉蕗Hardcoded Prompt菴應クコ邉サ扈溽コァ蜈懷コ?
- 謨ー謐ョ蠎捺衍隸「螟ア雍・譌カ霑泌屓鮟倩ョ、迚域悽
---
## 10. <20><> 蜿埼ヲ磯㊦郤ウ隸エ譏<EFBDB4>
### 10.1 驥<>コウ逧<EFBDB3><E980A7>髞ョ蟒コ隶?
蝓コ莠弱€?2-騾夂畑閭ス蜉帛ア<E5B89B>10-譚<>剞菴鍋ウサ譴ウ逅<EFBDB3>渚鬥井ク惹ソョ豁」蟒コ隶?md縲具シ御サ・荳句サコ隶ョ蟾イ謨エ蜷亥芦譛ャ譁<EFBDAC>。」<EFBDA1><EFBDA3>
#### 笨?**1. 蠅槫刈TenantQuotaAllocation陦ィ<E999A6><EFBDA8>0<EFBFBD>?*
**蜴溷屏<E6BAB7>?* PRD譏守。ョ隕∵アょ現髯「遶ッ謖臥ァ大ョ、/荳ェ莠コ蛻<EFBDBA><E89BBB>驟埼「<E59FBC>
**螳樊命<E6A88A>?* 蟾イ蝨ィ7.1.1遶<EFBFBD>闃よ眠蠅杼tenant_quota_allocations`陦?
```prisma
model TenantQuotaAllocation {
targetType String // 'DEPARTMENT' | 'USER'
targetKey String // DepartmentID 謌?UserID
limitAmount BigInt // 蛻<><E89BBB><EFBFBD>「晏コ?
usedAmount BigInt // 蟾イ菴ソ逕?
}
```
#### 笨?**2. 陦ィ蜷肴隼荳コTenantMember<65><72>1<EFBFBD>?*
**蜴溷屏<E6BAB7>?* "Member"隸ュ荵牙シコ隹<EFBDBA><EFBFBD><EFBFBD><EFBDBB>邉サ<E98289>?User"騾壼クク謖<EFBDB8>匳蠖戊エヲ蜿キ螳樔ス?
**螳樊命<E6A88A>?* 蟾イ蟆<EFBDB2>TenantUser`謾ケ荳コ`TenantMember`
#### 笨?**3. 螳。隶。譌・蠢怜「槫刈module蟄玲ョオ<EFBDAE><EFBDB5>1<EFBFBD>?*
**蜴溷屏<E6BAB7>?* 闕ッ莨∫ォッ髴€隕∵衍隸「IIT讓。蝮嶺ク灘ア樊律蠢暦シ<E69AA6>DA 21 CFR Part 11蜷郁ァ<E98381>シ?
**螳樊命<E6A88A>?* 蟾イ蝨ィ`AdminOperationLog`陦ィ蠅槫刈`module`蟄玲ョオ蜥檎エ「蠑?
#### 笨?**4. Prompt蟾・遞句喧譚<E596A7><EFBFBD><E5899E>0<EFBFBD>?*
**蜴溷屏<E6BAB7>?* 霑占是邂。逅<EFBDA1>ォッ譬ク蠢<EFBDB8>粥閭?
**螳樊命<E6A88A>?* 蟾イ蝨ィ隨?遶<>螳梧紛隶セ隶。Prompt邂。逅<EFBDA1>ウサ扈<EFBDBB>
#### 笨?**5. 雜<>コァ邂。逅<EFBDA1>遭遘榊ュ先焚謐ョ<E8AC90><EFBDAE>0<EFBFBD>?*
**蜴溷屏<E6BAB7>?* 蜷ヲ蛻咏ウサ扈滉ク顔コソ蜷取裏豕戊ソ帛<EFBDBF>蜷主<E89CB7>?
**螳樊命<E6A88A>?* 蟆<>惠Phase 0螳樒鴫Prisma Seed閼壽悽
#### 笨?**6. Phase 0蝗樊サ壽婿譯茨シ<E88CA8>0<EFBFBD>?*
**蜴溷屏<E6BAB7>?* 謨ー謐ョ螳牙<E89EB3>蝓コ譛ャ蜴溷<E89CB4>
**螳樊命<E6A88A>?* 霑∫ァサ閼壽悽蟆<E682BD><E89F86>驥榊多蜷港public.users`荳コ`public.users_backup`<60>御ソ晉<EFBDBF>?蜻?
#### 笨?**7. 遘滓姐驟咲スョAPI郛灘ュ假シ<E58187>1<EFBFBD>?*
**蜴溷屏<E6BAB7>?* 豈丈クェ逕ィ謌キ謇灘シ€逋サ蠖暮。オ驛ス莨夊ー<E5A48A><EFBFBD>碁ォ伜ケカ蜿台ク矩怙隕∫シ灘ュ?
**螳樊命<E6A88A>?* 蟆<>惠螳樊命譌カ豺サ蜉<EFBDBB>`Cache-Control: public, max-age=3600`
### 10.2 蜷守サュ謾ケ霑帛サコ隶ョ
莉・荳句サコ隶ョ證ゆク榊惠MVP髦カ谿オ螳樊命<EFBFBD>御ス<EFBFBD><EFBFBD>蜈・謚€譛ッ蛟コ蜉。貂<EFBFBD><EFBFBD>?
#### <20>売 **1. JWT螳牙<E89EB3>諤ァ<E8ABA4><EFBDA7>2<EFBFBD>?*
**蟒コ隶ョ<E99AB6>?* 菴ソ逕ィHttpOnly Cookie譖ソ莉」localStorage
**逅<><EFBFBD>?* localStorage螳ケ譏灘女XSS謾サ蜃サ
**隶。蛻抵シ?* 蝨ィ闕ッ莨∫ォッ荳顔コソ蜑搾シ磯怙譖エ鬮伜ョ牙<EFBDAE>諤ァ<E8ABA4>牙ョ樊命
#### <20>売 **2. Prisma Extension螟夂ァ滓姐髫皮ヲサ<EFBDA6><EFBDBB>1<EFBFBD>?*
**蟒コ隶ョ<E99AB6>?* 蝨ィORM螻ょシコ蛻カ蜉<EFBDB6>蜈・`tenantId`霑<>サ、
**逅<><EFBFBD>?* 髦イ豁「蠑€蜿台ココ蜻伜ソ倩ョー蝨ィController螻ょ刈荳ュ髣エ莉?
**隶。蛻抵シ?* Phase 2蠑募<E8A091>
```typescript
const prismaExtended = prisma.$extends({
query: {
$allModels: {
async findMany({ args, query }) {
args.where = { ...args.where, tenantId: currentTenantId };
return query(args);
}
}
}
});
```
### 10.3 蜿埼ヲ郁エィ驥剰ッ<E589B0>サキ
**諤サ菴楢ッ<E6A5A2>シー<EFBDBC>?* 莨倡ァ€ 箝絶ュ絶ュ絶ュ絶ュ?
- 笨?9譚。蟒コ隶ョ荳ュ<E88DB3>?譚。遶句叉驥<E58F89>コウ<EFBDBA><EFBDB3>2譚。郤ウ蜈・蜷守サュ隶。蛻?
- 笨?蜿醍鴫莠<E9B4AB><E88EA0>鬚晏<E9AC9A>驟肴ィ。蝙狗噪隶セ隶。郛コ髯キ<E9ABAF><EFBDB7>ritical<61>?
- 笨?蠑コ隹<EFBDBA><EFBFBD>rompt邂。逅<EFBDA1>噪譬ク蠢<EFBDB8>慍菴?
- 笨?謠仙<E8ACA0><EFBFBD>ョ樒畑逧<E79591>キ・遞句ョ櫁キオ蟒コ隶ョ<E99AB6>亥屓貊壽婿譯医€∫ァ榊ュ先焚謐ョ<E8AC90><EFBDAE>
**扈楢ョコ<EFBDAE>?* 譁<>。」雍ィ驥城ォ假シ碁」朱勦蜿ッ謗ァ<E8AC97>?*蜿ッ莉・蠑€蟋句シ€蜿?*縲?
---
**謚・蜻雁ョ梧ッ輔€ょ㊥螟<E38AA5>・ス蠑€蟋句シ€蜿台コ<E58FB0><EFBFBD><E99B9B>** <20>