회원가입 | 고객센터 |
DESIGNONEX
dxcms.kr
로그인 회원가입
고객센터
10. 마이페이지

마이페이지 구조

D DX
2026.05.10 16:06(수정됨) 122 0

1장. 마이페이지 개요

마이페이지(/auth/mypage)는 로그인 회원이 자신의 정보를 확인하고 관리하는 페이지입니다. 단일 PHP 파일(core/auth/mypage.php)이 10개 탭을 모두 처리하며, 탭 파라미터(tab=...)에 따라 데이터를 동적으로 로드하고 렌더링합니다. 최종 출력은 현재 활성 테마의 layout/main.php를 통해 래핑됩니다.


1.1 진입 경로 및 접근 제어

URL: /auth/mypage
    ?tab=profile|notifications|memo|points|exp|scraps|purchases|friends|blocks|social
    &sub=my|followers           (friends 탭 전용)
    &mbox=received_all|received_friend|sent_all|sent_friend|send  (memo 탭 전용)
    &p=1                        (페이지 번호, 기본 20개/페이지)

비로그인 접근 시:
  → /auth/login?redirect=/auth/mypage 로 자동 리다이렉트

파일 위치:
  core/auth/mypage.php   ← 메인 로직 (탭 데이터 로드 + 렌더링)
  assets/css/mypage.css  ← 마이페이지 전용 CSS (dx_head 훅으로 자동 로드)


1.2 10개 탭 구성

탭 (tab=) 아이콘 기능
profile 👤 프로필 수정, 비밀번호 변경, 이미지 업로드, SNS 연결, 회원 탈퇴
notifications 🔔 실시간 알림 전체 목록 조회, 읽음 처리, 삭제
memo ✉️ 쪽지(메모) 수신함/발신함, 보내기, 읽음 처리, 삭제
points 💰 포인트 내역 조회 (변동·잔액·유형), 페이지네이션
exp 경험치 내역, 레벨 프로그레스바, 레벨 기준표
scraps 🔖 스크랩한 게시글 목록, 스크랩 해제
purchases 🛒 포인트샵 구매 내역, 상태(구매완료/환불됨)
friends 👥 내가 추가한 친구(sub=my), 나를 추가한 사람(sub=followers), 서로친구 배지
blocks 🚫 차단한 회원 목록, 차단 해제
social 🔗 소셜 계정 연결 현황(카카오/네이버/구글/GitHub), 연결하기 링크


1.3 전체 처리 흐름

GET /auth/mypage?tab=profile
  ↓
1. 비로그인 체크 → 리다이렉트
2. 최신 회원 정보 조회 (dx_members WHERE id=?)
3. dx_head 훅으로 mypage.css 로드
4. tab 파라미터 파싱
5. POST면 CSRF 검증 → _action 처리 (profile 수정 / withdraw 탈퇴)
6. 탭별 데이터 로드 (points/exp/scraps/friends/blocks/purchases/notifications)
7. ob_start() → HTML 렌더링 → ob_get_clean() → $dx_content 저장
8. _dx_mypage_pagination() 헬퍼 함수 정의
9. DxTheme::resolve("layout/main.php") → require → 테마 래핑 출력


2장. 프로필 헤더 카드

모든 탭에서 공통으로 표시되는 회원 정보 요약 카드입니다. 아바타•이름•레벨 배지•경험치 바•포인트/EXP/친구 수 스탯으로 구성됩니다.


2.1 구성 요소

요소 설명 및 CSS 클래스
아바타 profile_img 있으면 <img> 태그. 없으면 이름 첫 글자 div (.mp-avatar). 62px 원형
이름 + 레벨 배지 .mp-name + .mp-lv-badge. Lv.N + 레벨명 (DxPoint::getLevelName)
로그인 아이디 .mp-loginid. 회색 소문자로 표시
경험치 바 .mp-exp-bar → .mp-exp-fill (width: $progress%). 다음 레벨까지 EXP 표시
스탯 (PC) .mp-stats-pc. 포인트(금색)·EXP(보라)·친구수(어두운). 600px 이상에서만 표시
스탯 (모바일) .mp-stats-mo. 카드 하단 3분할 가로 배치. 600px 미만에서만 표시


2.2 레벨•경험치 계산

// PHP 마이페이지에서
$level    = (int)$member["level"];
$exp      = (int)$member["exp"];
$progress = DxPoint::getLevelProgress($exp);   // 0~100 (현재 레벨 내 진행률 %)
$nextExp  = DxPoint::getNextLevelExp($exp);    // 다음 레벨까지 필요 EXP. null이면 최고레벨

// 친구 수 — 1분 DxCache 캐시 적용
$_fcVal = DxFriend::getFriendCount($memberId);
// DxCache::get("friend_cnt_{$memberId}") → 없으면 조회 후 60초 캐시


2.3 탭 버튼 렌더링

탭 버튼은 가로 스크롤 가능한 row로 렌더링됩니다. 현재 탭은 bg-blue-600 text-white, 나머지는 bg-white text-slate-500 border 스타일입니다. 메모 탭에는 미읽음 쪽지 수 빨간 배지(mp-memo-badge)가 표시됩니다.
// 탭 배열 정의
$tabs = array(
    "profile"       => array("icon"=>"👤", "label"=>"프로필"),
    "notifications" => array("icon"=>"🔔", "label"=>"알림"),
    "memo"          => array("icon"=>"✉️", "label"=>"메모"),
    "points"        => array("icon"=>"💰", "label"=>"포인트"),
    "exp"           => array("icon"=>"⭐", "label"=>"경험치"),
    "scraps"        => array("icon"=>"북마크", "label"=>"스크랩"),
    "purchases"     => array("icon"=>"🛒", "label"=>"구매내역"),
    "friends"       => array("icon"=>"👥", "label"=>"친구"),
    "blocks"        => array("icon"=>"🚫", "label"=>"차단"),
    "social"        => array("icon"=>"🔗", "label"=>"소셜연결"),
);

// 메모 미읽음 수 — 30초 DxCache 캐시
$_unreadMemo = 0;  // memos WHERE to_id=? AND is_read=0 AND is_deleted_receiver=0


3장. POST 처리 — 프로필 수정 및 회원 탈퇴


3.1 프로필 수정 (_action=profile)

form enctype="multipart/form-data" 으로 POST 전송됩니다. CSRF 검증 후 아래 필드를 처리합니다.
 
필드 (name) 필수 처리 방식
name 필수 DxSanitizer::text(). 빈값이면 오류
email 선택 filter_var FILTER_VALIDATE_EMAIL 검증. 빈값이면 업데이트 생략
bio 선택 300자 초과 시 오류. DxSanitizer::text() 처리
website / blog 선택 http로 시작하지 않으면 https:// 자동 추가 (cleanUrl 클로저)
sns_instagram / twitter / facebook / youtube / github 선택 DxSanitizer::text(). members 테이블에 해당 컬럼 있을 때만 저장
cur_pw / new_pw 변경 시 cur_pw: password_verify(). new_pw: 6자 이상. password_hash(BCRYPT)
profile_img (파일) 선택 jpg/png/gif/webp, 10MB 이내. GD로 400×400px JPEG 85품질 리사이즈
delete_profile_img 선택 "1"이면 기존 이미지 파일 unlink + DB 컬럼 빈값으로 업데이트


3.2 프로필 이미지 업로드 상세

// 저장 경로: data/uploads/profiles/
// 파일명: YYYYMMDD_{8자 랜덤hex}.jpg (항상 .jpg로 통일)

// GD 리사이즈 로직
if (extension_loaded("gd") && function_exists("imagecreatefromstring")) {
    $raw = file_get_contents($imgTmp);
    $src = imagecreatefromstring($raw);  // 확장자 무관, 바이너리로 판별

    // 비율 유지 축소 (이미 400×400 이하면 그대로)
    $ratio = min(400/$srcW, 400/$srcH);
    $dst   = imagecreatetruecolor($dstW, $dstH);

    // PNG/GIF/WebP 투명 → 흰색 배경 변환
    $white = imagecolorallocate($dst, 255, 255, 255);
    imagefill($dst, 0, 0, $white);

    imagecopyresampled($dst, $src, 0,0,0,0, $dstW, $dstH, $srcW, $srcH);
    imagejpeg($dst, $imgFinal, 85);  // JPEG 품질 85

    // GD 없거나 실패 시: move_uploaded_file()로 원본 확장자 그대로 저장
}

// 성공 시: 기존 이미지 unlink 후 "profiles/{파일명}" DB 저장
$upd["profile_img"] = "profiles/" . $imgSave;

⚠️ 컬럼 존재 여부 동적 체크
bio, website, blog, sns_* 컬럼은 추가 설치된 경우에만 존재합니다.
SHOW COLUMNS FROM dx_members 결과를 DxCache(1시간)로 캐시하여
in_array()로 컬럼 존재 여부를 확인 후 UPDATE합니다.
→ 컬럼이 없어도 오류 없이 기본 정보(name, email, password)만 업데이트됩니다.


3.3 회원 탈퇴 (_action=withdraw)

// 탈퇴 확인 폼 필드
// 1. withdraw_confirm: "DELETE" 텍스트 입력 (클라이언트 측 확인용)
// 2. withdraw_pw: 현재 비밀번호 (서버 측 password_verify 검증)

// 처리 로직
if (!password_verify($curPw, $member["password"])) {
    // 소셜 로그인 회원(password 없음)은 비밀번호 검증 생략
    $withdrawMsg = array("type"=>"error", "text"=>"비밀번호가 올바르지 않습니다.");
} else {
    // 실제 삭제 아님! status=0으로 비활성화
    $db->query("UPDATE dx_members SET status=0 WHERE login_id=?", [$member["login_id"]]);
    $auth->logout();  // 세션 삭제 + Remember Me 쿠키 제거
    dx_set_flash("회원 탈퇴가 완료되었습니다. 이용해 주셔서 감사합니다.");
    dx_redirect(dx_base_url());
}

// 탈퇴 결과: 데이터 보존 (게시글, 댓글, 포인트 그대로)
// 계정 접근만 불가 (status=0 → 로그인 시 "비활성 계정" 처리)


4장. 알림 탭 (tab=notifications)


4.1 알림 탭 데이터 로드

// DxNotification::getList() 호출
$notifList = DxNotification::getList($memberId, $pp, ($page-1)*$pp);
// $pp = 20개/페이지

// 총 건수
$total = (int)$db->value("SELECT COUNT(*) FROM dx_notifications WHERE to_member_id=?", [$memberId]);


4.2 알림 타입별 이모지

type 이모지 및 표시 레이블
comment 💬 댓글
comment_reply ↩️ 답글
friend 👥 친구
scrap 스크랩
memo ✉️ 쪽지
(기타) 🔔 (fallback)


4.3 알림 액션 API

액션 설명
POST /api/notification (_sub=read) 개별 읽음 처리. is_read=1, 미읽음 수 반환
POST /api/notification (_sub=read_all) 전체 읽음 처리. 배지 초기화
POST /api/notification (_sub=delete) 개별 삭제. id 파라미터. 삭제 후 unread 수 반환
POST /api/notification (_sub=delete_all) 전체 삭제. 목록 비움


4.4 알림 탭 UI 흐름

  • 미읽음 항목 — 배경 #eff6ff(연파랑) + 파란 점 표시
  • 읽은 항목 — 배경 #fff + 점 없음
  • "모두 읽음" 버튼 — mpNotifReadAll() → POST read_all → 배경색 초기화 + 헤더 벨 배지 초기화
  • "전체 삭제" 버튼 — mpNotifDelAll() → POST delete_all → 목록 비움
  • 개별 삭제 ✕ 버튼 — mpNotifDel(id) → POST delete → 해당 행 fadeOut 제거
  • 헤더 벨 배지 동기화 — dx-notif-badge 요소의 숫자를 r.unread 값으로 갱신


5장. 메모(쪽지) 탭 (tab=memo)


5.1 메모함 구분

mbox 설명
received_all (기본) 나에게 온 전체 쪽지 (is_deleted_receiver=0)
received_friend 친구에게서 받은 쪽지 (from_id IN 친구ID 목록)
sent_all 내가 보낸 전체 쪽지 (is_deleted_sender=0)
sent_friend 친구에게 보낸 쪽지 (to_id IN 친구ID 목록)
send 쪽지 보내기 폼 화면


5.2 쪽지 목록 쿼리 구조

// 받은 쪽지 (received_all)
SELECT m.*, u.name AS other_name, u.profile_img AS other_img, u.id AS other_id
FROM dx_memos m
LEFT JOIN dx_members u ON m.from_id = u.id    -- 발신자 정보
WHERE m.to_id = ? AND m.is_deleted_receiver = 0
ORDER BY m.id DESC LIMIT 20 OFFSET ?

// 보낸 쪽지 (sent_all)
SELECT m.*, u.name AS other_name, ...
FROM dx_memos m
LEFT JOIN dx_members u ON m.to_id = u.id      -- 수신자 정보
WHERE m.from_id = ? AND m.is_deleted_sender = 0
ORDER BY m.id DESC

// 친구 필터 (received_friend)
WHERE m.to_id = ? AND m.is_deleted_receiver = 0
  AND m.from_id IN ({친구ID 목록})   -- 쉼표 구분 정수 목록


5.3 쪽지 목록 UI 기능

  • 클릭 펼치기 — mxToggleMemo(id, isRead) — 본문 영역 toggle. 미읽음이면 /api/memo POST read 호출
  • 읽음 처리 — 행 배경 변경 + NEW 배지 제거 + mp-memo-badge 숫자 감소 + mx-badge-new 감소
  • 답장 버튼 — mxReply(toId, toName) — /auth/mypage?tab=memo&mbox=send&to_id=N&to_name=이름 으로 이동
  • 개별 삭제 — mxDeleteMemo(id, box) — box=received or sent. 행 fadeOut 후 제거
  • 전체 삭제 — mxDeleteAll(mbox) — 현재 목록 모든 항목 순차 삭제
  • 친구 메모 표시 — fr-row friend-memo 클래스 추가 + 👥 친구 배지 표시
  • 발신함 읽음 확인 — 수신자가 읽었으면 ✓ 읽음 배지 표시


5.4 쪽지 보내기 폼 (mbox=send)

  1. 받는 사람 검색 입력 → mxSearchUser() → GET /api/memo?_sub=search_user&q= 호출
  2. 검색 결과 버튼 클릭 → mxSelectUser(id, name) → MX_TO_ID 변수에 ID 저장
  3. 내용 입력 (최대 1000자) + 글자 수 실시간 표시
  4. 보내기 버튼 → mxDoSend() → POST /api/memo (_sub=send)
  5. 전송 성공 시: "메모가 전송되었습니다!" 메시지 표시
  6. 소켓 DM 전달: dm 기능 활성화 + 연결 중이면 sendEvent({type:"dm", to_login_id, from_name, content_preview})


5.5 메모 API 엔드포인트

엔드포인트 설명
GET /api/memo?_sub=search_user&q=검색어 회원 검색. name 또는 login_id로 검색. 최대 10건 반환
POST /api/memo (_sub=send) 쪽지 발송. to_id, content 필수. dx_memos 테이블 INSERT
POST /api/memo (_sub=read) 읽음 처리. memo_id, is_read=1 업데이트. 미읽음 수 반환
POST /api/memo (_sub=delete) 삭제. memo_id, box(received/sent). 해당 deleted 컬럼 1로 변경


5.6 dx_memos 테이블 구조

컬럼 타입 설명
id BIGINT UNSIGNED PK (AUTO_INCREMENT)
from_id INT UNSIGNED 발신자 회원 ID
to_id INT UNSIGNED 수신자 회원 ID
content TEXT 쪽지 내용
is_read TINYINT(1) 0=미읽음, 1=읽음
read_at DATETIME 읽은 시각 (NULL=미읽음)
is_deleted_sender TINYINT(1) 발신자가 삭제했으면 1. 실제 행 삭제 아님
is_deleted_receiver TINYINT(1) 수신자가 삭제했으면 1. 양쪽 모두 1이면 실질적 삭제
created_at DATETIME 발송 일시


6장. 포인트 탭 (tab=points)


6.1 포인트 내역 표

포인트 내역은 5개 컬럼으로 표시됩니다: 일시(m.d H:i) • 유형(DxPoint::typeName()) • 변동(+N P / -N P) • 잔액 • 메모(note). 변동이 양수면 td-plus(초록), 음수면 td-minus(빨강) 스타일이 적용됩니다.
// 포인트 내역 조회
$pointLogs = DxPoint::getLogs($memberId, $pp, $offset);
// → dx_point_log 테이블 ORDER BY id DESC LIMIT 20 OFFSET ?

// 컬럼: created_at, type, point, balance, note
// DxPoint::typeName($type): 유형 코드 → 한글 이름 변환
//   예: "write" → "게시글 작성", "comment" → "댓글 작성", "admin" → "관리자 지급" 등


6.2 포인트 헤더 카드

탭 헤더 우측에 현재 보유 포인트를 금색 배경 카드로 강조 표시합니다. number_format()으로 천 단위 구분자가 적용됩니다.


7장. 경험치 탭 (tab=exp)


7.1 레벨 프로그레스바

// 현재 레벨 내 진행률 (0~100%)
$progress = DxPoint::getLevelProgress($exp);

// 다음 레벨까지 필요 EXP
$nextExp = DxPoint::getNextLevelExp($exp);  // null이면 최고레벨

// HTML: 보라색 그라디언트 바
<div style="height:10px;background:#e2e8f0;border-radius:5px">
  <div style="width:{$progress}%;background:linear-gradient(90deg,#7c3aed,#a78bfa)"></div>
</div>


7.2 레벨 기준표

경험치 탭에는 details/summary 토글로 레벨 기준표가 펼쳐집니다. DxPoint::getThresholds()가 {레벨=>필요EXP} 배열을 반환하며, 현재 레벨은 보라색 강조 박스로 표시됩니다.
// DxPoint::getThresholds() 반환 예시
array(
    1  => 0,
    2  => 100,
    3  => 300,
    4  => 600,
    5  => 1000,
    // ...
)


8장. 스크랩 탭 (tab=scraps)


8.1 스크랩 목록

// 스크랩 목록 조회
$scraps = DxFriend::getScrapList($memberId, $pp, $offset);
// → dx_scraps JOIN dx_posts JOIN dx_boards
// 컬럼: post_id, title, board_key, board_name, created_at, memo

// 삭제된 게시글 처리: title이 비어있으면 "삭제된 게시글" 표시


8.2 스크랩 해제

// 해제 버튼 onclick
window.dxUnscrap = function(postId, btn) {
    if (!confirm("스크랩을 취소할까요?")) return;
    // POST /api/scrap {action:"remove", post_id:postId}
    // 성공 시 해당 행 display:none
};


8.3 dx_scraps 테이블

컬럼 타입 설명
id INT UNSIGNED PK (AUTO_INCREMENT)
member_id INT UNSIGNED 스크랩한 회원 ID
post_id BIGINT UNSIGNED 스크랩한 게시글 ID
memo VARCHAR(191) 스크랩 메모 (선택)
created_at DATETIME 스크랩 일시


9장. 친구 탭 (tab=friends)


9.1 두 가지 서브탭

서브탭 (sub=) 설명
my (기본) 내가 추가한 친구 목록. dx_friends WHERE member_id=? AND type="friend"
followers 나를 추가한 사람 목록. dx_friends WHERE target_id=? AND type="friend"


9.2 서로친구 배지 로직

// sub=my (내가 추가한 친구) 탭에서
// 나를 추가한 사람 ID 목록(followerIds)을 별도 조회
$followerIds = array_column(
    $db->rows("SELECT member_id FROM dx_friends WHERE target_id=? AND type='friend' AND status=1", [$memberId]),
    "member_id"
);

// 렌더링 시: 상대방이 followerIds에 포함되면 "서로친구" 배지 표시
$_fMutual = in_array((int)$_f["target_id"], array_map("intval", $followerIds));

// sub=followers 탭에서도 반대로 동일한 로직 적용
$_fwAdded = in_array((int)$_fw["member_id"], array_map("intval", $_myFriendIds));


9.3 친구 액션 API

// window.dxFriendAction(targetId, action, btn, mode)
// POST /api/friend {action, target_id}

// action 종류:
// "remove_friend" — 내 친구 목록에서 삭제 (dx_friends status=0)
// "block"         — 차단 (dx_friends type="block"으로 변경)
// "unblock"       — 차단 해제
// "add_friend"    — 나를 추가한 사람을 나도 맞추가

// mode="row"이면 성공 시 해당 fr-row 엘리먼트 fadeOut 후 제거


9.4 dx_friends 테이블

컬럼 타입 설명
id INT UNSIGNED PK
member_id INT UNSIGNED 요청자 (추가한 사람)
target_id INT UNSIGNED 대상자 (추가된 사람)
type ENUM(friend, block) friend: 친구, block: 차단
status TINYINT(1) 1=활성, 0=삭제(논리 삭제)
created_at DATETIME 관계 생성 일시

💡 서로친구 개념
DXCMS의 친구는 단방향(follow) 구조입니다.
내가 A를 추가 → dx_friends(member_id=나, target_id=A, type=friend)
A도 나를 추가 → dx_friends(member_id=A, target_id=나, type=friend)
양쪽 레코드가 모두 있으면 "서로친구" 배지 표시


10장. 소셜 연결 탭 (tab=social)


10.1 소셜 연결 현황 표시

// 활성화된 소셜 프로바이더 목록
$_allProviders = DxSocialAuth::providers();
// → ["kakao", "naver", "google", "github"] 등

// 현재 회원의 연결된 소셜 계정 조회
$stmt = $pdo->prepare("SELECT * FROM dx_social_accounts WHERE member_id=?");
$stmt->execute([$memberId]);
$_linkedAccounts = [$row["provider"] => $row, ...];

// 렌더링 조건: cfg["enabled"] && cfg["client_id"] 가 모두 있는 경우만 표시


10.2 소셜 연결 UI

상태 UI
연결됨 "✓ 연결됨" 초록 배지. 연결된 이메일(또는 이름) + 마지막 로그인 날짜 표시
미연결 "연결하기" 버튼 → /auth/social?provider=카카오&redirect=/auth/mypage?tab=social


11장. 공개 프로필 페이지 (/auth/profile)

/auth/profile?id={member_id} 는 다른 사람의 프로필을 볼 수 있는 공개 페이지입니다. core/auth/profile.php 파일이 처리하며, 회원 본인이 보면 "프로필 수정" 버튼이, 타 회원이 보면 "메모 보내기" + "1:1 채팅" 버튼이 표시됩니다.


11.1 표시 정보

  • 커버 + 아바타 — var(--p) → 인디고 그라디언트 커버. 76px 원형 아바타 (사진 또는 이름 첫 글자)
  • 이름 + 레벨 — 이름 h1 + Lv.N + 가입일
  • 통계 — 게시글 수 / 댓글 수 / 포인트 / 경험치 (4개 가로 배치)
  • 자기소개 — bio 컬럼. nl2br()로 줄바꿈 표시
  • 링크 카드 — website, blog, sns_instagram/twitter/facebook/youtube/github 있을 때만 표시

11.2 버튼 표시 조건

상황 표시 버튼
타 회원이 볼 때 (로그인) 메모 보내기 (파란색) + 1:1 채팅 (초록색, DM 기능 ON일 때만 표시)
내 프로필 볼 때 ($isSelf) 프로필 수정 버튼 → /auth/mypage
비로그인 버튼 없음


11.3 1:1 채팅 초대 버튼

// profile.php의 1:1 채팅 버튼 (id="dx-chat-invite-btn")
// 기본 display:none → DM 기능 ON + 소켓 연결 시 JS가 자동으로 표시

<button id="dx-chat-invite-btn" '이름')"
        style="display:none">
  1:1 채팅
</button>

// socket-core.js.php가 features.dm ON이면 display:inline-flex로 변경
// dxSendChatInvite()는 sendEvent({type:"dm_invite", to_login_id, from_name, from_login_id, room_id})


12장. CSS 구조 (mypage.css)


12.1 주요 CSS 클래스

클래스 역할
.mp-profile-card 프로필 헤더 카드 래퍼. 흰 배경, 18px 둥근 모서리, 미세 그림자
.mp-avatar 아바타 div. 62px 원형. 파란→인디고 그라디언트
.mp-profile-img 프로필 사진 img. 62px 원형, object-fit:cover
.mp-lv-badge 레벨 배지. 파란 배경, 흰 텍스트, 99px 둥근
.mp-exp-bar / .mp-exp-fill 경험치 바. fill은 파란→인디고 그라디언트
.mp-stats-mo / .mp-stats-pc 스탯 모바일(하단 3분할) / PC(우측 3열). 600px 기준 전환
.mp-hd 탭 헤더 영역. flex justify-between
.mp-tbl 포인트/경험치 내역 테이블. fixed 레이아웃
.mp-type-badge 포인트 유형 배지. 회색 배경, 작은 글씨
.mp-empty 빈 데이터 상태. 중앙 정렬 아이콘+텍스트
.pf-section 프로필 수정 폼 섹션. 패딩+하단 구분선
.pf-section-title 섹션 제목. 대문자, 트래킹, 우측 선 자동 연장 (::after)
.pf-row 입력 2컬럼 그리드. 600px 이하에서 1컬럼
.fr-row 친구 목록 행. flex align-center
.fr-ava 친구 아바타 원형. 40px
.fr-mutual-badge "서로친구" 초록 배지
.mx-tab / .mx-tab.on 메모함 탭 버튼 / 활성 탭
.mx-row / .mx-memo-unread 메모 목록 행 / 미읽음 행 (파란 배경)
.mx-badge-new 빨간 NEW 배지. 원형, 중앙정렬


12.2 반응형 브레이크포인트

조건 적용 변경
min-width: 600px 아바타 62→72px, .mp-stats-mo 숨김, .mp-stats-pc 표시
max-width: 600px .pf-row 1컬럼
max-width: 480px 탭 버튼 패딩/폰트 축소 (.mp-tab-btn)


13장. 관련 DB 스키마 총정리


13.1 dx_members — 회원 정보

컬럼 타입 마이페이지 사용 방식
id INT UNSIGNED 회원 식별자. 모든 탭 데이터 조회 기준
name VARCHAR(100) 이름/닉네임. 프로필 헤더 + 수정 폼
login_id VARCHAR(50) 아이디. 헤더 카드 + 탈퇴 처리
email VARCHAR(191) 이메일. 수정 폼 + FILTER_VALIDATE_EMAIL 검증
password VARCHAR(255) BCrypt 해시. 비밀번호 변경 + 탈퇴 검증
profile_img VARCHAR(500) "profiles/{파일명}" 형식. 헤더 카드 아바타
bio TEXT 자기소개. 프로필 탭 textarea
website / blog VARCHAR(500) 개인 사이트/블로그. 프로필 폼 + 공개 프로필
sns_instagram ~ sns_github VARCHAR(300) SNS URL. 수정 폼 5개 입력란
level SMALLINT 현재 레벨. 헤더 배지 + 경험치 탭
exp INT 누적 경험치. 프로그레스바 계산
point INT 보유 포인트. 헤더 스탯 + 포인트 탭
status TINYINT 0=비활성(탈퇴). withdraw 처리 시 0으로 변경
join_date DATETIME 가입일. 프로필 탭 가입일 표시
last_login DATETIME 마지막 로그인. 프로필 탭 표시


13.2 dx_notifications — 알림

컬럼 타입 설명
id BIGINT UNSIGNED PK
to_member_id INT UNSIGNED 수신자 회원 ID. 알림 탭 조회 기준
from_member_id INT UNSIGNED 발신자 회원 ID. 0이면 시스템 알림
type VARCHAR(30) comment/comment_reply/friend/scrap/memo
message VARCHAR(255) 알림 메시지 본문
url VARCHAR(500) 클릭 시 이동 URL
is_read TINYINT(1) 0=미읽음, 1=읽음
created_at DATETIME 알림 생성 일시


13.3 헬퍼 함수 _dx_mypage_pagination()

// mypage.php 하단에 로컬 정의된 페이지네이션 헬퍼
function _dx_mypage_pagination($pages, $current, $baseUrl) {
    if ($pages <= 1) return;
    // 현재 페이지 ±4 범위만 표시 (최대 9개 버튼)
    for ($i = max(1,$current-4); $i <= min($pages,$current+4); $i++) {
        // 현재 페이지: bg-blue-600 text-white
        // 나머지: bg-slate-50 text-slate-500
        echo '<a href="' . $baseUrl . '&p=' . $i . '">' . $i . '</a>';
    }
}

// 각 탭에서 호출 예시:
_dx_mypage_pagination($pages, $page, $baseUrl . "?tab=points");


14장. 사용방법 정리


14.1 회원이 마이페이지를 사용하는 방법

  1. 로그인 후 헤더의 [회원이름]님 또는 "마이페이지" 링크 클릭
  2. 프로필 탭: 이름•이메일•자기소개•사진 변경 후 "프로필 저장" 클릭
  3. 비밀번호 변경: 현재 비밀번호 입력 후 새 비밀번호 입력 → 프로필 저장
  4. SNS 연결: 소셜연결 탭에서 "연결하기" 버튼 클릭 → 소셜 로그인 완료
  5. 메모: 메모 탭 → "메모 보내기" 클릭 → 받는 사람 검색 → 내용 작성 → 보내기
  6. 친구: 게시판 글쓴이 클릭 → 공개 프로필 → "친구 추가" 버튼
  7. 스크랩 해제: 스크랩 탭에서 "해제" 버튼 클릭
  8. 회원 탈퇴: 프로필 탭 하단 "탈퇴하기" → "DELETE" 입력 → 비밀번호 확인 → 탈퇴


14.2 개발자가 마이페이지를 커스텀하는 방법

  • 탭 추가 — $tabs 배열에 새 항목 추가 후 해당 elseif 블록 추가
  • CSS 수정 — assets/css/mypage.css 직접 수정 또는 테마 CSS에서 오버라이드
  • 프로필 필드 추가 — dx_members 테이블에 컬럼 추가 후 SHOW COLUMNS 캐시 만료 대기 (1시간) 또는 DxCache 초기화
  • 포인트 유형 추가 — DxPoint::typeName() 메서드에 새 type 코드와 한글명 추가
  • 메모 API 확장 — core/api/memo.php에 새 _sub 액션 추가


14.3 주의사항

  • 프로필 이미지는 data/uploads/profiles/ 폴더에 저장됩니다. 폴더가 없으면 자동 생성됩니다.
  • GD 확장이 없는 서버에서는 리사이즈 없이 원본 파일 그대로 저장됩니다.
  • 회원 탈퇴는 물리적 삭제가 아닌 status=0 비활성화입니다. 데이터는 보존됩니다.
  • 소셜 연결은 DxSocialAuth 설정(client_id)이 완료된 프로바이더만 표시됩니다.
  • 메모•친구•차단 API는 모두 CSRF 토큰 검증이 적용됩니다.
  • 친구 수는 1분, 메모 미읽음 수는 30초 DxCache로 캐시됩니다.

댓글0

로그인 후 댓글을 작성할 수 있습니다.
3.10 모듈 로딩 구조 플러그인 / 확장 로딩 방식 2026.04.21 3.9 공통 함수 / 유틸 재사용 방식 2026.04.21 3.9 공통 함수 / 유틸 공통 클래스 구조 2026.04.21 3.9 공통 함수 / 유틸 전역 함수 구조 2026.04.21 3.8 Extend 구조 실제 적용 흐름 2026.04.21 3.8 Extend 구조 Extend 개념 2026.04.21 3.7 Hook 시스템 Hook 시스템 활용 사례 2026.04.21 3.7 Hook 시스템 실행 타이밍 2026.04.21 3.7 Hook 시스템 Hook 개념 2026.04.21 3.6 데이터 처리 구조 공통 함수 활용 2026.04.21 3.6 데이터 처리 구조 데이터 흐름 상세 기술 2026.04.21 3.6 데이터 처리 구조 DB 접근 방식 2026.04.21 3.5 컨트롤러 구조 컨트롤러 구조 • 데이터 전달 • 실행 방식 • 역할 2026.04.21 3.4 라우팅 시스템 URL 처리 방식 • 라우팅 규칙 • 동적 라이팅 2026.04.21 3.3 실행 흐름 초기 로딩 과정 및 공통 초기화 흐름 2026.04.21 3.2 폴더 구조 install/ — 설치 및 마이그레이션 2026.04.21 3.2 폴더 구조 pages/ — 커스텀 페이지 2026.04.21 3.2 폴더 구조 data/ — 런타임 데이터 2026.04.21 3.2 폴더 구조 extend/ — 코드 자동 삽입 2026.04.21 3.2 폴더 구조 routes/ + controllers/ — 라라벨 스타일 라우팅 2026.04.21
31
전체 회원
503
전체 게시글
770
전체 댓글
441
오늘 방문
33,173
전체 방문
2
현재 접속
인기글 7일 이내
최신글
최신댓글
목록