delete fortify, jetstream

This commit is contained in:
2025-07-28 12:57:08 +09:00
parent c9f4e27ad1
commit 1233058eda
11 changed files with 790 additions and 791 deletions

View File

@@ -17,11 +17,15 @@ class Handler extends ExceptionHandler
{
public function report(Throwable $e): void
{
if (
app()->environment('local') || app()->environment('production')
|| app()->environment('LOCAL') || app()->environment('DEV')
) {
$this->sendSlackException($e);
try {
if (
app()->environment('local') || app()->environment('production')
|| app()->environment('LOCAL') || app()->environment('DEV')
) {
$this->sendSlackException($e);
}
} catch (\Throwable $ex) {
// app()이 아직 사용 불가하거나 env 문제가 있을 때는 무시
}
parent::report($e); // 로그는 그대로

View File

@@ -1,5 +1,7 @@
<?php
namespace App\Models\Boards;
use Illuminate\Database\Eloquent\Model;
class BoardSetting extends Model

View File

@@ -5,13 +5,12 @@
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Fortify\TwoFactorAuthenticatable;
use Laravel\Sanctum\HasApiTokens;
use App\Traits\ModelTrait;
class User extends Authenticatable
{
use HasApiTokens, Notifiable, TwoFactorAuthenticatable, SoftDeletes, ModelTrait;
use HasApiTokens, Notifiable, SoftDeletes, ModelTrait;
protected $hidden = [
'password', 'remember_token',

View File

@@ -1,76 +0,0 @@
<?php
namespace App\Providers;
use App\Actions\Fortify\CreateNewUser;
use App\Actions\Fortify\ResetUserPassword;
use App\Actions\Fortify\UpdateUserPassword;
use App\Actions\Fortify\UpdateUserProfileInformation;
use App\Models\Member;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Str;
use Laravel\Fortify\Fortify;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Log;
use Laravel\Fortify\Contracts\LoginResponse;
use App\Http\Responses\CustomLoginResponse;
class FortifyServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
// ✅ 커스텀 로그인 응답 등록
$this->app->singleton(LoginResponse::class, CustomLoginResponse::class);
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Fortify::createUsersUsing(CreateNewUser::class);
Fortify::updateUserProfileInformationUsing(UpdateUserProfileInformation::class);
Fortify::updateUserPasswordsUsing(UpdateUserPassword::class);
Fortify::resetUserPasswordsUsing(ResetUserPassword::class);
// ✅ 로그인 시 `USER_ID`를 사용하도록 변경
Fortify::authenticateUsing(function (Request $request) {
$user = Member::where('mb_id', $request->USER_ID)->first();
if(!$user) return null;
if (Str::startsWith($user->mb_pass, '$2y$')) {
// bcrypt로 해싱된 경우
if(Hash::check($request->password, $user->mb_pass)) return $user;
} else {
// sha256으로 해싱된 경우
if(strtoupper(hash('sha256', $request->password))) return $user;;
}
return null;
});
Fortify::loginView(fn() => view('auth.login')); // 로그인 페이지 지정
RateLimiter::for('login', function (Request $request) {
$throttleKey = Str::transliterate(Str::lower($request->input('USER_ID')).'|'.$request->ip());
return Limit::perMinute(5)->by($throttleKey);
});
RateLimiter::for('two-factor', function (Request $request) {
return Limit::perMinute(5)->by($request->session()->get('login.id'));
});
}
}

View File

@@ -1,43 +0,0 @@
<?php
namespace App\Providers;
use App\Actions\Jetstream\DeleteUser;
use Illuminate\Support\ServiceProvider;
use Laravel\Jetstream\Jetstream;
class JetstreamServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
//
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
$this->configurePermissions();
Jetstream::deleteUsersUsing(DeleteUser::class);
}
/**
* Configure the permissions that are available within the application.
*/
protected function configurePermissions(): void
{
Jetstream::defaultApiTokenPermissions(['read']);
Jetstream::permissions([
'create',
'read',
'update',
'delete',
]);
}
}

View File

@@ -2,6 +2,4 @@
return [
App\Providers\AppServiceProvider::class,
App\Providers\FortifyServiceProvider::class,
App\Providers\JetstreamServiceProvider::class,
];

View File

@@ -10,7 +10,6 @@
"darkaonline/l5-swagger": "^9.0",
"doctrine/dbal": "^4.3",
"laravel/framework": "^12.0",
"laravel/jetstream": "^5.3",
"laravel/sanctum": "^4.0",
"laravel/tinker": "^2.10.1",
"livewire/livewire": "^3.0"

422
composer.lock generated
View File

@@ -4,62 +4,8 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "592e08448fda5a7d5260d0ed24f8e7ce",
"content-hash": "9827ba355b77e4e0b827c6f2a101003d",
"packages": [
{
"name": "bacon/bacon-qr-code",
"version": "v3.0.1",
"source": {
"type": "git",
"url": "https://github.com/Bacon/BaconQrCode.git",
"reference": "f9cc1f52b5a463062251d666761178dbdb6b544f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/f9cc1f52b5a463062251d666761178dbdb6b544f",
"reference": "f9cc1f52b5a463062251d666761178dbdb6b544f",
"shasum": ""
},
"require": {
"dasprid/enum": "^1.0.3",
"ext-iconv": "*",
"php": "^8.1"
},
"require-dev": {
"phly/keep-a-changelog": "^2.12",
"phpunit/phpunit": "^10.5.11 || 11.0.4",
"spatie/phpunit-snapshot-assertions": "^5.1.5",
"squizlabs/php_codesniffer": "^3.9"
},
"suggest": {
"ext-imagick": "to generate QR code images"
},
"type": "library",
"autoload": {
"psr-4": {
"BaconQrCode\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-2-Clause"
],
"authors": [
{
"name": "Ben Scholzen 'DASPRiD'",
"email": "mail@dasprids.de",
"homepage": "https://dasprids.de/",
"role": "Developer"
}
],
"description": "BaconQrCode is a QR code generator for PHP.",
"homepage": "https://github.com/Bacon/BaconQrCode",
"support": {
"issues": "https://github.com/Bacon/BaconQrCode/issues",
"source": "https://github.com/Bacon/BaconQrCode/tree/v3.0.1"
},
"time": "2024-10-01T13:55:55+00:00"
},
{
"name": "brick/math",
"version": "0.13.1",
@@ -270,56 +216,6 @@
],
"time": "2025-02-28T06:25:02+00:00"
},
{
"name": "dasprid/enum",
"version": "1.0.6",
"source": {
"type": "git",
"url": "https://github.com/DASPRiD/Enum.git",
"reference": "8dfd07c6d2cf31c8da90c53b83c026c7696dda90"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/DASPRiD/Enum/zipball/8dfd07c6d2cf31c8da90c53b83c026c7696dda90",
"reference": "8dfd07c6d2cf31c8da90c53b83c026c7696dda90",
"shasum": ""
},
"require": {
"php": ">=7.1 <9.0"
},
"require-dev": {
"phpunit/phpunit": "^7 || ^8 || ^9 || ^10 || ^11",
"squizlabs/php_codesniffer": "*"
},
"type": "library",
"autoload": {
"psr-4": {
"DASPRiD\\Enum\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-2-Clause"
],
"authors": [
{
"name": "Ben Scholzen 'DASPRiD'",
"email": "mail@dasprids.de",
"homepage": "https://dasprids.de/",
"role": "Developer"
}
],
"description": "PHP 7.1 enum implementation",
"keywords": [
"enum",
"map"
],
"support": {
"issues": "https://github.com/DASPRiD/Enum/issues",
"source": "https://github.com/DASPRiD/Enum/tree/1.0.6"
},
"time": "2024-08-09T14:30:48+00:00"
},
{
"name": "dflydev/dot-access-data",
"version": "v3.0.3",
@@ -1469,71 +1365,6 @@
],
"time": "2025-02-03T10:55:03+00:00"
},
{
"name": "laravel/fortify",
"version": "v1.27.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/fortify.git",
"reference": "0fb2ec99dfee77ed66884668fc06683acca91ebd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/fortify/zipball/0fb2ec99dfee77ed66884668fc06683acca91ebd",
"reference": "0fb2ec99dfee77ed66884668fc06683acca91ebd",
"shasum": ""
},
"require": {
"bacon/bacon-qr-code": "^3.0",
"ext-json": "*",
"illuminate/support": "^10.0|^11.0|^12.0",
"php": "^8.1",
"pragmarx/google2fa": "^8.0",
"symfony/console": "^6.0|^7.0"
},
"require-dev": {
"mockery/mockery": "^1.0",
"orchestra/testbench": "^8.16|^9.0|^10.0",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^10.4|^11.3"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Laravel\\Fortify\\FortifyServiceProvider"
]
},
"branch-alias": {
"dev-master": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"Laravel\\Fortify\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
}
],
"description": "Backend controllers and scaffolding for Laravel authentication.",
"keywords": [
"auth",
"laravel"
],
"support": {
"issues": "https://github.com/laravel/fortify/issues",
"source": "https://github.com/laravel/fortify"
},
"time": "2025-06-11T14:30:52+00:00"
},
{
"name": "laravel/framework",
"version": "v12.20.0",
@@ -1749,73 +1580,6 @@
},
"time": "2025-07-08T15:02:21+00:00"
},
{
"name": "laravel/jetstream",
"version": "v5.3.7",
"source": {
"type": "git",
"url": "https://github.com/laravel/jetstream.git",
"reference": "b606c21daeaa38547f853789212e3802b0f6ff08"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/jetstream/zipball/b606c21daeaa38547f853789212e3802b0f6ff08",
"reference": "b606c21daeaa38547f853789212e3802b0f6ff08",
"shasum": ""
},
"require": {
"ext-json": "*",
"illuminate/console": "^11.0|^12.0",
"illuminate/support": "^11.0|^12.0",
"laravel/fortify": "^1.20",
"mobiledetect/mobiledetectlib": "^4.8.08",
"php": "^8.2.0",
"symfony/console": "^7.0"
},
"require-dev": {
"inertiajs/inertia-laravel": "^2.0",
"laravel/sanctum": "^4.0",
"livewire/livewire": "^3.3",
"mockery/mockery": "^1.0",
"orchestra/testbench": "^9.0|^10.0",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^11.0"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Laravel\\Jetstream\\JetstreamServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Laravel\\Jetstream\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
}
],
"description": "Tailwind scaffolding for the Laravel framework.",
"keywords": [
"auth",
"laravel",
"tailwind"
],
"support": {
"issues": "https://github.com/laravel/jetstream/issues",
"source": "https://github.com/laravel/jetstream"
},
"time": "2025-06-16T13:27:00+00:00"
},
{
"name": "laravel/prompts",
"version": "v0.3.6",
@@ -2693,71 +2457,6 @@
],
"time": "2025-04-12T22:26:52+00:00"
},
{
"name": "mobiledetect/mobiledetectlib",
"version": "4.8.09",
"source": {
"type": "git",
"url": "https://github.com/serbanghita/Mobile-Detect.git",
"reference": "a06fe2e546a06bb8c2639d6823d5250b2efb3209"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/serbanghita/Mobile-Detect/zipball/a06fe2e546a06bb8c2639d6823d5250b2efb3209",
"reference": "a06fe2e546a06bb8c2639d6823d5250b2efb3209",
"shasum": ""
},
"require": {
"php": ">=8.0",
"psr/cache": "^3.0",
"psr/simple-cache": "^3"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^v3.65.0",
"phpbench/phpbench": "^1.2",
"phpstan/phpstan": "^1.12.x-dev",
"phpunit/phpunit": "^9.6.18",
"squizlabs/php_codesniffer": "^3.11.1"
},
"type": "library",
"autoload": {
"psr-4": {
"Detection\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Serban Ghita",
"email": "serbanghita@gmail.com",
"homepage": "http://mobiledetect.net",
"role": "Developer"
}
],
"description": "Mobile_Detect is a lightweight PHP class for detecting mobile devices. It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.",
"homepage": "https://github.com/serbanghita/Mobile-Detect",
"keywords": [
"detect mobile devices",
"mobile",
"mobile detect",
"mobile detector",
"php mobile detect"
],
"support": {
"issues": "https://github.com/serbanghita/Mobile-Detect/issues",
"source": "https://github.com/serbanghita/Mobile-Detect/tree/4.8.09"
},
"funding": [
{
"url": "https://github.com/serbanghita",
"type": "github"
}
],
"time": "2024-12-10T15:32:06+00:00"
},
{
"name": "monolog/monolog",
"version": "3.9.0",
@@ -3259,73 +2958,6 @@
],
"time": "2025-05-08T08:14:37+00:00"
},
{
"name": "paragonie/constant_time_encoding",
"version": "v3.0.0",
"source": {
"type": "git",
"url": "https://github.com/paragonie/constant_time_encoding.git",
"reference": "df1e7fde177501eee2037dd159cf04f5f301a512"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/df1e7fde177501eee2037dd159cf04f5f301a512",
"reference": "df1e7fde177501eee2037dd159cf04f5f301a512",
"shasum": ""
},
"require": {
"php": "^8"
},
"require-dev": {
"phpunit/phpunit": "^9",
"vimeo/psalm": "^4|^5"
},
"type": "library",
"autoload": {
"psr-4": {
"ParagonIE\\ConstantTime\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Paragon Initiative Enterprises",
"email": "security@paragonie.com",
"homepage": "https://paragonie.com",
"role": "Maintainer"
},
{
"name": "Steve 'Sc00bz' Thomas",
"email": "steve@tobtu.com",
"homepage": "https://www.tobtu.com",
"role": "Original Developer"
}
],
"description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)",
"keywords": [
"base16",
"base32",
"base32_decode",
"base32_encode",
"base64",
"base64_decode",
"base64_encode",
"bin2hex",
"encoding",
"hex",
"hex2bin",
"rfc4648"
],
"support": {
"email": "info@paragonie.com",
"issues": "https://github.com/paragonie/constant_time_encoding/issues",
"source": "https://github.com/paragonie/constant_time_encoding"
},
"time": "2024-05-08T12:36:18+00:00"
},
{
"name": "phpoption/phpoption",
"version": "1.9.3",
@@ -3401,58 +3033,6 @@
],
"time": "2024-07-20T21:41:07+00:00"
},
{
"name": "pragmarx/google2fa",
"version": "v8.0.3",
"source": {
"type": "git",
"url": "https://github.com/antonioribeiro/google2fa.git",
"reference": "6f8d87ebd5afbf7790bde1ffc7579c7c705e0fad"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/antonioribeiro/google2fa/zipball/6f8d87ebd5afbf7790bde1ffc7579c7c705e0fad",
"reference": "6f8d87ebd5afbf7790bde1ffc7579c7c705e0fad",
"shasum": ""
},
"require": {
"paragonie/constant_time_encoding": "^1.0|^2.0|^3.0",
"php": "^7.1|^8.0"
},
"require-dev": {
"phpstan/phpstan": "^1.9",
"phpunit/phpunit": "^7.5.15|^8.5|^9.0"
},
"type": "library",
"autoload": {
"psr-4": {
"PragmaRX\\Google2FA\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Antonio Carlos Ribeiro",
"email": "acr@antoniocarlosribeiro.com",
"role": "Creator & Designer"
}
],
"description": "A One Time Password Authentication package, compatible with Google Authenticator.",
"keywords": [
"2fa",
"Authentication",
"Two Factor Authentication",
"google2fa"
],
"support": {
"issues": "https://github.com/antonioribeiro/google2fa/issues",
"source": "https://github.com/antonioribeiro/google2fa/tree/v8.0.3"
},
"time": "2024-09-05T11:56:40+00:00"
},
{
"name": "psr/cache",
"version": "3.0.0",

View File

@@ -1,160 +0,0 @@
<?php
use Laravel\Fortify\Features;
return [
/*
|--------------------------------------------------------------------------
| Fortify Guard
|--------------------------------------------------------------------------
|
| Here you may specify which authentication guard Fortify will use while
| authenticating users. This value should correspond with one of your
| guards that is already present in your "auth" configuration file.
|
*/
'guard' => 'web',
/*
|--------------------------------------------------------------------------
| Fortify Password Broker
|--------------------------------------------------------------------------
|
| Here you may specify which password broker Fortify can use when a user
| is resetting their password. This configured value should match one
| of your password brokers setup in your "auth" configuration file.
|
*/
'passwords' => 'users',
/*
|--------------------------------------------------------------------------
| Username / Email
|--------------------------------------------------------------------------
|
| This value defines which model attribute should be considered as your
| application's "username" field. Typically, this might be the email
| address of the users but you are free to change this value here.
|
| Out of the box, Fortify expects forgot password and reset password
| requests to have a field named 'email'. If the application uses
| another name for the field you may define it below as needed.
|
*/
'username' => 'USER_ID', // 기본 로그인 필드 변경
'password' => 'USER_PWD', // 기본 비밀번호 필드 변경
'email' => 'email',
/*
|--------------------------------------------------------------------------
| Lowercase Usernames
|--------------------------------------------------------------------------
|
| This value defines whether usernames should be lowercased before saving
| them in the database, as some database system string fields are case
| sensitive. You may disable this for your application if necessary.
|
*/
'lowercase_usernames' => true,
/*
|--------------------------------------------------------------------------
| Home Path
|--------------------------------------------------------------------------
|
| Here you may configure the path where users will get redirected during
| authentication or password reset when the operations are successful
| and the user is authenticated. You are free to change this value.
|
*/
'home' => '/dashboard',
/*
|--------------------------------------------------------------------------
| Fortify Routes Prefix / Subdomain
|--------------------------------------------------------------------------
|
| Here you may specify which prefix Fortify will assign to all the routes
| that it registers with the application. If necessary, you may change
| subdomain under which all of the Fortify routes will be available.
|
*/
'prefix' => '',
'domain' => null,
/*
|--------------------------------------------------------------------------
| Fortify Routes Middleware
|--------------------------------------------------------------------------
|
| Here you may specify which middleware Fortify will assign to the routes
| that it registers with the application. If necessary, you may change
| these middleware but typically this provided default is preferred.
|
*/
'middleware' => ['web'],
/*
|--------------------------------------------------------------------------
| Rate Limiting
|--------------------------------------------------------------------------
|
| By default, Fortify will throttle logins to five requests per minute for
| every email and IP address combination. However, if you would like to
| specify a custom rate limiter to call then you may specify it here.
|
*/
'limiters' => [
'login' => 'login',
'two-factor' => 'two-factor',
],
/*
|--------------------------------------------------------------------------
| Register View Routes
|--------------------------------------------------------------------------
|
| Here you may specify if the routes returning views should be disabled as
| you may not need them when building your own application. This may be
| especially true if you're writing a custom single-page application.
|
*/
'views' => true,
/*
|--------------------------------------------------------------------------
| Features
|--------------------------------------------------------------------------
|
| Some of the Fortify features are optional. You may disable the features
| by removing them from this array. You're free to only remove some of
| these features or you can even remove all of these if you need to.
|
*/
'features' => [
Features::registration(),
Features::resetPasswords(),
// Features::emailVerification(),
Features::updateProfileInformation(),
Features::updatePasswords(),
Features::twoFactorAuthentication([
'confirm' => true,
'confirmPassword' => true,
// 'window' => 0,
]),
],
];

View File

@@ -1,81 +0,0 @@
<?php
use Laravel\Jetstream\Features;
use Laravel\Jetstream\Http\Middleware\AuthenticateSession;
return [
/*
|--------------------------------------------------------------------------
| Jetstream Stack
|--------------------------------------------------------------------------
|
| This configuration value informs Jetstream which "stack" you will be
| using for your application. In general, this value is set for you
| during installation and will not need to be changed after that.
|
*/
'stack' => 'livewire',
/*
|--------------------------------------------------------------------------
| Jetstream Route Middleware
|--------------------------------------------------------------------------
|
| Here you may specify which middleware Jetstream will assign to the routes
| that it registers with the application. When necessary, you may modify
| these middleware; however, this default value is usually sufficient.
|
*/
'middleware' => ['web'],
'auth_session' => AuthenticateSession::class,
/*
|--------------------------------------------------------------------------
| Jetstream Guard
|--------------------------------------------------------------------------
|
| Here you may specify the authentication guard Jetstream will use while
| authenticating users. This value should correspond with one of your
| guards that is already present in your "auth" configuration file.
|
*/
'guard' => 'sanctum',
/*
|--------------------------------------------------------------------------
| Features
|--------------------------------------------------------------------------
|
| Some of Jetstream's features are optional. You may disable the features
| by removing them from this array. You're free to only remove some of
| these features or you can even remove all of these if you need to.
|
*/
'features' => [
// Features::termsAndPrivacyPolicy(),
// Features::profilePhotos(),
// Features::api(),
// Features::teams(['invitations' => true]),
Features::accountDeletion(),
],
/*
|--------------------------------------------------------------------------
| Profile Photo Disk
|--------------------------------------------------------------------------
|
| This configuration value determines the default disk that will be used
| when storing profile photos for your application's users. Typically
| this will be the "public" disk but you may adjust this if needed.
|
*/
'profile_photo_disk' => 'public',
];

777
storage/api-docs/api-docs-v1.json Executable file
View File

@@ -0,0 +1,777 @@
{
"openapi": "3.0.0",
"info": {
"title": "SAM API Documentation",
"description": "===============================<br><strong>[공통 에러 응답 포맷]</strong><br>400: 필수 파라미터 누락<br>401: 인증 실패<br>403: 권한 없음<br>404: 존재하지 않는 URI 또는 데이터<br>405: 허용되지 않는 메서드<br>500: 서버 에러<br><br><strong>모든 에러 응답 예시:</strong><br>{<br>&nbsp;&nbsp;&quot;success&quot;: false,<br>&nbsp;&nbsp;&quot;message&quot;: &quot;에러 메시지&quot;,<br>&nbsp;&nbsp;&quot;data&quot;: null<br>}<br>===============================",
"contact": {
"email": "shine1324@gmail.com"
},
"version": "1.0.0"
},
"servers": [
{
"url": "https://api.5130.co.kr",
"description": "SAM관리시스템 API 서버"
}
],
"paths": {
"/api/v1/debug-apikey": {
"get": {
"tags": [
"API Key 인증"
],
"summary": "API Key 인증 확인",
"operationId": "8d05f26a859e82207ba533ab88682ddf",
"responses": {
"200": {
"description": "API Key 인증 성공"
},
"401": {
"description": "인증 실패"
}
},
"security": [
{
"ApiKeyAuth": []
},
{
"BearerAuth": []
}
]
}
},
"/api/v1/login": {
"post": {
"tags": [
"Auth"
],
"summary": "회원 토큰 정보확인",
"operationId": "3878a009ac5aef1ebe0e72b7716e24ac",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"required": [
"user_id",
"user_pwd"
],
"properties": {
"user_id": {
"type": "string",
"example": "test"
},
"user_pwd": {
"type": "string",
"example": "testpass"
}
},
"type": "object"
}
}
}
},
"responses": {
"200": {
"description": "로그인 성공",
"content": {
"application/json": {
"schema": {
"properties": {
"message": {
"type": "string"
},
"user_token": {
"type": "string"
}
},
"type": "object"
}
}
}
},
"401": {
"description": "로그인 실패"
}
},
"security": [
{
"ApiKeyAuth": []
}
]
}
},
"/api/v1/logout": {
"post": {
"tags": [
"Auth"
],
"summary": "로그아웃 (Access 및 Token 무효화)",
"operationId": "39200ed8c17c34aa7af9a24f064e13a4",
"responses": {
"200": {
"description": "로그아웃 성공"
},
"401": {
"description": "인증 실패"
}
},
"security": [
{
"ApiKeyAuth": []
},
{
"BearerAuth": []
}
]
}
},
"/api/v1/member/index": {
"get": {
"tags": [
"Member"
],
"summary": "회원 목록 조회",
"description": "회원 목록을 페이징 형태로 반환합니다.",
"operationId": "9243d8df1b20c9552b21389ce84415ea",
"parameters": [
{
"name": "page",
"in": "query",
"description": "페이지 번호 (기본값: 1)",
"required": false,
"schema": {
"type": "integer",
"example": 1
}
},
{
"name": "size",
"in": "query",
"description": "페이지당 항목 수 (기본값: 20)",
"required": false,
"schema": {
"type": "integer",
"example": 20
}
}
],
"responses": {
"200": {
"description": "회원 목록 조회 성공",
"content": {
"application/json": {
"schema": {
"properties": {
"success": {
"type": "boolean",
"example": true
},
"message": {
"type": "string",
"example": "회원목록 조회 성공"
},
"data": {
"properties": {
"current_page": {
"type": "integer",
"example": 1
},
"data": {
"type": "array",
"items": {
"properties": {
"id": {
"type": "integer",
"example": 1
},
"user_id": {
"type": "string",
"example": "hamss"
},
"phone": {
"type": "string",
"example": "010-4820-9104"
},
"options": {
"type": "string",
"example": null,
"nullable": true
},
"name": {
"type": "string",
"example": "권혁성"
},
"email": {
"type": "string",
"example": "shine1324@gmail.com"
},
"email_verified_at": {
"type": "string",
"format": "date-time",
"example": null,
"nullable": true
},
"last_login_at": {
"type": "string",
"format": "date-time",
"example": null,
"nullable": true
},
"current_team_id": {
"type": "integer",
"example": null,
"nullable": true
},
"profile_photo_path": {
"type": "string",
"example": null,
"nullable": true
},
"created_at": {
"type": "string",
"format": "date-time",
"example": "2025-07-16 18:28:41"
},
"updated_at": {
"type": "string",
"format": "date-time",
"example": "2025-07-25 23:13:06"
},
"deleted_at": {
"type": "string",
"format": "date-time",
"example": null,
"nullable": true
}
},
"type": "object"
}
},
"first_page_url": {
"type": "string",
"example": "http://api.sam.kr/api/v1/member/index?page=1"
},
"from": {
"type": "integer",
"example": 1
},
"last_page": {
"type": "integer",
"example": 1
},
"last_page_url": {
"type": "string",
"example": "http://api.sam.kr/api/v1/member/index?page=1"
},
"links": {
"type": "array",
"items": {
"properties": {
"url": {
"type": "string",
"example": null,
"nullable": true
},
"label": {
"type": "string",
"example": "&laquo; Previous"
},
"active": {
"type": "boolean",
"example": false
}
},
"type": "object"
}
},
"next_page_url": {
"type": "string",
"example": null,
"nullable": true
},
"path": {
"type": "string",
"example": "http://api.sam.kr/api/v1/member/index"
},
"per_page": {
"type": "integer",
"example": 20
},
"prev_page_url": {
"type": "string",
"example": null,
"nullable": true
},
"to": {
"type": "integer",
"example": 3
},
"total": {
"type": "integer",
"example": 3
}
},
"type": "object"
}
},
"type": "object"
}
}
}
}
},
"security": [
{
"ApiKeyAuth": []
},
{
"BearerAuth": []
}
]
}
},
"/api/v1/member/show/{user_no}": {
"get": {
"tags": [
"Member"
],
"summary": "회원 상세조회",
"description": "user_no 기준으로 회원 상세 정보를 조회합니다.",
"operationId": "b4c822915531828ea5f3a50d5112ef26",
"parameters": [
{
"name": "user_no",
"in": "path",
"description": "회원 번호 (USER_NO)",
"required": true,
"schema": {
"type": "integer",
"example": 1
}
}
],
"responses": {
"200": {
"description": "회원 상세조회 성공",
"content": {
"application/json": {
"schema": {
"properties": {
"success": {
"type": "boolean",
"example": true
},
"message": {
"type": "string",
"example": "회원 상세조회 성공"
},
"data": {
"properties": {
"id": {
"type": "integer",
"example": 1
},
"user_id": {
"type": "string",
"example": "hamss"
},
"phone": {
"type": "string",
"example": "010-4820-9104"
},
"options": {
"type": "string",
"example": null,
"nullable": true
},
"name": {
"type": "string",
"example": "권혁성"
},
"email": {
"type": "string",
"example": "shine1324@gmail.com"
},
"email_verified_at": {
"type": "string",
"format": "date-time",
"example": null,
"nullable": true
},
"last_login_at": {
"type": "string",
"format": "date-time",
"example": null,
"nullable": true
},
"current_team_id": {
"type": "integer",
"example": null,
"nullable": true
},
"profile_photo_path": {
"type": "string",
"example": null,
"nullable": true
},
"created_at": {
"type": "string",
"format": "date-time",
"example": "2025-07-16 18:28:41"
},
"updated_at": {
"type": "string",
"format": "date-time",
"example": "2025-07-25 23:13:06"
},
"deleted_at": {
"type": "string",
"format": "date-time",
"example": null,
"nullable": true
}
},
"type": "object"
}
},
"type": "object"
}
}
}
},
"401": {
"description": "인증 실패"
},
"404": {
"description": "회원 정보 없음"
}
},
"security": [
{
"ApiKeyAuth": []
},
{
"BearerAuth": []
}
]
}
},
"/api/v1/member/me": {
"get": {
"tags": [
"Member"
],
"summary": "내 정보 조회",
"description": "내정보와 테넌트 정보를 전달 합니다.",
"operationId": "0c641be8a4e4ab5e1c2db29989b219ce",
"responses": {
"200": {
"description": "나의 정보 조회 성공",
"content": {
"application/json": {
"schema": {
"properties": {
"success": {
"type": "boolean",
"example": true
},
"message": {
"type": "string",
"example": "나의 정보 조회 성공"
},
"data": {
"properties": {
"user": {
"properties": {
"id": {
"type": "integer",
"example": 3
},
"user_id": {
"type": "string",
"example": "test"
},
"phone": {
"type": "string",
"example": "010-1234-5678"
},
"options": {
"type": "string",
"example": null,
"nullable": true
},
"name": {
"type": "string",
"example": "테스트"
},
"email": {
"type": "string",
"example": "test@5130.co.kr"
},
"email_verified_at": {
"type": "string",
"format": "date-time",
"example": null,
"nullable": true
},
"last_login_at": {
"type": "string",
"format": "date-time",
"example": null,
"nullable": true
},
"current_team_id": {
"type": "integer",
"example": null,
"nullable": true
},
"profile_photo_path": {
"type": "string",
"example": null,
"nullable": true
},
"created_at": {
"type": "string",
"format": "date-time",
"example": "2025-07-17 13:19:37"
},
"updated_at": {
"type": "string",
"format": "date-time",
"example": "2025-07-26 15:51:14"
},
"deleted_at": {
"type": "string",
"format": "date-time",
"example": null,
"nullable": true
}
},
"type": "object"
},
"tenant": {
"properties": {
"id": {
"type": "integer",
"example": 1
},
"company_name": {
"type": "string",
"example": "(주)경동기업"
},
"code": {
"type": "string",
"example": "KDCOM"
},
"email": {
"type": "string",
"example": "kd5130@naver.com"
},
"phone": {
"type": "string",
"example": "01083935130"
},
"address": {
"type": "string",
"example": "경기도 김포시 통진읍 옹정로 45-22"
},
"business_num": {
"type": "string",
"example": "1398700333"
},
"corp_reg_no": {
"type": "string",
"example": null,
"nullable": true
},
"ceo_name": {
"type": "string",
"example": "이경호"
},
"homepage": {
"type": "string",
"example": null,
"nullable": true
},
"fax": {
"type": "string",
"example": null,
"nullable": true
},
"logo": {
"type": "string",
"example": null,
"nullable": true
},
"admin_memo": {
"type": "string",
"example": null,
"nullable": true
},
"options": {
"type": "string",
"example": null,
"nullable": true
}
},
"type": "object"
}
},
"type": "object"
}
},
"type": "object"
}
}
}
},
"401": {
"description": "인증 실패 (헤더 누락, 유효하지 않은 토큰/키 등)"
}
},
"security": [
{
"ApiKeyAuth": []
},
{
"BearerAuth": []
}
]
}
},
"/api/v1/product/category": {
"get": {
"tags": [
"Product"
],
"summary": "제품 카테고리 목록 조회",
"description": "제품 카테고리(최상위, parent_id=null) 리스트를 반환합니다.",
"operationId": "ae018aa8eec41762f28513ae1aecebfc",
"responses": {
"200": {
"description": "카테고리 목록 조회 성공",
"content": {
"application/json": {
"schema": {
"properties": {
"status": {
"type": "string",
"example": "success"
},
"message": {
"type": "string",
"example": "get 성공"
},
"data": {
"type": "array",
"items": {
"properties": {
"id": {
"type": "integer",
"example": 4
},
"code_group": {
"type": "string",
"example": "category"
},
"code": {
"type": "string",
"example": "BP"
},
"name": {
"type": "string",
"example": "절곡판"
},
"parent_id": {
"type": "integer",
"example": null
},
"attributes": {
"type": "string",
"example": "[{...}]"
},
"description": {
"type": "string",
"example": "절곡판"
},
"is_active": {
"type": "integer",
"example": 1
},
"sort_order": {
"type": "integer",
"example": 10
},
"created_at": {
"type": "string",
"format": "date-time",
"example": "2025-07-23T09:00:00Z"
},
"updated_at": {
"type": "string",
"format": "date-time",
"example": "2025-07-23T09:00:00Z"
}
},
"type": "object"
}
}
},
"type": "object"
}
}
}
},
"401": {
"description": "인증 실패"
},
"500": {
"description": "서버 에러"
}
},
"security": [
{
"ApiKeyAuth": []
},
{
"BearerAuth": []
}
]
}
}
},
"components": {
"securitySchemes": {
"ApiKeyAuth": {
"type": "apiKey",
"in": "header",
"name": "X-API-KEY",
"description": "API Key 인증: X-API-KEY: {API_KEY}"
},
"BearerAuth": {
"type": "http",
"bearerFormat": "JWT",
"scheme": "bearer"
}
}
},
"tags": [
{
"name": "API Key 인증",
"description": "API Key 인증"
},
{
"name": "Auth",
"description": "Auth"
},
{
"name": "Member",
"description": "Member"
},
{
"name": "Product",
"description": "Product"
}
]
}