Thursday, January 30, 2020

FCM 푸시 알림, '한글 토픽'으로 사용자 경험을 혁신하는 비결

오늘날 모바일 애플리케이션 환경에서 사용자에게 시의적절한 정보를 전달하는 푸시 알림은 필수적인 기능으로 자리 잡았습니다. 신규 콘텐츠 업데이트, 중요한 공지사항, 개인화된 메시지 등 푸시 알림은 사용자의 재방문을 유도하고 앱의 가치를 높이는 핵심적인 소통 채널입니다. 구글의 Firebase Cloud Messaging(FCM)은 이러한 푸시 알림을 안정적이고 효율적으로 구현할 수 있도록 돕는 강력한 크로스플랫폼 메시징 솔루션입니다.

FCM이 제공하는 여러 기능 중 '토픽 메시징(Topic Messaging)'은 특정 주제에 관심 있는 다수의 사용자 그룹에게 한 번에 메시지를 보낼 수 있는 매우 유용한 기능입니다. 예를 들어, '스포츠' 뉴스에 관심 있는 모든 사용자에게 새로운 경기 소식을 보내거나, '할인 이벤트'에 동의한 사용자들에게 프로모션 정보를 전송하는 시나리오를 손쉽게 구현할 수 있습니다.

하지만 많은 국내 개발자들이 FCM 토픽 기능을 활용하면서 한 가지 예상치 못한 장벽에 부딪히게 됩니다. 바로 토픽 이름에 한글을 직접 사용할 수 없다는 점입니다. FCM의 공식 문서에 따르면 토픽 이름은 [a-zA-Z0-9-_.~%] 정규 표현식에 맞는 문자열만 허용합니다. 이 규칙 때문에 '스포츠'나 '오늘의 핫딜'과 같이 직관적인 한글 단어를 토픽으로 사용하려는 시도는 실패로 돌아가기 일쑤입니다. 이는 사용자 그룹을 관리하고 코드를 작성하는 개발자에게 상당한 불편함을 초래합니다. 관리의 편의성을 위해 'sports'나 'hotdeal_today'와 같은 영어 또는 로마자 표기를 사용해야만 했을까요?

결론부터 말하자면, 그렇지 않습니다. 이 제약은 간단하고 영리한 방법으로 우회할 수 있습니다. 이 글에서는 FCM의 문자열 제약이라는 기술적 한계를 넘어, 어떻게 한글 토픽을 자유자재로 사용하고 이를 통해 사용자 경험을 한 단계 끌어올릴 수 있는지, 그 원리와 구체적인 구현 방법, 그리고 실제 서비스에 적용할 수 있는 다양한 활용 사례까지 심도 있게 다뤄보겠습니다.

1. FCM과 토픽 메시징의 기본 원리 다시보기

본격적인 해결책을 논하기에 앞서, 왜 이 문제가 발생하는지 근본적으로 이해하기 위해 FCM 토픽 메시징의 작동 방식을 간단히 짚고 넘어갈 필요가 있습니다.

FCM 토픽이란 무엇인가? (Publish/Subscribe 모델)

FCM 토픽 메시징은 '게시/구독(Publish/Subscribe, 이하 Pub/Sub)' 모델을 기반으로 동작합니다. 이 모델은 메시지를 보내는 '게시자(Publisher)'와 메시지를 받는 '구독자(Subscriber)' 사이의 관계를 느슨하게 연결(loosely coupled)하는 강력한 아키텍처 패턴입니다.

  • 토픽(Topic): 메시지를 분류하는 가상의 채널 또는 이름입니다. '날씨', '정치', '연예' 등이 토픽이 될 수 있습니다.
  • 게시자(Publisher): 보통 앱 서버를 의미합니다. 특정 토픽에 메시지를 보냅니다. 게시자는 어떤 기기들이 이 토픽을 구독하고 있는지 알 필요가 없습니다. 그저 '날씨' 토픽에 "오늘 오후 소나기 예보"라는 메시지를 던져주기만 하면 됩니다.
  • 구독자(Subscriber): 사용자의 앱(클라이언트)을 의미합니다. 사용자가 앱 내에서 특정 주제에 대한 알림을 받기로 선택하면, 앱은 해당 토픽을 '구독(subscribe)'합니다. 예를 들어, 사용자가 날씨 알림을 켜면 클라이언트 앱은 FCM에 '날씨' 토픽을 구독하겠다고 요청합니다.

이러한 구조 덕분에 서버는 수백만 명의 사용자 개개인의 토큰(FCM Token)을 일일이 관리할 필요 없이, 단 한 번의 API 호출로 '날씨' 토픽을 구독한 모든 기기에 메시지를 전송할 수 있습니다. 이는 서버의 부하를 줄이고 메시징 로직을 매우 단순하게 만들어 줍니다.

FCM 토픽 메시징 동작 원리 도식도

FCM 토픽 메시징의 Pub/Sub 모델: 서버는 토픽에 메시지를 게시하고, FCM은 해당 토픽을 구독한 모든 클라이언트 앱에 메시지를 전달합니다.

왜 FCM은 토픽 이름에 제약을 둘까?

그렇다면 왜 FCM은 이토록 편리한 토픽 기능의 이름에 [a-zA-Z0-9-_.~%]라는 까다로운 제약을 두었을까요? 몇 가지 기술적인 이유를 추론해 볼 수 있습니다.

  1. URL 및 시스템 호환성: 토픽 이름은 내부적으로 시스템의 식별자(Identifier)나 리소스 경로의 일부로 사용될 가능성이 높습니다. 다양한 운영체제와 파일 시스템, 네트워크 프로토콜에서 문제를 일으키지 않는 안전한 문자(URL-safe characters) 집합으로 제한하는 것은 시스템의 안정성과 예측 가능성을 높이는 일반적인 설계 방식입니다. 한글이나 특수문자, 공백 등은 특정 환경에서 예기치 않은 오류를 발생시킬 수 있습니다.
  2. 크로스플랫폼 일관성: FCM은 Android, iOS, Web 등 다양한 플랫폼을 지원합니다. 모든 플랫폼에서 동일하게 해석되고 처리될 수 있는 표준화된 문자 집합을 사용하는 것이 구현의 복잡성을 줄이고 일관성을 유지하는 데 유리합니다.
  3. 단순성과 성능: 단순한 문자열은 파싱(parsing)하고 인덱싱(indexing)하기에 더 효율적입니다. 수억, 수십억 개의 구독 관계를 관리해야 하는 FCM의 거대한 인프라에서 식별자를 단순하게 유지하는 것은 성능 최적화의 한 부분이 될 수 있습니다.

이러한 제약은 타당한 이유를 가지고 있지만, 개발자, 특히 비영어권 개발자에게는 분명한 한계로 다가옵니다. '부동산'이라는 키워드를 'budongsan'으로 변환하여 관리하는 것은 직관적이지 않으며, 시간이 지나면 어떤 키워드가 어떻게 매핑되었는지 추적하기 어려워지는 관리상의 문제를 낳습니다. 이제 이 문제를 해결할 열쇠를 살펴볼 시간입니다.

2. 마법의 열쇠, 'URI 인코딩'으로 한글 토픽 잠금 해제

문제의 해결책은 의외로 간단하며, 웹 개발자라면 매우 친숙할 'URI 인코딩(URI Encoding, 또는 퍼센트 인코딩)' 기술에 있습니다.

URI 인코딩이란?

URI(Uniform Resource Identifier)는 인터넷상의 리소스를 고유하게 식별하기 위한 주소 체계입니다. 우리가 흔히 사용하는 URL이 URI의 한 종류입니다. URI에는 알파벳, 숫자, 그리고 일부 특수문자(-, _, ., ~)만 직접 사용할 수 있도록 약속되어 있습니다.

만약 한글, 공백, 또는 다른 특수문자를 URI에 포함시켜야 할 경우, 이 문자들을 직접 사용하는 대신 정해진 규칙에 따라 안전한 문자들의 조합으로 변환하는 과정이 필요한데, 이것이 바로 URI 인코딩입니다.

변환 규칙은 다음과 같습니다.

  1. 인코딩할 문자를 특정 문자 인코딩 방식(일반적으로 UTF-8)에 따라 1개 이상의 바이트(byte) 시퀀스로 변환합니다.
  2. 변환된 각 바이트를 % 기호 뒤에 두 자리 16진수(Hexadecimal) 값으로 표기합니다.

예를 들어, '테스트'라는 한글 문자열을 UTF-8 기반으로 URI 인코딩하면 다음과 같은 과정으로 변환됩니다.

  • '테' (U+D14C) → UTF-8 바이트: ED 85 8C → 인코딩된 문자열: %ED%85%8C
  • '스' (U+C2A4) → UTF-8 바이트: EC 8A A4 → 인코딩된 문자열: %EC%8A%A4
  • '트' (U+D2B8) → UTF-8 바이트: ED 8A B8 → 인코딩된 문자열: %ED%8A%B8

따라서 '테스트'라는 문자열은 최종적으로 '%ED%85%8C%EC%8A%A4%ED%8A%B8'라는 문자열로 변환됩니다.

FCM 토픽에 URI 인코딩 적용하기

여기서 중요한 포인트가 나옵니다. FCM 토픽이 허용하는 문자 패턴 [a-zA-Z0-9-_.~%]을 다시 한번 자세히 살펴보세요. 놀랍게도 이 패턴에는 퍼센트 기호(%)가 포함되어 있습니다. 이는 FCM이 애초에 URI 인코딩된 문자열을 토픽 이름으로 사용하는 것을 염두에 두고 설계되었음을 강력하게 시사합니다.

따라서 우리는 한글 토픽을 FCM에 전달하기 전에 간단히 URI 인코딩 처리만 해주면 됩니다. FCM 시스템은 이 인코딩된 문자열을 유효한 토픽 이름으로 인식하고 정상적으로 처리합니다.

원본 한글 토픽: 오늘의 뉴스
URI 인코딩된 토픽: %EC%98%A4%EB%8A%98%EC%9D%98%20%EB%89%B4%EC%8A%A4 (공백은 %20으로 인코딩됩니다)

클라이언트 앱은 '%EC%98%A4%EB%8A%98%EC%9D%98%20%EB%89%B4%EC%8A%A4'라는 이름의 토픽을 구독하고, 서버 역시 동일한 이름의 토픽으로 메시지를 보내면, '오늘의 뉴스' 알림을 받고 싶어하는 사용자에게 정확하게 푸시가 전달됩니다. 개발자는 데이터베이스나 관리자 페이지에서 '오늘의 뉴스'라는 직관적인 한글 이름을 그대로 관리하고, FCM과 통신하는 시점에만 인코딩/디코딩을 적용하면 됩니다.

3. 실전! 플랫폼별 한글 토픽 구독/발송 코드 구현

원리를 이해했으니 이제 실제 코드에 적용해 보겠습니다. 다행히 대부분의 최신 프로그래밍 언어와 플랫폼은 URI 인코딩/디코딩을 위한 표준 라이브러리나 함수를 기본적으로 제공하므로 구현은 매우 간단합니다.

클라이언트 측 구현 (토픽 구독)

클라이언트(사용자 앱)는 사용자의 요청에 따라 특정 한글 토픽을 구독해야 합니다.

Android (Kotlin)

Android에서는 java.net.URLEncoder를 사용하여 손쉽게 문자열을 인코딩할 수 있습니다.


import com.google.firebase.ktx.Firebase
import com.google.firebase.messaging.ktx.messaging
import java.net.URLEncoder
import java.nio.charset.StandardCharsets

// ...

fun subscribeToKoreanTopic(koreanTopic: String) {
    // 1. 한글 토픽을 UTF-8 기반으로 URI 인코딩합니다.
    val encodedTopic = URLEncoder.encode(koreanTopic, StandardCharsets.UTF_8.toString())

    // 2. 인코딩된 토픽으로 구독을 요청합니다.
    Firebase.messaging.subscribeToTopic(encodedTopic)
        .addOnCompleteListener { task ->
            var msg = "구독 성공: $koreanTopic (encoded: $encodedTopic)"
            if (!task.isSuccessful) {
                msg = "구독 실패: $koreanTopic"
            }
            Log.d("FCM_TOPIC", msg)
            // 사용자에게 UI 피드백 제공 (예: Toast 메시지)
        }
}

// 사용 예시
subscribeToKoreanTopic("오늘의 핫딜") // 내부적으로 "%EC%98%A4%EB%8A%98%EC%9D%98%20%ED%95%AB%EB%94%9C" 토픽을 구독

토픽 구독을 취소(unsubscribe)할 때도 마찬가지로 동일한 방식으로 인코딩된 토픽 이름을 사용해야 합니다.

iOS (Swift)

Swift에서는 StringaddingPercentEncoding(withAllowedCharacters:) 메서드를 사용하여 인코딩할 수 있습니다. .urlQueryAllowed는 일반적으로 사용되는 안전한 문자 집합입니다.


import FirebaseMessaging

// ...

func subscribeToKoreanTopic(koreanTopic: String) {
    // 1. 한글 토픽을 퍼센트 인코딩합니다.
    // .urlQueryAllowed는 공백 등 일부 문자를 인코딩하지 않으므로, 더 엄격한 문자 집합을 정의하거나
    // 필요에 따라 추가적인 처리를 할 수 있습니다. 일반적으로는 잘 동작합니다.
    guard let encodedTopic = koreanTopic.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {
        print("Error: Failed to encode topic string.")
        return
    }

    // 2. 인코딩된 토픽으로 구독을 요청합니다.
    Messaging.messaging().subscribe(toTopic: encodedTopic) { error in
        if let error = error {
            print("Error subscribing to topic: \(koreanTopic), error: \(error.localizedDescription)")
        } else {
            print("Successfully subscribed to topic: \(koreanTopic) (encoded: \(encodedTopic))")
        }
    }
}

// 사용 예시
subscribeToKoreanTopic("주간 웹툰 업데이트")

서버 측 구현 (토픽 메시지 발송)

서버에서는 발송하려는 한글 토픽 이름을 클라이언트와 동일한 방식으로 인코딩하여 FCM API를 호출해야 합니다.

Node.js (Firebase Admin SDK)

Node.js 환경에서는 내장된 encodeURIComponent() 함수를 사용하는 것이 가장 편리합니다.


const admin = require("firebase-admin");

// ... Firebase Admin SDK 초기화 코드 ...

async function sendToKoreanTopic(koreanTopic, messagePayload) {
  // 1. 한글 토픽을 URI 인코딩합니다.
  const encodedTopic = encodeURIComponent(koreanTopic);

  const message = {
    ...messagePayload, // { notification: { title: '...', body: '...' }, data: { ... } }
    topic: encodedTopic
  };

  try {
    // 2. 인코딩된 토픽으로 메시지를 발송합니다.
    const response = await admin.messaging().send(message);
    console.log(`Successfully sent message to topic: ${koreanTopic} (encoded: ${encodedTopic})`, response);
    return response;
  } catch (error) {
    console.error(`Error sending message to topic: ${koreanTopic}`, error);
    throw error;
  }
}

// 사용 예시
const payload = {
  notification: {
    title: "부동산 속보!",
    body: "서울 지역 아파트 실거래가 업데이트 알림"
  }
};
sendToKoreanTopic("부동산", payload); // 내부적으로 "부동산"을 "%EB%B6%80%EB%8F%99%EC%82%B0"으로 변환하여 발송

Python (Firebase Admin SDK)

Python에서는 urllib.parse.quote() 함수를 사용합니다.


import firebase_admin
from firebase_admin import credentials, messaging
from urllib.parse import quote

# ... Firebase Admin SDK 초기화 코드 ...

def send_to_korean_topic(korean_topic: str, message_payload: dict):
    # 1. 한글 토픽을 UTF-8 기반으로 URI 인코딩합니다.
    # safe='' 인자는 '/'를 포함한 모든 특수문자를 인코딩하도록 합니다.
    encoded_topic = quote(korean_topic.encode('utf-8'), safe='')

    message = messaging.Message(
        notification=messaging.Notification(
            title=message_payload.get('title'),
            body=message_payload.get('body'),
        ),
        topic=encoded_topic,
    )

    try:
        # 2. 인코딩된 토픽으로 메시지를 발송합니다.
        response = messaging.send(message)
        print(f"Successfully sent message to topic: {korean_topic} (encoded: {encoded_topic}), response: {response}")
        return response
    except Exception as e:
        print(f"Error sending message to topic: {korean_topic}, error: {e}")
        raise e

# 사용 예시
payload = {
    "title": "IT 기술 세미나 안내",
    "body": "6월 개발자 밋업 신청이 시작되었습니다."
}
send_to_korean_topic("IT 행사", payload) # 내부적으로 "%IT%20%ED%96%89%EC%82%AC"로 변환하여 발송

보시다시피, 어떤 플랫폼을 사용하든 핵심은 'FCM과 통신하기 직전에 한글 토픽을 URI 인코딩한다'는 단 하나의 규칙입니다. 이 규칙만 지키면 클라이언트와 서버는 완벽하게 동일한 토픽 채널을 바라보게 되어 한글 토픽 메시징이 원활하게 이루어집니다.

4. 상상력을 더하다: 한글 토픽 실전 활용 사례

한글 토픽을 사용할 수 있게 되었다는 것은 단순히 관리의 편의성을 넘어, 서비스의 기능을 더욱 풍부하고 직관적으로 만들 수 있는 새로운 가능성을 열어줍니다. 몇 가지 구체적인 활용 시나리오를 통해 그 잠재력을 살펴보겠습니다.

사례 1: 초개인화 '키워드 알림' 시스템 구축

가장 강력하고 대표적인 활용 사례입니다. 뉴스, 커뮤니티, 중고거래, 쇼핑몰 등 다양한 앱에서 사용자가 특정 키워드에 대한 새 글이나 상품이 등록되었을 때 알림을 받도록 설정하는 기능입니다.

  • 사용자 경험: 사용자가 앱 설정 화면에서 '알림 받고 싶은 키워드' 입력란에 '삼성전자 주가', '제주도 2인 항공권', '나이키 270 사이즈'와 같은 구체적인 문구를 직접 입력하고 저장합니다.
  • 기술 구현 흐름:
    1. 사용자가 '삼성전자 주가'를 입력하고 저장 버튼을 누릅니다.
    2. 클라이언트 앱은 '삼성전자 주가' 문자열을 URI 인코딩하여 (예: %EC%82%BC%EC%84%B1%EC%A0%84%EC%9E%90%20%EC%A3%BC%EA%B0%80) 해당 토픽을 구독합니다. 동시에 서버 DB에 이 키워드를 저장하여 관리합니다.
    3. 서버의 콘텐츠 수집 시스템(크롤러, 파서 등)이 '삼성전자 주가'와 관련된 새로운 뉴스를 발견합니다.
    4. 서버는 해당 키워드인 '삼성전자 주가'를 즉시 URI 인코딩하여 FCM 토픽 메시징 API를 호출합니다.
    5. FCM은 이 토픽을 구독한 모든 사용자에게 '삼성전자 주가 관련 새 소식!'이라는 푸시 알림을 발송합니다.
  • 장점: 개발자는 미리 정해진 카테고리(스포츠, 연예 등)에 사용자를 가두는 것이 아니라, 사용자의 능동적인 관심사를 기반으로 무한히 확장 가능한 개인화된 알림 채널을 제공할 수 있습니다. 이는 사용자의 서비스 충성도를 크게 높이는 요인이 됩니다.

사례 2: 지역 기반 하이퍼로컬(Hyperlocal) 서비스

당근마켓과 같은 지역 커뮤니티나 배달 앱에서 특정 동네, 아파트 단지, 지하철역 등을 기반으로 한 타겟팅 메시지를 보낼 때 매우 유용합니다.

  • 사용자 경험: 사용자가 자신의 '동네 인증'을 하면 앱은 자동으로 해당 동네 이름(예: '역삼동', '판교테크노밸리')을 토픽으로 구독합니다.
  • 기술 구현 흐름:
    1. 신규 사용자가 가입 후 주소 인증을 통해 '역삼동' 주민임이 확인됩니다.
    2. 클라이언트 앱은 '역삼동'을 URI 인코딩하여 토픽을 구독합니다.
    3. '역삼동'에 위치한 한 카페 사장님이 앱의 광고 시스템을 통해 "오늘 오후 2시~4시, 역삼동 주민 커피 50% 할인!" 이라는 이벤트를 등록합니다.
    4. 서버는 타겟 지역인 '역삼동'을 URI 인코딩하여 해당 토픽에 프로모션 메시지를 발송합니다.
  • 장점: 관리자는 'yeoksam-dong'과 같은 불분명한 식별자 대신 '역삼동'이라는 명확한 이름으로 타겟 그룹을 관리할 수 있습니다. 이는 운영 실수를 줄이고 마케팅 효율을 극대화합니다.

사례 3: 사용자 생성 콘텐츠(UGC) 태그 구독

블로그, 인스타그램, 브런치와 같은 콘텐츠 플랫폼에서 사용자가 특정 해시태그나 관심 작가를 팔로우(구독)하는 기능을 구현할 수 있습니다.

  • 사용자 경험: 사용자가 '#반려동물일상' 이라는 태그가 붙은 게시물을 보고, 해당 태그 옆의 '구독하기' 버튼을 누릅니다. 또는 '김작가'라는 필명의 작가 페이지에서 '새 글 알림받기'를 선택합니다.
  • 기술 구현 흐름:
    1. 사용자가 '#반려동물일상' 태그 구독을 요청합니다.
    2. 클라이언트 앱은 '#반려동물일상' 또는 작가 필명 '김작가'를 URI 인코딩하여 토픽을 구독합니다. (특수문자 #도 인코딩됩니다.)
    3. 다른 사용자가 '#반려동물일상' 태그를 포함한 새 글을 작성하거나, '김작가'가 새 글을 발행합니다.
    4. 서버는 해당 태그나 작가 이름을 즉시 토픽으로 사용하여 새 글 알림을 발송합니다.
  • 장점: 정적인 카테고리를 넘어, 사용자들이 동적으로 생성하는 관심의 흐름(태그)을 실시간 알림 시스템과 직접 연결할 수 있어 매우 유연하고 확장성 있는 서비스 아키텍처를 구축할 수 있습니다.

5. 반드시 알아야 할 주의사항과 고급 팁

한글 토픽을 사용하는 것은 매우 강력하지만, 실제 운영 환경에 적용하기 전에 몇 가지 주의해야 할 점이 있습니다.

1. 토픽 문자열 길이 제한

FCM 토픽 이름에는 길이 제한이 있습니다. 공식적으로 명시된 바는 없지만, 실제 테스트 결과에 따르면 인코딩된 후의 문자열 길이가 900자를 넘지 않아야 합니다.

한글 한 글자는 보통 UTF-8에서 3바이트를 차지하고, 각 바이트는 %XX 형태로 3개의 문자로 인코딩됩니다. 따라서 한글 한 글자는 인코딩 후 9개의 문자가 됩니다 (예: '한' → %ED%95%9C).

이를 계산해보면, 순수 한글로만 이루어진 토픽의 경우 약 100자 (900 / 9 = 100) 까지 사용 가능하다고 볼 수 있습니다. 일반적인 키워드나 문장으로는 충분히 긴 길이지만, 사용자가 임의로 매우 긴 문자열을 토픽으로 구독하려는 경우를 대비하여 클라이언트 단에서 입력 길이를 제한하는 방어 코드를 추가하는 것이 안전합니다.


// Android (Kotlin) 예시 - 길이 제한 추가
fun subscribeToKoreanTopic(koreanTopic: String) {
    if (koreanTopic.length > 100) { // 원본 한글 문자열 길이로 체크
        Log.w("FCM_TOPIC", "토픽 길이가 너무 깁니다: ${koreanTopic.length}자")
        // 사용자에게 길이 제한에 대한 피드백을 주고 구독을 막음
        return
    }
    // ... 이후 구독 로직은 동일
}

2. 인코딩/디코딩 로직의 일관성 유지

매우 중요합니다. 클라이언트(Android, iOS, Web)와 서버(Node.js, Python, Java 등)에서 사용하는 URI 인코딩 방식과 문자셋(Character Set)이 반드시 동일해야 합니다. 모든 플랫폼에서 UTF-8을 표준으로 사용하는 것이 가장 안전하고 일반적인 방법입니다.

만약 한쪽은 UTF-8로, 다른 한쪽은 EUC-KR로 인코딩한다면 완전히 다른 토픽 문자열이 생성되어 메시징이 실패하게 됩니다. 이는 디버깅하기 매우 어려운 '조용한 오류(silent error)'로 이어질 수 있으므로, 프로젝트 시작 단계에서 인코딩 표준을 명확히 정의하고 모든 팀원이 공유해야 합니다.

3. 동적 토픽 생성에 따른 관리 전략

사용자가 직접 토픽(키워드, 태그 등)을 생성하는 기능을 제공하면, 시간이 지남에 따라 수백만, 수천만 개의 고유한 토픽이 생성될 수 있습니다. FCM 자체는 토픽의 개수에 대한 명시적인 제한은 없다고 알려져 있지만, 앱 서버 입장에서 이 토픽들을 관리하는 것은 또 다른 문제입니다.

  • 토픽 정리(Cleanup): 아무도 구독하지 않는 토픽은 사실상 의미가 없습니다. 정기적으로 각 토픽의 구독자 수를 확인하고, 구독자가 0명인 토픽을 DB에서 삭제하는 등의 정리 로직을 구현하는 것을 고려해볼 수 있습니다. (참고: FCM은 특정 토픽의 구독자 목록을 직접 조회하는 API를 제공하지 않으므로, 앱 서버에서 각 사용자가 어떤 토픽을 구독하는지 별도로 추적/관리해야 합니다.)
  • 입력 값 검증(Input Sanitization): 사용자의 입력을 그대로 토픽으로 사용하는 만큼, 악의적인 사용자가 비정상적으로 길거나 의미 없는 문자열을 대량으로 생성하여 시스템에 부하를 주는 것을 방지하기 위한 최소한의 검증 로직(길이 제한, 금칙어 필터링 등)이 필요합니다.

결론: 제약을 넘어 창의적인 사용자 경험으로

FCM 토픽의 [a-zA-Z0-9-_.~%] 문자열 제약은 처음 마주했을 때 넘기 힘든 벽처럼 느껴질 수 있습니다. 많은 개발자들이 이로 인해 한글 토픽 사용을 포기하고 영어 약어나 숫자 조합으로 우회하는 불편함을 감수해왔습니다.

하지만 이 글에서 살펴보았듯이, 'URI 인코딩'이라는 표준 웹 기술을 활용하는 것만으로 이 제약은 아무런 문제가 되지 않습니다. 오히려 FCM이 퍼센트 기호(%)를 허용함으로써 이러한 확장성을 공식적으로 지원하고 있음을 알 수 있습니다.

이제 우리는 기술적 한계에 갇혀 'hotdeal_1225'와 같은 기계적인 토픽을 만드는 대신, '크리스마스 특별 할인'이라는 사람 친화적이고 직관적인 토픽을 자유롭게 설계하고 구현할 수 있습니다. 이는 단순히 개발자의 편의성을 높이는 것을 넘어, 사용자의 숨겨진 니즈를 정확히 파고드는 '키워드 알림', 우리 동네 소식을 전하는 '하이퍼로컬 메시징', 관심사를 따라 흐르는 '태그 구독' 등 과거에는 구현하기 까다로웠던 창의적인 기능들을 현실로 만들 수 있는 강력한 무기가 됩니다.

FCM의 숨겨진 잠재력을 100% 활용하여, 당신의 애플리케이션에 더욱 섬세하고 개인화된 소통의 다리를 놓아보시기 바랍니다. 작은 아이디어의 전환이 사용자에게는 커다란 가치와 경험의 차이를 만들어낼 것입니다.


1 comment:

  1. 하진짜 제 영웅이십니다 FCM 한글꺠짐때문에 얼마나 고생헀는지 모릅니다 ㅠㅠ 감사합니다

    ReplyDelete