diff --git a/frontend/src/pages/admin/SampleCodePage.tsx b/frontend/src/pages/admin/SampleCodePage.tsx
new file mode 100644
index 0000000..774b9b2
--- /dev/null
+++ b/frontend/src/pages/admin/SampleCodePage.tsx
@@ -0,0 +1,107 @@
+import { useState, useEffect } from 'react';
+import { getSystemConfig, updateSystemConfig } from '../../services/configService';
+
+const COMMON_SAMPLE_CODE_KEY = 'COMMON_SAMPLE_CODE';
+
+const INPUT_CLS =
+ 'w-full border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded-lg px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:outline-none text-sm font-mono';
+
+const SampleCodePage = () => {
+ const [sampleCode, setSampleCode] = useState('');
+ const [loading, setLoading] = useState(true);
+ const [saving, setSaving] = useState(false);
+ const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null);
+
+ useEffect(() => {
+ const fetchConfig = async () => {
+ try {
+ const res = await getSystemConfig(COMMON_SAMPLE_CODE_KEY);
+ if (res.success && res.data?.configValue != null) {
+ setSampleCode(res.data.configValue);
+ }
+ } catch {
+ setMessage({ type: 'error', text: '샘플 코드를 불러오는데 실패했습니다.' });
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ fetchConfig();
+ }, []);
+
+ const handleSave = async () => {
+ setSaving(true);
+ setMessage(null);
+ try {
+ const res = await updateSystemConfig(COMMON_SAMPLE_CODE_KEY, sampleCode);
+ if (res.success) {
+ setMessage({ type: 'success', text: '저장되었습니다.' });
+ } else {
+ setMessage({ type: 'error', text: res.message || '저장에 실패했습니다.' });
+ }
+ } catch {
+ setMessage({ type: 'error', text: '저장 중 오류가 발생했습니다.' });
+ } finally {
+ setSaving(false);
+ setTimeout(() => setMessage(null), 3000);
+ }
+ };
+
+ if (loading) {
+ return (
+
+ );
+ }
+
+ return (
+
+
+
+
공통 샘플 코드 관리
+
+ API HUB 상세 페이지에 공통으로 표시되는 샘플 코드를 관리합니다.
+
+
+
+
+
+ {message && (
+
+ {message.text}
+
+ )}
+
+
+
+ );
+};
+
+export default SampleCodePage;
diff --git a/frontend/src/services/configService.ts b/frontend/src/services/configService.ts
new file mode 100644
index 0000000..159a0b8
--- /dev/null
+++ b/frontend/src/services/configService.ts
@@ -0,0 +1,12 @@
+import { get, put } from './apiClient';
+import type { SystemConfigInfo } from '../types/service';
+import type { ApiResponse } from '../types/api';
+
+export const getSystemConfig = (configKey: string): Promise> =>
+ get(`/config/${configKey}`);
+
+export const updateSystemConfig = (
+ configKey: string,
+ configValue: string,
+): Promise> =>
+ put(`/config/${configKey}`, { configValue });
diff --git a/src/main/java/com/gcsc/connection/common/controller/SystemConfigController.java b/src/main/java/com/gcsc/connection/common/controller/SystemConfigController.java
new file mode 100644
index 0000000..dbf8e95
--- /dev/null
+++ b/src/main/java/com/gcsc/connection/common/controller/SystemConfigController.java
@@ -0,0 +1,46 @@
+package com.gcsc.connection.common.controller;
+
+import com.gcsc.connection.common.dto.ApiResponse;
+import com.gcsc.connection.common.dto.SystemConfigResponse;
+import com.gcsc.connection.common.dto.UpdateSystemConfigRequest;
+import com.gcsc.connection.common.service.SystemConfigService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 시스템 공통 설정 API
+ */
+@RestController
+@RequestMapping("/api/config")
+@RequiredArgsConstructor
+public class SystemConfigController {
+
+ private final SystemConfigService systemConfigService;
+
+ /**
+ * 설정 값 단건 조회
+ */
+ @GetMapping("/{configKey}")
+ public ResponseEntity> getConfig(@PathVariable String configKey) {
+ SystemConfigResponse response = systemConfigService.getConfigValue(configKey);
+ return ResponseEntity.ok(ApiResponse.ok(response));
+ }
+
+ /**
+ * 설정 값 저장 (upsert)
+ */
+ @PutMapping("/{configKey}")
+ public ResponseEntity> updateConfig(
+ @PathVariable String configKey,
+ @RequestBody UpdateSystemConfigRequest request
+ ) {
+ SystemConfigResponse response = systemConfigService.updateConfig(configKey, request);
+ return ResponseEntity.ok(ApiResponse.ok(response));
+ }
+}
diff --git a/src/main/java/com/gcsc/connection/common/dto/SystemConfigResponse.java b/src/main/java/com/gcsc/connection/common/dto/SystemConfigResponse.java
new file mode 100644
index 0000000..586fb18
--- /dev/null
+++ b/src/main/java/com/gcsc/connection/common/dto/SystemConfigResponse.java
@@ -0,0 +1,26 @@
+package com.gcsc.connection.common.dto;
+
+import com.gcsc.connection.common.entity.SnpSystemConfig;
+
+import java.time.LocalDateTime;
+
+public record SystemConfigResponse(
+ Long configId,
+ String configKey,
+ String configValue,
+ String description,
+ LocalDateTime createdAt,
+ LocalDateTime updatedAt
+) {
+
+ public static SystemConfigResponse from(SnpSystemConfig config) {
+ return new SystemConfigResponse(
+ config.getConfigId(),
+ config.getConfigKey(),
+ config.getConfigValue(),
+ config.getDescription(),
+ config.getCreatedAt(),
+ config.getUpdatedAt()
+ );
+ }
+}
diff --git a/src/main/java/com/gcsc/connection/common/dto/UpdateSystemConfigRequest.java b/src/main/java/com/gcsc/connection/common/dto/UpdateSystemConfigRequest.java
new file mode 100644
index 0000000..1e28044
--- /dev/null
+++ b/src/main/java/com/gcsc/connection/common/dto/UpdateSystemConfigRequest.java
@@ -0,0 +1,6 @@
+package com.gcsc.connection.common.dto;
+
+public record UpdateSystemConfigRequest(
+ String configValue
+) {
+}
diff --git a/src/main/java/com/gcsc/connection/common/entity/SnpSystemConfig.java b/src/main/java/com/gcsc/connection/common/entity/SnpSystemConfig.java
new file mode 100644
index 0000000..13cc18a
--- /dev/null
+++ b/src/main/java/com/gcsc/connection/common/entity/SnpSystemConfig.java
@@ -0,0 +1,44 @@
+package com.gcsc.connection.common.entity;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.Table;
+import lombok.AccessLevel;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@Getter
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@Entity
+@Table(name = "snp_system_config", schema = "common")
+public class SnpSystemConfig extends BaseEntity {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "config_id")
+ private Long configId;
+
+ @Column(name = "config_key", unique = true, nullable = false, length = 100)
+ private String configKey;
+
+ @Column(name = "config_value", columnDefinition = "TEXT")
+ private String configValue;
+
+ @Column(name = "description", length = 500)
+ private String description;
+
+ @Builder
+ public SnpSystemConfig(String configKey, String configValue, String description) {
+ this.configKey = configKey;
+ this.configValue = configValue;
+ this.description = description;
+ }
+
+ public void update(String configValue) {
+ this.configValue = configValue;
+ }
+}
diff --git a/src/main/java/com/gcsc/connection/common/repository/SnpSystemConfigRepository.java b/src/main/java/com/gcsc/connection/common/repository/SnpSystemConfigRepository.java
new file mode 100644
index 0000000..75a6635
--- /dev/null
+++ b/src/main/java/com/gcsc/connection/common/repository/SnpSystemConfigRepository.java
@@ -0,0 +1,11 @@
+package com.gcsc.connection.common.repository;
+
+import com.gcsc.connection.common.entity.SnpSystemConfig;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.Optional;
+
+public interface SnpSystemConfigRepository extends JpaRepository {
+
+ Optional findByConfigKey(String configKey);
+}
diff --git a/src/main/java/com/gcsc/connection/common/service/SystemConfigService.java b/src/main/java/com/gcsc/connection/common/service/SystemConfigService.java
new file mode 100644
index 0000000..7d62797
--- /dev/null
+++ b/src/main/java/com/gcsc/connection/common/service/SystemConfigService.java
@@ -0,0 +1,48 @@
+package com.gcsc.connection.common.service;
+
+import com.gcsc.connection.common.dto.SystemConfigResponse;
+import com.gcsc.connection.common.dto.UpdateSystemConfigRequest;
+import com.gcsc.connection.common.entity.SnpSystemConfig;
+import com.gcsc.connection.common.repository.SnpSystemConfigRepository;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class SystemConfigService {
+
+ private final SnpSystemConfigRepository systemConfigRepository;
+
+ /**
+ * 설정 값 단건 조회
+ */
+ @Transactional(readOnly = true)
+ public SystemConfigResponse getConfigValue(String configKey) {
+ return systemConfigRepository.findByConfigKey(configKey)
+ .map(SystemConfigResponse::from)
+ .orElse(null);
+ }
+
+ /**
+ * 설정 값 저장 (upsert: 없으면 생성, 있으면 수정)
+ */
+ @Transactional
+ public SystemConfigResponse updateConfig(String configKey, UpdateSystemConfigRequest request) {
+ SnpSystemConfig config = systemConfigRepository.findByConfigKey(configKey)
+ .map(existing -> {
+ existing.update(request.configValue());
+ return existing;
+ })
+ .orElseGet(() -> systemConfigRepository.save(
+ SnpSystemConfig.builder()
+ .configKey(configKey)
+ .configValue(request.configValue())
+ .build()
+ ));
+ log.info("시스템 설정 저장: configKey={}", configKey);
+ return SystemConfigResponse.from(config);
+ }
+}