chore: [env] .env.example 업데이트 및 .gitignore 정리

- .env.example을 SAM 프로젝트 실제 키 구조로 업데이트
- .gitignore에 !.env.example 예외 추가
- GCS_* 중복 키 제거, Gemini/Claude/Vertex 키 섹션 추가
This commit is contained in:
김보곤
2026-02-23 10:17:37 +09:00
parent 3ae3a1dcda
commit 240199af9d
51 changed files with 623 additions and 2726 deletions

View File

@@ -8,14 +8,13 @@
use App\Models\Tenants\Tenant;
use App\Traits\Auditable;
use App\Traits\BelongsToTenant;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Spatie\Permission\Models\Role as SpatieRole;
/**
* @mixin IdeHelperRole
*/
class Role extends SpatieRole
class Role extends Model
{
use Auditable, BelongsToTenant, SoftDeletes;
@@ -35,6 +34,14 @@ class Role extends SpatieRole
'tenant_id' => 'integer',
];
/**
* 관계: 메뉴 권한 (다대다)
*/
public function menuPermissions()
{
return $this->hasMany(RoleMenuPermission::class, 'role_id');
}
/**
* 관계: 테넌트
*/
@@ -54,7 +61,7 @@ public function userRoles()
/**
* 관계: 사용자 (user_roles 테이블 통해)
*/
public function users(): BelongsToMany
public function users()
{
return $this->belongsToMany(
User::class,
@@ -64,6 +71,19 @@ public function users(): BelongsToMany
);
}
/**
* 관계: 권한 (role_has_permissions 테이블 통해)
*/
public function permissions()
{
return $this->belongsToMany(
Permission::class,
'role_has_permissions',
'role_id',
'permission_id'
);
}
/**
* 스코프: 공개된 역할만
*/

View File

@@ -40,34 +40,16 @@ class BankAccount extends Model
'account_number',
'account_holder',
'account_name',
'account_type',
'balance',
'currency',
'opened_at',
'last_transaction_at',
'branch_name',
'memo',
'status',
'assigned_user_id',
'is_primary',
'sort_order',
'created_by',
'updated_by',
'deleted_by',
];
protected $hidden = [
'created_by',
'updated_by',
'deleted_by',
'deleted_at',
];
protected $casts = [
'balance' => 'decimal:2',
'is_primary' => 'boolean',
'opened_at' => 'date',
'last_transaction_at' => 'datetime',
];
protected $attributes = [
@@ -107,69 +89,22 @@ public function updater(): BelongsTo
// 헬퍼 메서드
// =========================================================================
// =========================================================================
// Accessors
// =========================================================================
/**
* 포맷된 잔액
*/
public function getFormattedBalanceAttribute(): string
{
$amount = abs($this->balance ?? 0);
if ($amount >= 100000000) {
return number_format($amount / 100000000, 1).'억원';
} elseif ($amount >= 10000000) {
return number_format($amount / 10000000, 0).'천만원';
} elseif ($amount >= 10000) {
return number_format($amount / 10000, 0).'만원';
}
return number_format($amount).'원';
}
/**
* 마스킹된 계좌번호
* 마스킹된 계좌번호 조회
*/
public function getMaskedAccountNumber(): string
{
$number = $this->account_number;
if (strlen($number) <= 6) {
return $number;
$length = strlen($this->account_number);
if ($length <= 4) {
return $this->account_number;
}
return substr($number, 0, 3).'-***-'.substr($number, -4);
$visibleEnd = substr($this->account_number, -4);
$maskedPart = str_repeat('*', $length - 4);
return $maskedPart.$visibleEnd;
}
// =========================================================================
// Scopes
// =========================================================================
public function scopeActive($query)
{
return $query->where('status', 'active');
}
public function scopePrimary($query)
{
return $query->where('is_primary', true);
}
public function scopeByType($query, string $accountType)
{
return $query->where('account_type', $accountType);
}
public function scopeOrdered($query)
{
return $query->orderBy('sort_order')->orderBy('bank_name');
}
// =========================================================================
// 헬퍼 메서드
// =========================================================================
/**
* 활성 상태 여부
*/
@@ -187,13 +122,10 @@ public function toggleStatus(): void
}
/**
* 잔액 업데이트
* 대표계좌로 설정
*/
public function updateBalance(float $newBalance): void
public function setAsPrimary(): void
{
$this->update([
'balance' => $newBalance,
'last_transaction_at' => now(),
]);
$this->is_primary = true;
}
}

View File

@@ -1,40 +0,0 @@
<?php
namespace App\Models\Tenants;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class BarobillConfig extends Model
{
use SoftDeletes;
protected $fillable = [
'name',
'environment',
'cert_key',
'corp_num',
'base_url',
'description',
'is_active',
];
protected $casts = [
'is_active' => 'boolean',
];
public static function getActiveTest(): ?self
{
return self::where('environment', 'test')->first();
}
public static function getActiveProduction(): ?self
{
return self::where('environment', 'production')->first();
}
public static function getActive(bool $isTestMode = false): ?self
{
return $isTestMode ? self::getActiveTest() : self::getActiveProduction();
}
}

View File

@@ -1,66 +0,0 @@
<?php
namespace App\Models\Tenants;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
class BarobillMember extends Model
{
use SoftDeletes;
protected $table = 'barobill_members';
protected $fillable = [
'tenant_id',
'biz_no',
'corp_name',
'ceo_name',
'addr',
'biz_type',
'biz_class',
'barobill_id',
'barobill_pwd',
'manager_name',
'manager_email',
'manager_hp',
'status',
'server_mode',
'last_sales_fetch_at',
'last_purchases_fetch_at',
];
protected $casts = [
'created_at' => 'datetime',
'updated_at' => 'datetime',
'deleted_at' => 'datetime',
'barobill_pwd' => 'encrypted',
'last_sales_fetch_at' => 'datetime',
'last_purchases_fetch_at' => 'datetime',
];
protected $hidden = [
'barobill_pwd',
];
public function tenant(): BelongsTo
{
return $this->belongsTo(Tenant::class);
}
public function getFormattedBizNoAttribute(): string
{
$bizNo = preg_replace('/[^0-9]/', '', $this->biz_no);
if (strlen($bizNo) === 10) {
return substr($bizNo, 0, 3).'-'.substr($bizNo, 3, 2).'-'.substr($bizNo, 5);
}
return $this->biz_no;
}
public function isTestMode(): bool
{
return $this->server_mode !== 'production';
}
}

View File

@@ -22,17 +22,8 @@
* @property string $expiry_date
* @property string|null $card_password_encrypted
* @property string $card_name
* @property string|null $card_type
* @property string|null $alias
* @property string|null $cvc_encrypted
* @property int|null $payment_day
* @property float|null $total_limit
* @property float|null $used_amount
* @property float|null $remaining_limit
* @property string $status
* @property bool $is_manual
* @property int|null $assigned_user_id
* @property string|null $memo
* @property int|null $created_by
* @property int|null $updated_by
* @property int|null $deleted_by
@@ -46,22 +37,13 @@ class Card extends Model
protected $fillable = [
'tenant_id',
'card_company',
'card_type',
'card_number_encrypted',
'card_number_last4',
'expiry_date',
'card_password_encrypted',
'card_name',
'alias',
'cvc_encrypted',
'payment_day',
'total_limit',
'used_amount',
'remaining_limit',
'status',
'is_manual',
'assigned_user_id',
'memo',
'created_by',
'updated_by',
'deleted_by',
@@ -70,29 +52,12 @@ class Card extends Model
protected $hidden = [
'card_number_encrypted',
'card_password_encrypted',
'cvc_encrypted',
];
protected $appends = [
'csv',
];
protected $attributes = [
'status' => 'active',
'is_manual' => false,
];
protected function casts(): array
{
return [
'payment_day' => 'integer',
'total_limit' => 'decimal:2',
'used_amount' => 'decimal:2',
'remaining_limit' => 'decimal:2',
'is_manual' => 'boolean',
];
}
// =========================================================================
// 관계 정의
// =========================================================================
@@ -162,38 +127,6 @@ public function getDecryptedCardPassword(): ?string
: null;
}
/**
* CVC/CVV 암호화 설정
*/
public function setCvc(?string $cvc): void
{
$this->cvc_encrypted = $cvc
? Crypt::encryptString($cvc)
: null;
}
/**
* CVC/CVV 복호화 조회
*/
public function getDecryptedCvc(): ?string
{
return $this->cvc_encrypted
? Crypt::decryptString($this->cvc_encrypted)
: null;
}
// =========================================================================
// Accessor (JSON 직렬화용)
// =========================================================================
/**
* CSV(CVC) 복호화 값 — $appends로 JSON 응답에 포함
*/
public function getCsvAttribute(): ?string
{
return $this->getDecryptedCvc();
}
// =========================================================================
// 헬퍼 메서드
// =========================================================================

View File

@@ -1,110 +0,0 @@
<?php
namespace App\Models\Tenants;
use App\Traits\BelongsToTenant;
use App\Traits\ModelTrait;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* 법인카드 모델
*
* @property int $id
* @property int $tenant_id
* @property string $card_name
* @property string $card_company
* @property string $card_number
* @property string $card_type
* @property int $payment_day
* @property float $credit_limit
* @property float $current_usage
* @property string $card_holder_name
* @property string $actual_user
* @property string|null $expiry_date
* @property string|null $cvc
* @property string $status
* @property string|null $memo
*/
class CorporateCard extends Model
{
use BelongsToTenant, ModelTrait, SoftDeletes;
protected $table = 'corporate_cards';
protected $fillable = [
'tenant_id',
'card_name',
'card_company',
'card_number',
'card_type',
'payment_day',
'credit_limit',
'current_usage',
'card_holder_name',
'actual_user',
'expiry_date',
'cvc',
'status',
'memo',
];
protected $hidden = [
'cvc',
'deleted_at',
];
protected $casts = [
'payment_day' => 'integer',
'credit_limit' => 'decimal:2',
'current_usage' => 'decimal:2',
];
protected $attributes = [
'status' => 'active',
'payment_day' => 15,
'credit_limit' => 0,
'current_usage' => 0,
];
// =========================================================================
// Scopes
// =========================================================================
public function scopeActive($query)
{
return $query->where('status', 'active');
}
public function scopeByType($query, string $cardType)
{
return $query->where('card_type', $cardType);
}
// =========================================================================
// 헬퍼 메서드
// =========================================================================
public function isActive(): bool
{
return $this->status === 'active';
}
public function toggleStatus(): void
{
$this->status = $this->status === 'active' ? 'inactive' : 'active';
}
/**
* 마스킹된 카드번호
*/
public function getMaskedCardNumber(): string
{
$number = preg_replace('/[^0-9]/', '', $this->card_number);
if (strlen($number) <= 4) {
return $this->card_number;
}
return '****-****-****-'.substr($number, -4);
}
}