fix : Tenant API 추가
- 테넌트 목록 조회 - 테넌트 정보 조회 - 테넌트 정보 수정 - 테넌트 등록 - 테넌트 삭제 - 테넌트 복구
This commit is contained in:
@@ -25,17 +25,19 @@ public static function debugQueryLog(): array
|
|||||||
{
|
{
|
||||||
$logs = DB::getQueryLog();
|
$logs = DB::getQueryLog();
|
||||||
|
|
||||||
return collect($logs)->map(function ($log) {
|
return collect($logs)
|
||||||
$query = $log['query'];
|
->skip(3)
|
||||||
foreach ($log['bindings'] as $binding) {
|
->map(function ($log) {
|
||||||
$binding = is_numeric($binding) ? $binding : "'" . addslashes($binding) . "'";
|
$query = $log['query'];
|
||||||
$query = preg_replace('/\\?/', $binding, $query, 1);
|
foreach ($log['bindings'] as $binding) {
|
||||||
}
|
$binding = is_numeric($binding) ? $binding : "'" . addslashes($binding) . "'";
|
||||||
|
$query = preg_replace('/\\?/', $binding, $query, 1);
|
||||||
|
}
|
||||||
|
|
||||||
// \n 제거
|
// \n 제거
|
||||||
$query = str_replace(["\n", "\r"], ' ', $query)." (time: {$log['time']})";
|
$query = str_replace(["\n", "\r"], ' ', $query)." (time: {$log['time']})";
|
||||||
return trim($query);
|
return trim($query);
|
||||||
})->toArray();
|
})->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
# ApiResponse Helper
|
# ApiResponse Helper
|
||||||
@@ -79,8 +81,7 @@ public static function validate(
|
|||||||
|
|
||||||
public static function response($type = '', $query = '', $key = ''): array
|
public static function response($type = '', $query = '', $key = ''): array
|
||||||
{
|
{
|
||||||
$debug = (app()->environment('local')) ? true : false;
|
$debug = app()->environment('local') && request()->is('api/*');
|
||||||
if ($debug) DB::enableQueryLog(); // 쿼리 추적
|
|
||||||
|
|
||||||
$result = match ($type) {
|
$result = match ($type) {
|
||||||
'get' => $key ? $query->get()->keyBy($key) : $query->get(),
|
'get' => $key ? $query->get()->keyBy($key) : $query->get(),
|
||||||
@@ -103,7 +104,12 @@ public static function response($type = '', $query = '', $key = ''): array
|
|||||||
}
|
}
|
||||||
|
|
||||||
$response['data'] = $result;
|
$response['data'] = $result;
|
||||||
$response['query'] = ($debug) ? self::debugQueryLog() : [];
|
$response['query'] = $debug ? self::debugQueryLog() : [];
|
||||||
|
|
||||||
|
// 다음 요청에 로그가 섞이지 않도록 비워준다 (로컬에서만 의미있음)
|
||||||
|
if ($debug) {
|
||||||
|
DB::flushQueryLog();
|
||||||
|
}
|
||||||
|
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,70 +4,52 @@
|
|||||||
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Services\MemberService;
|
use App\Services\TenantService;
|
||||||
use App\Helpers\ApiResponse;
|
use App\Helpers\ApiResponse;
|
||||||
|
|
||||||
class TenantController extends Controller
|
class TenantController extends Controller
|
||||||
{
|
{
|
||||||
public function index(Request $request)
|
public function index(Request $request)
|
||||||
{
|
{
|
||||||
try {
|
return ApiResponse::handle(function () use ($request) {
|
||||||
$result = MemberService::getMembers($request);
|
return TenantService::getTenants($request->all());
|
||||||
return ApiResponse::success($result['data'], '회원목록 조회 성공',$result['query']);
|
}, '테넌트목록 조회');
|
||||||
} catch (\Throwable $e) {
|
|
||||||
return ApiResponse::error('회원목록 조회 실패', 500, [
|
|
||||||
'details' => $e->getMessage(),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function show(Request $request)
|
||||||
/**
|
|
||||||
* 나의 테넌트 전환
|
|
||||||
*/
|
|
||||||
public function switch()
|
|
||||||
{
|
{
|
||||||
//
|
return ApiResponse::handle(function () use ($request) {
|
||||||
|
return TenantService::getTenant($request->all());
|
||||||
|
}, '테넌트정보 조회');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function update(Request $request)
|
||||||
* Store a newly created resource in storage.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for editing the specified resource.
|
|
||||||
*/
|
|
||||||
public function edit(string $id)
|
|
||||||
{
|
{
|
||||||
//
|
return ApiResponse::handle(function () use ($request) {
|
||||||
|
return TenantService::updateTenant($request->all());
|
||||||
|
}, '테넌트정보 수정');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function store(Request $request)
|
||||||
* Update the specified resource in storage.
|
|
||||||
*/
|
|
||||||
public function update(Request $request, string $id)
|
|
||||||
{
|
{
|
||||||
//
|
return ApiResponse::handle(function () use ($request) {
|
||||||
|
return TenantService::storeTenants($request->all());
|
||||||
|
}, '테넌트 등록');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function destroy(Request $request)
|
||||||
* Remove the specified resource from storage.
|
|
||||||
*/
|
|
||||||
public function delAdmin($userNo, Request $request)
|
|
||||||
{
|
{
|
||||||
return ApiResponse::handle(function () use ($userNo, $request) {
|
return ApiResponse::handle(function () use ($request) {
|
||||||
return MemberService::delAdmin($userNo);
|
return TenantService::destroyTenant($request->all());
|
||||||
}, '관리자 제외 성공', '관리자 제외 실패');
|
}, '테넌트 삭제(탈퇴)');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function restore(Request $request)
|
||||||
* 관리자 설정
|
|
||||||
*/
|
|
||||||
public function setAdmin($userNo, Request $request)
|
|
||||||
{
|
{
|
||||||
return ApiResponse::handle(function () use ($userNo, $request) {
|
return ApiResponse::handle(function () use ($request) {
|
||||||
return MemberService::setAdmin($userNo);
|
return TenantService::restoreTenant($request->all());
|
||||||
}, '관리자 설정 성공', '관리자 설정 실패');
|
}, '테넌트 복구');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,28 +11,11 @@ class UserController extends Controller
|
|||||||
{
|
{
|
||||||
public function index(Request $request)
|
public function index(Request $request)
|
||||||
{
|
{
|
||||||
try {
|
return ApiResponse::handle(function () use ($request) {
|
||||||
$result = MemberService::getMembers($request);
|
return MemberService::getMembers($request->all());
|
||||||
return ApiResponse::success($result['data'], '회원목록 조회 성공',$result['query']);
|
}, '회원목록 조회');
|
||||||
} catch (\Throwable $e) {
|
|
||||||
return ApiResponse::error('회원목록 조회 실패', 500, [
|
|
||||||
'details' => $e->getMessage(),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for creating a new resource.
|
|
||||||
*/
|
|
||||||
public function create()
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store a newly created resource in storage.
|
|
||||||
*/
|
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
return ApiResponse::handle(function () use ($request) {
|
return ApiResponse::handle(function () use ($request) {
|
||||||
@@ -47,7 +30,6 @@ public function show($userNo)
|
|||||||
}, '회원 상세조회');
|
}, '회원 상세조회');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function me(Request $request)
|
public function me(Request $request)
|
||||||
{
|
{
|
||||||
return ApiResponse::handle(function () use ($request) {
|
return ApiResponse::handle(function () use ($request) {
|
||||||
@@ -55,7 +37,6 @@ public function me(Request $request)
|
|||||||
}, '나의 정보 조회');
|
}, '나의 정보 조회');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function meUpdate(Request $request)
|
public function meUpdate(Request $request)
|
||||||
{
|
{
|
||||||
return ApiResponse::handle(function () use ($request) {
|
return ApiResponse::handle(function () use ($request) {
|
||||||
@@ -63,7 +44,6 @@ public function meUpdate(Request $request)
|
|||||||
}, '나의 정보 수정');
|
}, '나의 정보 수정');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function changePassword(Request $request)
|
public function changePassword(Request $request)
|
||||||
{
|
{
|
||||||
return ApiResponse::handle(function () use ($request) {
|
return ApiResponse::handle(function () use ($request) {
|
||||||
@@ -85,21 +65,5 @@ public function switchTenant(Request $request)
|
|||||||
return MemberService::switchMyTenant($tenant_id);
|
return MemberService::switchMyTenant($tenant_id);
|
||||||
}, '활성 테넌트 전환');
|
}, '활성 테넌트 전환');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for editing the specified resource.
|
|
||||||
*/
|
|
||||||
public function edit(string $id)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the specified resource in storage.
|
|
||||||
*/
|
|
||||||
public function update(Request $request, string $id)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,8 @@ class User extends Authenticatable
|
|||||||
|
|
||||||
protected $hidden = [
|
protected $hidden = [
|
||||||
'password', 'remember_token',
|
'password', 'remember_token',
|
||||||
'two_factor_secret', 'two_factor_recovery_codes', 'two_factor_confirmed_at'
|
'two_factor_secret', 'two_factor_recovery_codes', 'two_factor_confirmed_at',
|
||||||
|
'deleted_at',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function userTenants()
|
public function userTenants()
|
||||||
|
|||||||
@@ -16,18 +16,20 @@ class Tenant extends Model
|
|||||||
use SoftDeletes, ModelTrait;
|
use SoftDeletes, ModelTrait;
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'name',
|
'company_name',
|
||||||
'code',
|
'code',
|
||||||
'email',
|
'email',
|
||||||
'phone',
|
'phone',
|
||||||
'address',
|
'address',
|
||||||
|
'business_num',
|
||||||
|
'corp_reg_no',
|
||||||
|
'ceo_name',
|
||||||
|
'homepage',
|
||||||
|
'fax',
|
||||||
|
'logo',
|
||||||
|
'admin_memo',
|
||||||
|
'options',
|
||||||
'tenant_st_code',
|
'tenant_st_code',
|
||||||
'plan_id',
|
|
||||||
'subscription_id',
|
|
||||||
'max_users',
|
|
||||||
'trial_ends_at',
|
|
||||||
'expires_at',
|
|
||||||
'last_paid_at',
|
|
||||||
'billing_tp_code',
|
'billing_tp_code',
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -51,7 +53,6 @@ class Tenant extends Model
|
|||||||
];
|
];
|
||||||
|
|
||||||
protected $hidden = [
|
protected $hidden = [
|
||||||
'admin_memo',
|
|
||||||
'deleted_at',
|
'deleted_at',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
class AppServiceProvider extends ServiceProvider
|
class AppServiceProvider extends ServiceProvider
|
||||||
{
|
{
|
||||||
@@ -12,7 +13,13 @@ class AppServiceProvider extends ServiceProvider
|
|||||||
*/
|
*/
|
||||||
public function register(): void
|
public function register(): void
|
||||||
{
|
{
|
||||||
//
|
// 개발환경 + API 라우트에서만 쿼리 로그 수집
|
||||||
|
if (app()->environment('local')) {
|
||||||
|
// 콘솔/큐 등 non-HTTP 컨텍스트 보호
|
||||||
|
if (function_exists('request') && request() && request()->is('api/*')) {
|
||||||
|
DB::enableQueryLog();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -48,9 +48,6 @@ public static function getMember(int $userNo)
|
|||||||
*/
|
*/
|
||||||
public static function getMyInfo()
|
public static function getMyInfo()
|
||||||
{
|
{
|
||||||
$debug = (app()->environment('local')) ? true : false;
|
|
||||||
if ($debug) DB::enableQueryLog(); // 쿼리 추적
|
|
||||||
|
|
||||||
$apiUser = app('api_user');
|
$apiUser = app('api_user');
|
||||||
|
|
||||||
$user = User::with([
|
$user = User::with([
|
||||||
@@ -71,8 +68,6 @@ public static function getMyInfo()
|
|||||||
*/
|
*/
|
||||||
public static function getMyUpdate($request)
|
public static function getMyUpdate($request)
|
||||||
{
|
{
|
||||||
$debug = app()->environment('local');
|
|
||||||
if ($debug) DB::enableQueryLog();
|
|
||||||
|
|
||||||
$apiUser = app('api_user');
|
$apiUser = app('api_user');
|
||||||
|
|
||||||
@@ -104,9 +99,6 @@ public static function getMyUpdate($request)
|
|||||||
*/
|
*/
|
||||||
public static function setMyPassword($request)
|
public static function setMyPassword($request)
|
||||||
{
|
{
|
||||||
$debug = app()->environment('local');
|
|
||||||
if ($debug) DB::enableQueryLog();
|
|
||||||
|
|
||||||
$apiUserId = app('api_user'); // 현재 로그인한 사용자 PK
|
$apiUserId = app('api_user'); // 현재 로그인한 사용자 PK
|
||||||
|
|
||||||
// 유효성 검사 (확인 비밀번호는 선택)
|
// 유효성 검사 (확인 비밀번호는 선택)
|
||||||
@@ -152,8 +144,6 @@ public static function setMyPassword($request)
|
|||||||
*/
|
*/
|
||||||
public static function getMyTenants()
|
public static function getMyTenants()
|
||||||
{
|
{
|
||||||
$debug = app()->environment('local');
|
|
||||||
if ($debug) DB::enableQueryLog();
|
|
||||||
|
|
||||||
$apiUser = app('api_user');
|
$apiUser = app('api_user');
|
||||||
$data = UserTenant::join('tenants', 'user_tenants.tenant_id', '=', 'tenants.id')
|
$data = UserTenant::join('tenants', 'user_tenants.tenant_id', '=', 'tenants.id')
|
||||||
@@ -174,8 +164,6 @@ public static function getMyTenants()
|
|||||||
*/
|
*/
|
||||||
public static function switchMyTenant(int $tenantId)
|
public static function switchMyTenant(int $tenantId)
|
||||||
{
|
{
|
||||||
$debug = app()->environment('local');
|
|
||||||
if ($debug) DB::enableQueryLog();
|
|
||||||
|
|
||||||
$apiUser = app('api_user');
|
$apiUser = app('api_user');
|
||||||
|
|
||||||
|
|||||||
358
app/Services/TenantService.php
Normal file
358
app/Services/TenantService.php
Normal file
@@ -0,0 +1,358 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Helpers\ApiResponse;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use App\Models\Tenants\Tenant;
|
||||||
|
use App\Models\Members\UserTenant;
|
||||||
|
|
||||||
|
class TenantService
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 한글 자음 배열
|
||||||
|
*/
|
||||||
|
private const INITIALS = ['ㄱ','ㄲ','ㄴ','ㄷ','ㄸ','ㄹ','ㅁ','ㅂ','ㅃ','ㅅ','ㅆ','ㅇ','ㅈ','ㅉ','ㅊ','ㅋ','ㅌ','ㅍ','ㅎ'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 대소문자를 구분하지 않는 36진수 문자열로 변경
|
||||||
|
*/
|
||||||
|
private string $base36Chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 한글 업체명에서 초성 약어를 추출합니다.
|
||||||
|
* 외부 라이브러리 없이 자체적으로 구현했습니다.
|
||||||
|
*
|
||||||
|
* @param string $tenantName
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function getInitials(string $tenantName): string
|
||||||
|
{
|
||||||
|
$initials = '';
|
||||||
|
$charLength = mb_strlen($tenantName, 'UTF-8');
|
||||||
|
|
||||||
|
for ($i = 0; $i < $charLength; $i++) {
|
||||||
|
$char = mb_substr($tenantName, $i, 1, 'UTF-8');
|
||||||
|
$code = mb_ord($char, 'UTF-8');
|
||||||
|
|
||||||
|
// 한글 초성을 추출
|
||||||
|
if ($code >= 0xAC00 && $code <= 0xD7A3) { // 한글 유니코드 범위
|
||||||
|
$index = floor(($code - 0xAC00) / 588);
|
||||||
|
$initials .= self::INITIALS[$index];
|
||||||
|
}
|
||||||
|
// 한글이 아닌 문자는 무시합니다.
|
||||||
|
}
|
||||||
|
|
||||||
|
$koreanInitials = ['ㄱ','ㄲ','ㄴ','ㄷ','ㄸ','ㄹ','ㅁ','ㅂ','ㅃ','ㅅ','ㅆ','ㅇ','ㅈ','ㅉ','ㅊ','ㅋ','ㅌ','ㅍ','ㅎ'];
|
||||||
|
$englishInitials = ['G','KK','N','D','TT','R','M','B','BB','S','SS','O','J','JJ','CH','K','T','P','H'];
|
||||||
|
$initials = strtr($initials, array_combine($koreanInitials, $englishInitials));
|
||||||
|
|
||||||
|
$initials = str_replace(' ', '', $initials);
|
||||||
|
return strtoupper($initials);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 10진수 숫자를 4자리 36진수 문자열로 변환합니다.
|
||||||
|
*
|
||||||
|
* @param int $number
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function toBase36(int $number): string
|
||||||
|
{
|
||||||
|
$result = '';
|
||||||
|
$base = strlen($this->base36Chars);
|
||||||
|
|
||||||
|
// **수정된 부분: 4자리 고정**
|
||||||
|
for ($i = 0; $i < 4; $i++) {
|
||||||
|
$remainder = $number % $base;
|
||||||
|
$result = $this->base36Chars[$remainder] . $result;
|
||||||
|
$number = floor($number / $base);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 36진수 문자열을 10진수 숫자로 변환합니다.
|
||||||
|
*
|
||||||
|
* @param string $base36String
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
private function fromBase36(string $base36String): int
|
||||||
|
{
|
||||||
|
$number = 0;
|
||||||
|
$base = strlen($this->base36Chars);
|
||||||
|
$len = strlen($base36String);
|
||||||
|
|
||||||
|
for ($i = 0; $i < $len; $i++) {
|
||||||
|
$char = $base36String[$i];
|
||||||
|
$charValue = strpos($this->base36Chars, $char);
|
||||||
|
|
||||||
|
// strpos가 false를 반환할 경우를 대비해 예외 처리
|
||||||
|
if ($charValue === false) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
$number += $charValue * ($base ** ($len - 1 - $i));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 한글 업체명 기반으로 순환형 테넌트 코드를 생성합니다.
|
||||||
|
*
|
||||||
|
* @param string $tenantName
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function generateTenantCode(string $tenantName): string
|
||||||
|
{
|
||||||
|
$cleanTenantName = str_replace(['주식회사', '(주)', '유한회사', '(유)', '유한책임회사', '(유)책', '합명회사', '(합)', '합자회사', '(합자)'], '', $tenantName);
|
||||||
|
|
||||||
|
// 1. 전처리된 업체명에서 초성 약어 생성
|
||||||
|
$initials = $this->getInitials($cleanTenantName);
|
||||||
|
|
||||||
|
// 2. 모든 테넌트들의 코드 중 가장 큰 순번을 찾습니다.
|
||||||
|
$lastNumber = -1;
|
||||||
|
$existingTenants = Tenant::all();
|
||||||
|
|
||||||
|
foreach ($existingTenants as $tenant) {
|
||||||
|
// **수정된 부분: 코드 마지막 4자리를 순번으로 간주**
|
||||||
|
if (strlen($tenant->code) >= 4) {
|
||||||
|
$sequenceString = substr($tenant->code, -4);
|
||||||
|
|
||||||
|
// 마지막 4자리가 36진수 문자열인지 확인
|
||||||
|
if (strspn($sequenceString, $this->base36Chars) === 4) {
|
||||||
|
$sequence = $this->fromBase36($sequenceString);
|
||||||
|
if ($sequence > $lastNumber) {
|
||||||
|
$lastNumber = $sequence;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 마지막 순번에 1을 더하고 36^4 (1,679,616)로 나눈 나머지로 순환하도록 유지합니다.
|
||||||
|
// **수정된 부분: 46656 -> 1679616 으로 변경**
|
||||||
|
$nextSequence = ($lastNumber + 1) % 1679616;
|
||||||
|
|
||||||
|
// 4. 순번을 4자리 36진수 문자열로 포맷
|
||||||
|
// **수정된 부분: toBase36 호출**
|
||||||
|
$formattedSequence = $this->toBase36($nextSequence);
|
||||||
|
|
||||||
|
// 5. 초성 약어와 순번을 조합하여 최종 코드 생성
|
||||||
|
$code = $initials . $formattedSequence;
|
||||||
|
|
||||||
|
return $code;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 테넌트 목록 조회 (페이징)
|
||||||
|
*
|
||||||
|
* @param array $params [page, size, search 등]
|
||||||
|
*/
|
||||||
|
public static function getTenants(array $params = [])
|
||||||
|
{
|
||||||
|
|
||||||
|
$pageNo = isset($params['page']) ? (int)$params['page'] : 1;
|
||||||
|
$pageSize = isset($params['size']) ? (int)$params['size'] : 10;
|
||||||
|
|
||||||
|
$query = Tenant::query();
|
||||||
|
|
||||||
|
// (옵션) 간단 검색 예시: 회사명/코드
|
||||||
|
if (!empty($params['q'])) {
|
||||||
|
$q = trim($params['q']);
|
||||||
|
$query->where(function ($qq) use ($q) {
|
||||||
|
$qq->where('company_name', 'like', "%{$q}%")
|
||||||
|
->orWhere('code', 'like', "%{$q}%")
|
||||||
|
->orWhere('email', 'like', "%{$q}%");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// (옵션) 정렬
|
||||||
|
if (!empty($params['sort']) && in_array($params['sort'], ['company_name','code','created_at','updated_at'])) {
|
||||||
|
$dir = (!empty($params['dir']) && in_array(strtolower($params['dir']), ['asc','desc'])) ? $params['dir'] : 'desc';
|
||||||
|
$query->orderBy($params['sort'], $dir);
|
||||||
|
} else {
|
||||||
|
$query->orderByDesc('id');
|
||||||
|
}
|
||||||
|
|
||||||
|
$paginator = $query->paginate($pageSize, ['*'], 'page', $pageNo);
|
||||||
|
|
||||||
|
return ApiResponse::response('result', $paginator);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 단일 테넌트 조회
|
||||||
|
* - params.tenant_id 가 있으면 해당 테넌트
|
||||||
|
* - 없으면 현재 사용자 기본(is_default=1) 테넌트
|
||||||
|
*
|
||||||
|
* @param array $params [tenant_id]
|
||||||
|
*/
|
||||||
|
public static function getTenant(array $params = [])
|
||||||
|
{
|
||||||
|
|
||||||
|
$tenantId = $params['tenant_id'] ?? app('tenant_id');
|
||||||
|
|
||||||
|
if (!$tenantId) {
|
||||||
|
// 현재 사용자 기본 테넌트 조회
|
||||||
|
$apiUser = app('api_user');
|
||||||
|
$userTenant = UserTenant::where('user_id', $apiUser)
|
||||||
|
->where('is_default', 1)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if (!$userTenant) {
|
||||||
|
return ApiResponse::error('활성(기본) 테넌트를 찾을 수 없습니다.', 404);
|
||||||
|
}
|
||||||
|
$tenantId = $userTenant->tenant_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 필요한 컬럼만 선택 (원하면 조정)
|
||||||
|
$query = Tenant::query()
|
||||||
|
->select('id','company_name','code','email','phone','address','business_num','corp_reg_no','ceo_name','homepage','fax','logo','admin_memo','options','created_at','updated_at')
|
||||||
|
->where('id', $tenantId);
|
||||||
|
|
||||||
|
return ApiResponse::response('first', $query);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 테넌트 등록
|
||||||
|
*
|
||||||
|
* @param array $params
|
||||||
|
*/
|
||||||
|
public static function storeTenants(array $params = [])
|
||||||
|
{
|
||||||
|
|
||||||
|
$validator = Validator::make($params, [
|
||||||
|
'company_name' => 'required|string|max:255',
|
||||||
|
'email' => 'nullable|email|max:100',
|
||||||
|
'phone' => 'nullable|string|max:30',
|
||||||
|
'address' => 'nullable|string|max:255',
|
||||||
|
'business_num' => 'nullable|string|max:30',
|
||||||
|
'corp_reg_no' => 'nullable|string|max:30',
|
||||||
|
'ceo_name' => 'nullable|string|max:100',
|
||||||
|
'homepage' => 'nullable|string|max:255',
|
||||||
|
'fax' => 'nullable|string|max:50',
|
||||||
|
'logo' => 'nullable|string|max:255',
|
||||||
|
'admin_memo' => 'nullable|string',
|
||||||
|
'options' => 'nullable', // JSON 문자열 저장이라면 'nullable|json'
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
if ($validator->fails()) {
|
||||||
|
return ApiResponse::error($validator->errors()->first(), 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$payload = $validator->validated();
|
||||||
|
|
||||||
|
// TenantService 인스턴스를 가져옵니다.
|
||||||
|
$tenantService = app(TenantService::class);
|
||||||
|
|
||||||
|
// 업체명 기반으로 고유한 코드를 생성합니다.
|
||||||
|
$code = $tenantService->generateTenantCode($payload['company_name']);
|
||||||
|
|
||||||
|
// 생성된 코드를 페이로드에 추가합니다.
|
||||||
|
$payload['code'] = $code;
|
||||||
|
|
||||||
|
$tenant = Tenant::create($payload);
|
||||||
|
|
||||||
|
// 생성된 리소스를 그대로 반환 (목록 카드용 요약 원하면 컬럼 제한)
|
||||||
|
return ApiResponse::response('result', $tenant);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 테넌트 수정
|
||||||
|
*
|
||||||
|
* @param array $params
|
||||||
|
*/
|
||||||
|
public static function updateTenant(array $params = [])
|
||||||
|
{
|
||||||
|
|
||||||
|
$validator = Validator::make($params, [
|
||||||
|
'company_name' => 'sometimes|string|max:255',
|
||||||
|
'email' => 'sometimes|nullable|email|max:100',
|
||||||
|
'phone' => 'sometimes|nullable|string|max:30',
|
||||||
|
'address' => 'sometimes|nullable|string|max:255',
|
||||||
|
'business_num' => 'sometimes|nullable|string|max:30',
|
||||||
|
'corp_reg_no' => 'sometimes|nullable|string|max:30',
|
||||||
|
'ceo_name' => 'sometimes|nullable|string|max:100',
|
||||||
|
'homepage' => 'sometimes|nullable|string|max:255',
|
||||||
|
'fax' => 'sometimes|nullable|string|max:50',
|
||||||
|
'logo' => 'sometimes|nullable|string|max:255',
|
||||||
|
'admin_memo' => 'sometimes|nullable|string',
|
||||||
|
'options' => 'sometimes|nullable', // JSON 문자열이면 'sometimes|nullable|json'
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($validator->fails()) {
|
||||||
|
return ApiResponse::error($validator->errors()->first(), 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$payload = $validator->validated();
|
||||||
|
$tenantId = app('tenant_id') ?? null;
|
||||||
|
unset($payload['tenant_id']);
|
||||||
|
|
||||||
|
if (empty($payload)) {
|
||||||
|
return ApiResponse::error('수정할 데이터가 없습니다.', 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$tenant = Tenant::find($tenantId);
|
||||||
|
if (!$tenant) {
|
||||||
|
return ApiResponse::error('테넌트를 찾을 수 없습니다.', 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
$tenant->update($payload);
|
||||||
|
|
||||||
|
return ApiResponse::response('result', $tenant->fresh());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 테넌트 삭제(탈퇴) — 소프트 삭제 가정
|
||||||
|
*
|
||||||
|
* @param int $tenant_id
|
||||||
|
*/
|
||||||
|
public static function destroyTenant(array $params = [])
|
||||||
|
{
|
||||||
|
$tenantId = $params['tenant_id'] ?? app('tenant_id');
|
||||||
|
if (!$tenantId) {
|
||||||
|
return ApiResponse::error('tenant_id가 필요합니다.', 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$tenant = Tenant::find($tenantId);
|
||||||
|
if (!$tenant) {
|
||||||
|
return ApiResponse::error('테넌트를 찾을 수 없습니다.', 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
$tenant->delete(); // SoftDeletes 트레이트가 있으면 소프트 삭제
|
||||||
|
|
||||||
|
return ApiResponse::response('success');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 테넌트 복구 (소프트 삭제된 레코드 대상)
|
||||||
|
*
|
||||||
|
* @param array $params [tenant_id:int]
|
||||||
|
*/
|
||||||
|
public static function restoreTenant(array $params = [])
|
||||||
|
{
|
||||||
|
$tenantId = $params['tenant_id'] ?? app('tenant_id');
|
||||||
|
|
||||||
|
// 소프트 삭제 포함 조회
|
||||||
|
$tenant = Tenant::withTrashed()->find($tenantId);
|
||||||
|
if (!$tenant) {
|
||||||
|
return ApiResponse::error('테넌트를 찾을 수 없습니다.', 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_null($tenant->deleted_at)) {
|
||||||
|
// 이미 활성 상태
|
||||||
|
return ApiResponse::error('이미 활성화된 테넌트입니다.', 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$tenant->restore();
|
||||||
|
|
||||||
|
// 복구 결과를 data에 담고 싶으면 fresh() 후 필요한 필드만 반환
|
||||||
|
// return ApiResponse::response('result', $tenant->fresh());
|
||||||
|
|
||||||
|
return ApiResponse::response('success');
|
||||||
|
}
|
||||||
|
}
|
||||||
281
app/Swagger/v1/TenantApi.php
Normal file
281
app/Swagger/v1/TenantApi.php
Normal file
@@ -0,0 +1,281 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Swagger\v1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @OA\Tag(name="Auth", description="로그인/로그아웃")
|
||||||
|
* @OA\Tag(name="User", description="사용자 본인 정보/비밀번호 변경 등")
|
||||||
|
* @OA\Tag(name="Tenant", description="테넌트 정보 조회/수정/등록/삭제")
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @OA\Schema(
|
||||||
|
* schema="Tenant",
|
||||||
|
* type="object",
|
||||||
|
* description="테넌트 상세 정보",
|
||||||
|
* required={"id","company_name"},
|
||||||
|
* @OA\Property(property="id", type="integer", example=1),
|
||||||
|
* @OA\Property(property="company_name", type="string", example="(주)경동기업"),
|
||||||
|
* @OA\Property(property="code", type="string", example="KDCOM"),
|
||||||
|
* @OA\Property(property="email", type="string", example="kd5130@naver.com"),
|
||||||
|
* @OA\Property(property="phone", type="string", example="01083935130"),
|
||||||
|
* @OA\Property(property="address", type="string", example="경기도 김포시 통진읍 옹정로 45-22"),
|
||||||
|
* @OA\Property(property="business_num", type="string", example="1398700333"),
|
||||||
|
* @OA\Property(property="corp_reg_no", type="string", nullable=true, example=null),
|
||||||
|
* @OA\Property(property="ceo_name", type="string", example="이대표"),
|
||||||
|
* @OA\Property(property="homepage", type="string", nullable=true, example=null),
|
||||||
|
* @OA\Property(property="fax", type="string", nullable=true, example=null),
|
||||||
|
* @OA\Property(property="logo", type="string", nullable=true, example=null),
|
||||||
|
* @OA\Property(property="admin_memo", type="string", nullable=true, example=null),
|
||||||
|
* @OA\Property(property="options", type="string", nullable=true, example=null),
|
||||||
|
* @OA\Property(property="created_at", type="string", format="date-time", example="2025-07-16 18:28:41"),
|
||||||
|
* @OA\Property(property="updated_at", type="string", format="date-time", example="2025-07-25 23:13:06"),
|
||||||
|
* @OA\Property(property="deleted_at", type="string", format="date-time", nullable=true, example=null)
|
||||||
|
* )
|
||||||
|
*
|
||||||
|
* @OA\Schema(
|
||||||
|
* schema="TenantPagination",
|
||||||
|
* type="object",
|
||||||
|
* description="라라벨 LengthAwarePaginator 기본 구조",
|
||||||
|
* @OA\Property(property="current_page", type="integer", example=1),
|
||||||
|
* @OA\Property(
|
||||||
|
* property="data",
|
||||||
|
* type="array",
|
||||||
|
* @OA\Items(ref="#/components/schemas/TenantBrief")
|
||||||
|
* ),
|
||||||
|
* @OA\Property(property="first_page_url", type="string", example="/api/v1/tenants/list?page=1"),
|
||||||
|
* @OA\Property(property="from", type="integer", example=1),
|
||||||
|
* @OA\Property(property="last_page", type="integer", example=1),
|
||||||
|
* @OA\Property(property="last_page_url", type="string", example="/api/v1/tenants/list?page=1"),
|
||||||
|
* @OA\Property(
|
||||||
|
* property="links",
|
||||||
|
* type="array",
|
||||||
|
* @OA\Items(
|
||||||
|
* type="object",
|
||||||
|
* @OA\Property(property="url", type="string", nullable=true, example=null),
|
||||||
|
* @OA\Property(property="label", type="string", example="« Previous"),
|
||||||
|
* @OA\Property(property="active", type="boolean", example=false)
|
||||||
|
* )
|
||||||
|
* ),
|
||||||
|
* @OA\Property(property="next_page_url", type="string", nullable=true, example=null),
|
||||||
|
* @OA\Property(property="path", type="string", example="/api/v1/tenants/list"),
|
||||||
|
* @OA\Property(property="per_page", type="integer", example=20),
|
||||||
|
* @OA\Property(property="prev_page_url", type="string", nullable=true, example=null),
|
||||||
|
* @OA\Property(property="to", type="integer", example=3),
|
||||||
|
* @OA\Property(property="total", type="integer", example=3)
|
||||||
|
* )
|
||||||
|
*
|
||||||
|
* @OA\Schema(
|
||||||
|
* schema="TenantCreateRequest",
|
||||||
|
* type="object",
|
||||||
|
* required={"company_name"},
|
||||||
|
* @OA\Property(property="company_name", type="string", example="(주)신규기업", description="회사명"),
|
||||||
|
* @OA\Property(property="email", type="string", nullable=true, example="newcompany@example.com", description="대표 이메일"),
|
||||||
|
* @OA\Property(property="phone", type="string", nullable=true, example="01012345678", description="대표 연락처"),
|
||||||
|
* @OA\Property(property="address", type="string", nullable=true, example="서울시 강남구", description="주소"),
|
||||||
|
* @OA\Property(property="business_num", type="string", nullable=true, example="1234567890", description="사업자등록번호"),
|
||||||
|
* @OA\Property(property="ceo_name", type="string", nullable=true, example="김대표", description="대표자명")
|
||||||
|
* )
|
||||||
|
*
|
||||||
|
* @OA\Schema(
|
||||||
|
* schema="TenantUpdateRequest",
|
||||||
|
* type="object",
|
||||||
|
* @OA\Property(property="tenant_id", type="integer", example=1, description="수정 대상 테넌트 ID"),
|
||||||
|
* @OA\Property(property="company_name", type="string", example="(주)신규기업", description="회사명"),
|
||||||
|
* @OA\Property(property="email", type="string", example="newcompany@example.com", description="대표 이메일"),
|
||||||
|
* @OA\Property(property="phone", type="string", example="01012345678", description="대표 연락처"),
|
||||||
|
* @OA\Property(property="address", type="string", nullable=true, example="서울시 강남구", description="주소"),
|
||||||
|
* @OA\Property(property="business_num", type="string", nullable=true, example="1234567890", description="사업자등록번호"),
|
||||||
|
* @OA\Property(property="ceo_name", type="string", nullable=true, example="김대표", description="대표자명")
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
class TenantApi
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @OA\Get(
|
||||||
|
* path="/api/v1/tenants/list",
|
||||||
|
* summary="테넌트 목록 조회",
|
||||||
|
* description="등록된 모든 테넌트 목록을 페이징 형태로 반환합니다.",
|
||||||
|
* tags={"Tenant"},
|
||||||
|
* security={{"ApiKeyAuth": {}},{"BearerAuth": {}}},
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/Page"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/Size"),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="테넌트 목록 조회 성공",
|
||||||
|
* @OA\JsonContent(
|
||||||
|
* allOf={
|
||||||
|
* @OA\Schema(ref="#/components/schemas/ApiResponse"),
|
||||||
|
* @OA\Schema(@OA\Property(property="data", ref="#/components/schemas/TenantPagination"))
|
||||||
|
* }
|
||||||
|
* )
|
||||||
|
* ),
|
||||||
|
* @OA\Response(response=401, description="인증 실패", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||||||
|
* @OA\Response(response=403, description="권한 없음", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||||||
|
* @OA\Response(response=405, description="허용되지 않는 메서드", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||||||
|
* @OA\Response(response=500, description="서버 에러", @OA\JsonContent(ref="#/components/schemas/ErrorResponse"))
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function index() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @OA\Get(
|
||||||
|
* path="/api/v1/tenants",
|
||||||
|
* summary="테넌트 정보 조회",
|
||||||
|
* description="활성(현재) 테넌트의 상세 정보를 조회합니다. 필요 시 쿼리로 특정 테넌트를 확장할 수 있습니다.",
|
||||||
|
* tags={"Tenant"},
|
||||||
|
* security={{"ApiKeyAuth": {}},{"BearerAuth": {}}},
|
||||||
|
* @OA\Parameter(
|
||||||
|
* name="tenant_id",
|
||||||
|
* in="query",
|
||||||
|
* required=false,
|
||||||
|
* description="조회할 테넌트 ID (없으면 활성 테넌트)",
|
||||||
|
* @OA\Schema(type="integer", example=1)
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="테넌트 정보 조회 성공",
|
||||||
|
* @OA\JsonContent(
|
||||||
|
* allOf={
|
||||||
|
* @OA\Schema(ref="#/components/schemas/ApiResponse"),
|
||||||
|
* @OA\Schema(@OA\Property(property="data", ref="#/components/schemas/Tenant"))
|
||||||
|
* }
|
||||||
|
* )
|
||||||
|
* ),
|
||||||
|
* @OA\Response(response=401, description="인증 실패", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||||||
|
* @OA\Response(response=403, description="권한 없음", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||||||
|
* @OA\Response(response=404, description="존재하지 않는 URI 또는 데이터", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||||||
|
* @OA\Response(response=405, description="허용되지 않는 메서드", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||||||
|
* @OA\Response(response=500, description="서버 에러", @OA\JsonContent(ref="#/components/schemas/ErrorResponse"))
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function show() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @OA\Post(
|
||||||
|
* path="/api/v1/tenants",
|
||||||
|
* summary="테넌트 등록",
|
||||||
|
* description="새로운 테넌트를 등록합니다.",
|
||||||
|
* tags={"Tenant"},
|
||||||
|
* security={{"ApiKeyAuth": {}},{"BearerAuth": {}}},
|
||||||
|
* @OA\RequestBody(required=true, @OA\JsonContent(ref="#/components/schemas/TenantCreateRequest")),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="등록 성공",
|
||||||
|
* @OA\JsonContent(
|
||||||
|
* allOf={
|
||||||
|
* @OA\Schema(ref="#/components/schemas/ApiResponse"),
|
||||||
|
* @OA\Schema(
|
||||||
|
* @OA\Property(property="message", type="string", example="등록 성공"),
|
||||||
|
* @OA\Property(property="data", ref="#/components/schemas/TenantBrief")
|
||||||
|
* )
|
||||||
|
* }
|
||||||
|
* )
|
||||||
|
* ),
|
||||||
|
* @OA\Response(response=400, description="필수 파라미터 누락", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||||||
|
* @OA\Response(response=401, description="인증 실패", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||||||
|
* @OA\Response(response=403, description="권한 없음", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||||||
|
* @OA\Response(response=405, description="허용되지 않는 메서드", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||||||
|
* @OA\Response(response=500, description="서버 에러", @OA\JsonContent(ref="#/components/schemas/ErrorResponse"))
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function store() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @OA\Put(
|
||||||
|
* path="/api/v1/tenants",
|
||||||
|
* summary="테넌트 정보 수정",
|
||||||
|
* description="기존 테넌트 정보를 수정합니다.",
|
||||||
|
* tags={"Tenant"},
|
||||||
|
* security={{"ApiKeyAuth": {}},{"BearerAuth": {}}},
|
||||||
|
* @OA\RequestBody(required=true, @OA\JsonContent(ref="#/components/schemas/TenantUpdateRequest")),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="수정 성공",
|
||||||
|
* @OA\JsonContent(
|
||||||
|
* allOf={
|
||||||
|
* @OA\Schema(ref="#/components/schemas/ApiResponse"),
|
||||||
|
* @OA\Schema(
|
||||||
|
* @OA\Property(property="message", type="string", example="수정 성공"),
|
||||||
|
* @OA\Property(property="data", ref="#/components/schemas/TenantBrief")
|
||||||
|
* )
|
||||||
|
* }
|
||||||
|
* )
|
||||||
|
* ),
|
||||||
|
* @OA\Response(response=400, description="필수 파라미터 누락", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||||||
|
* @OA\Response(response=401, description="인증 실패", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||||||
|
* @OA\Response(response=403, description="권한 없음", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||||||
|
* @OA\Response(response=404, description="데이터 없음", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||||||
|
* @OA\Response(response=405, description="허용되지 않는 메서드", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||||||
|
* @OA\Response(response=500, description="서버 에러", @OA\JsonContent(ref="#/components/schemas/ErrorResponse"))
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function update() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @OA\Delete(
|
||||||
|
* path="/api/v1/tenants",
|
||||||
|
* summary="테넌트 삭제(탈퇴)",
|
||||||
|
* description="테넌트를 삭제(또는 탈퇴 처리)합니다.",
|
||||||
|
* tags={"Tenant"},
|
||||||
|
* security={{"ApiKeyAuth": {}},{"BearerAuth": {}}},
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="삭제 성공",
|
||||||
|
* @OA\JsonContent(
|
||||||
|
* allOf={
|
||||||
|
* @OA\Schema(ref="#/components/schemas/ApiResponse"),
|
||||||
|
* @OA\Schema(
|
||||||
|
* @OA\Property(property="message", type="string", example="삭제 성공"),
|
||||||
|
* @OA\Property(property="data", type="object", nullable=true, example=null)
|
||||||
|
* )
|
||||||
|
* }
|
||||||
|
* )
|
||||||
|
* ),
|
||||||
|
* @OA\Response(response=400, description="필수 파라미터 누락", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||||||
|
* @OA\Response(response=401, description="인증 실패", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||||||
|
* @OA\Response(response=403, description="권한 없음", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||||||
|
* @OA\Response(response=404, description="데이터 없음", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||||||
|
* @OA\Response(response=405, description="허용되지 않는 메서드", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||||||
|
* @OA\Response(response=500, description="서버 에러", @OA\JsonContent(ref="#/components/schemas/ErrorResponse"))
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function destroy() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @OA\Put(
|
||||||
|
* path="/api/v1/tenants/restore/{tenant_id}",
|
||||||
|
* summary="테넌트 복구",
|
||||||
|
* description="삭제(소프트 삭제)된 테넌트를 복구합니다.",
|
||||||
|
* tags={"Tenant"},
|
||||||
|
* security={{"ApiKeyAuth": {}},{"BearerAuth": {}}},
|
||||||
|
* @OA\Parameter(
|
||||||
|
* name="tenant_id",
|
||||||
|
* in="path",
|
||||||
|
* required=true,
|
||||||
|
* description="복구할 테넌트 ID",
|
||||||
|
* @OA\Schema(type="integer", example=1)
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="복구 성공",
|
||||||
|
* @OA\JsonContent(
|
||||||
|
* allOf={
|
||||||
|
* @OA\Schema(ref="#/components/schemas/ApiResponse"),
|
||||||
|
* @OA\Schema(
|
||||||
|
* @OA\Property(property="message", type="string", example="복구 성공"),
|
||||||
|
* @OA\Property(property="data", type="object", nullable=true, example=null)
|
||||||
|
* )
|
||||||
|
* }
|
||||||
|
* )
|
||||||
|
* ),
|
||||||
|
* @OA\Response(response=400, description="필수 파라미터 누락", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||||||
|
* @OA\Response(response=401, description="인증 실패", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||||||
|
* @OA\Response(response=403, description="권한 없음", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||||||
|
* @OA\Response(response=404, description="데이터 없음", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||||||
|
* @OA\Response(response=405, description="허용되지 않는 메서드", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||||||
|
* @OA\Response(response=500, description="서버 에러", @OA\JsonContent(ref="#/components/schemas/ErrorResponse"))
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function restore() {}
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
use App\Http\Controllers\Api\V1\ModelController;
|
use App\Http\Controllers\Api\V1\ModelController;
|
||||||
use App\Http\Controllers\Api\V1\BomController;
|
use App\Http\Controllers\Api\V1\BomController;
|
||||||
use App\Http\Controllers\Api\V1\UserController;
|
use App\Http\Controllers\Api\V1\UserController;
|
||||||
|
use App\Http\Controllers\Api\V1\TenantController;
|
||||||
|
|
||||||
// error test
|
// error test
|
||||||
Route::get('/test-error', function () {
|
Route::get('/test-error', function () {
|
||||||
@@ -61,6 +62,17 @@
|
|||||||
Route::patch('me/tenants/switch', [UserController::class, 'switchTenant'])->name('v1.users.me.tenants.switch'); // 활성 테넌트 전환
|
Route::patch('me/tenants/switch', [UserController::class, 'switchTenant'])->name('v1.users.me.tenants.switch'); // 활성 테넌트 전환
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Tenant API
|
||||||
|
Route::prefix('tenants')->group(function () {
|
||||||
|
Route::get('list', [TenantController::class, 'index'])->name('v1.tenant.index'); // 테넌트 목록 조회
|
||||||
|
Route::get('/', [TenantController::class, 'show'])->name('v1.tenant.show'); // 테넌트 정보 조회
|
||||||
|
Route::put('/', [TenantController::class, 'update'])->name('v1.tenant.update'); // 테넌트 정보 수정
|
||||||
|
Route::post('/', [TenantController::class, 'store'])->name('v1.tenant.store'); // 테넌트 등록
|
||||||
|
Route::delete('/', [TenantController::class, 'destroy'])->name('v1.tenant.destroy'); // 테넌트 삭제(탈퇴)
|
||||||
|
Route::put('/restore/{tenant_id}', [TenantController::class, 'restore'])->name('v1.tenant.restore'); // 테넌트 복구
|
||||||
|
});
|
||||||
|
|
||||||
// File API
|
// File API
|
||||||
Route::prefix('file')->group(function () {
|
Route::prefix('file')->group(function () {
|
||||||
Route::post('upload', [FileController::class, 'upload'])->name('v1.file.upload'); // 파일 업로드 (등록/수정)
|
Route::post('upload', [FileController::class, 'upload'])->name('v1.file.upload'); // 파일 업로드 (등록/수정)
|
||||||
|
|||||||
Reference in New Issue
Block a user