회원가입 | 고객센터 |
DESIGNONEX
디자인원엑스
About
Service
Q&A
PR리그
자유게시판N
갤러리
포인트게임
공지사항N
통계
로그인 회원가입
고객센터
4.1 CMS 아키텍처

DX 위에 CMS가 올라가는 구조

A Administrator
2026.04.21 01:04(수정됨) 95 0

1. 개요 및 설계 철학

DXCMS는 "DX(DesignOneX) 프레임워크 위에 CMS 기능이 층위별로 올라가는" 계층형 아키텍처를 따릅니다. 각 계층은 독립적으로 교체•확장 가능하며, 하위 계층은 상위 계층에 대해 알지 못합니다. 이 원칙을 통해 CMS는 저가형 공유 호스팅부터 동접 1만 명 대규모 서버까지 단일 코드베이스로 동작합니다.


1.1 핵심 설계 원칙

원칙 내용
단일 진입점 index.php가 모든 HTTP 요청을 수신. URL Rewrite 없는 환경에서도 ?_url= 방식으로 동일하게 동작
계층 분리 Infrastructure(DB·캐시·보안) → DX Core(라우터·훅·DI) → CMS Services(인증·게시판·SEO) → Presentation(테마·스킨) 4계층 엄격 분리
상향 의존 금지 하위 계층은 상위 계층을 import하지 않음. 하위에서 상위로의 통신은 훅(Hook) 시스템을 통해서만 허용
광범위 PHP 호환 PHP 5.6~8.4 단일 코드베이스. 삼항 연산자(?:)·array()·dirname(__FILE__) 사용, fn()·::class·반환타입 힌트 미사용
폴백 체인 테마 파일, 게시판 스킨, 플러그인 모두 "현재 → 커스텀 → 기본값" 3단계 폴백 체인으로 무결성 보장
격리와 안전 DxExtend·PluginRegistry·DxBoardSkin은 외부 코드를 안전하게 실행(safeExec). 오류가 전체 시스템에 전파되지 않음


2. 전체 계층 구조 (아키텍처 다이어그램)

DXCMS의 아키텍처는 4개의 주요 계층으로 구성됩니다. 최하단의 Infrastructure 계층이 가장 먼저 초기화되고, 상위 계층은 하위 계층이 완전히 준비된 후에만 동작합니다.
 
┌────────────────────────────────────────────────────────────────┐
│               LAYER 4 — Presentation Layer                    │
│  테마(DxTheme) • 게시판스킨(DxBoardSkin) • 카테고리스킨        │
│  themes/default/ • boards/skins/ • pages/ • extend/           │
├────────────────────────────────────────────────────────────────┤
│               LAYER 3 — CMS Service Layer                     │
│  DxSite • Auth • DxSeo • DxCategory • DxNotification          │
│  DxPoint • DxShop • DxFriend • DxMemberMonitor • DxPopup      │
│  DxSms • DxMailer • DxCaptcha • DxSocialAuth • DxMarket       │
├────────────────────────────────────────────────────────────────┤
│               LAYER 2 — DX Core Layer                         │
│  HookManager • PluginRegistry • DxContainer(DI)               │
│  Router • Dispatcher • DxRouter • DxExtend                    │
│  DxCache • DxSanitizer • QueryBuilder • DxMigration           │
├────────────────────────────────────────────────────────────────┤
│               LAYER 1 — Infrastructure Layer                  │
│  Secure.php • Database(PDO) • functions.php • DxCache          │
│  data/config.php • PHP Runtime • Web Server • MySQL/MariaDB    │
└────────────────────────────────────────────────────────────────┘
                              ▲ ▲ ▲
                    HTTP Request (index.php)
 
계층 이름 핵심 컴포넌트 역할
Layer 4 Presentation DxTheme, DxBoardSkin, 테마파일, 스킨파일 HTML 렌더링, UI 표현, 폴백 체인
Layer 3 CMS Service DxSite, Auth, DxSeo, DxCategory, DxPoint 비즈니스 로직, 회원/게시판/SEO/포인트
Layer 2 DX Core HookManager, DxContainer, Router, DxCache 라우팅, 훅, DI, 캐시, 확장 메커니즘
Layer 1 Infrastructure Secure.php, Database, config.php 보안, DB 연결, 설정, PHP 런타임


3. Layer 1 — Infrastructure (기반 인프라)

모든 CMS 기능의 토대가 되는 계층입니다. 이 계층이 초기화되지 않으면 상위 계층은 전혀 동작하지 않습니다. index.php의 STEP 1~3에 해당합니다.


3.1 Secure.php — 보안 전담 클래스

보안 관련 모든 기능이 단일 파일에 집중되어 있습니다. 보안 패치 시 이 파일만 수정하면 됩니다. 설치 시 고유 해시 경로(core/security/{hash}/Secure.php)에 배치되어 파일 경로 예측 공격을 방어합니다.
 
기능 설명
세션 보안 HttpOnly · Secure · SameSite=Lax 쿠키 설정, 세션 고정 공격 방지
CSRF 토큰 발급(csrfToken()) / 검증(csrfCheck()). 모든 POST 요청에 자동 적용
보안 헤더 X-Frame-Options, X-Content-Type-Options, Referrer-Policy 자동 발행
XSS 방어 출력 이스케이프 함수(dx_esc()) 제공
경로 순회 방어 realpath() 검증으로 디렉터리 탈출 공격 차단
업로드 검증 MIME 타입 + 확장자 이중 검증, getimagesize() 실제 이미지 검증, 이중확장자 차단
비밀번호 해시 bcrypt 해싱, PHP 5.6 폴백 포함
Rate Limiting 시크릿 키 기반 동적 세션 키 이름으로 요청 제한
시크릿 키 주입 64자리 랜덤 secret_key로 세션/CSRF/RateLimit 키 이름을 동적 도출


3.2 Database — PDO 래퍼 (싱글턴)

MySQL/MariaDB PDO 연결을 싱글턴으로 관리합니다. data/config.php 로드 시 자동 연결됩니다. 준비된 구문(Prepared Statement)을 강제하여 SQL Injection을 원천 차단합니다.
 
메서드 / 기능 설명
Database::getInstance() PDO 싱글턴 반환. 요청 내 연결 재사용
$db->rows($sql, $params) 다중 행 SELECT. PDO Prepared Statement 사용
$db->row($sql, $params) 단일 행 SELECT (LIMIT 1)
$db->value($sql, $params) 단일 값 반환 (COUNT, MAX 등)
$db->insertRow($table, $data) INSERT. 배열을 자동 바인딩
$db->table($name) 테이블명에 프리픽스 자동 추가 (dx_prefix)
$db->tableExists($table) 테이블 존재 여부 확인 (마이그레이션 호환)
$db->pdo() 원시 PDO 객체 반환 (고급 용도)
QueryBuilder + dx_db() 라라벨 스타일 체이닝: dx_db('boards')->where('status',1)->get()


3.3 data/config.php — 설정 로드 및 DB 연결 트리거

📋  config.php가 로드되는 순간 DB 연결이 실행됩니다.
 
define('DB_HOST', 'localhost');         // DB 호스트
define('DB_NAME', 'my_database');        // DB 이름
define('DX_SITE_URL', 'https://...');    // 사이트 URL
define('DX_SECURITY_PATH', 'a1b2...');   // 보안 경로 해시 (16자리)
define('DX_SECRET_KEY', '...');          // 64자리 랜덤 시크릿 키
// $db->connect() 자동 실행됨


4. Layer 2 — DX Core (프레임워크 핵심)

DX Core는 CMS 기능과 인프라 사이의 미들웨어 역할을 합니다. 훅 시스템, DI 컨테이너, 라우터, 캐시 등 모든 CMS 서비스가 의존하는 공통 메커니즘을 제공합니다.


4.1 HookManager — 훅/이벤트 시스템

WordPress Action/Filter와 동일한 철학의 훅 시스템입니다. CMS의 모든 확장 포인트가 훅을 통해 제공됩니다. 플러그인과 테마는 훅을 통해 CMS 동작을 수정하거나 기능을 추가합니다.
 
유형 등록 실행 반환값
Action (액션) dx_add_hook($name, $cb, $priority) dx_run_hook($name, $args) 없음. 부수효과 실행 용도
Filter (필터) dx_add_filter($name, $cb, $priority) dx_apply_filter($name, $value) 변형된 값 반환. 데이터 변환 용도


주요 시스템 훅 포인트

훅 이름 발생 위치 용도
dx_head <head> 내부 CSS/JS 추가
dx_body_bottom </body> 직전 스크립트, 팝업 자동출력
dx_top / dx_middle / dx_bottom 페이지 상/중/하단 콘텐츠 삽입
dx_after_login 로그인 성공 직후 포인트 지급, 모니터링
dx_after_logout 로그아웃 직후 세션 정리
dx_board_list_context 게시판 목록 컨텍스트 생성 후 목록 데이터 변형
dx_board_view_context 게시글 보기 컨텍스트 생성 후 보기 데이터 변형
dx_board_after_save 게시글 저장 후 알림, 포인트, 인덱싱
dx_editor_init 에디터 초기화 요청 에디터 플러그인 렌더
dx_editor_render 에디터 실제 렌더 플러그인이 등록
dx_extend_top/middle/bottom extend/ 파일 실행 후 추가 처리 훅


4.2 DxContainer — 경량 DI 컨테이너

Laravel의 Service Container와 동일한 철학의 PHP 5.6 호환 경량 DI 컨테이너입니다. 기존 getInstance() 싱글턴 패턴을 유지하면서 추가적인 의존성 주입을 지원합니다.
 
메서드 설명
bind($abstract, $factory) 팩토리 바인딩 — make() 호출마다 새 인스턴스 생성
singleton($abstract, $factory) 싱글턴 바인딩 — 첫 make() 이후 동일 인스턴스 반환
instance($abstract, $obj) 이미 생성된 인스턴스 직접 등록 (항상 싱글턴)
alias($abstract, $alias) 별칭 등록. dx_app()->make("db") === dx_app()->make("database")
make($abstract) 서비스 꺼내기. 바인딩 없으면 클래스명으로 직접 인스턴스화
call('Controller@method', $params) 컨트롤러 메서드 자동 호출 + 의존성 주입
registerCoreServices() DB, Auth, Secure, Cache, Hook, SEO, Site, Theme 자동 등록


4.3 Router + Dispatcher — 라우팅 엔진

DXCMS는 두 가지 라우팅 방식을 병행합니다. DxRouter(라라벨 스타일 클래스 기반)가 먼저 시도되고, 매칭 실패 시 기존 Router+Dispatcher(파일 기반) 방식으로 폴백됩니다.


Router — URL 파싱 및 라우트 결정

URL 패턴 TYPE 상수 처리
/ TYPE_HOME themes/{테마}/page/home.php → DB is_home=1 → pages/home.php (우선순위 폴백)
/{slug} TYPE_PAGE DB dx_pages 조회 → page_type/location에 따라 렌더
/{board_key}/list TYPE_BOARD boards/handler.php → DxBoardSkin 폴백 체인
/{board_key}/view/{id} TYPE_BOARD 게시글 상세. BIGINT 오버플로우 방지(문자열 유지)
/{board_key}/write TYPE_BOARD 게시글 작성. CSRF 검증
/admin/{action} TYPE_ADMIN admin/{action}/index.php 실행
/auth/{action} TYPE_AUTH core/auth/{action}.php 실행
/api/{action} TYPE_API core/api/{action}.php 실행
/search TYPE_SEARCH core/search/handler.php 실행
/sitemap.xml TYPE_API core/api/sitemap.php 실행
/robots.txt TYPE_API core/api/robots.php 실행


Dispatcher — 라우트 → 핸들러 실행

Router가 결정한 route 객체를 받아 실제 핸들러 파일을 실행합니다. 라우트 확정 직후 extend/middle/을 실행한 후 switch 문으로 타입별 dispatch 함수를 호출합니다.
 
// Dispatcher::dispatch() 핵심 흐름
$this->route = $this->router->resolve();
$GLOBALS['dx_route'] = $this->route;

// extend/middle/ 실행 (라우트 확정 직후)
DxExtend::getInstance()->runMiddle(['type' => $this->route['type'], ...]);

switch ($this->route['type']) {
    case Router::TYPE_HOME:   $this->dispatchHome();   break;
    case Router::TYPE_PAGE:   $this->dispatchPage();   break;
    case Router::TYPE_BOARD:  $this->dispatchBoard();  break;
    case Router::TYPE_ADMIN:  $this->dispatchAdmin();  break;
    case Router::TYPE_AUTH:   $this->dispatchAuth();   break;
    case Router::TYPE_API:    $this->dispatchApi();    break;
    case Router::TYPE_SEARCH: $this->dispatchSearch(); break;
    default:                  $this->dispatch404();    break;
}


4.4 DxCache — 파일/APCu 이중 드라이버 캐시

APCu 설치 여부를 자동 감지하여 드라이버를 선택합니다. 저가형 공유 호스팅에서는 파일 캐시를 사용하고, APCu가 있으면 메모리 캐시로 자동 전환됩니다.
 
캐시 항목 캐시 키 TTL 무효화 시점
전체 설정 dx_settings 5분 (300초) 관리자 설정 저장 → 전체 flush
게시판 목록 board_list_* 1분 (60초) 게시글 작성/수정/삭제
사이트맵 XML sitemap_* 10분 (600초) 게시글 작성/삭제
멀티사이트 설정 site_{md5(domain)} 5분 (300초) 사이트 설정 저장
카테고리 목록 cat_board_{id} 5분 (300초) 카테고리 변경


4.5 DxExtend — extend/ 폴더 자동 실행 엔진

파일을 지정된 폴더에 놓는 것만으로 코드를 자동 실행할 수 있는 노-코드 확장 시스템입니다. 플러그인이나 훅 없이도 CMS 동작을 수정할 수 있습니다.
  • extend/top/      ← 초기화 완료 직후 (점검모드, IP차단, 커스텀 인증)
  • extend/middle/   ← 라우트 확정 직후 (방문자 로그, A/B 테스트)
  • extend/bottom/   ← 렌더링 완료 후 (캐시 저장, 성능 로그)

규칙:

파일명 오름차순 실행 • 하위 폴더 1단계 재귀 탐색
에러 발생해도 다음 파일 계속 실행 (격리)
보안: realpath() 검증으로 경로 탈출 공격 차단


5. Layer 3 — CMS Service Layer (CMS 서비스 계층)

비즈니스 로직의 핵심 계층입니다. DB 연결과 DX Core가 준비된 후 초기화됩니다. 각 서비스 클래스는 싱글턴 패턴으로 구현되어 요청 내에서 한 번만 인스턴스화됩니다.


5.1 CMS 서비스 클래스 전체 목록

클래스 싱글턴 역할
DxSite 싱글턴 멀티사이트 관리. 도메인별 설정(theme, site_name, menu_group)을 $dx_config에 오버라이드
Auth 싱글턴 세션 기반 인증. 로그인/로그아웃/권한 확인. isLoggedIn(), get('id') 등
DxSeo static SEO 메타 자동 생성. OG, Twitter Card, JSON-LD, Canonical URL, noindex 처리
DxCategory static 게시판 카테고리. DB 기반 무한 계층, 목록/뷰 독립 표시, 배지 색상
DxNotification static 실시간 알림. DB 저장 + 소켓 서버 HTTP push. 댓글/답글/친구/스크랩/쪽지
DxPoint static 포인트/경험치/레벨. 로그인·작성·댓글·좋아요 등 이벤트별 자동 적립
DxShop 싱글턴 유료 콘텐츠 구매. 결제 플러그인 연동 추상화
DxFriend static 친구 관계 관리. 친구 추가/삭제/목록
DxMemberMonitor static 회원 모니터링. 로그인/로그아웃/last_seen/접속자 추적
DxPopup static 팝업 자동 출력. dx_body_bottom 훅에서 자동 렌더
DxSms 싱글턴 SMS 발송 추상화. 알리고/NCP/CoolSMS/Twilio 드라이버
DxMailer 싱글턴 이메일 발송 추상화. SMTP/Sendmail/PHP mail() 드라이버
DxCaptcha static CAPTCHA 추상화. reCAPTCHA v2/v3, hCaptcha, Turnstile, 내장
DxSocialAuth 싱글턴 소셜 로그인. 카카오/네이버/구글/GitHub OAuth2
DxMarket 싱글턴 플러그인/테마 마켓 클라이언트. SHA-256 해시 검증 설치
DxSanitizer static 입력값 정제. HTML XSS 필터, 파일명 정규화
DxThumb static 이미지 썸네일. GD 기반 리사이즈, WebP 지원, 비율 유지


5.2 DxSite — 멀티사이트 관리자

같은 DB에 여러 도메인을 운영할 때 도메인별 독립 설정을 적용합니다. 요청이 들어오면 HTTP_HOST를 감지하여 dx_sites 테이블에서 해당 도메인 설정을 로드하고 전역 $dx_config를 오버라이드합니다.
 
동작 단계 설명
도메인 감지 HTTP_HOST에서 포트 번호 제거 후 소문자 정규화
캐시 조회 site_{md5(domain)} 키로 DxCache 조회 (TTL 300초). 히트 시 DB 조회 생략
③ DB 조회 dx_sites WHERE domain=? AND status=1. 미등록 도메인은 null 캐시
설정 오버라이드 site_name, site_description, site_url, theme, language, timezone, footer_text를 dx_config에 덮어쓰기
⑤ menu_group 주입 active_menu_group을 도메인별 메뉴 그룹으로 설정
⑥ extra_config JSON 필드. 추가 설정 자유롭게 확장 가능

멀티사이트 도메인 독립 항목
사이트명 • 설명 • URL • 테마 • 언어 • 시간대 • 푸터 텍스트 • 메뉴 그룹
SEO 사이트맵 (각 도메인이 자신의 URL 기준으로 독립 생성)
게시판/페이지의 site_domain 컬럼으로 도메인별 콘텐츠 분리


5.3 Auth — 세션 기반 인증

DB 연결 후 세션을 검증하여 로그인 상태를 확인합니다. DI 컨테이너에 auth 키로 등록되어 dx_make('auth')로 어디서나 접근 가능합니다.
 
메서드 설명
isLoggedIn() 로그인 여부. 세션 검증 완료된 결과
get($key, $default) 로그인한 회원 정보 접근. get('id'), get('level') 등
check($permission) 권한 확인. level, group, 게시판별 권한 등
login($loginId, $password) 로그인 처리. bcrypt 검증, 세션 갱신, dx_after_login 훅 실행
logout() 로그아웃. 세션 파기, dx_after_logout 훅 실행


5.4 DxSeo — SEO 메타 자동 생성

페이지 타입(게시글 보기 / 목록 / 페이지 / 홈)에 따라 SEO 메타 데이터를 자동으로 생성합니다. 테마 레이아웃(layout/main.php)에서 DxSeo::render()를 호출하여 출력합니다.
 
build() 타입 자동 생성 내용
board_view title=게시글제목—게시판명|사이트명, description=본문앞150자, image=첫번째img src, JSON-LD Article, 비밀글→noindex
board_list title=게시판명|사이트명, 카테고리/검색 포함, 2페이지~=페이지번호 추가, 검색결과→noindex
page title=페이지명|사이트명, 페이지 description 사용
home title=사이트명, site_description 사용, JSON-LD WebSite


5.5 DxPoint — 포인트/경험치/레벨 엔진

회원 활동에 따라 포인트와 경험치를 자동으로 지급합니다. 레벨 설정은 DB dx_level_config 테이블에서 관리자가 커스터마이징 가능합니다. 테이블 없으면 하드코딩 기본값(1~15레벨)으로 폴백합니다.
 
이벤트 포인트 경험치 설명
signup 10 20 회원가입
login 1 2 로그인
write 5 10 게시글 작성
comment 2 5 댓글 작성
like_recv 1 2 좋아요 받음
scrap_recv 1 0 스크랩 받음


5.6 DxNotification — 실시간 알림 엔진

알림은 DB 저장과 소켓 서버 HTTP push를 동시에 처리합니다. 소켓 플러그인(dx-socket)이 비활성 상태여도 DB 기반 알림은 정상 동작합니다. 알림 실패가 댓글 작성 등 본 기능을 막지 않도록 모든 예외를 흡수합니다.


알림 타입:

comment (댓글) • comment_reply (답글) • friend (친구추가), scrap (스크랩) • memo (쪽지)


동작 흐름:

    1. DxNotification::add() 호출
    2. DB dx_notifications 테이블에 저장
    3. 소켓서버 활성 시: POST https://socket-host:port/push → 실시간 전송
    4. 소켓서버 없으면: 클라이언트가 폴링으로 조회 (API /api/notification)


6. Layer 4 — Presentation Layer (프레젠테이션 계층)

사용자에게 보이는 HTML을 생성하는 최상위 계층입니다. 테마 엔진(DxTheme)과 게시판 스킨 엔진(DxBoardSkin)이 폴백 체인을 통해 파일을 해석하고 렌더링합니다.


6.1 DxTheme — 테마 엔진

테마 파일을 해석하고 폴백 체인을 실행하는 핵심 엔진입니다. 현재 테마에 파일이 없으면 default 테마에서 자동으로 찾습니다.
 
메서드 역할
resolve($relPath) 테마 파일 경로 반환 (현재 테마 → default 폴백)
resolveBoardSkin($skin, $action) 게시판 스킨 파일 해석 (4단계 폴백 체인)
resolvePart($name) 테마 파셜 파일 해석 (pagination, breadcrumb 등)
resolveLatestSkin($skin) 최신글 위젯 스킨 해석 (list/card/simple 등)
meta($themeName) theme.json 메타정보 반환 (이름, 버전, 작성자, 옵션)
option($key, $default) 테마 옵션 값 반환 (DB theme_{테마명}_{키} 저장)
assetUrl($path) 테마 에셋 URL 반환
allThemes() 설치된 모든 테마 목록 반환 (관리자용)


테마 파일 폴백 체인

// DxTheme::resolve() 폴백 체인
1. themes/{현재 테마}/{relPath}   ← 현재 테마 파일 (최우선)
2. themes/default/{relPath}       ← default 테마 폴백
3. null 반환 → 404               ← 어디에도 없음

// DxTheme::resolveBoardSkin() 폴백 체인 (4단계)
1. themes/{테마}/board/{스킨}/{액션}.php
2. themes/{테마}/board/{액션}.php
3. themes/default/board/{스킨}/{액션}.php
4. themes/default/board/{액션}.php      ← 최종 폴백


6.2 DxBoardSkin — 게시판 스킨 엔진

게시판의 외형을 담당하는 스킨 시스템입니다. boards/skins/ 폴더에 스킨을 추가하여 게시판별로 완전히 다른 UI를 구현할 수 있습니다. 기본 제공 스킨으로는 gallery와 shop이 있습니다.
 
우선순위 파일 경로 (예: gallery 스킨, list 액션)
1 boards/skins/gallery/list/handler.php  ← 완전 독립 핸들러 (있으면 바로 실행)
2 boards/skins/gallery/list.php           ← 독립 뷰 파일
3 themes/{현재테마}/board/gallery/list.php
4 themes/{현재테마}/board/list.php
5 themes/default/board/gallery/list.php
6 themes/default/board/list.php           ← 최종 폴백


6.3 테마 디렉터리 구조

themes/
  default/              ← 기본 테마 (항상 존재, 폴백 기준)
    theme.json          ← 테마 메타정보 (이름, 버전, 옵션 정의)
    layout/
      main.php          ← 전체 레이아웃 (헤더+본문+푸터)
    board/
      list.php          ← 게시판 목록
      view.php          ← 게시글 상세 (가장 큰 파일, ~90KB)
      write.php         ← 게시글 작성/수정
      _list_rows.php    ← 목록 행 파셜
    board_latest/
      list.php          ← 최신글 위젯 목록형
      card.php          ← 최신글 위젯 카드형
      simple.php        ← 최신글 위젯 심플형
    page/
      home.php          ← 홈페이지
      404.php           ← 404 페이지
      403.php           ← 403 페이지
    parts/
      pagination.php    ← 페이지네이션
    search/
      list.php          ← 통합검색 결과
    assets/             ← 테마 전용 CSS/JS
  my-theme/             ← 커스텀 테마 (있는 파일만 오버라이드)
    theme.json
    layout/main.php
    board/list.php      ← 목록만 커스터마이징, 나머지는 default 폴백


6.4 홈페이지(/) 렌더링 우선순위

/ URL 접근 시 Dispatcher::dispatchHome()이 4단계 우선순위로 홈페이지 파일을 탐색합니다.
 
순위 경로/조건 설명
1 themes/{현재테마}/page/home.php 테마 홈 파일 (최우선). 파일 존재 시 즉시 사용
2 DB: is_home=1, status=1, site_domain={현재도메인} 멀티사이트 도메인 전용 홈페이지
3 DB: is_home=1, status=1, site_domain='' 공통 홈페이지 (도메인 무관)
4 pages/home.php 기본 폴백 홈페이지


7. 플러그인 시스템 — CMS 위의 확장 계층

플러그인은 Layer 3(CMS Service)과 Layer 4(Presentation) 사이에서 동작하는 선택적 확장 계층입니다. 플러그인을 활성화하면 CMS 핵심 파일을 수정하지 않고도 에디터, 결제, 소켓, CAPTCHA 등의 기능을 추가할 수 있습니다.


7.1 플러그인 타입 및 기본 제공 플러그인

플러그인 타입 활성 설정키 역할
ckeditor4-editor editor active_editor CKEditor 4 로컬 파일 서빙. 멀티이미지, 유튜브 자동임베드
jodit-editor editor active_editor Jodit WYSIWYG 에디터
tinymce-editor editor active_editor TinyMCE 에디터
dx-socket socket active_socket WebSocket 실시간 접속자 추적, 채팅, 알림 push
tosspay-payment payment active_payment 토스페이 결제 연동
kg-inicis-payment payment active_payment KG이니시스 결제 연동
nicepay-payment payment active_payment 나이스페이 결제 연동
kakaopay-payment payment active_payment 카카오페이 결제 연동
naverpay-payment payment active_payment 네이버페이 결제 연동
paypal-payment payment active_payment PayPal 결제 연동
stripe-payment payment active_payment Stripe 결제 연동


7.2 플러그인 등록 구조

각 플러그인은 plugins/{id}/plugin.php 파일을 통해 CMS에 자신을 등록합니다. PluginRegistry에 타입과 메타데이터를 등록하고, HookManager에 콜백을 등록하여 동작합니다.
 
// plugins/my-editor/plugin.php
dx_register_plugin([
    'id'      => 'my-editor',
    'type'    => 'editor',      // editor | payment | socket | captcha | sms | social_login
    'name'    => 'My Editor',
    'version' => '1.0.0',
    'settings' => [
        'toolbar' => ['label'=>'툴바 설정', 'type'=>'select',
            'options'=>['full'=>'전체','basic'=>'기본']],
    ],
]);

// 에디터 렌더링 훅 등록
dx_add_hook('dx_editor_render', function($args) {
    $name  = $args['name'];
    $value = $args['value'];
    echo "<textarea id='{$name}' class='my-editor'>{$value}</textarea>";
    echo "<script>MyEditor.init('#{$name}');</script>";
}, 10);


8. 게시판 처리 전체 흐름

/{board_key}/view/{id} URL 요청이 들어왔을 때 DXCMS가 어떻게 처리하는지 전체 흐름을 추적합니다. 이 흐름은 CMS 아키텍처의 4개 계층이 어떻게 협력하는지 가장 잘 보여주는 예시입니다.
 
HTTP GET /free/view/123
    │
    ▼ index.php
[Layer 1] Secure → DB → config.php 로드
    │
    ▼
[Layer 2] HookManager, PluginRegistry, load_plugins() 완료
    │
    ▼
[Layer 3] DxSite::getInstance() → 도메인 설정 오버라이드
          DxTheme::getInstance() → 테마 결정
          Auth::getInstance()    → 로그인 상태 확인
    │
    ▼
[Layer 2] DxRouter::dispatch() → 라우트 없음 → Dispatcher 폴백
    │
    ▼
[Layer 2] Router::resolve() → TYPE_BOARD, slug='free', action='view', id='123'
    │
    ▼
[Layer 2] DxExtend::runMiddle()  (extend/middle/ 파일 실행)
    │
    ▼
[Layer 2] Dispatcher::dispatchBoard()
    │
    ▼
[Layer 3] boards/handler.php 실행
          • DB에서 posts WHERE id=123 조회
          • 조회수 +1 (세션으로 중복 방지)
          • 댓글 목록 조회
          • DxSeo::build('board_view', $ctx) → SEO 메타 생성
          • DxCategory::getByBoard($boardId, 'view') → 카테고리 로드
          • dx_run_hook('dx_board_view_context', $ctx)
    │
    ▼
[Layer 4] DxBoardSkin::resolveView($skin, 'view')
          폴백 체인: boards/skins/{skin}/view.php
                  → themes/{테마}/board/{skin}/view.php
                  → themes/default/board/view.php
    │
    ▼
[Layer 4] Dispatcher::renderWithLayout($viewFile, $ctx)
          → themes/{테마}/layout/main.php 실행
          → DxSeo::render() 호출 (layout <head> 내)
          → dx_run_hook('dx_head') (CSS/JS 추가)
          → view.php include (본문 렌더링)
          → dx_run_hook('dx_body_bottom') (팝업, 스크립트)
    │
    ▼
[Layer 2] DxExtend::runBottom()  (extend/bottom/ 파일 실행)
    │
    ▼
HTTP Response (HTML)


9. 데이터베이스 테이블 구조

DXCMS는 모든 테이블에 dx_ 프리픽스를 사용합니다. 테이블명은 Database::table($name)을 통해 자동으로 프리픽스가 추가됩니다.
 
테이블 관련 클래스/계층 주요 컬럼
dx_members Auth, DxPoint, DxFriend id, login_id, password, name, level, point, exp, profile_img
dx_social_accounts DxSocialAuth member_id, provider(kakao/naver/google/github), provider_id
dx_boards Router, Dispatcher board_key, board_name, skin, site_domain, status
dx_posts boards/handler.php id(BIGINT), board_id, member_id, title, content, is_secret, view_count
dx_comments core/api/comment.php id, post_id, member_id, content, parent_id
dx_categories DxCategory id, board_id, parent_id, name, color, show_in_list, show_in_view
dx_pages Router, Dispatcher slug, title, content, page_type, is_home, site_domain, is_standalone
dx_menus DxSite, 레이아웃 id, menu_group, label, url, sort_order
dx_settings dx_config() setting_key, setting_value (전체 사이트 설정)
dx_sites DxSite domain, site_name, theme, menu_group, extra_config, status
dx_notifications DxNotification to_member_id, from_member_id, type, message, url, is_read
dx_point_log DxPoint member_id, type, point, exp, description
dx_level_config DxPoint level, exp_threshold, name (관리자 커스터마이징)
dx_likes core/api/like.php post_id, member_id, type
dx_scraps boards/handler.php post_id, member_id
dx_visitors extend/middle/ id, ip, member_id, url, visited_at
dx_member_monitor DxMemberMonitor member_id, last_seen, is_online
dx_popups DxPopup title, content, start_at, end_at, conditions


10. 주요 전역 헬퍼 함수 레퍼런스

functions.php와 각 클래스 하단에 정의된 전역 함수들입니다. 테마/플러그인/extend 코드에서 자유롭게 사용할 수 있습니다.
 
함수 정의 위치 설명
dx_config($key, $default) functions.php 전역 설정값 반환
dx_config_set($key, $val) functions.php 전역 설정값 변경 (멀티사이트 오버라이드에 사용)
dx_base_url($path) functions.php 기본 URL + 경로 반환
dx_request_uri() functions.php 현재 요청 URI (URL Rewrite 호환)
dx_esc($str) functions.php HTML 출력 이스케이프 (XSS 방어)
dx_csrf_token() functions.php CSRF 토큰 값 반환
dx_csrf_field() functions.php <input type=hidden name=csrf ...> 출력
dx_csrf_check() functions.php POST 요청 CSRF 토큰 검증
dx_app() DxContainer.php DI 컨테이너 인스턴스 반환
dx_make($abstract) DxContainer.php 컨테이너에서 서비스 꺼내기
dx_db($table) QueryBuilder.php QueryBuilder 인스턴스 반환
dx_add_hook($name, $cb, $pri) HookManager.php 훅 Action 등록
dx_run_hook($name, $args) HookManager.php 훅 Action 실행
dx_apply_filter($name, $val) HookManager.php 훅 Filter 실행
dx_theme_file($relPath) DxTheme.php 테마 파일 경로 반환 (폴백 포함)
dx_include_part($name, $vars) DxTheme.php 테마 파셜 include
dx_theme_asset($path) DxTheme.php 테마 에셋 URL 반환
dx_theme() DxSite.php 현재 테마명 반환
dx_menu_group() DxSite.php 현재 메뉴 그룹명 반환
load_plugins() functions.php plugins/**/plugin.php 자동 로드
dx_register_plugin($info) PluginRegistry.php 플러그인 타입 등록
dx_log($msg, $level) functions.php data/error.log에 에러/경고 기록
dx_path_inside($path, $base) functions.php 경로 탈출 방어 검증


11. 아키텍처 설계 결정 요약

DXCMS의 주요 설계 결정과 그 이유를 정리합니다.
 
설계 결정 이유 및 트레이드오프
싱글턴 패턴 우선 PHP 5.6 호환성 + 간결함. Composer autoload 없이도 동작. DI 컨테이너가 추가로 감싸 Laravel 스타일도 지원
Secure.php 해시 경로 파일 경로를 알아도 공격 불가. 보안 패치 시 1파일만 교체하면 되는 단일 책임 원칙
DxCache 최우선 로드 config.php 로드 전에 캐시가 준비되어야 설정 캐싱 가능. 매 요청마다 DB 조회 방지
이중 라우팅(DxRouter + Dispatcher) 기존 파일 기반 방식 100% 유지로 하위 호환. 새로운 routes/*.php 방식은 선택적 확장
extend/ 폴더 시스템 훅 없이 파일만 놓으면 실행. 개발자가 아닌 운영자도 사용 가능. 에러 격리로 안전
DxTheme 폴백 체인 커스텀 테마는 바꾸고 싶은 파일만 오버라이드. 나머지는 default에서 자동 상속
BIGINT post_id 문자열 유지 32bit PHP에서 (int) 캐스팅 시 오버플로우 발생. ctype_digit()으로 검증 후 문자열 유지
DxSite 캐싱 모든 요청마다 dx_sites DB 조회는 비효율. DxCache로 도메인별 설정을 300초 캐싱
DxNotification 예외 완전 흡수 알림 실패가 댓글 작성 등 본 기능을 막으면 UX 파괴. try-catch로 완전 격리
DxMarket SHA-256 검증 개발자 서버 → 사용자 서버 직접 다운로드 후 중앙서버 해시와 대조. 무결성 보장

 한 줄 요약: DX 프레임워크 위에 CMS가 올라가는 구조

Layer 1 (Infrastructure) — 보안•DB•설정: 모든 것의 토대
Layer 2 (DX Core)        — 훅•DI•라우터•캐시: CMS가 작동하는 메커니즘
Layer 3 (CMS Service)    — 인증•게시판•SEO•포인트: 비즈니스 로직
Layer 4 (Presentation)   — 테마•스킨•폴백 체인: 사용자가 보는 HTML

플러그인 계층이 Layer 3~4 사이에서 선택적으로 기능을 추가합니다.
extend/ 파일이 Layer 2~4 전반에 걸쳐 코드를 삽입합니다.

댓글0

로그인 후 댓글을 작성할 수 있습니다.
4.1 CMS 아키텍처 데이터 흐름 연결 2026.04.21 4.1 CMS 아키텍처 DX 위에 CMS가 올라가는 구조 2026.04.21
30
전체 회원
269
전체 게시글
144
전체 댓글
181
오늘 방문
28,530
전체 방문
1
현재 접속
인기글 7일 이내
최신글
최신댓글
목록