fix: 게시판 시스템 tenant_id 및 custom_fields 처리 개선

- 시스템 게시판도 tenant_id 항상 설정 (본사=1 글만 전체 공개)
- applySystemBoardScope() 헬퍼 추가로 쿼리 조건 통일
- saveCustomFields()에 field_key → field_id 매핑 로직 추가
- createComment()에 tenant_id 추가 (NOT NULL 제약조건 충족)
- 시스템 게시판 조회 조건: (tenant_id = 1) OR (tenant_id = 현재테넌트)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-28 02:45:16 +09:00
parent bd8adffb34
commit 4a2c185c54

View File

@@ -12,6 +12,24 @@
class PostService extends Service
{
/**
* 본사 테넌트 ID (시스템 게시판에서 본사 글은 모든 테넌트에게 공개)
*/
private const HQ_TENANT_ID = 1;
/**
* 시스템 게시판 조회 조건 적용
* - 본사(HQ_TENANT_ID) 글은 모든 테넌트에게 공개
* - 각 테넌트 글은 해당 테넌트만 조회 가능
*/
private function applySystemBoardScope($query): void
{
$query->where(function ($q) {
$q->where('tenant_id', self::HQ_TENANT_ID)
->orWhere('tenant_id', $this->tenantId());
});
}
// =========================================================================
// 게시글 조회 메서드
// =========================================================================
@@ -19,14 +37,20 @@ class PostService extends Service
/**
* 게시글 목록 조회 (페이징)
*
* @param bool $isSystemBoard 시스템 게시판 여부 (시스템 게시판은 tenant_id 필터 제외)
* @param bool $isSystemBoard 시스템 게시판 여부
* - 시스템 게시판: 본사(tenant_id=1) 글 + 현재 테넌트 글 조회
* - 일반 게시판: 현재 테넌트 글만 조회
*/
public function getPostsByBoard(int $boardId, array $filters = [], int $perPage = 15, bool $isSystemBoard = false): LengthAwarePaginator
{
return Post::where('board_id', $boardId)
// 시스템 게시판: tenant_id 필터 없음 (모든 게시글 조회)
// 일반 게시판: 현재 테넌트 게시글만 조회
->when(! $isSystemBoard, fn ($q) => $q->where('tenant_id', $this->tenantId()))
->when($isSystemBoard, function ($q) {
// 시스템 게시판: 본사(HQ) 글 + 현재 테넌트 글
$q->where(function ($query) {
$query->where('tenant_id', self::HQ_TENANT_ID)
->orWhere('tenant_id', $this->tenantId());
});
}, fn ($q) => $q->where('tenant_id', $this->tenantId()))
->when(isset($filters['search']), function ($q) use ($filters) {
$q->where(function ($query) use ($filters) {
$query->where('title', 'like', "%{$filters['search']}%")
@@ -89,13 +113,18 @@ public function getPost(int $postId, ?bool $isSystemBoard = null): ?Post
if ($isSystemBoard === null) {
// 게시글에서 board 정보로 시스템 게시판 여부 판단
// 시스템 게시판이면 tenant_id 필터 없음
$query->where(function ($q) {
// 현재 테넌트 글
$q->where('tenant_id', $this->tenantId())
->orWhereHas('board', fn ($b) => $b->where('is_system', true));
// 또는 시스템 게시판의 본사 글
->orWhere(function ($sub) {
$sub->where('tenant_id', self::HQ_TENANT_ID)
->whereHas('board', fn ($b) => $b->where('is_system', true));
});
});
} elseif ($isSystemBoard) {
// 시스템 게시판: tenant_id 필터 없음
// 시스템 게시판: 본사 글 + 현재 테넌트 글
$this->applySystemBoardScope($query);
} else {
$query->where('tenant_id', $this->tenantId());
}
@@ -133,9 +162,11 @@ public function getPostByCodeAndId(string $boardCode, int $postId): ?Post
$query = Post::with(['files', 'comments.replies', 'board'])
->where('board_id', $board->id);
// 시스템 게시판: tenant_id 필터 없음
// 시스템 게시판: 본사 글 + 현재 테넌트 글
// 일반 게시판: 현재 테넌트 게시글만 조회
if (! $board->is_system) {
if ($board->is_system) {
$this->applySystemBoardScope($query);
} else {
$query->where('tenant_id', $this->tenantId());
}
@@ -156,9 +187,13 @@ public function getPostBySystemBoardCodeAndId(string $boardCode, int $postId): ?
return null;
}
return Post::with(['files', 'comments.replies', 'board'])
->where('board_id', $board->id)
->find($postId);
$query = Post::with(['files', 'comments.replies', 'board'])
->where('board_id', $board->id);
// 시스템 게시판: 본사 글 + 현재 테넌트 글
$this->applySystemBoardScope($query);
return $query->find($postId);
}
/**
@@ -193,7 +228,7 @@ public function getPostByTenantBoardCodeAndId(string $boardCode, int $postId): ?
public function createPost(int $boardId, array $data, bool $isSystemBoard = false): Post
{
$data['board_id'] = $boardId;
$data['tenant_id'] = $isSystemBoard ? null : $this->tenantId();
$data['tenant_id'] = $this->tenantId(); // 시스템 게시판도 tenant_id 설정 (본사=1의 글만 전체 공개)
$data['user_id'] = $this->apiUserId();
$data['ip_address'] = request()->ip();
$data['status'] = $data['status'] ?? 'published';
@@ -203,7 +238,7 @@ public function createPost(int $boardId, array $data, bool $isSystemBoard = fals
// 커스텀 필드 저장
if (isset($data['custom_fields'])) {
$this->saveCustomFields($post->id, $data['custom_fields']);
$this->saveCustomFields($post->id, $boardId, $data['custom_fields']);
}
return $post->fresh(['board', 'files']);
@@ -262,13 +297,18 @@ public function updatePost(int $postId, array $data, ?bool $isSystemBoard = null
if ($isSystemBoard === null) {
// 게시글에서 board 정보로 시스템 게시판 여부 판단
// 시스템 게시판이면 tenant_id 필터 없음
$query->where(function ($q) {
// 현재 테넌트 글
$q->where('tenant_id', $this->tenantId())
->orWhereHas('board', fn ($b) => $b->where('is_system', true));
// 또는 시스템 게시판의 본사 글
->orWhere(function ($sub) {
$sub->where('tenant_id', self::HQ_TENANT_ID)
->whereHas('board', fn ($b) => $b->where('is_system', true));
});
});
} elseif ($isSystemBoard) {
// 시스템 게시판: tenant_id 필터 없음
// 시스템 게시판: 본사 글 + 현재 테넌트 글
$this->applySystemBoardScope($query);
} else {
$query->where('tenant_id', $this->tenantId());
}
@@ -283,7 +323,7 @@ public function updatePost(int $postId, array $data, ?bool $isSystemBoard = null
// 커스텀 필드 업데이트
if (isset($data['custom_fields'])) {
$this->saveCustomFields($post->id, $data['custom_fields']);
$this->saveCustomFields($post->id, $post->board_id, $data['custom_fields']);
}
return $post->fresh(['board', 'files']);
@@ -304,9 +344,11 @@ public function updatePostByBoardCode(string $boardCode, int $postId, array $dat
$query = Post::where('board_id', $board->id);
// 시스템 게시판: tenant_id 필터 없음
// 시스템 게시판: 본사 글 + 현재 테넌트 글
// 일반 게시판: 현재 테넌트 게시글만
if (! $board->is_system) {
if ($board->is_system) {
$this->applySystemBoardScope($query);
} else {
$query->where('tenant_id', $this->tenantId());
}
@@ -319,7 +361,7 @@ public function updatePostByBoardCode(string $boardCode, int $postId, array $dat
$post->update($data);
if (isset($data['custom_fields'])) {
$this->saveCustomFields($post->id, $data['custom_fields']);
$this->saveCustomFields($post->id, $board->id, $data['custom_fields']);
}
return $post->fresh(['board', 'files']);
@@ -339,7 +381,12 @@ public function updatePostBySystemBoardCode(string $boardCode, int $postId, arra
return null;
}
$post = Post::where('board_id', $board->id)->find($postId);
$query = Post::where('board_id', $board->id);
// 시스템 게시판: 본사 글 + 현재 테넌트 글
$this->applySystemBoardScope($query);
$post = $query->find($postId);
if (! $post) {
return null;
@@ -348,7 +395,7 @@ public function updatePostBySystemBoardCode(string $boardCode, int $postId, arra
$post->update($data);
if (isset($data['custom_fields'])) {
$this->saveCustomFields($post->id, $data['custom_fields']);
$this->saveCustomFields($post->id, $board->id, $data['custom_fields']);
}
return $post->fresh(['board', 'files']);
@@ -379,7 +426,7 @@ public function updatePostByTenantBoardCode(string $boardCode, int $postId, arra
$post->update($data);
if (isset($data['custom_fields'])) {
$this->saveCustomFields($post->id, $data['custom_fields']);
$this->saveCustomFields($post->id, $board->id, $data['custom_fields']);
}
return $post->fresh(['board', 'files']);
@@ -400,13 +447,18 @@ public function deletePost(int $postId, ?bool $isSystemBoard = null): bool
if ($isSystemBoard === null) {
// 게시글에서 board 정보로 시스템 게시판 여부 판단
// 시스템 게시판이면 tenant_id 필터 없음
$query->where(function ($q) {
// 현재 테넌트 글
$q->where('tenant_id', $this->tenantId())
->orWhereHas('board', fn ($b) => $b->where('is_system', true));
// 또는 시스템 게시판의 본사 글
->orWhere(function ($sub) {
$sub->where('tenant_id', self::HQ_TENANT_ID)
->whereHas('board', fn ($b) => $b->where('is_system', true));
});
});
} elseif ($isSystemBoard) {
// 시스템 게시판: tenant_id 필터 없음
// 시스템 게시판: 본사 글 + 현재 테넌트 글
$this->applySystemBoardScope($query);
} else {
$query->where('tenant_id', $this->tenantId());
}
@@ -435,9 +487,11 @@ public function deletePostByBoardCode(string $boardCode, int $postId): bool
$query = Post::where('board_id', $board->id);
// 시스템 게시판: tenant_id 필터 없음
// 시스템 게시판: 본사 글 + 현재 테넌트 글
// 일반 게시판: 현재 테넌트 게시글만
if (! $board->is_system) {
if ($board->is_system) {
$this->applySystemBoardScope($query);
} else {
$query->where('tenant_id', $this->tenantId());
}
@@ -464,7 +518,12 @@ public function deletePostBySystemBoardCode(string $boardCode, int $postId): boo
return false;
}
$post = Post::where('board_id', $board->id)->find($postId);
$query = Post::where('board_id', $board->id);
// 시스템 게시판: 본사 글 + 현재 테넌트 글
$this->applySystemBoardScope($query);
$post = $query->find($postId);
if (! $post) {
return false;
@@ -521,6 +580,7 @@ public function getComments(int $postId): Collection
public function createComment(int $postId, array $data): BoardComment
{
$data['post_id'] = $postId;
$data['tenant_id'] = $this->tenantId();
$data['user_id'] = $this->apiUserId();
$data['ip_address'] = request()->ip();
$data['status'] = 'active';
@@ -569,10 +629,26 @@ public function deleteComment(int $commentId): bool
/**
* 커스텀 필드 값 저장
*
* @param int $postId 게시글 ID
* @param int $boardId 게시판 ID (field_key → field_id 변환용)
* @param array $customFields [field_key => value] 또는 [field_id => value]
*/
protected function saveCustomFields(int $postId, array $customFields): void
protected function saveCustomFields(int $postId, int $boardId, array $customFields): void
{
foreach ($customFields as $fieldId => $value) {
// field_key → field_id 매핑 조회
$fieldMap = \App\Models\Boards\BoardSetting::where('board_id', $boardId)
->pluck('id', 'field_key')
->toArray();
foreach ($customFields as $fieldKey => $value) {
// field_key가 문자열이면 field_id로 변환
$fieldId = is_numeric($fieldKey) ? (int) $fieldKey : ($fieldMap[$fieldKey] ?? null);
if ($fieldId === null) {
continue; // 존재하지 않는 필드는 무시
}
PostCustomFieldValue::updateOrCreate(
[
'post_id' => $postId,
@@ -601,16 +677,12 @@ public function getCustomFieldValues(int $postId): Collection
/**
* 나의 게시글 목록 조회
* 시스템 게시판(tenant_id = null) 및 테넌트 게시판의 게시글 모두 조회
* 현재 테넌트에서 내가 작성한 게시글 조회
*/
public function getMyPosts(array $filters = [], int $perPage = 15): LengthAwarePaginator
{
return Post::where('user_id', $this->apiUserId())
->where(function ($q) {
// 시스템 게시판 게시글 또는 현재 테넌트 게시글
$q->whereNull('tenant_id')
->orWhere('tenant_id', $this->tenantId());
})
->where('tenant_id', $this->tenantId())
->with(['board:id,board_code,name,is_system'])
->when(isset($filters['board_code']), function ($q) use ($filters) {
$q->whereHas('board', fn ($query) => $query->where('board_code', $filters['board_code']));