fix(core,ecommerce,board,page,admin_basic,basic): 목록 응답의 하위 컬렉션 전량 직렬화 해소

관리자 상품목록을 한 페이지 여는 것만으로 그 페이지 모든 상품의 옵션이 응답에 실렸다.
같은 패턴을 저장소 전역에서 찾아 14개 목록 엔드포인트를 함께 정리했다.

근본 원인은 둘이다. Resource 가 whenLoaded 로 방어하는데 Repository 가 목록 쿼리에서
관계를 무조건 로드해 가드가 항상 참이 되는 가짜 가드, 그리고 toListArray 경량 표현을
정의해 두고도 컬렉션이 toArray 를 부르는 목록/상세 미분리다. 둘 다 응답만 보면
정상이라 오류도 경고도 없이 페이로드만 불어난다.

목록은 화면이 실제로 그리는 것만 싣는다. 개수·합계는 PHP 컬렉션 연산이 아니라 DB
집계로, 대표 1건이 필요한 곳은 관계 자체를 oldestOfMany 로 좁힌다. eager load 의
limit(1) 은 부모별이 아니라 배치 쿼리 전체에 걸려 첫 행만 값을 갖게 되므로 쓸 수 없다.

뺀 값에는 대체 경로를 먼저 만들었다. 상품 옵션은 행을 펼칠 때 배치로 불러오고(상품 수와
무관하게 쿼리 상수), 종전 동작이 필요한 호출자를 위해 ?with_options=1 등 opt-in 을 남겼다.
배송정책 국가설정과 리뷰 첨부 이미지는 소비처를 실측한 결과 화면이 실제로 그리고 있어
제거하지 않았다 — 그 소비 사실을 회귀 테스트로 고정했다.

재발 방지로 정적 검사 룰 4종과 규정 문서 항목을 함께 넣었다.
This commit is contained in:
HeuJung
2026-08-05 21:20:05 +09:00
parent f5b411d9a0
commit b5c0ec1178
265 changed files with 22679 additions and 39095 deletions
+59 -358
View File
@@ -8,8 +8,8 @@
```text
1. 이 문서는 실제 API 호출로 실측한 Settings 엔드포인트 레퍼런스입니다
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 실측 응답 필드 표
3. 응답 필드의 예시값은 실제 호출 응답에서 관측된 값입니다
2. 각 엔드포인트: 메서드/URI/권한 + 요청 파라미터 표 + 요청 예시(curl) + 실측 응답 필드 표 + 응답 예시(envelope)
3. 응답 필드의 예시값·응답 예시 JSON 은 실제 호출 응답에서 관측된 값입니다
4. 갱신: 코드 변경 후 php artisan api:docgen 재실행
5. 설명(TODO) 칸은 사람이 채웁니다
```
@@ -42,20 +42,21 @@ _단건 응답: `data` 객체의 필드._
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
| --- | --- | --- | --- |
| general | object | `{"site_name":"Test Site","site_url":"https:\/\/test.examp…` | 일반 탭 설정 그룹 (사이트명·사이트 URL·설명·관리자 이메일·타임존·기본 언어·통화·점검 모드·사이트 로고 첨부). site_logo 는 SettingsService 가 별도 주입한 첨부 정보 |
| security | object | `{"force_https":true,"login_attempt_enabled":true,"auth_to…` | 보안 탭 설정 그룹 (HTTPS 강제·로그인 시도 제한 사용·인증 토큰 유지시간(분, 0=무한)·최대 로그인 시도 횟수·잠금 시간·내부 네트워크 주소 호출 허용). `allow_internal_outbound_urls`(boolean, 기본 false): 서버가 대신 호출하는 outbound 요청(예약 작업 URL 호출, 외부 API 연동)에서 사설 IP·`localhost` 등 내부 주소를 허용할지 여부 — 켜면 사내 서버 호출이 가능해지지만 서버가 내부망으로 요청을 보낼 수 있게 되므로 기본은 차단입니다. 언어팩 URL 설치는 원격 코드를 내려받으므로 이 설정과 무관하게 항상 내부 주소를 거부합니다 |
| general | object | `{"site_name":"그누보드7","site_url":"https:\/\/g7_2.dev","sit…` | 일반 탭 설정 그룹 (사이트명·사이트 URL·설명·관리자 이메일·타임존·기본 언어·통화·점검 모드·사이트 로고 첨부). site_logo 는 SettingsService 가 별도 주입한 첨부 정보 |
| security | object | `{"force_https":false,"login_attempt_enabled":true,"auth_t…` | 보안 탭 설정 그룹 (HTTPS 강제·로그인 시도 제한 사용·인증 토큰 유지시간(분, 0=무한)·최대 로그인 시도 횟수·잠금 시간·내부 네트워크 주소 호출 허용). `allow_internal_outbound_urls`(boolean, 기본 false): 서버가 대신 호출하는 outbound 요청(예약 작업 URL 호출, 외부 API 연동)에서 사설 IP·`localhost` 등 내부 주소를 허용할지 여부 — 켜면 사내 서버 호출이 가능해지지만 서버가 내부망으로 요청을 보낼 수 있게 되므로 기본은 차단입니다. 언어팩 URL 설치는 원격 코드를 내려받으므로 이 설정과 무관하게 항상 내부 주소를 거부합니다 |
| mail | object | `{"mailer":"smtp","host":"","port":587,"username":"","pass…` | 메일 탭 설정 그룹 (메일러 종류(smtp/mailgun/ses)·SMTP 호스트/포트/인증 정보·암호화 방식·발신자 주소/이름·Mailgun/SES 자격 정보) |
| upload | object | `{"max_file_size":10,"allowed_extensions":["jpg","jpeg","p…` | 업로드 탭 설정 그룹 (최대 파일 크기(MB)·허용 확장자 목록·이미지 최대 가로/세로·이미지 품질) |
| seo | object | `{"meta_title_suffix":"","meta_description":"","meta_keywo…` | SEO 탭 설정 그룹 (메타 타이틀 접미사·메타 설명/키워드·검색엔진 인증 코드·봇 감지·OG/Twitter 기본값·SEO 캐시·사이트맵·생성기 설정) |
| seo | object | `{"meta_title_suffix":null,"meta_description":null,"meta_k…` | SEO 탭 설정 그룹 (메타 타이틀 접미사·메타 설명/키워드·검색엔진 인증 코드·봇 감지·OG/Twitter 기본값·SEO 캐시·사이트맵·생성기 설정) |
| advanced | object | `{"cache_enabled":true,"cache_default_ttl":86400,"layout_c…` | 고급 탭 설정 그룹 (캐시·디버그·코어 업데이트·GeoIP 설정을 한 탭으로 합친 병합 뷰). cache/debug 카테고리 값이 함께 노출됨 |
| cache | object | `{"cache_enabled":true,"cache_default_ttl":86400,"layout_c…` | 캐시 원본 카테고리 (전역 캐시 사용·기본 TTL·레이아웃/통계/SEO 캐시 사용 및 TTL). advanced 탭에 병합되면서 개별 접근용으로 별도 노출된 파생 뷰 |
| debug | object | `{"debug_mode":true,"sql_query_log":false,"log_level":"err…` | 디버그 원본 카테고리 (디버그 모드·SQL 쿼리 로그·로그 레벨). advanced 탭에 병합되면서 개별 접근용으로 별도 노출된 파생 뷰 |
| debug | object | `{"debug_mode":false,"sql_query_log":false,"log_level":"er…` | 디버그 원본 카테고리 (디버그 모드·SQL 쿼리 로그·로그 레벨). advanced 탭에 병합되면서 개별 접근용으로 별도 노출된 파생 뷰 |
| drivers | object | `{"storage_driver":"local","s3_bucket":null,"s3_region":"a…` | 드라이버 탭 설정 그룹 (스토리지/캐시/세션/큐/로그 드라이버 선택 + S3·Redis·Memcached·WebSocket·검색엔진 접속 파라미터) |
| core_update | object | `{"core_update_github_url":"https:\/\/github.com\/custom\/…` | 코어 업데이트 원본 카테고리 (코어 업데이트를 받아올 GitHub 저장소 URL·비공개 저장소 접근용 토큰). advanced 탭에 병합된 파생 뷰 |
| core_update | object | `{"core_update_github_url":"https:\/\/github.com\/gnuboard…` | 코어 업데이트 원본 카테고리 (코어 업데이트를 받아올 GitHub 저장소 URL·비공개 저장소 접근용 토큰). advanced 탭에 병합된 파생 뷰 |
| geoip | object | `{"geoip_enabled":false,"geoip_license_key":null,"geoip_au…` | GeoIP 원본 카테고리 (GeoIP 사용 여부·MaxMind 라이선스 키·DB 자동 갱신 사용). advanced 탭에 병합된 파생 뷰 |
| notifications | object | `{"channels":[{"id":"mail","is_active":true,"sort_order":1…` | 알림 탭 설정 그룹. channels 는 알림 채널 목록으로 각 원소가 id(채널 식별자)·is_active(활성 여부)·sort_order(표시 순서)를 가짐 |
| identity | object | `{"default_provider":"g7:core.mail","purpose_providers":{"…` | 본인인증(IDV) 탭 설정 그룹 (기본 provider·목적별 provider 매핑(purpose_providers)·챌린지 유효시간(분)·최대 시도 횟수) |
| available_drivers | object | `{"storage":[{"id":"local","label":{"ko":"로컬","en":"Local"…` | 드라이버 선택지 카탈로그 (DriverRegistryService 산물). 종류별(storage/cache/session/queue 등) 선택 가능한 드라이버 목록을 id/다국어 label 형태로 제공 |
| _meta | object | `{"limits":{"upload_max_file_size_min":1,"upload_max_file_…` | <!-- TODO: 설명 --> |
| abilities | object | `{"can_update":true}` | 현재 사용자가 이 리소스에 수행 가능한 작업 불리언 맵 (can_update, can_delete 등 — 권한 맵 기반) |
**응답 예시**
@@ -70,25 +71,20 @@ HTTP/1.1 200
"message": "설정을 성공적으로 가져왔습니다.",
"data": {
"general": {
"site_name": "Test Site",
"site_url": "https://test.example.com",
"site_description": "",
"admin_email": "admin@example.com",
"site_name": "그누보드7",
"site_url": "https://api.example.com",
"site_description": null,
"admin_email": "heuristing@gmail.com",
"timezone": "Asia/Seoul",
"language": "ko",
"currency": "KRW",
"maintenance_mode": false,
"site_logo": []
"...": "(5개 키 생략, 총 10개)"
},
"security": {
"force_https": true,
"force_https": false,
"login_attempt_enabled": true,
"auth_token_lifetime": "{MASKED}",
"max_login_attempts": 5,
"login_lockout_time": 30,
"two_factor_auth": false,
"password_min_length": "{MASKED}",
"require_password_special_char": "{MASKED}"
"login_lockout_time": 5,
"...": "(4개 키 생략, 총 9개)"
},
"mail": {
"mailer": "smtp",
@@ -96,15 +92,7 @@ HTTP/1.1 200
"port": 587,
"username": "",
"password": "{MASKED}",
"encryption": "tls",
"mailgun_domain": "",
"mailgun_secret": "{MASKED}",
"mailgun_endpoint": "api.mailgun.net",
"ses_key": "",
"ses_secret": "{MASKED}",
"ses_region": "ap-northeast-2",
"from_address": "heuristing@gmail.com",
"from_name": "그누보드7"
"...": "(9개 키 생략, 총 14개)"
},
"upload": {
"max_file_size": 10,
@@ -114,313 +102,21 @@ HTTP/1.1 200
"png",
"gif",
"webp",
"pdf",
"doc",
"docx",
"xls",
"xlsx",
"zip"
"... (총 11건 중 5건 표시)"
],
"image_max_width": 2000,
"image_max_height": 2000,
"image_max_width": "800",
"image_max_height": "600",
"image_quality": 85
},
"seo": {
"meta_title_suffix": "",
"meta_description": "",
"meta_keywords": "",
"google_analytics_id": "",
"google_site_verification": "",
"naver_site_verification": "",
"bot_user_agents": [
"kakaotalk-scrap",
"Meta-ExternalAgent",
"ChatGPT-User"
],
"bot_detection_enabled": true,
"bot_detection_library_enabled": true,
"og_default_site_name": "",
"og_image_default_width": 1200,
"og_image_default_height": 630,
"twitter_default_card": "summary_large_image",
"twitter_default_site": "",
"cache_enabled": true,
"cache_ttl": 7200,
"sitemap_enabled": true,
"sitemap_cache_ttl": 86400,
"sitemap_urls_per_file": 50000,
"sitemap_gzip": false,
"sitemap_serve_stale_on_miss": true,
"sitemap_max_urls_per_contributor": 0,
"sitemap_hreflang_enabled": true,
"sitemap_schedule": "daily",
"sitemap_schedule_time": "02:00",
"sitemap_last_updated_at": "2026-07-08T03:14:49+00:00",
"generator_enabled": true,
"generator_content": ""
"meta_title_suffix": null,
"meta_description": null,
"meta_keywords": null,
"google_analytics_id": null,
"google_site_verification": null,
"...": "(24개 키 생략, 총 29개)"
},
"advanced": {
"cache_enabled": true,
"cache_default_ttl": 86400,
"layout_cache_enabled": true,
"layout_cache_ttl": 3600,
"seo_cache_enabled": true,
"seo_cache_ttl": 7200,
"seo_sitemap_cache_ttl": 86400,
"stats_cache_enabled": true,
"stats_cache_ttl": 1800,
"notification_cache_ttl": 3600,
"extension_status_cache_ttl": 86400,
"geoip_cache_enabled": true,
"geoip_cache_ttl": 86400,
"version_check_cache_ttl": 3600,
"debug_mode": true,
"sql_query_log": false,
"log_level": "error",
"core_update_github_url": "https://github.com/custom/repo",
"core_update_github_token": "{MASKED}",
"geoip_enabled": false,
"geoip_license_key": null,
"geoip_auto_update_enabled": true,
"geoip_last_updated_at": ""
},
"cache": {
"cache_enabled": true,
"cache_default_ttl": 86400,
"layout_cache_enabled": true,
"layout_cache_ttl": 3600,
"seo_cache_enabled": true,
"seo_cache_ttl": 7200,
"seo_sitemap_cache_ttl": 86400,
"stats_cache_enabled": true,
"stats_cache_ttl": 1800,
"notification_cache_ttl": 3600,
"extension_status_cache_ttl": 86400,
"geoip_cache_enabled": true,
"geoip_cache_ttl": 86400,
"version_check_cache_ttl": 3600
},
"debug": {
"debug_mode": true,
"sql_query_log": false,
"log_level": "error"
},
"drivers": {
"storage_driver": "local",
"s3_bucket": null,
"s3_region": "ap-northeast-2",
"s3_access_key": null,
"s3_secret_key": null,
"s3_url": null,
"cache_driver": "file",
"redis_host": "127.0.0.1",
"redis_port": 6379,
"redis_password": null,
"redis_database": "1",
"memcached_host": "127.0.0.1",
"memcached_port": 11211,
"session_driver": "file",
"session_lifetime": 120,
"queue_driver": "sync",
"log_driver": "daily",
"log_level": "error",
"log_days": 14,
"websocket_enabled": true,
"websocket_app_id": "test-app-id",
"websocket_app_key": "{MASKED}",
"websocket_app_secret": "{MASKED}",
"websocket_host": "localhost",
"websocket_port": 8080,
"websocket_scheme": "https",
"websocket_verify_ssl": true,
"websocket_server_host": "127.0.0.1",
"websocket_server_port": 8080,
"websocket_server_scheme": "http",
"search_engine_driver": "mysql-fulltext"
},
"core_update": {
"core_update_github_url": "https://github.com/custom/repo",
"core_update_github_token": "{MASKED}"
},
"geoip": {
"geoip_enabled": false,
"geoip_license_key": null,
"geoip_auto_update_enabled": true,
"geoip_last_updated_at": ""
},
"notifications": {
"channels": [
{
"id": "mail",
"is_active": true,
"sort_order": 1
},
{
"id": "database",
"is_active": true,
"sort_order": 2
}
]
},
"identity": {
"default_provider": "g7:core.mail",
"purpose_providers": {
"signup": null,
"password_reset": null,
"inicis": {
"adult_verification": "inicis"
}
},
"challenge_ttl_minutes": 15,
"max_attempts": 5
},
"available_drivers": {
"storage": [
{
"id": "local",
"label": {
"ko": "로컬",
"en": "Local",
"fr": "로컬"
}
},
{
"id": "s3",
"label": {
"ko": "Amazon S3",
"en": "Amazon S3",
"fr": "Amazon S3"
}
}
],
"cache": [
{
"id": "file",
"label": {
"ko": "파일",
"en": "File",
"fr": "파일"
}
},
{
"id": "redis",
"label": {
"ko": "Redis",
"en": "Redis",
"fr": "Redis"
}
}
],
"session": [
{
"id": "file",
"label": {
"ko": "파일",
"en": "File",
"fr": "파일"
}
},
{
"id": "database",
"label": {
"ko": "데이터베이스",
"en": "Database",
"fr": "데이터베이스"
}
},
{
"id": "redis",
"label": {
"ko": "Redis",
"en": "Redis",
"fr": "Redis"
}
}
],
"queue": [
{
"id": "sync",
"label": {
"ko": "동기",
"en": "Sync",
"fr": "동기"
}
},
{
"id": "database",
"label": {
"ko": "데이터베이스",
"en": "Database",
"fr": "데이터베이스"
}
},
{
"id": "redis",
"label": {
"ko": "Redis",
"en": "Redis",
"fr": "Redis"
}
}
],
"log": [
{
"id": "single",
"label": {
"ko": "단일 파일",
"en": "Single File",
"fr": "단일 파일"
}
},
{
"id": "daily",
"label": {
"ko": "일별 파일",
"en": "Daily File",
"fr": "일별 파일"
}
}
],
"websocket": [
{
"id": "reverb",
"label": {
"ko": "Laravel Reverb",
"en": "Laravel Reverb",
"fr": "Laravel Reverb"
}
}
],
"mail": [
{
"id": "smtp",
"label": {
"ko": "SMTP",
"en": "SMTP",
"fr": "SMTP"
}
},
{
"id": "mailgun",
"label": {
"ko": "Mailgun",
"en": "Mailgun",
"fr": "Mailgun"
}
},
{
"id": "ses",
"label": {
"ko": "SES (Amazon)",
"en": "SES (Amazon)",
"fr": "SES (Amazon)"
}
}
]
},
"abilities": {
"can_update": true
}
"...": "(11개 키 생략, 총 16개)"
}
}
```
@@ -505,7 +201,7 @@ Content-Type: application/json
**응답 필드** (`data` 내부)
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
**응답 예시**
@@ -551,7 +247,7 @@ _단건 응답: `data` 객체의 필드._
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
| --- | --- | --- | --- |
| app_key | string | `base64:97gZH*************************…` | 현재 애플리케이션 키(`APP_KEY`)를 마스킹한 문자열. 앞부분 일부만 노출하고 나머지는 별표로 가려 전체 원문은 반환하지 않음 |
| app_key | string | `base64:YlAis*************************…` | 현재 애플리케이션 키(`APP_KEY`)를 마스킹한 문자열. 앞부분 일부만 노출하고 나머지는 별표로 가려 전체 원문은 반환하지 않음 |
**응답 예시**
@@ -604,7 +300,7 @@ Authorization: Bearer {YOUR_TOKEN}
**응답 필드** (`data` 내부)
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
<!-- 실측 제외: side-effectful-write — 응답 필드는 사람이 작성하세요. -->
**응답 예시**
@@ -645,7 +341,7 @@ Authorization: Bearer {YOUR_TOKEN}
**응답 필드** (`data` 내부)
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
<!-- 실측 제외: side-effectful-write — 응답 필드는 사람이 작성하세요. -->
**응답 예시**
@@ -686,7 +382,7 @@ Authorization: Bearer {YOUR_TOKEN}
**응답 필드** (`data` 내부)
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
<!-- 실측 제외: side-effectful-write — 응답 필드는 사람이 작성하세요. -->
**응답 예시**
@@ -727,7 +423,7 @@ Authorization: Bearer {YOUR_TOKEN}
**응답 필드** (`data` 내부)
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
<!-- 실측 제외: side-effectful-write — 응답 필드는 사람이 작성하세요. -->
**응답 예시**
@@ -830,7 +526,7 @@ Content-Type: application/json
**응답 필드** (`data` 내부)
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
<!-- 실측 제외: http-403 — 응답 필드는 사람이 작성하세요. -->
**응답 예시**
@@ -881,7 +577,7 @@ Content-Type: application/json
**응답 필드** (`data` 내부)
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
<!-- 실측 제외: side-effectful-write — 응답 필드는 사람이 작성하세요. -->
**응답 예시**
@@ -928,19 +624,20 @@ _단건 응답: `data` 객체의 필드._
| 필드 | 타입 | 실측 예시값 | 용도/설명 |
| --- | --- | --- | --- |
| os_info | string | `Windows NT 10.0` | 운영체제 종류와 버전 (`php_uname` 산물). probe 차단 시 "알 수 없음" 폴백 |
| web_server | string | `Apache/2.4.62 (Win64) OpenSSL/3.0.16 …` | 웹서버 소프트웨어 식별 문자열 (`$_SERVER['SERVER_SOFTWARE']`) |
| web_server | string | `nginx/1.27.3` | 웹서버 소프트웨어 식별 문자열 (`$_SERVER['SERVER_SOFTWARE']`) |
| php_version | string | `8.3.26` | 실행 중인 PHP 버전 (`PHP_VERSION`) |
| mysql_version | string | `Mysql 8.4.3` | 연결된 데이터베이스 서버 종류와 버전 (DB 조회 산물). probe 실패 시 "알 수 없음" 폴백 |
| g7_version | string | `7.0.1` | G7 코어 버전 (`config('app.version')`) |
| g7_version | string | `7.0.6` | G7 코어 버전 (`config('app.version')`) |
| g7_release_year | string | `2026` | G7 릴리즈 연도 (`config('app.release_year')`, 저작권 표기 등에 사용) |
| laravel_version | string | `12.54.1` | 프레임워크 Laravel 버전 (`app()->version()`) |
| laravel_version | string | `12.62.0` | 프레임워크 Laravel 버전 (`app()->version()`) |
| environment | string | `local` | 현재 실행 환경 (`app()->environment()` — local/production/testing 등) |
| cpu_info | string | `Intel(R) Core(TM) Ultra 5 225H` | CPU 모델명 (OS별 시스템 probe 산물). 수집 실패 시 "알 수 없음" 폴백 |
| memory_usage | object | `{"total":"31.49 GB","used":"29.63 GB","free":"1.86 GB","p…` | 물리 메모리 사용량. total/used/free 는 사람이 읽기 쉬운 단위 문자열, percentage 는 사용률(%) |
| disk_usage | object | `{"total":"474.72 GB","used":"360.2 GB","free":"114.51 GB"…` | 설치 볼륨 디스크 사용량. total/used/free 단위 문자열 + percentage 사용률(%) |
| memory_usage | object | `{"total":"31.49 GB","used":"24.31 GB","free":"7.18 GB","p…` | 물리 메모리 사용량. total/used/free 는 사람이 읽기 쉬운 단위 문자열, percentage 는 사용률(%) |
| disk_usage | object | `{"total":"474.72 GB","used":"408.15 GB","free":"66.57 GB"…` | 설치 볼륨 디스크 사용량. total/used/free 단위 문자열 + percentage 사용률(%) |
| php_memory_limit | string | `512M` | PHP `memory_limit` ini 값 |
| max_execution_time | string | `36000초` | PHP `max_execution_time` ini 값 (초 단위 접미사 부착) |
| upload_max_filesize | string | `2G` | PHP `upload_max_filesize` ini 값 |
| opcache | object | `{"loaded":true,"enabled":true}` | <!-- TODO: 설명 --> |
| install_path | string | `C:\Users\HeuJung\htdocs\g7_2` | 애플리케이션 설치 루트 경로 (`base_path()`) |
| config_path | string | `C:\Users\HeuJung\htdocs\g7_2\storage\…` | 설정 파일 저장 경로 (`storage/app/settings`) |
| log_path | string | `C:\Users\HeuJung\htdocs\g7_2\storage\…` | 로그 파일 저장 경로 (`storage/logs`) |
@@ -948,7 +645,7 @@ _단건 응답: `data` 객체의 필드._
| php_extensions | object | `{"required":{"openssl":true,"pdo":true,"mbstring":true,"t…` | PHP 확장 로드 상태. required(필수)·optional(선택) 두 그룹으로 나뉘며 각 확장명→로드 여부(bool) 매핑 |
| database_config | object | `{"has_read_write_split":false,"write":{"host":"localhost"…` | DB 연결 구성 요약. has_read_write_split(읽기/쓰기 분리 여부)·write(쓰기 연결 정보)·read(읽기 replica 목록, write 와 동일하면 제외) |
| timezone | string | `UTC` | 애플리케이션 기본 타임존 (`config('app.timezone')`) |
| server_time | string | `2026-07-07 05:08:58` | 서버 현재 시각 (Y-m-d H:i:s) |
| server_time | string | `2026-08-04 12:53:55` | 서버 현재 시각 (Y-m-d H:i:s) |
**응답 예시**
@@ -962,29 +659,33 @@ HTTP/1.1 200
"message": "성공적으로 처리되었습니다.",
"data": {
"os_info": "Windows NT 10.0",
"web_server": "Apache/2.4.62 (Win64) OpenSSL/3.0.16 PHP/8.3.26",
"web_server": "nginx/1.27.3",
"php_version": "8.3.26",
"mysql_version": "Mysql 8.4.3",
"g7_version": "7.0.1",
"g7_version": "7.0.6",
"g7_release_year": "2026",
"laravel_version": "12.54.1",
"laravel_version": "12.62.0",
"environment": "local",
"cpu_info": "Intel(R) Core(TM) Ultra 5 225H",
"memory_usage": {
"total": "31.49 GB",
"used": "26.92 GB",
"free": "4.57 GB",
"percentage": 85.49
"used": "24.31 GB",
"free": "7.18 GB",
"percentage": 77.2
},
"disk_usage": {
"total": "474.72 GB",
"used": "362.59 GB",
"free": "112.12 GB",
"percentage": 76.38
"used": "408.15 GB",
"free": "66.57 GB",
"percentage": 85.98
},
"php_memory_limit": "512M",
"max_execution_time": "36000초",
"upload_max_filesize": "2G",
"opcache": {
"loaded": true,
"enabled": true
},
"install_path": "C:\\Users\\HeuJung\\htdocs\\g7_2",
"config_path": "C:\\Users\\HeuJung\\htdocs\\g7_2\\storage\\app/settings",
"log_path": "C:\\Users\\HeuJung\\htdocs\\g7_2\\storage\\logs",
@@ -1025,7 +726,7 @@ HTTP/1.1 200
"read": []
},
"timezone": "UTC",
"server_time": "2026-07-08 03:14:54"
"server_time": "2026-08-04 12:53:55"
}
}
```
@@ -1112,7 +813,7 @@ Content-Type: application/json
**응답 필드** (`data` 내부)
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
<!-- 실측 제외: http-422 — 응답 필드는 사람이 작성하세요. -->
**응답 예시**
@@ -1191,7 +892,7 @@ Content-Type: application/json
**응답 필드** (`data` 내부)
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
<!-- 실측 제외: http-500 — 응답 필드는 사람이 작성하세요. -->
**응답 예시**
@@ -1287,7 +988,7 @@ Content-Type: application/json
**응답 필드** (`data` 내부)
<!-- 실측 제외: write-method — 응답 필드는 사람이 작성하세요. -->
<!-- 실측 제외: unresolved-path-param — 응답 필드는 사람이 작성하세요. -->
**응답 예시**