🃏 명함 프로필 (종이명함) — 완전 분석 매뉴얼
URL: [서비스URL]/?cur_win=paper_card
이 페이지의 모든 JavaScript 소스, 알고리즘, 데이터 흐름, CSS 스타일까지
한 글자도 빠짐없이 분석하여 초등학생도 이해할 수 있도록 정리했습니다.
📋 명함 프로필이란?
명함 프로필(종이명함, paper_card)은 IAM(아이엠) 플랫폼의 핵심 기능 중 하나로, 실제 종이명함을 디지털로 관리하는 페이지입니다.
이 페이지에서는 다음과 같은 일을 할 수 있습니다:
- 📸 종이명함 촬영/등록 — 스마트폰 카메라로 명함을 찍어 등록
- 🤖 AI OCR 인식 — 명함 이미지에서 이름·전화번호·회사명 자동 추출
- ✏️ 직접 입력 등록 — 이름, 직책, 기관명, 주소, 전화 등을 직접 입력
- 🔍 검색 & 정렬 — 등록된 명함을 이름순·등록일순·회사명순으로 정렬
- 📤 AI 명함퍼널 — AI가 발신자 정보를 바탕으로 맞춤 메시지 자동 생성
- 📱 폰문자/웹문자 발송 — 생성된 메시지를 실제 문자로 발송
- 💰 결제 시스템 — 카드·계좌이체·포인트로 IAM 만들기 결제
[서비스도메인] 도메인에서 동작하며,
cur_win=paper_card라는 URL 파라미터로 어떤 화면을 보여줄지 결정합니다.
🔗 접속 URL 구조
명함 프로필 페이지는 다음과 같은 URL로 접속합니다:
URL의 각 부분이 하는 역할은 다음과 같습니다:
| 부분 | 설명 |
|---|---|
https:// |
보안 연결(HTTPS) 프로토콜 |
[서비스도메인] |
사용자 전용 서브도메인 (송조은님의 IAM) |
/? |
루트 경로 + 쿼리스트링 시작 |
cur_win=paper_card |
현재 창(window)을 "종이명함"으로 설정 |
cur_win 파라미터 값에 따라 완전히 다른 화면이 표시됩니다.
예: paper_card=종이명함, we_story=추천피드, my_info=내명함
📦 로딩되는 파일 목록
이 페이지가 로드될 때 함께 불러오는 모든 CSS와 JS 파일입니다:
CSS 파일 (스타일시트) — 총 10개
| # | 파일 경로 | 역할 |
|---|---|---|
| 1 | [내부경로]/[부트스트랩]/bootstrap.min.css | Bootstrap UI 프레임워크 (버튼, 모달, 그리드) |
| 2 | [내부경로]/[한글폰트] | 한글 폰트 (Noto Sans KR) |
| 3 | [내부경로]/[아이콘폰트] | 아이콘 폰트 (Font Awesome 4) |
| 4 | [내부경로]/[메인스타일] | 메인 스타일 (IAM 전역 스타일) |
| 5 | [내부경로]/[스타일]/new_style.css | 새로운 스타일 추가분 |
| 6 | [내부경로]/[스타일]/grid.min.css | 그리드 레이아웃 시스템 |
| 7 | [내부경로]/[스타일]/slick.min.css | 슬라이더/캐러셀 UI |
| 8 | [내부경로]/[스타일]/style_j.css | 추가 커스텀 스타일 |
| 9 | [내부경로]/[스타일]/iam.css | 명함 카드 전용 스타일 (square, content, sample_card) |
| 10 | /css/pretend-font.css | Pretendard 폰트 (현대적 한글 폰트) |
JavaScript 파일 — 총 11개
| # | 파일 경로 | 핵심 역할 |
|---|---|---|
| 1 | //developers.kakao.com/sdk/js/kakao.min.js | 카카오톡 공유 SDK |
| 2 | [내부경로]/[JS]/jquery-3.1.1.min.js | jQuery 3.1.1 (DOM 조작, AJAX, 이벤트) |
| 3 | [내부경로]/[JS]/slick.min.js | 슬라이더 라이브러리 |
| 4 | [내부경로]/[JS]/main.js | UI 토글, 사이드바, 패널 스크롤 애니메이션 |
| 5 | [내부경로]/[부트스트랩]/js/bootstrap.min.js | Bootstrap JS (모달, 탭, 드롭다운) |
| 6 | [내부경로]/[JS]/Sortable.min.js | 드래그 앤 드롭 정렬 |
| 7 | /js/rlatjd_fun.js | 유틸함수 모음 (쿠키, 브라우저체크, 숫자포맷, 창 이동) |
| 8 | /js/rlatjd.js | 회원관련 함수 (로그인, 회원가입, 비번검사) |
| 9 | /plugin/toastr/js/toastr.min.js | 토스트 알림 팝업 |
| 10 | [내부경로]/[JS]/layer.min.js | 레이어 팝업 |
| 11 | [내부경로]/[JS]/qrcode.min.js | QR코드 생성 라이브러리 |
🏗️ 전체 아키텍처 구조도
페이지가 로드되고 동작하는 전체 구조를 도식화하면 다음과 같습니다:
┌─────────────────────────────────────────────────────┐
│ Browser / WebView │
├─────────────────────────────────────────────────────┤
│ 1. HTML 파싱 시작 │
│ ├── CSS 10개 로드 │
│ ├── JS 11개 로드 (순차적) │
│ └── 인라인 script #1: callAppBridge() 정의 │
│ │
│ 2. DOMContentLoaded (페이지 로딩 완료) │
│ ├── 인라인 script #2 실행 │
│ │ ├── sign_toggle(): 2초 간격 점멸 │
│ │ ├── jQuery(document).ready() #1 │
│ │ │ └── 알림 팝업 체크 & 표시 │
│ │ ├── jQuery(document).ready() #2 │
│ │ │ ├── cur_win_name 설정 │
│ │ │ ├── 레이아웃 모드 감지 (key1_gwc_show) │
│ │ │ │ ├── mode=4: 와이드 모드 │
│ │ │ │ └── mode≠4: 일반 모드 │
│ │ │ ├── 미디어 높이 계산 │
│ │ │ ├── 모바일/데스크탑 감지 (checkMobile) │
│ │ │ └── 카드 너비 동적 설정 │
│ │ └── 전역 함수 80+개 정의 │
│ │ │
│ 3. 페이지 콘텐츠 렌더링 │
│ ├── 헤더(header): 로고, 메뉴, 언어, 검색 │
│ ├── 푸터 메뉴(footer_menu): 4개 탭 │
│ │ ├── 앱홈 → goIamHome() │
│ │ ├── 내명함 → iam_mystory('my_info') │
│ │ ├── 추천 → iam_mystory('we_story') │
│ │ └── 명함관리 → [내부페이지]/[로그인] │
│ ├── 미들(middle): 종이명함 검색 & 리스트 │
│ └── 바텀(bottom): 콘텐츠 그리드 │
│ │
│ 4. AJAX 데이터 로딩 │
│ ├── getIamPaper() → [내부API]/[명함목록] │
│ ├── displaySample() → [내부API]/[콘텐츠조회] │
│ └── displayMall() → [내부API]/[상품조회] │
│ │
│ 5. 사용자 인터랙션 │
│ ├── 종이명함 추가 → add_paper_card() │
│ │ ├── 모바일: callAppBridge('goCardCamera') │
│ │ └── 데스크탑: alert("휴대폰에서 이용해주세요") │
│ ├── 종이명함 편집 → create_paper() │
│ │ └── 모달 #paper_list_edit_modal 열기 │
│ ├── AI명함퍼널 → edit_papersender() │
│ │ └── 모달 #paper_sender_edit_modal 열기 │
│ ├── 저장 → save_paper() │
│ │ └── POST → [내부API]/[명함관리] │
│ └── 삭제 → delete_paper(id) │
│ └── POST → [내부API]/[명함관리] │
└─────────────────────────────────────────────────────┘
🔄 데이터 흐름도
클라이언트(브라우저) ↔ 서버(PHP) 간 데이터가 어떻게 오가는지 보여줍니다:
| 동작 | 요청 방식 | 서버 엔드포인트 | 보내는 데이터 | 받는 데이터 |
|---|---|---|---|---|
| 종이명함 목록 로드 | GET | [내부API]/[명함목록] | card_owner, page, search_str, search_range | HTML (명함 리스트) |
| 종이명함 저장 | POST | [내부API]/[명함관리] | name, job, org, mobile, phone, email, addr, memo, display_top, img_url | JSON {result, seq, msg} |
| 종이명함 삭제 | POST | [내부API]/[명함관리] | seq, del='Y' | JSON {result} |
| 명함 이미지 OCR | POST | [내부API]/[명함관리] | image file (multipart) | JSON {name, mobile, org_name, job, addr, email, fax, img_url} |
| 콘텐츠 기록 저장 | POST | [내부API]/[콘텐츠처리] | post_type='history', mem_id, cont_id, event_kind | HTML (로그) |
| 카드 결제 | POST | [내부API]/[명함발송] | [결제타입], [결제수단], [결제금액], [포인트값], [명함URL], [메시지] | JSON {result} |
| 포인트 충전 | POST | [내부API]/[포인트처리] | [결제방식], [금액], [수수료비율], [결제유형] | JSON {result} |
| AI 발신자 저장 | POST (FormData) | [내부API]/[명함관리] | sender_* 필드들, ai_step, prompt_*, files | JSON {result} |
| AI 프롬프트 미리보기 | POST | [내부API]/[프롬프트미리보기] | sys_prompt, user_prompt, generation_mode | HTML (미리보기 메시지) |
📊 함수 분류 체계
페이지 내에 정의된 80개 이상의 함수를 8가지 카테고리로 분류했습니다:
1️⃣ 페이지 초기화 함수 (6개)
sign_toggle()— 온라인 상태 표시등 점멸 (2초 간격)callAppBridge(method, ...args)— Android/iOS 네이티브 브릿지panelGroupState()— 상단 패널 스크롤 애니메이션mallGroupState()— 몰 그룹 스크롤 애니메이션checkMobile()— 모바일 기기 감지resize(img, maxW, maxH)— 로고 이미지 크기 조정
2️⃣ 데이터 로딩 함수 (8개)
displaySample(lim, off)— 샘플 콘텐츠 로드 (AJAX GET)displayMall(lim, off)— 몰 상품 로드 (AJAX GET)getIamPaper(...)— 종이명함 목록 로드getIamContact(...)— 연락처 목록 로드getIamFriends(...)— 프렌즈 목록 로드get_request_list(page)— 요청 리스트 로드get_recom_list(page, page2)— 추천 리스트 로드get_pay_*_list(...)— 결제 내역 로드 (3개 함수)
3️⃣ 종이명함 CRUD 함수 (7개)
add_paper_card()— 종이명함 추가 (카메라 호출)create_paper()— 직접 입력 모달 열기edit_papersender()— AI 발신자 설정 모달 열기save_paper()— 종이명함 저장 (POST)save_aipaper_sender()— AI 발신자 설정 저장delete_paper(id)— 종이명함 삭제togglePaperImg()— 명함 이미지 보기/접기 토글
4️⃣ 검색·정렬·필터 함수 (6개)
paper_submit()— 검색어로 종이명함 검색paper_range(range, label)— 정렬 기준 변경 (등록일순/이름순/회사명순)paper_chk_count()— 선택된 명함 개수 표시paper_del()— 선택된 명함 일괄 삭제groupCheckClick_paper(obj)— 전체 선택/해제 토글enterkey(v1)— 엔터키 입력 감지
5️⃣ 결제·포인트 함수 (8개)
settlement(val, frm, auto_up)— 통합 결제 처리기 (카드/계좌이체/자동결제)card_settle(cur_win)— 카드 결제 페이지로 이동cashtoseed_chung(cur_win)— 캐시→씨드 포인트 전환point_pay_ok()— 포인트 결제 실행show_contents()— 결제/이용내역 모달 표시start_making()— IAM 자동 생성 시작 (크롤링)startAISMS(...)— AI SMS 발송 시작
6️⃣ 네비게이션 함수 (5개)
iam_mystory(url)— 페이지 이동 (내명함/추천피드 등)goIamHome()— 앱 홈으로 이동go_cart()— 장바구니로 이동refresh_page()— 페이지 새로고침go_mall_page(type, url)— 몰 페이지로 이동
7️⃣ SNS·공유 함수 (4개)
showSNSModal(cur_win, preview)— SNS 공유 모달 표시showSNSModal_byContents(...)— 콘텐츠별 공유 모달make_qr()— QR 코드 생성copy_recommend_link()— 추천 링크 복사
8️⃣ 유틸리티 함수 (10+)
save_load(mem_id, cont_id, event_kind)— 노출/클릭 이벤트 기록recvPhoneStatus(status)/recvPhonePos(lat, lng)— 위치 정보 수신addslashes(string)— 문자열 이스케이프setCookie1(name, value, seconds, path)— 쿠키 설정getCookie(name)— 쿠키 읽기iam_count(str)— 사용 통계 기록showIframeModal(url)— iframe 팝업openNoticeModal()/showIntro()— 공지/소개 모달
🧮 핵심 알고리즘 요약
알고리즘 #1: 디바이스 감지 (checkMobile)
User-Agent 문자열을 소문자로 변환한 후, 모바일 키워드가 포함되어 있는지 확인합니다:
입력: navigator.userAgent (브라우저 정보 문자열)
처리:
1. userAgent를 소문자로 변환
2. mobileKeywords = ['iphone','ipod','ipad','android','windows phone','blackberry','nokia','opera mini','mobile']
3. mobileKeywords 배열을 순회하면서 userAgent에 포함되어 있는지 확인
4. 하나라도 포함되어 있으면 → true (모바일)
5. 없으면 → false (데스크탑)
출력: boolean
알고리즘 #2: 이미지 크기 조정 (resize)
로고 이미지가 주어진 최대 크기를 넘지 않도록 비율을 유지하며 축소합니다:
입력: img (이미지 객체), maxW (최대 너비), maxH (최대 높이)
처리:
1. 현재 이미지 너비(width)와 높이(height)를 가져옴
2. IF width > maxW:
ratio = maxW / width
너비를 maxW로, 높이를 height * ratio로 설정
3. 조정된 너비/높이를 다시 읽음
4. IF height > maxH:
ratio = maxH / height
높이를 maxH로, 너비를 width * ratio로 설정
출력: 없음 (DOM 직접 수정)
알고리즘 #3: 쿠키 읽기 (getCookie)
입력: name (찾을 쿠키 이름)
처리:
1. document.cookie를 ';' 기준으로 분리해서 배열 생성
2. 각 항목을 trim()으로 공백 제거
3. 항목이 name + '=' 으로 시작하는지 확인
4. 시작하면 '=' 이후 문자열을 반환
5. 끝까지 찾지 못하면 null 반환
출력: string | null
알고리즘 #4: AJAX 무한 스크롤 (displaySample)
입력: lim (한 번에 가져올 개수), off (시작 위치)
처리:
1. 쿠키에서 'contents_mode' 값을 읽음
2. GET 요청: [내부API]/[콘텐츠조회]
파라미터: limit=lim, offset=off, search_key="", sample_type="paper_card"
3. 응답 HTML을 .sample_main에 추가(append)
4. 응답이 10자 이하면 → window.busy = true (더 이상 데이터 없음)
응답이 10자 초과면 → window.busy = false
출력: 없음 (DOM 직접 수정)
🎒 초등학생도 따라 하는 종이명함 등록 가이드
-
1스마트폰을 켜고 인터넷 앱을 열어요스마트폰 화면에서 크롬(Chrome)이나 삼성 인터넷 같은 인터넷 앱 아이콘을 찾아 눌러요. 컴퓨터로는 명함 사진을 찍을 수 없으니 꼭 스마트폰을 사용해야 해요!
-
2IAM 페이지에 접속해요주소창에
[서비스도메인]이라고 입력하고 엔터를 눌러요. 로그인이 안 되어 있다면 로그인 화면이 나올 거예요. 아이디와 비밀번호를 입력해요. -
3화면 아래쪽에서 '명함관리'를 눌러요화면 맨 아래에 4개의 버튼이 있어요: 앱홈, 내명함, 추천, 명함관리.
그중에서 명함관리 버튼을 눌러요. 그러면 종이명함 관리 화면이 나와요. -
4새 명함 추가 버튼(+)을 눌러요화면 오른쪽 위에 + 버튼이 보일 거예요. 그걸 누르면 스마트폰 카메라가 켜져요! 만약 + 버튼이 안 보이면, 대신 '직접 입력하기' 기능으로 이름과 전화번호를 직접 쓸 수도 있어요.
-
5명함을 찍어요 (카메라로 촬영하기)카메라가 켜지면, 종이명함을 평평한 곳에 놓고 초점이 잘 맞도록 찍어요.
글자가 잘 보이게, 빛이 반사되지 않게 찍는 게 중요해요!
사진을 찍으면 AI가 자동으로 이름, 전화번호, 회사 이름을 읽어서 채워줘요. -
6AI가 읽은 정보를 확인해요AI가 명함 사진에서 글자를 읽어서 이름, 직책, 회사명, 전화번호 등을 자동으로 채워줘요.
혹시 AI가 잘못 읽은 부분이 있으면 직접 고쳐서 입력할 수 있어요.
상단의 '명함이미지보기'를 누르면 찍은 사진을 다시 볼 수 있어요. -
7저장 버튼을 눌러요모든 정보가 맞는지 확인한 후, 아래쪽에 있는 저장 버튼을 눌러요.
'내 명함등록' 체크박스를 선택하면 내 명함으로도 등록돼요.
저장이 완료되면 "저장되었습니다"라는 메시지가 나와요! -
8등록된 명함을 관리해요저장된 명함은 리스트에 나타나요. 검색창에 이름을 입력하면 원하는 명함을 빨리 찾을 수 있어요.
'등록일순', '이름순', '회사명순' 중에서 정렬 방식을 바꿀 수도 있어요.
필요 없는 명함은 체크박스로 선택해서 삭제할 수 있어요.
📜 전체 소스코드 주석 해설
페이지의 전체 인라인 JavaScript 코드를 한 줄 한 줄 분석했습니다. 각 함수가 어떤 일을 하는지, 왜 이렇게 작성했는지 설명합니다.
📖 총 17페이지에 걸쳐 명함 프로필의 모든 것을 담았습니다.
왼쪽 사이드바 메뉴에서 원하는 주제를 클릭하면 상세 내용을 볼 수 있어요!