- LOGICAL_RELATIONSHIPS.md 업데이트 - 한국어 메시지 파일 업데이트 - API 라우트 정비 - CURRENT_WORKS.md 업데이트
19 KiB
SAM API 작업 현황
2025-11-27 (수) - 시스템 게시판 기능 확장
작업 목표
- 기존 boards 테이블에 시스템 게시판 지원 추가
- mng에서 시스템 게시판 생성, sam에서 테넌트 게시판 + 시스템 게시판 조회
수정된 파일
Migration:
database/migrations/2025_11_27_205429_add_system_fields_to_boards_table.php(NEW)tenant_idnullable 변경is_systemboolean 컬럼 추가board_typeVARCHAR(50) 컬럼 추가deleted_at,deleted_bySoftDeletes 추가- 인덱스 추가
Model:
-
app/Models/Boards/Board.php- SoftDeletes 추가
- fillable, casts 업데이트
scopeAccessible(tenantId),scopeSystemOnly(),scopeTenantOnly(tenantId)스코프 추가- 권한 헬퍼 메서드 (canRead, canWrite, canManage)
-
app/Models/Boards/BoardSetting.php- casts, fillable 업데이트
- getMeta() 헬퍼 추가
Service:
app/Services/Boards/BoardService.php(NEW)- 시스템/테넌트 게시판 CRUD
- 필드 관리 (add, update, delete, reorder)
- 유틸리티 메서드
DB 스키마 변경
-- boards 테이블 추가 컬럼
is_system TINYINT(1) DEFAULT 0 COMMENT '시스템 게시판 여부'
board_type VARCHAR(50) NULL COMMENT '게시판 유형'
deleted_at TIMESTAMP NULL
deleted_by BIGINT UNSIGNED NULL
다음 작업
- mng 게시판 관리 화면 개발 ✅
- sam API 개발 (Swagger 포함) ✅
- 검증 및 테스트 ✅
2025-11-27 (수) - sam API 게시판/게시글 API 개발
작업 목표
- 테넌트용 게시판/게시글 V1 API 개발
- Swagger 문서 작성
추가된 파일
Service:
app/Services/Boards/PostService.php(NEW)- 게시글 CRUD (boardCode 기반)
- 댓글 CRUD
- 커스텀 필드 관리
- 조회수 증가
Controller:
-
app/Http/Controllers/Api/V1/BoardController.php(NEW)- index: 접근 가능한 게시판 목록 (시스템 + 테넌트)
- tenantBoards: 테넌트 게시판만
- show: 게시판 상세 (코드 기반)
- store/update/destroy: 테넌트 게시판 CRUD
- fields: 게시판 필드 목록
-
app/Http/Controllers/Api/V1/PostController.php(NEW)- index/show/store/update/destroy: 게시글 CRUD
- comments/storeComment/updateComment/destroyComment: 댓글 CRUD
FormRequest:
app/Http/Requests/Boards/BoardStoreRequest.php(NEW)app/Http/Requests/Boards/BoardUpdateRequest.php(NEW)app/Http/Requests/Boards/PostStoreRequest.php(NEW)app/Http/Requests/Boards/PostUpdateRequest.php(NEW)app/Http/Requests/Boards/CommentStoreRequest.php(NEW)
Swagger:
-
app/Swagger/v1/BoardApi.php(NEW)- Board, BoardField 스키마
- BoardCreateRequest, BoardUpdateRequest 스키마
- 7개 엔드포인트 문서화
-
app/Swagger/v1/PostApi.php(NEW)- Post, PostPagination, Comment 스키마
- PostCreateRequest, PostUpdateRequest, CommentCreateRequest 스키마
- 9개 엔드포인트 문서화
수정된 파일
routes/api.php- BoardController, PostController import 추가
- /v1/boards 프리픽스로 16개 라우트 등록
API 엔드포인트 (16개)
게시판 관리:
| Method | Path | 설명 |
|---|---|---|
| GET | /v1/boards | 접근 가능한 게시판 목록 |
| GET | /v1/boards/tenant | 테넌트 게시판만 |
| POST | /v1/boards | 테넌트 게시판 생성 |
| GET | /v1/boards/{code} | 게시판 상세 (코드 기반) |
| PUT | /v1/boards/{id} | 테넌트 게시판 수정 |
| DELETE | /v1/boards/{id} | 테넌트 게시판 삭제 |
| GET | /v1/boards/{code}/fields | 게시판 필드 목록 |
게시글 관리:
| Method | Path | 설명 |
|---|---|---|
| GET | /v1/boards/{code}/posts | 게시글 목록 |
| POST | /v1/boards/{code}/posts | 게시글 작성 |
| GET | /v1/boards/{code}/posts/{id} | 게시글 상세 |
| PUT | /v1/boards/{code}/posts/{id} | 게시글 수정 |
| DELETE | /v1/boards/{code}/posts/{id} | 게시글 삭제 |
댓글 관리:
| Method | Path | 설명 |
|---|---|---|
| GET | /v1/boards/{code}/posts/{postId}/comments | 댓글 목록 |
| POST | /v1/boards/{code}/posts/{postId}/comments | 댓글 작성 |
| PUT | /v1/boards/{code}/posts/{postId}/comments/{commentId} | 댓글 수정 |
| DELETE | /v1/boards/{code}/posts/{postId}/comments/{commentId} | 댓글 삭제 |
검증 결과
- PHP 문법 검사: ✅ 통과
- Pint 코드 포맷팅: ✅ 완료
- Swagger 문서 생성: ✅ 완료
- 라우트 등록: ✅ 16개 라우트 확인
2025-11-27 (수) - ItemMaster API group_id(계층번호) 추가 및 Swagger 보완
작업 목표
- FormRequest에 누락된
group_id필드 추가 - Swagger 스키마에
group_iddescription="계층번호" 추가 - API 문서 정확도 개선
배경
POST /api/v1/item-master/pages/{pageId}/sectionsSwagger 문서 점검 중group_id누락 발견- Service에서
$data['group_id'] ?? 1로 사용하지만 FormRequest와 Swagger에 미정의 group_id는 "계층번호"로 통일하여 주석 및 description 작성
수정된 파일 (4개)
FormRequest (group_id 필드 추가):
app/Http/Requests/ItemMaster/ItemSectionStoreRequest.phpapp/Http/Requests/ItemMaster/ItemFieldStoreRequest.phpapp/Http/Requests/ItemMaster/ItemBomItemStoreRequest.php
Swagger:
app/Swagger/v1/ItemMasterApi.php
Swagger 스키마 업데이트 상세
모델 스키마 (3개) - description="계층번호" 추가:
ItemSectionItemFieldItemBomItem
Request 스키마 (6개) - group_id 추가 또는 description 추가:
ItemSectionStoreRequest- group_id 신규 추가ItemFieldStoreRequest- group_id 신규 추가ItemBomItemStoreRequest- group_id 신규 추가IndependentSectionStoreRequest- description 추가IndependentFieldStoreRequest- description 추가IndependentBomItemStoreRequest- description 추가
12개 EntityRelationship 엔드포인트
EntityRelationshipApi.php에 이미 문서화 완료 확인:
- POST/DELETE
/pages/{pageId}/link-section,/unlink-section/{sectionId} - POST/DELETE
/pages/{pageId}/link-field,/unlink-field/{fieldId} - GET
/pages/{pageId}/relationships,/structure - POST/DELETE
/sections/{sectionId}/link-field,/unlink-field/{fieldId} - POST/DELETE
/sections/{sectionId}/link-bom,/unlink-bom/{bomId} - GET
/sections/{sectionId}/relationships - POST
/relationships/reorder
검증 결과
- Pint 코드 포맷팅: ✅ 통과
- Swagger 문서 생성: ✅ 완료
Git 커밋
commit 4f78eed
feat: ItemMaster API group_id(계층번호) 추가 및 Swagger 보완
2025-11-26 (화) - AccessService permission_overrides 테이블 사용으로 수정
주요 작업
- API AccessService가 존재하지 않는 테이블(user_permission_overrides, department_permissions)을 참조하던 문제 수정
- 실제 DB의
permission_overrides테이블을 사용하도록 수정
수정된 파일:
app/Services/Authz/AccessService.phphasUserOverride():user_permission_overrides→permission_overrides(model_type='App\Models\Members\User')departmentAllows():department_permissions→permission_overrides(model_type='App\Models\Tenants\Department')- 필드명 변경:
is_allowed→effect,user_id→model_id
기술 상세:
permission_overrides 테이블 구조:
model_type: 폴리모픽 타입 (User, Department)model_id: 대상 IDpermission_id: 권한 IDeffect: 0=DENY, 1=ALLOWeffective_from,effective_to: 유효 기간
코드 품질:
- ✅ PHP 문법 검사 통과
- ✅ Pint 포맷팅 통과
2025-11-26 (화) - Item Master 독립 엔티티 API 추가 ✅ 완료
작업 목표
- 독립 엔티티(섹션, 필드, BOM) CRUD API 10개 추가
SectionTemplate모델 삭제 →ItemSection.is_template플래그로 통합- Swagger 문서 업데이트
변경 내용
1. SectionTemplate → ItemSection 통합
section_templates테이블 삭제item_sections테이블에is_template컬럼 추가- 기존
/section-templatesAPI는 유지 (내부적으로is_template=true사용)
2. 10개 독립 API 추가
| API | 메서드 | 설명 |
|---|---|---|
/sections |
GET | 섹션 목록 (is_template 필터) |
/sections |
POST | 독립 섹션 생성 |
/sections/{id}/clone |
POST | 섹션 복제 |
/sections/{id}/usage |
GET | 섹션 사용처 조회 |
/fields |
GET | 필드 목록 |
/fields |
POST | 독립 필드 생성 |
/fields/{id}/clone |
POST | 필드 복제 |
/fields/{id}/usage |
GET | 필드 사용처 조회 |
/bom-items |
GET | BOM 항목 목록 |
/bom-items |
POST | 독립 BOM 생성 |
추가된 파일
app/Http/Requests/ItemMaster/IndependentSectionStoreRequest.phpapp/Http/Requests/ItemMaster/IndependentFieldStoreRequest.phpapp/Http/Requests/ItemMaster/IndependentBomItemStoreRequest.php
삭제된 파일
app/Models/ItemMaster/SectionTemplate.php
수정된 파일
app/Http/Controllers/Api/V1/ItemMaster/ItemSectionController.phpapp/Http/Controllers/Api/V1/ItemMaster/ItemFieldController.phpapp/Http/Controllers/Api/V1/ItemMaster/ItemBomItemController.phpapp/Services/ItemMaster/ItemSectionService.phpapp/Services/ItemMaster/ItemFieldService.phpapp/Services/ItemMaster/ItemBomItemService.phpapp/Models/ItemMaster/ItemSection.php(is_template, scopeTemplates 추가)routes/api.phpapp/Swagger/v1/ItemMasterApi.php
마이그레이션
# 실행된 마이그레이션
2025_11_26_120000_add_is_template_to_item_sections_and_drop_section_templates.php
검증 결과
- PHP 문법 검사: ✅ 통과
- Pint 코드 포맷팅: ✅ 통과
- Swagger 문서 생성: ✅ 완료
2025-11-26 (화) - Item Master 하이브리드 구조 전환 (독립 엔티티 + 링크 테이블) ✅ 완료
작업 목표
기존 CASCADE FK 기반 계층 구조를 독립 엔티티 + 링크 테이블 구조로 전환
배경
- 문제점: 현재 구조에서 섹션 삭제 시 항목(필드)도 함께 삭제됨 (CASCADE)
- 요구사항:
- 페이지, 섹션, 항목은 독립적으로 존재
- 관계는 링크 테이블로 관리 (Many-to-Many)
- 페이지에서 섹션/항목 모두 직접 연결 가능
- 섹션에서 항목 연결 가능
- 엔티티 삭제 시 링크만 제거, 다른 엔티티는 유지
group_id로 카테고리 격리 (품목관리=1, 향후 확장)
변경 구조
Before (CASCADE FK):
item_pages
↓ page_id FK (CASCADE)
item_sections
↓ section_id FK (CASCADE)
item_fields / item_bom_items
After (독립 + 링크):
item_pages (독립)
item_sections (독립)
item_fields (독립)
item_bom_items (독립)
⇄ entity_relationships (링크 테이블)
Phase 계획
| Phase | 작업 내용 | 상태 |
|---|---|---|
| 1 | 마이그레이션: FK 제거 + group_id 추가 | ✅ 완료 |
| 2 | 마이그레이션: entity_relationships 테이블 생성 | ✅ 완료 |
| 3 | 마이그레이션: 기존 데이터 이관 | ✅ 완료 |
| 4 | 모델 및 Service 수정 | ✅ 완료 |
| 5 | 새로운 API 엔드포인트 추가 | ✅ 완료 |
| 6 | Swagger 문서 업데이트 | ✅ 완료 |
| 7 | 테스트 및 검증 | ✅ 완료 |
추가된 파일
마이그레이션 (Batch 26으로 실행):
database/migrations/2025_11_26_100001_convert_item_tables_to_independent_entities.phpdatabase/migrations/2025_11_26_100002_create_entity_relationships_table.phpdatabase/migrations/2025_11_26_100003_migrate_existing_relationships_to_entity_relationships.php
모델:
app/Models/ItemMaster/EntityRelationship.php(신규)
서비스:
app/Services/ItemMaster/EntityRelationshipService.php(신규)
컨트롤러:
app/Http/Controllers/Api/V1/ItemMaster/EntityRelationshipController.php(신규)
Request:
app/Http/Requests/ItemMaster/LinkEntityRequest.php(신규)app/Http/Requests/ItemMaster/ReorderRelationshipsRequest.php(신규)
Swagger:
app/Swagger/v1/EntityRelationshipApi.php(신규)
수정된 파일
모델 (group_id 추가 + relationship 메서드):
app/Models/ItemMaster/ItemPage.phpapp/Models/ItemMaster/ItemSection.phpapp/Models/ItemMaster/ItemField.phpapp/Models/ItemMaster/ItemBomItem.phpapp/Models/ItemMaster/SectionTemplate.phpapp/Models/ItemMaster/ItemMasterField.php
라우트:
routes/api.php(새로운 엔드포인트 추가)
언어 파일:
lang/ko/message.php(linked, unlinked 추가)lang/ko/error.php(page_not_found, section_not_found, field_not_found, bom_not_found 추가)
새로운 API 엔드포인트 (14개)
페이지-섹션 연결:
POST /api/v1/item-master/pages/{pageId}/link-sectionDELETE /api/v1/item-master/pages/{pageId}/unlink-section/{sectionId}
페이지-필드 직접 연결:
POST /api/v1/item-master/pages/{pageId}/link-fieldDELETE /api/v1/item-master/pages/{pageId}/unlink-field/{fieldId}
페이지 관계 조회:
GET /api/v1/item-master/pages/{pageId}/relationshipsGET /api/v1/item-master/pages/{pageId}/structure
섹션-필드 연결:
POST /api/v1/item-master/sections/{sectionId}/link-fieldDELETE /api/v1/item-master/sections/{sectionId}/unlink-field/{fieldId}
섹션-BOM 연결:
POST /api/v1/item-master/sections/{sectionId}/link-bomDELETE /api/v1/item-master/sections/{sectionId}/unlink-bom/{bomId}
섹션 관계 조회:
GET /api/v1/item-master/sections/{sectionId}/relationships
관계 순서 변경:
POST /api/v1/item-master/relationships/reorder
검증 결과
- PHP 문법 검사: ✅ 통과
- Pint 코드 포맷팅: ✅ 통과 (9개 신규 파일)
- Swagger 문서 생성: ✅ 완료
- 라우트 등록: ✅ 44개 item-master 라우트 확인
롤백 방법
php artisan migrate:rollback --step=3
다음 작업 (옵션)
- 기존 API (POST /pages/{pageId}/sections 등) 내부적으로 entity_relationships 사용하도록 수정
- 독립 엔티티 CRUD API 추가 (POST /sections, POST /fields 등)
2025-11-25 (월) - API 인증 에러 처리 개선 및 요청 로그 강화
문제 상황
- GET /item-master/init 요청 시
Route [login] not defined에러 발생 - user_id null (인증 실패 상태)
- API Request 로그에 헤더 정보 누락
근본 원인
- Handler.php:
expectsJson()체크만 있어서, Accept 헤더 없는 API 요청이 기본 동작(로그인 리다이렉트)으로 처리됨 - ApiKeyMiddleware: 요청 로그에 헤더 정보 (X-API-KEY, Authorization) 미포함
해결 방안
Handler.php (app/Exceptions/Handler.php)
- Line 60: API 라우트 체크 추가 (
str_starts_with($request->path(), 'api/')) - Line 62:
$request->expectsJson() || $isApiRoute조건으로 변경 - 효과: Accept 헤더 없어도 API 라우트는 무조건 JSON 응답 반환
ApiKeyMiddleware (app/Http/Middleware/ApiKeyMiddleware.php)
- Line 52-57: headers 필드 추가
- X-API-KEY: 마스킹 ('***')
- Authorization: Bearer 토큰 마스킹 ('Bearer ***')
- Accept, Content-Type: 원본 그대로
- 효과: 인증 문제 디버깅 용이
수정된 파일
app/Exceptions/Handler.phpapp/Http/Middleware/ApiKeyMiddleware.php
검증 결과
- PHP 문법 체크: ✅ 통과
- Pint 코드 포맷팅: ✅ 통과
기대 효과
- API 요청 시 Accept 헤더 없어도 정상 JSON 응답
- 인증 실패 시 로그인 리다이렉트 대신 401 JSON 응답
- 요청 로그에서 헤더 정보 확인 가능 (디버깅 개선)
2025-11-24 (일) - 소프트삭제 및 타임스탬프 감사 컬럼 추가
작업 목표
- deleted_at이 있는 테이블에 deleted_by 컬럼 추가
- created_at, updated_at이 있는 테이블에 created_by, updated_by 컬럼 추가
작업 내용
1. DB 스키마 분석 (INFORMATION_SCHEMA 쿼리)
- deleted_at은 있지만 deleted_by가 없는 테이블: 30개
- created_at은 있지만 created_by, updated_by가 없는 테이블: 45개
2. 마이그레이션 생성
-
2025_11_24_192518_add_deleted_by_to_soft_delete_tables.php- 30개 테이블에 deleted_by 추가
- nullable, COMMENT('삭제자 사용자 ID')
- after('deleted_at') 배치
-
2025_11_24_192518_add_audit_columns_to_tables.php- 38개 비즈니스 테이블에 created_by, updated_by 추가
- 시스템 테이블 제외 (jobs, job_batches, password_reset_tokens, personal_access_tokens, taggables, tags)
- nullable, COMMENT
- after('updated_at'), after('created_by') 배치
3. 마이그레이션 실행 및 검증
- 실행 시간: deleted_by (429.53ms), audit_columns (1초)
- 샘플 테이블 검증: users, products, models, bom_templates, department_user 모두 정상
추가된 파일
database/migrations/2025_11_24_192518_add_deleted_by_to_soft_delete_tables.phpdatabase/migrations/2025_11_24_192518_add_audit_columns_to_tables.php
마이그레이션 상태
- Batch 25로 실행 완료
- 롤백 가능 (down 메서드 구현)
2025-11-24 (일) - CORS Preflight 문제 해결
문제 상황
- React 프론트엔드(http://192.0.0.2:3001)에서 API 호출 시 CORS 에러
- 에러:
Request header field x-api-key is not allowed by Access-Control-Allow-Headers in preflight response - 서버 로그: OPTIONS 요청만 있고 Response 로그 없음 (401 차단)
근본 원인 (root-cause-analyst 스킬 활용)
- CorsMiddleware에서
Access-Control-Allow-Headers에X-API-KEY누락 - OPTIONS 요청(Preflight)이 ApiKeyMiddleware에서 401로 차단
- 브라우저는 커스텀 헤더 사용 시 Preflight 요청을 자동 전송
해결 방안
CorsMiddleware 수정:
- OPTIONS 요청을 미들웨어 체인 진입 전에 즉시 200 OK 처리
Access-Control-Allow-Headers에X-API-KEY추가- PATCH 메서드 추가, Max-Age 86400초 설정
ApiKeyMiddleware 정리:
- 불필요한 OPTIONS 체크 제거
CORS 설정 업데이트:
config/cors.php: exposed_headers, max_age 설정
수정된 파일
app/Http/Middleware/CorsMiddleware.phpapp/Http/Middleware/ApiKeyMiddleware.phpconfig/cors.php
Git 커밋
2e96660- CORS preflight 요청 처리 개선 및 X-API-KEY 헤더 허용8e8ab65- CORS preflight 응답에 x-api-key 헤더 허용 추가
다음 작업
- React에서 API 호출 테스트
- 개발 서버 로그 확인 (Request/Response 쌍 기록 여부)
2025-11-20 (수) - ItemMaster API 테스트 및 버그 수정
주요 작업
- ItemMaster API 통합 테스트 작성 (12개 테스트, 82개 assertion)
- 누락된 마이그레이션 실행 (section_templates, tab_columns)
- API Key 미들웨어 수정 (로그인 엔드포인트 API Key 필수화)
- ReorderRequest validation 수정 (범용성 확보)
- 네임스페이스 오류 수정 (5개 Controller)
- Route 순서 수정 (specific route 우선)
테스트 결과
✅ 12/12 테스트 통과 (100%)
2025-11-19 (화) - ItemMaster API Swagger 문서 작성
주요 작업
- ItemMaster 전체 API (32개 엔드포인트) Swagger 문서화 완료
- OpenAPI 3.0 표준 준수
- Model Schemas 8개, Request Schemas 12개 작성
2025-11-18 (월) - Category API 테스트 및 개선
주요 작업
- Category CRUD 테스트 작성 (9개 테스트, 98개 assertion)
- 계층 구조 및 필드 관리 테스트
- Validation 로직 개선