본문으로 건너뛰기

Tenant 패널 (Level 2)

📝 초안 (Draft)

이 문서는 검토 중입니다. 내용이 변경될 수 있습니다.

Tenant Admin 전용 패널 기능을 설명합니다.

개요

Tenant 패널은 **Level 2 (Tenant Admin)**을 위한 관리 패널입니다. 테넌트(고객사) 내의 조직 구조, 사용자, Guardian 관계 등을 관리합니다.

접근 권한

항목
권한 레벨Level 2 (Tenant Admin)
기본 경로/tenant
환경변수PANEL_PATH_TENANT
접근 가능자Level 0, 1, 2

담당 범위

Tenant Admin은 자신의 테넌트 내에서만 권한을 가집니다:

Tenant A (담당)
├── Organization 1 ✅ 관리 가능
│ ├── Workspace 1 ✅
│ └── Workspace 2 ✅
├── Organization 2 ✅ 관리 가능
│ └── Workspace 3 ✅
└── 모든 사용자 ✅ 관리 가능

Tenant B (타 테넌트)
└── 모든 데이터 ❌ 접근 불가 (RLS 격리)

범용 UX 기능

기능설명
brandName좌상단에 테넌트 이름 표시 (logo_url 등록 시 로고 표시)
tenantMenu테넌트 선택 드롭다운 숨김 (URL로 결정)
패널간 네비게이션우상단 메뉴에서 Platform/SaaS 패널로 이동 (L0/L1만)
SafeDeleteAction모든 삭제에 "DELETE {대상명}" 입력 확인
homeUrl좌상단 로고 클릭 시 현재 테넌트 대시보드로 이동

주요 기능

1. 조직(Organization) 관리

테넌트 내의 조직 구조를 관리합니다. 조직은 계층 구조를 가질 수 있습니다.

OrganizationResource 주요 필드:

필드설명예시
name조직명"영업부"
code조직 코드"SALES-001"
type조직 유형headquarters, division, department, team
parent_id상위 조직null (최상위) 또는 조직 ID
org_level조직 레벨1, 2, 3...
is_active활성화 여부true/false

조직 유형:

유형설명색상
headquarters본사빨강
division사업부주황
department부서파랑
team초록

2. Guardian 관계 관리

Guardian 확장이 활성화된 경우, 보호자-피보호자 관계를 관리합니다.

GuardianRelationshipResource 기능:

  • 관계 생성 (학부모-학생, 담당교사-학생 등)
  • 승인 대기 목록 확인
  • 승인/거부 액션
액션설명
ApproveAction관계 요청 승인 (pending → approved)
RejectAction관계 요청 거부 (pending → rejected)
// GuardianRelationshipResource.php
use App\Core\Extensions\Guardian\Filament\Actions\ApproveAction;
use App\Core\Extensions\Guardian\Filament\Actions\RejectAction;

->recordActions([
ApproveAction::make(),
RejectAction::make(),
EditAction::make(),
])

3. 사용자 관리

테넌트 내 모든 레벨의 사용자를 관리합니다.

관리 대상레벨설명
Organization AdminLevel 3조직 관리자 배정
Workspace AdminLevel 4워크스페이스 관리자 배정
Group LeaderLevel 5그룹 리더 배정
MemberLevel 6일반 회원 관리

4. 감사 로그

테넌트 내의 감사 로그를 조회합니다. (플랫폼 전체가 아닌 테넌트 범위)

// TenantAuditLogResource.php
public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->where('tenant_id', auth()->user()->tenant_id);
}

파일 구조

app/Filament/Tenant/
├── Resources/
│ ├── OrganizationResource.php
│ │ └── Pages/
│ │ ├── ListOrganizations.php
│ │ ├── CreateOrganization.php
│ │ └── EditOrganization.php
│ │
│ ├── GuardianRelationshipResource.php
│ │ └── Pages/
│ │ ├── ListGuardianRelationships.php
│ │ ├── CreateGuardianRelationship.php
│ │ └── EditGuardianRelationship.php
│ │
│ └── AuditLogResource.php
│ └── Pages/
│ ├── ListAuditLogs.php
│ └── ViewAuditLog.php

├── Pages/
│ └── Dashboard.php

└── Widgets/
├── OrganizationTreeWidget.php
└── GuardianPendingWidget.php

PanelProvider 설정

// app/Providers/Filament/TenantPanelProvider.php

class TenantPanelProvider extends PanelProvider
{
public function panel(Panel $panel): Panel
{
return $panel
->id('tenant')
->path(env('PANEL_PATH_TENANT', 'tenant'))
->login()
->colors(['primary' => Color::Blue])
->tenant(Tenant::class) // 멀티테넌트 활성화
->discoverResources(
in: app_path('Filament/Tenant/Resources'),
for: 'App\Filament\Tenant\Resources'
)
->authMiddleware([
Authenticate::class,
EnsureUserLevel::class.':0,1,2', // Level 0-2 접근
]);
}
}

RLS 데이터 격리

Tenant 패널의 모든 리소스는 **RLS(Row Level Security)**로 자동 격리됩니다.

HasTenantBasedAuthorization Trait

// OrganizationResource.php
use App\Core\Base\Permission\Filament\Traits\HasTenantBasedAuthorization;

class OrganizationResource extends Resource
{
use HasTenantBasedAuthorization;

// 자동으로 tenant_id 필터링 적용
}

자동 필터링

public static function getEloquentQuery(): Builder
{
return parent::getEloquentQuery()
->where('tenant_id', auth()->user()->tenant_id);
}
RLS 보장

PostgreSQL RLS 정책으로 DB 레벨에서도 격리가 보장됩니다. SQL Injection 공격으로도 다른 테넌트 데이터에 접근할 수 없습니다.


Guardian 확장 통합

Guardian 확장이 활성화되면 Tenant 패널에 Guardian 관련 기능이 추가됩니다.

활성화 확인

// config/core.php
'extensions' => [
'guardian' => env('CORE_GUARDIAN_ENABLED', false),
],

조건부 네비게이션

// GuardianRelationshipResource.php
public static function shouldRegisterNavigation(): bool
{
return config('core.extensions.guardian', false);
}

관련 문서