# MNG ν”„λ‘œμ νŠΈ Critical Rules > 🚨 **μ ˆλŒ€ μœ„λ°˜ν•˜μ§€ 말아야 ν•  κ·œμΉ™λ“€** **μž‘μ„±μΌ**: 2025-11-24 **λͺ©μ **: λ°˜λ³΅λ˜λŠ” μ‹€μˆ˜ λ°©μ§€ 및 ν”„λ‘œμ νŠΈ μ •μ±… λͺ…ν™•ν™” --- ## 🚫 μ ˆλŒ€ κΈˆμ§€ 사항 ### 1. DB λ§ˆμ΄κ·Έλ ˆμ΄μ…˜ κΈˆμ§€ **κ·œμΉ™:** - ❌ mng/μ—μ„œλŠ” **μ ˆλŒ€λ‘œ** λ§ˆμ΄κ·Έλ ˆμ΄μ…˜ 파일 생성 κΈˆμ§€ - ❌ κΈ°μ‘΄ ν…Œμ΄λΈ” ꡬ쑰 λ³€κ²½ κΈˆμ§€ - βœ… λͺ¨λΈ 관계 μ •μ˜λ§Œ κ°€λŠ₯ - βœ… ν•„μš” μ‹œ api/에 λ§ˆμ΄κ·Έλ ˆμ΄μ…˜ μš”μ²­ **이유:** - mng/λŠ” api/의 DBλ₯Ό **읽기 μ „μš©**으둜 μ‚¬μš© - DB μŠ€ν‚€λ§ˆλŠ” **api/μ—μ„œλ§Œ** 관리 - μ—¬λŸ¬ μ €μž₯μ†Œ(api, admin, mng)κ°€ 동일 DB 곡유 **mng μ „μš© ν…Œμ΄λΈ” 생성 μ‹œ:** - βœ… mngμ—μ„œλ§Œ μ‚¬μš©ν•˜λŠ” ν…Œμ΄λΈ”μ€ `admin_*` 접두사 μ‚¬μš© - βœ… **λ§ˆμ΄κ·Έλ ˆμ΄μ…˜μ€ 무쑰건 api/μ—μ„œ 생성** (mngμ—μ„œ 생성 κΈˆμ§€!) - 예: `admin_pm_projects`, `admin_pm_tasks` λ“± **μ‹€μˆ˜ 사둀:** ```php // ❌ 잘λͺ»λœ 예: mng/μ—μ„œ users ν…Œμ΄λΈ” μˆ˜μ • μ‹œλ„ Schema::table('users', function (Blueprint $table) { $table->foreignId('tenant_id')->comment('ν…Œλ„ŒνŠΈ ID'); }); // βœ… μ˜¬λ°”λ₯Έ 예: User λͺ¨λΈμ— κ΄€κ³„λ§Œ μ •μ˜ public function tenants(): BelongsToMany { return $this->belongsToMany(Tenant::class, 'user_tenants'); } ``` --- ### 2. κΈ°μ‘΄ ν…Œμ΄λΈ”μ€ μž¬μ‚¬μš©λ§Œ **μž¬μ‚¬μš© ν…Œμ΄λΈ”:** - `users` - μ‚¬μš©μž 계정 - `tenants` - ν…Œλ„ŒνŠΈ (νšŒμ‚¬) - `user_tenants` - μ‚¬μš©μž-ν…Œλ„ŒνŠΈ 관계 (pivot) - `roles` - μ—­ν•  - `departments` - λΆ€μ„œ - `permissions` - κΆŒν•œ - `products`, `materials`, `categories` λ“± λͺ¨λ“  λΉ„μ¦ˆλ‹ˆμŠ€ ν…Œμ΄λΈ” **μž‘μ—… 방법:** 1. **λͺ¨λΈ 볡사**: admin/app/Models β†’ mng/app/Models 2. **Filament μ½”λ“œ 제거**: form(), table() λ“± 제거 3. **κ΄€κ³„λ§Œ μœ μ§€**: belongsTo, hasMany, belongsToMany 4. **Traits 적용**: BelongsToTenant (ν•„μš” μ‹œ), SoftDeletes --- ### 3. Multi-tenant μ•„ν‚€ν…μ²˜ 이해 **user_tenants pivot ν…Œμ΄λΈ” ꡬ쑰:** ``` user_tenants: β”œβ”€β”€ user_id (FK β†’ users) β”œβ”€β”€ tenant_id (FK β†’ tenants) β”œβ”€β”€ is_active (ν™œμ„± μ—¬λΆ€) β”œβ”€β”€ is_default (κΈ°λ³Έ ν…Œλ„ŒνŠΈ) β”œβ”€β”€ joined_at (κ°€μž…μΌ) └── left_at (νƒˆν‡΄μΌ) ``` **관계 μ •μ˜:** ```php // User λͺ¨λΈ public function tenants(): BelongsToMany { return $this->belongsToMany(Tenant::class, 'user_tenants') ->withTimestamps() ->withPivot(['is_active', 'is_default', 'joined_at', 'left_at']); } // Tenant λͺ¨λΈ public function users(): BelongsToMany { return $this->belongsToMany(User::class, 'user_tenants'); } ``` **μ„Έμ…˜ 기반 ν…Œλ„ŒνŠΈ 선택:** - `session('selected_tenant_id')` - ν˜„μž¬ μ„ νƒλœ ν…Œλ„ŒνŠΈ - `currentTenant()` 헬퍼 λ©”μ„œλ“œ μ‚¬μš© ꢌμž₯ --- ### 4. BelongsToTenant Trait μ‚¬μš© 주의 **μ–Έμ œ μ‚¬μš©ν•˜μ§€ 말아야 ν•˜λ‚˜:** - ❌ `users` ν…Œμ΄λΈ” - user_tenants pivot μ‚¬μš© - ❌ `tenants` ν…Œμ΄λΈ” - ν…Œλ„ŒνŠΈ 자체 - ❌ λ‹€λŒ€λ‹€ 관계 ν…Œμ΄λΈ” **μ–Έμ œ μ‚¬μš©ν•΄μ•Ό ν•˜λ‚˜:** - βœ… `roles` - tenant_id 컬럼 있음 - βœ… `departments` - tenant_id 컬럼 있음 - βœ… `products` - tenant_id 컬럼 있음 **νŒλ‹¨ κΈ°μ€€:** - ν…Œμ΄λΈ”μ— 직접 `tenant_id` 컬럼이 있으면 β†’ BelongsToTenant μ‚¬μš© - pivot ν…Œμ΄λΈ”λ‘œ 관계가 λ§Ίμ–΄μ§€λ©΄ β†’ belongsToMany κ΄€κ³„λ§Œ μ •μ˜ --- ### 5. Service-First νŒ¨ν„΄ μ—„μˆ˜ **κ·œμΉ™:** - βœ… λΉ„μ¦ˆλ‹ˆμŠ€ λ‘œμ§μ€ **Service 클래슀**μ—λ§Œ - βœ… ControllerλŠ” FormRequest + Service 호좜만 - βœ… Model은 관계와 accessor만 **잘λͺ»λœ 예:** ```php // ❌ Controller에 둜직 public function store(Request $request) { $user = User::create($request->all()); $user->tenant_id = session('selected_tenant_id'); $user->save(); } ``` **μ˜¬λ°”λ₯Έ 예:** ```php // βœ… Service에 둜직 class UserService { public function createUser(array $data): User { // λΉ„μ¦ˆλ‹ˆμŠ€ 둜직 return User::create($data); } } // ControllerλŠ” 호좜만 public function store(StoreUserRequest $request, UserService $service) { $user = $service->createUser($request->validated()); return response()->json(['success' => true]); } ``` --- ### 6. FormRequest ν•„μˆ˜ μ‚¬μš© **κ·œμΉ™:** - ❌ Controllerμ—μ„œ `$request->validate()` κΈˆμ§€ - βœ… λͺ¨λ“  검증은 FormRequest 클래슀둜 **예:** ```php // βœ… StoreUserRequest.php class StoreUserRequest extends FormRequest { public function rules(): array { return [ 'name' => 'required|string|max:255', 'email' => 'required|email|unique:users', ]; } } // βœ… Controller public function store(StoreUserRequest $request) { // $request->validated() 만 Service에 전달 } ``` --- ### 7. MNG 데이터 μ ‘κ·Ό μ•„ν‚€ν…μ²˜ **MNGλŠ” 자체 λ‚΄λΆ€ API μ‚¬μš© (μ™ΈλΆ€ api/ ν”„λ‘œμ νŠΈ 호좜 μ•ˆ 함)** ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ routes/web.php (Blade ν™”λ©΄λ§Œ) β”‚ β”‚ └─ Controller β†’ view('xxx.index') (데이터 없이 ν™”λ©΄λ§Œ) β”‚ β”‚ β”‚ β”‚ routes/api.php (HTMX 호좜 + CRUD) β”‚ β”‚ └─ Api/Admin/Controller β†’ Service β†’ Model β†’ DB β”‚ β”‚ β”‚ β”‚ Bladeμ—μ„œ HTMX둜 /api/admin/* 호좜 β”‚ β”‚ └─ hx-get="/api/admin/tenants" β”‚ β”‚ └─ hx-post="/api/admin/tenants" β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` **κ·œμΉ™:** - ❌ μ™ΈλΆ€ api/ ν”„λ‘œμ νŠΈμ˜ API 호좜 κΈˆμ§€ - βœ… mng λ‚΄λΆ€ API (`/api/admin/*`) μ‚¬μš© - βœ… Service β†’ Model β†’ DB (직접 μ ‘κ·Ό) **Controller ꡬ뢄:** - `app/Http/Controllers/XxxController.php` β†’ Blade ν™”λ©΄λ§Œ (GET) - `app/Http/Controllers/Api/Admin/XxxController.php` β†’ CRUD 처리 (HTMX) **μ˜ˆμ‹œ:** ```php // βœ… Web Controller: ν™”λ©΄λ§Œ λ°˜ν™˜ class TenantController extends Controller { public function index(): View { return view('tenants.index'); // 데이터 없이 ν™”λ©΄λ§Œ } } // βœ… API Controller: CRUD 처리 class Api\Admin\TenantController extends Controller { public function index(Request $request) { $tenants = $this->tenantService->getTenants($request->all()); return view('tenants.partials.list', compact('tenants')); // HTML partial } } ``` --- ## πŸ“‹ μž‘μ—… μ „ 체크리슀트 ### DB μž‘μ—… μ‹œ: ``` β–‘ mng/μ—μ„œ μž‘μ—… 쀑인가? β†’ λ§ˆμ΄κ·Έλ ˆμ΄μ…˜ κΈˆμ§€! β–‘ κΈ°μ‘΄ ν…Œμ΄λΈ” μˆ˜μ •μΈκ°€? β†’ api/에 μš”μ²­! β–‘ mng μ „μš© μƒˆ ν…Œμ΄λΈ”μΈκ°€? β†’ admin_* 접두사 + api/에 λ§ˆμ΄κ·Έλ ˆμ΄μ…˜! β–‘ κ΄€κ³„λ§Œ 좔가인가? β†’ OK, λͺ¨λΈλ§Œ μˆ˜μ • ``` ### λͺ¨λΈ μž‘μ—… μ‹œ: ``` β–‘ tenant_id 컬럼 μžˆλŠ”κ°€? β†’ BelongsToTenant trait β–‘ pivot ν…Œμ΄λΈ” μ‚¬μš©ν•˜λŠ”κ°€? β†’ belongsToMany κ΄€κ³„λ§Œ β–‘ λΉ„μ¦ˆλ‹ˆμŠ€ 둜직 μžˆλŠ”κ°€? β†’ Service둜 이동! ``` ### Controller μž‘μ—… μ‹œ: ``` β–‘ FormRequest μƒμ„±ν–ˆλŠ”κ°€? β–‘ Service 클래슀 μƒμ„±ν–ˆλŠ”κ°€? β–‘ ControllerλŠ” 호좜만 ν•˜λŠ”κ°€? ``` --- ## πŸ”— κ΄€λ ¨ λ¬Έμ„œ - **[INDEX.md](./INDEX.md)** - MNG ν”„λ‘œμ νŠΈ κ°œμš” - **[MIGRATION_PLAN.md](./MIGRATION_PLAN.md)** - Admin β†’ MNG λ§ˆμ΄κ·Έλ ˆμ΄μ…˜ - **[DEV_PROCESS.md](../../claudedocs/mng/DEV_PROCESS.md)** - 개발 ν”„λ‘œμ„ΈμŠ€ - **[database-schema.md](../../docs/specs/database-schema.md)** - DB μŠ€ν‚€λ§ˆ - **[api-rules.md](../../docs/reference/api-rules.md)** - API 개발 κ·œμΉ™ --- ## πŸ“ μ‹€μˆ˜ 사둀 둜그 ### 2025-11-24: users ν…Œμ΄λΈ” λ§ˆμ΄κ·Έλ ˆμ΄μ…˜ μ‹œλ„ - **문제**: mng/μ—μ„œ users ν…Œμ΄λΈ”μ— tenant_id μΆ”κ°€ μ‹œλ„ - **원인**: user_tenants pivot ν…Œμ΄λΈ” 쑴재λ₯Ό κ°„κ³Ό - **κ΅ν›ˆ**: λ‹€λŒ€λ‹€ κ΄€κ³„λŠ” belongsToMany둜, λ§ˆμ΄κ·Έλ ˆμ΄μ…˜ κΈˆμ§€ - **ν•΄κ²°**: User λͺ¨λΈμ— tenants() κ΄€κ³„λ§Œ μΆ”κ°€ --- **μ΅œμ’… μ—…λ°μ΄νŠΈ**: 2025-11-27 **λ‹€μŒ 리뷰**: 반볡 μ‹€μˆ˜ λ°œμƒ μ‹œ μ—…λ°μ΄νŠΈ