Communitygithub.com

erberkk/social-publishing

앱의 마케팅 콘텐츠를 Instagram(릴스, 캐러셀, 스토리), Threads, X, TikTok에 공식 API를 통해 예약 게시할 때 사용합니다. Docker에서 Postiz를 자체 호스팅하고 Cloudflare Tunnel로 보호하며, Meta 앱(비즈니스 포트폴리오, Facebook 페이지와 연동된 Instagram 전문 계정, Threads 테스터 초대), X 개발자 종량제 크레딧 및 지출 한도, TikTok 및 YouTube 감사 제한, 개인 및 브랜드 계정이 혼재된 브라우저에서의 안전한 OAuth 계정 선택, 리소스 제한, 실제 출시 이벤트에 맞춘 게시 일정 수립 등을 다룹니다.

social-publishing란 무엇인가요?

이 스킬은 Postiz(오픈 소스, 자체 호스팅)를 사용하여 여러 소셜 미디어 플랫폼(Instagram, Threads, X, TikTok, YouTube)에 마케팅 콘텐츠를 예약 게시하는 방법을 상세히 설명합니다. 주요 목표는 개인 계정과 브랜드 계정을 안전하게 분리하고 각 플랫폼의 공식 API를 활용하여 게시하는 것입니다. Cloudflare Tunnel을 통해 로컬에서 실행되는 Postiz 서비스를 외부에 안전하게 노출시키고, 각 플랫폼별로 필요한 사전 준비 사항(예: Meta 앱 생성 시 비즈니스 포트폴리오 필수, X API 유료 크레딧, TikTok 감사 제한)과 구체적인 설정 절차를 단계별로 안내합니다. 또한, 실제 출시 이벤트에 맞춰 동적으로 조정되는 콘텐츠 캘린더 작성법과 자주 발생하는 실수(예: 개인 Instagram 계정 연결, 오래된 Instagram 로그인 방식 사용)를 방지하는 팁을 제공합니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/erberkk/mobile-app-launch-skills/tree/HEAD/skills/social-publishing

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

소셜 게시(Social publishing)

목적

출시 콘텐츠를 한 곳에서 예약하여 각 플랫폼의 공식 API를 통해 게시하고, 개인 계정을 브랜드에 잃거나 브랜드를 개인 계정에 잃지 않습니다. 여기서 사용하는 도구는 Postiz(오픈 소스, 자체 호스팅)이며, 플랫폼 단계는 다른 스케줄러에도 동일하게 적용됩니다.

사전 준비 사항

  • 브랜드 계정이 이미 생성되어 있어야 함: Instagram 전문(professional) 계정, Threads 프로필(Instagram에서 파생), X 계정, 선택적으로 TikTok.
  • Cloudflare에 등록된 도메인(터널 호스트명용), Docker Desktop, 게시 시간에 켜져 있는 머신(또는 소형 VPS).
  • 브라우저에서 콘솔을 사용하는 경우 console-automation 설정.
  • 콘텐츠 캘린더(아래 '캘린더' 참조).

플랫폼 현실(시작하기 전에 다시 확인하세요. 변경될 수 있음)

플랫폼공식 경로차단 요소
InstagramMeta 앱 + Facebook 로그인, Facebook 페이지에 연결된 IG 전문 계정새로운 Meta 앱은 '통합 로그인' Instagram 설정을 사용하며, 비즈니스 포트폴리오가 필요합니다. 이전 Instagram-로그인 전용 설정은 '새로운 앱에서는 사용할 수 없습니다'. 스토리는 일반 미디어로만 게시 가능: API를 통한 설문조사, 링크, 카운트다운 스티커는 불가능.
ThreadsThreads 사용 사례가 포함된 Meta 앱앱 검토(App Review) 전까지 Threads 테스터 역할이 있는 계정만 연결 가능. 테스터는 Threads › 설정 › 계정 › 웹사이트 권한 › 초대에서 수락합니다.
X유료 API 액세스가 포함된 개발자 계정(현재 X API 가격 확인)결제 수단 필요, 지출 한도 설정 필요.
TikTok콘텐츠 게시 API(Content Posting API)감사(audit)를 통과하지 않은 앱은 비공개(private) 로만 게시 가능(감사에는 시간이 걸림). 새 계정은 전화 인증이 필요하며, 하나의 번호는 하나의 계정에만 등록 가능.
YouTube데이터 API 업로드인증되지 않은 API 프로젝트는 규정 준수 감사(compliance audit) 전까지 비공개로 업로드됩니다.

차단 요소를 고려하여 계획을 세우세요: 감사를 일찍 시작하고, 감사가 통과될 때까지 TikTok/YouTube는 네이티브(TikTok Studio, YouTube Studio 스케줄러)로 게시하거나 해당 플랫폼을 포기하세요.

절차

1. Postiz 자체 호스팅(Docker)

  1. 공식 postiz-docker-compose 파일로 시작합니다. up 전에:
    • 필요 없는 서비스는 제거하고, 머신에서 이미 사용 중인 포트를 바인딩하는 서비스는 제거합니다(업스트림 파일은 Temporal UI를 127.0.0.1:8080에 바인딩함).
    • Elasticsearch 제거: Temporal ENABLE_ES=false 및 SKIP_ADD_CUSTOM_SEARCH_ATTRIBUTES=true로 설정(SQL 가시성 사용). Postiz는 키워드 속성 두 개만 등록합니다. Temporal이 ES와 함께 처음 시작된 경우 데이터베이스에 기본 텍스트 속성이 남아 있어 Postiz가 "cannot have more than 3 search attribute of type Text" 오류와 함께 실패합니다. 예약 전에 Temporal 데이터베이스 볼륨을 재생성하세요.
    • Postiz를 127.0.0.1에만 바인딩하고, MAIN_URL, FRONTEND_URL, NEXT_PUBLIC_BACKEND_URL은 공개 HTTPS 호스트명으로 설정합니다.
    • 비밀값(JWT_SECRET, 터널 토큰, 앱 키)은 git에서 무시되는 .env 파일에 저장하고, 컴포즈 파일에서는 ${VAR}로 참조합니다.
    • 서비스별로 mem_limit/cpus를 추가합니다. Postiz는 프론트엔드, 백엔드, 오케스트레이터를 하나의 컨테이너에서 실행하며, 약 1.5GB를 사용하는 것을 관찰했습니다. 따라서 2GB 제한으로 한도 초과를 방지합니다. Windows에서는 %USERPROFILE%\.wslconfig에서 WSL VM도 제한합니다(memory=4GB, processors=4, autoMemoryReclaim=gradual). 그런 다음 wsl --shutdown하고 Docker Desktop을 다시 시작합니다.
  2. 브라우저에서 페이지가 하이드레이션(hydrated)된 후에 첫 번째 계정을 생성합니다(하이드레이션되지 않은 양식은 GET으로 제출되어 비밀번호가 URL에 노출됨). 그런 다음 DISABLE_REGISTRATION=true를 설정하고 재시작합니다.
  3. restart: always를 유지하고 "시작할 때 Docker Desktop 시작"을 활성화합니다. 머신이 스케줄러인 경우 절전 모드를 비활성화합니다.

2. 공개 호스트명(Cloudflare Tunnel)

  • 원격 관리형 터널을 생성합니다(API: config_src: cloudflare와 함께 POST /accounts/{id}/cfd_tunnel, 인그레스 규칙과 함께 PUT .../configurations, 프록시된 CNAME을 <tunnel-id>.cfargotunnel.com으로, GET .../token).
  • 동일한 컴포즈 네트워크에서 cloudflared를 서비스로 실행하고, 인그레스를 localhost가 아닌 http://postiz:5000으로 지정합니다.
  • 승인 필요: 터널은 로컬 서비스를 인터넷에 노출시키므로 생성 전에 승인을 받아야 합니다. 선택적으로 Cloudflare Access를 앞에 추가할 수 있습니다(계정에 Zero Trust가 활성화되어 있어야 함. Meta의 미디어 가져오기를 위해 /uploads는 접근 가능하게 유지).

3. Meta(Instagram + Threads)

  1. 게시용으로 별도의 Meta 앱을 생성합니다(이미 앱 내 기능(예: Instagram 스토리 공유)을 지원하는 앱에 사용 사례를 추가하지 마세요). 사용 사례: "Instagram에서 메시징 및 콘텐츠 관리" 및 "Threads API 액세스".
  2. Instagram:
    • 사용 사례에서 요청할 때 비즈니스 포트폴리오를 생성합니다(무료, 이름, 소유자 이름, 비즈니스 이메일). 인증은 다른 사람의 데이터와 앱 검토(App Review)에만 필요합니다.
    • 브랜드용 Facebook 페이지를 생성하고(Meta 광고에도 필요함) Instagram 전문 계정을 연결합니다: 페이지 설정 › 연결된 계정 › Instagram › 연결. OAuth 팝업은 브라우저가 보유한 Instagram 계정으로 로그인합니다. "다음으로 로그인..." 이름을 읽고, 개인 계정이면 먼저 계정을 전환하세요(개인 계정을 연결하면 전문 계정으로 전환됨).
    • Instagram 사용 사례에서 스케줄러가 요청하는 정확한 범위를 추가합니다(Postiz: instagram_basic, pages_show_list, pages_read_engagement, business_management, instagram_content_publish, instagram_manage_comments, instagram_manage_insights). Facebook for Business 리디렉션 URI를 스케줄러의 콜백으로 설정합니다(Postiz: /integrations/social/instagram).
    • 앱 ID + 시크릿(앱 설정 › 기본, 시크릿을 표시하려면 Facebook 비밀번호 입력) → FACEBOOK_APP_ID/SECRET.
  3. Threads: threads_basic, threads_content_publish, threads_manage_replies, threads_manage_insights를 추가하고, 리디렉트(/integrations/social/threads)와 설치 해제/삭제 콜백 URL을 설정합니다. 별도의 Threads 앱 ID/시크릿을 가져오고, 브랜드 프로필을 Threads 테스터로 추가한 후 휴대폰에서 초대를 수락합니다.
  4. Threads 동의 URL이 동의 화면 대신 Threads 홈 페이지로 이동하는 경우, 브라우저 세션이 threads.com에 있는 반면 스케줄러는 threads.net을 사용합니다. 동일한 URL을 threads.com에서 열어보세요.
  5. 브라우저가 현재 페이지 역할을 하고 있는 경우(페이지를 편집한 후), Facebook 동의는 먼저 "(으)로 전환해야 합니다"를 표시합니다. 페이지가 아닌 사람으로 계속 진행하세요.
  6. Facebook 동의 중에 Meta는 기본적으로 "모든 현재 및 미래 페이지/비즈니스/Instagram 계정"을 선택합니다. 다른 브랜드를 관리하는 계정의 경우 "현재만"을 선택하고 브랜드의 자산을 선택하세요.

4. X

  1. 개발자 콘솔 온보딩: 계정 이름, 정확한 사용 사례 설명(자체 계정만, 데이터 재판매 없음, 자동 좋아요/팔로우/DM 없음), 이용약관 동의.
  2. 가장 작은 크레딧 팩을 구매합니다. 자동 재충전을 끄고 청구 기간 한도를 설정합니다. 대시보드 총액은 크레딧 페이지와 차이가 있을 수 있습니다.
  3. 앱 › 사용자 인증 설정: 읽기 및 쓰기, "웹 앱, 자동화된 앱 또는 봇", 콜백 = 스케줄러 콜백(Postiz: /integrations/social/x), 웹사이트, 이용약관 및 개인정보 보호 URL. 저장하면 OAuth 2.0 클라이언트 시크릿이 한 번 표시됩니다.
  4. Postiz는 OAuth 1.0a를 사용합니다. 소비자 키(Consumer Key) 를 재생성하고 키 + "소비자 키 시크릿(Consumer Key Secret)"(정확히 해당 레이블)을 한 번 복사합니다 → X_API_KEY/X_API_SECRET.
  5. 권한 부여: "이 앱을 신뢰합니다"를 체크하고, 화면에 브랜드 핸들이 표시되는지 확인한 후 Authorize를 클릭합니다.

5. TikTok(선택 사항)

계정:

  • 새 계정은 전화 인증이 필요하며, 하나의 번호는 하나의 계정에만 등록할 수 있습니다. 웹 가입은 "앱에서 계속"으로 끝날 수 있습니다. 옵션: 브랜드 계정용 두 번째 번호를 사용하거나 기존 개인 계정을 전환합니다(새 사용자 이름, 표시 이름, 프로필 사진, 약력, 기존 개인 동영상은 보관/비공개 처리).
  • 일부 지역에서는 "비즈니스 계정으로 전환" 원클릭 옵션이 사라졌습니다. 메뉴에는 "인증된 비즈니스 계정 되기"가 있는데, 회사 서류를 요구합니다. 개인 계정으로도 충분합니다: TikTok Studio 스케줄링, 분석, Spark Ads, 콘텐츠 게시 API 모두 개인 계정에서 작동합니다. 비즈니스 음악 라이브러리가 주된 손실입니다.
  • 사용자 이름은 30일에 한 번, 표시 이름은 7일에 한 번 변경할 수 있습니다. 웹 프로필(이름, 약력, 사진, 통계)은 앱보다 하루 이상 지연될 수 있으므로 앱을 신뢰하세요.
  • 계정 지역은 가입 시 SIM/IP를 기준으로 설정되며 설정에서 변경할 수 없었습니다.

개발자 앱(스케줄러용):

  • developers.tiktok.com 가입은 "엔터프라이즈 개발자"(이메일 + 코드 + 비밀번호)만 표시되지만, 앱을 생성할 때 개인(Individual) 소유권을 선택할 수 있으므로 시작하는 데 회사가 필요하지 않습니다.
  • 앱을 생성한 다음 샌드박스를 생성합니다: 기본 정보(아이콘 1024², 카테고리, 설명 120자 이하, 이용약관/개인정보 보호 URL, 웹 플랫폼 URL), 제품 로그인 키트(Login Kit)(웹 리디렉션 URI = 스케줄러 콜백, Postiz /integrations/social/tiktok) 및 콘텐츠 게시 API(Content Posting API)(Direct Post 켜기), 그리고 스케줄러가 요청하는 모든 범위. Postiz는 user.info.basic, user.info.profile, user.info.stats, video.list, video.upload, video.publish를 요청합니다. 하나라도 누락되면 동의 페이지에 "문제가 발생했습니다... 다음을 수정하세요: 범위(scope)"가 표시됩니다. 모든 편집 후에 "변경 사항 적용(Apply changes)"을 클릭하세요.
  • 브랜드 계정을 샌드박스 대상 사용자(Target user) 로 추가합니다(로그인 팝업에서 휴대폰 앱의 QR 스캔을 허용함). 스케줄러에서 샌드박스 클라이언트 키/시크릿을 사용합니다.
  • 파일로 푸시(Push-by-file)는 도메인 인증이 필요 없지만, URL로 가져오기(Pull-by-URL)는 필요합니다.
  • 감사 전: UPLOAD 모드는 동영상을 계정의 TikTok 받은 편지함에 초안으로 보냅니다(24시간 이내에 휴대폰에서 게시, 최대 5개 보류). DIRECT_POST는 작동하지만 비공개로만 게시됩니다. 공개 직접 게시를 위해 데모 동영상과 함께 프로덕션 앱 검토를 제출하세요.
  • 동의 단계에서 이메일 코드로 "본인 확인"을 요청할 수 있습니다. 하루에 많은 계정 변경(이메일, 이름, 약력, 새 로그인)을 수행한 후 TikTok은 이러한 코드를 속도 제한합니다("최대 시도 횟수 도달"). 강제로 시도하지 말고 중단하고 다음 날 다시 시도하세요.

6. 확인

  • 스케줄러 채널 목록에 각 브랜드 계정(이름/핸들)이 표시되고, 비활성화된 계정이 없어야 합니다.
  • 캘린더가 시작되기 전에 플랫폼당 하나의 비공개/위험 부담이 적은 테스트 또는 초안을 게시하세요.
  • 하루 후 리소스 사용량: docker stats --no-stream.

캘린더

  • 게시 캘린더를 고정된 날짜가 아닌 실제 출시 이벤트에 맞추세요: 출시 전(다운로드 클릭 유도 문구 없음, 가격 없음), 각 스토어 출시, 그리고 둘 다 라이브 상태. 스토어 리뷰 날짜는 변경됩니다. 변경 시 캘린더를 다시 조정하세요.
  • 게시물의 모든 주장을 출시된 빌드와 비교하여 확인하고, 모든 클릭 유도 문구가 각 스토어에서 실제로 라이브 상태인지 확인하세요.
  • 설문조사, 링크 또는 카운트다운이 포함된 스토리는 API를 통해 게시할 수 없습니다. 앱에서 직접 게시하세요.

사람의 승인이 필요한 결정 지점

브랜드 계정, 비즈니스 포트폴리오, Facebook 페이지 생성, 터널을 통한 로컬 서비스 노출, API 크레딧 구매 및 지출 한도, 절대 연결하면 안 되는 개인 계정, 개인 계정 전환, Docker 볼륨 또는 데이터 삭제.

일반적인 실수

  • OAuth 팝업이 브라우저 세션을 재사용하여 개인 Instagram 계정을 연결하는 경우.
  • 새 Meta 앱에 이전 Instagram-로그인 설정이 존재한다고 가정하는 경우.
  • 모바일 앱 내부에 있는 Meta 앱에 게시 사용 사례를 추가하는 경우.
  • Temporal SQL 가시성으로 충분할 때 Elasticsearch를 스택에 남겨두는 경우.
  • 업스트림 컴포즈 파일이 다른 로컬 서비스에서 이미 사용 중인 포트를 차지하는 경우.
  • X 키를 잘못된 레이블("소비자 키 시크릿(Consumer Key Secret)", 대화 상자 제목 아님)에서 저장한 경우.
  • 앱이 1일에 두 스토어 모두에 라이브 상태인 것처럼 캘린더를 작성하는 경우.
  • 모든 TikTok 계정 변경과 개발자 연결을 같은 날에 수행하여 인증 코드 속도 제한에 걸리는 경우.

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

erberkk/privacy-and-declarations

Use when filling in or auditing App Store privacy and compliance answers and Google Play App content declarations - Apple App Privacy labels, Play Data safety (CSV import), Health apps declaration and Health Connect permissions, advertising ID, PrivacyInfo.xcprivacy and required-reason APIs, export compliance (ITSAppUsesNonExemptEncryption), age rating, account deletion (in-app, web URL, re-authentication), consent and disclosure for AI features, and rules for health data. Derives every answer from a code and SDK scan so the forms, the privacy policy and the in-app text say the same thing.

erberkk/review-readiness

Use before submitting an app version or a first subscription for App Store or Google Play review, or after receiving a rejection. Runs a go/no-go checklist and writes a report - demo account that signs in with a password (no email one-time code), filled with data and premium unlocked; review notes; in-app purchases visible and purchasable (guideline 2.1(b)); iPad compatibility mode for iPhone-only apps; no placeholders or "coming soon"; metadata matching the app; live privacy URLs; crash-free cold start - and gives a playbook for replying in Resolution Center and deciding when to appeal.

erberkk/store-screenshots

Use when producing or updating App Store and Google Play screenshots and the Play feature graphic - planning a connected "panorama" story across frames, capturing real in-app screens with the app's own test/screenshot harness at each device's logical size and pixel ratio, covering the full device matrix (iPhone 6.9", the required medium Dynamic Island slot, iPhone Duo outer and inner displays, iPad 13" if the app runs on iPad, Play phone, 7" and 10" tablets, 1024x500 feature graphic), checking for alpha channels and wrong sizes, and uploading in order via the App Store Connect and Google Play APIs.

erberkk/web-presence-and-seo

Use when building, checking or deploying the website that a mobile app needs for its store listings and launch - privacy policy, terms, support and web account-deletion pages that work signed-out; hosting apple-app-site-association and assetlinks.json; invite/referral pages (/i/<code>) that open the app or fall back to the store with the Play install referrer; a landing page with store badges and honest per-country prices filled at the edge; Open Graph images; technical SEO (hreflang, canonical, sitemap, robots.txt, JSON-LD); Search Console, Bing Webmaster and IndexNow; AI crawler policy and llms.txt; and a Cloudflare Worker deploy with a production approval gate. Includes a site checker and an IndexNow ping script.

관련 스킬