diff --git a/.github/workflows/appstore-release.yml b/.github/workflows/appstore-release.yml new file mode 100644 index 00000000..41bd2750 --- /dev/null +++ b/.github/workflows/appstore-release.yml @@ -0,0 +1,127 @@ +name: App Store Release + +on: + push: + tags: + - "v*.*.*" + workflow_dispatch: + inputs: + version: + description: "출시 버전 (예: 1.0.0)" + required: true + type: string + release_notes: + description: "이번 버전 변경사항 (비워두면 metadata/ko/release_notes.txt 사용)" + required: false + type: string + +concurrency: + group: appstore-release + cancel-in-progress: false + +jobs: + # ────────────────────────────────────────────────────────── + # Validate (메타데이터·버전 사전 검증 — 빌드 전에 실패시킨다) + # ────────────────────────────────────────────────────────── + validate: + runs-on: ubuntu-latest + outputs: + version: ${{ steps.resolve.outputs.version }} + steps: + - uses: actions/checkout@v4 + + # 태그 실행이면 태그명(v1.0.0)에서, 수동 실행이면 입력값에서 버전을 확정한다 + - name: Resolve version + id: resolve + # 입력값은 셸에 직접 보간하지 않고 env 로 넘긴다 (스크립트 인젝션 방지) + env: + EVENT_NAME: ${{ github.event_name }} + INPUT_VERSION: ${{ inputs.version }} + run: | + if [ "$EVENT_NAME" = "push" ]; then + VERSION="${GITHUB_REF_NAME#v}" + else + VERSION="$INPUT_VERSION" + fi + + if ! echo "$VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$'; then + echo "::error::버전 형식이 올바르지 않습니다: $VERSION (예: 1.0.0)" + exit 1 + fi + + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + echo "🚀 배포 버전: $VERSION" + + - name: Setup Ruby & fastlane + uses: ruby/setup-ruby@v1 + with: + ruby-version: "3.3" + bundler-cache: true + + - name: Verify metadata + # 심사 담당자 연락처는 개인정보라 저장소에 두지 않고 Secrets 에서 주입한다 + env: + APP_REVIEW_FIRST_NAME: ${{ secrets.APP_REVIEW_FIRST_NAME }} + APP_REVIEW_LAST_NAME: ${{ secrets.APP_REVIEW_LAST_NAME }} + APP_REVIEW_PHONE_NUMBER: ${{ secrets.APP_REVIEW_PHONE_NUMBER }} + APP_REVIEW_EMAIL: ${{ secrets.APP_REVIEW_EMAIL }} + run: bundle exec fastlane verify_metadata + + # ────────────────────────────────────────────────────────── + # Release (TestFlight 검증 빌드 선택 → 메타데이터 업로드 → 심사 제출) + # ────────────────────────────────────────────────────────── + release: + needs: validate + # 새 아카이브를 만들지 않고 기존 TestFlight 빌드를 선택해 제출하므로 macOS·서명이 필요 없다 + runs-on: ubuntu-latest + # deliver 가 매달려도 러너를 오래 점유하지 않도록 상한을 둔다 + # (concurrency 가 cancel-in-progress: false 라 멈춘 잡이 후속 배포를 전부 막는다) + timeout-minutes: 20 + env: + # Appfile / Fastfile + APP_IDENTIFIER: ${{ secrets.APP_IDENTIFIER }} + APPLE_ID: ${{ secrets.APPLE_ID }} + TEAM_ID: ${{ secrets.TEAM_ID }} + # App Store Connect API (Fastfile 변수명) + APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }} + APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }} + APP_STORE_CONNECT_API_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_API_KEY_CONTENT }} + # deliver 가 대화형 확인을 요구하지 않도록 (CI 에서 입력 불가) + FASTLANE_SKIP_UPDATE_CHECK: "1" + # App Review 담당자 연락처 (개인정보라 metadata 파일이 아닌 Secrets 로만 관리) + APP_REVIEW_FIRST_NAME: ${{ secrets.APP_REVIEW_FIRST_NAME }} + APP_REVIEW_LAST_NAME: ${{ secrets.APP_REVIEW_LAST_NAME }} + APP_REVIEW_PHONE_NUMBER: ${{ secrets.APP_REVIEW_PHONE_NUMBER }} + APP_REVIEW_EMAIL: ${{ secrets.APP_REVIEW_EMAIL }} + steps: + - uses: actions/checkout@v4 + + - name: Setup Ruby & fastlane + uses: ruby/setup-ruby@v1 + with: + ruby-version: "3.3" + bundler-cache: true + + # 수동 실행에서 변경사항을 넘겼으면 이번 배포에 한해 릴리즈 노트를 덮어쓴다 (커밋하지 않음) + - name: Override release notes + if: github.event_name == 'workflow_dispatch' && inputs.release_notes != '' + env: + RELEASE_NOTES: ${{ inputs.release_notes }} + run: | + printf '%s\n' "$RELEASE_NOTES" > fastlane/metadata/ko/release_notes.txt + echo "릴리즈 노트를 입력값으로 교체했습니다." + + - name: Submit to App Store + env: + RELEASE_VERSION: ${{ needs.validate.outputs.version }} + run: bundle exec fastlane release version:"$RELEASE_VERSION" + + # 심사 반려·업로드 실패 원인 추적용 + - name: Upload fastlane logs + if: always() + uses: actions/upload-artifact@v4 + with: + name: fastlane-logs-${{ needs.validate.outputs.version }} + path: fastlane/report.xml + retention-days: 14 + if-no-files-found: ignore diff --git a/.gitignore b/.gitignore index ad7a67c9..d962e9cc 100644 --- a/.gitignore +++ b/.gitignore @@ -65,6 +65,9 @@ Carthage/Build/ fastlane/report.xml fastlane/Preview.html fastlane/screenshots/**/*.png +# App Store 등록용 스크린샷은 snapshot 자동 생성물이 아니라 카피가 얹힌 마케팅 이미지라 +# 재생성이 불가능하다. CI 러너가 체크아웃만으로 업로드할 수 있도록 예외로 추적한다 +!fastlane/screenshots/ko/*.png fastlane/test_output # Compiled binaries diff --git a/AGENTS.md b/AGENTS.md index e43bb4e2..c83f2496 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -15,6 +15,8 @@ | `xcodebuild -workspace Bangawo.xcworkspace -scheme Bangawo build` | 빌드 | | `xcodebuild -workspace Bangawo.xcworkspace -scheme Bangawo test` | 테스트 | | `fastlane match_development` | 개발용 인증서·프로파일 로컬 설치 | +| `fastlane verify_metadata` | App Store 메타데이터 사전 검증 | +| `fastlane release version:1.0.0` | App Store 메타데이터 업로드 + 심사 제출 | > 파일 생성/삭제, `Project.swift` 수정, 의존성 추가/제거 시 반드시 `./tuisttool generate` 실행. > Tuist는 glob으로 소스를 수집하므로, generate 없이는 Xcode에 반영되지 않는다. diff --git a/Projects/Presentation/AuthFlowFeature/Sources/Common/TermClause.swift b/Projects/Presentation/AuthFlowFeature/Sources/Common/TermClause.swift index 19d386ae..85c26174 100644 --- a/Projects/Presentation/AuthFlowFeature/Sources/Common/TermClause.swift +++ b/Projects/Presentation/AuthFlowFeature/Sources/Common/TermClause.swift @@ -38,19 +38,19 @@ public extension TermClause { TermClause( id: 1, title: "개인정보처리방침", - urlString: "https://kimhyeji-dev.notion.site/48c9a7dac7408215a43d01ddf14942f2?source=copy_link", + urlString: "https://lightning-weight-c0c.notion.site/3a619ccc6d3a80089f59dcb19af2b673?source=copy_link", isRequired: true ), TermClause( id: 2, title: "이용약관", - urlString: "https://kimhyeji-dev.notion.site/a1c9a7dac7408391befe0108a872fe6c?source=copy_link", + urlString: "https://lightning-weight-c0c.notion.site/3a619ccc6d3a80d6af97f6503a959b1b?source=copy_link", isRequired: true ), TermClause( id: 3, title: "마케팅 정보 수신 동의", - urlString: "https://kimhyeji-dev.notion.site/3a39a7dac74080ce9580f3a0aa14739f?source=copy_link", + urlString: "https://lightning-weight-c0c.notion.site/3a619ccc6d3a80f0b334dde67ec0e5b0?source=copy_link", isRequired: false ) ] diff --git a/docs/app-store-release.md b/docs/app-store-release.md new file mode 100644 index 00000000..5e16fb7c --- /dev/null +++ b/docs/app-store-release.md @@ -0,0 +1,100 @@ +# App Store 배포 자동화 + +TestFlight 업로드(`beta`)와 별개로, App Store 심사 제출·출시까지 자동화한 파이프라인이다. + +| 대상 | lane | 워크플로 | +| --- | --- | --- | +| TestFlight | `fastlane beta` | `.github/workflows/testflight-deploy.yml` | +| App Store | `fastlane release version:1.0.0` | `.github/workflows/appstore-release.yml` | + +> **`release` 는 새로 아카이브하지 않는다.** TestFlight 에서 검증 끝난 RC 빌드를 그대로 심사에 올린다. 즉 출시하려는 버전의 빌드가 먼저 `beta` 로 TestFlight 에 올라가 있어야 하며, 없으면 release 는 즉시 실패한다. +> +> App Store Connect 는 빌드의 마케팅 버전(`CFBundleShortVersionString`)과 같은 App Store 버전에만 그 빌드를 붙일 수 있고 빌드 버전은 빌드 시점에 고정된다. 따라서 **마케팅 버전은 RC 빌드를 만들기 전에 정해져야 한다.** 현재 마케팅 버전 소스는 `Plugins/ProjectTemplatePlugin/ProjectDescriptionHelpers/Project+Templete/Extension+String.swift` 의 `appVersion(version:)` 기본값(`1.0.0`)이므로, 다음 버전을 출시하려면 이 값을 올려 `tuist generate` 후 커밋하고 `beta` 로 RC 를 올린 뒤 같은 버전으로 release 한다. + +## 배포 절차 + +### 1. 메타데이터 갱신 + +`fastlane/metadata/` 아래 텍스트 파일이 원본이다. App Store Connect 웹에서 수정하지 말고 이 파일들을 고쳐 커밋한다(배포 시 덮어쓰기된다). + +``` +fastlane/metadata/ +├── copyright.txt # 저작권 표기 +├── primary_category.txt # 기본 카테고리 +├── secondary_category.txt # 보조 카테고리 +├── ko/ +│ ├── name.txt # 앱 이름 (30자) +│ ├── subtitle.txt # 부제 (30자) +│ ├── description.txt # 설명 (4000자) +│ ├── keywords.txt # 키워드, 쉼표 구분 (100자) +│ ├── promotional_text.txt # 홍보 텍스트 (170자, 심사 없이 수정 가능) +│ ├── release_notes.txt # 이번 버전 변경사항 (4000자) +│ ├── support_url.txt +│ └── privacy_url.txt +└── review_information/ + └── notes.txt # 심사 담당자용 기능 확인 안내 +``` + +> **심사 담당자 연락처(이름·전화번호·이메일)는 저장소에 두지 않는다.** 개인정보이므로 파일 대신 환경변수로만 다룬다. 로컬은 `fastlane/.env`(gitignore 대상), CI는 GitHub Secrets에서 주입한다. +> +> ```sh +> # fastlane/.env 에 추가 +> APP_REVIEW_FIRST_NAME=길동 +> APP_REVIEW_LAST_NAME=홍 +> APP_REVIEW_PHONE_NUMBER=+82 10-1234-5678 +> APP_REVIEW_EMAIL=contact@example.com +> ``` + +스크린샷은 `fastlane/screenshots/ko/` 에 둔다. 파일명 순서대로 App Store에 정렬되므로 `bangawo_01_`, `bangawo_02_` 처럼 번호를 붙인다. + +> 스크린샷은 카피가 얹힌 마케팅 이미지라 재생성이 불가능하므로 `.gitignore` 예외로 저장소에 추적한다. CI 러너는 체크아웃한 파일을 그대로 업로드한다. + +### 2. 사전 검증 + +```sh +bundle exec fastlane verify_metadata +``` + +필수 파일 누락, `TODO_` 자리표시자, 글자 수 초과, 스크린샷 부재, 심사 연락처 환경변수 누락을 잡는다. 빌드는 30분 이상 걸리므로 반드시 먼저 통과시킨다. + +### 3. 배포 실행 + +**태그 방식(권장)** + +```sh +git tag v1.0.0 +git push origin v1.0.0 +``` + +**수동 방식** + +GitHub Actions → `App Store Release` → `Run workflow` → 버전 입력. 이때 변경사항을 함께 입력하면 이번 배포에 한해 `release_notes.txt` 를 덮어쓴다(커밋되지는 않는다). + +### 4. 워크플로 동작 + +1. **validate** (ubuntu) — 버전 형식과 메타데이터를 검증한다. 여기서 실패하면 다음 잡을 실행하지 않는다. +2. **release** (ubuntu) — 아카이브를 새로 만들지 않는다. 요청 버전에 해당하는 TestFlight 최신 빌드를 조회 → (없으면 실패) → 그 빌드를 선택해 메타데이터·스크린샷과 함께 심사 제출한다. 서명·Xcode·Tuist 가 필요 없어 ubuntu 에서 돈다. + +심사 승인 시 **자동으로 출시된다**(`automatic_release: true`). 수동 출시로 바꾸려면 `Fastfile` 의 해당 값을 `false` 로 둔다. + +## 주의 사항 + +- 버전은 `v1.0.0` 형식만 허용한다. 태그명에서 `v` 를 뗀 값이 **제출할 TestFlight 빌드를 고르는 키**가 된다(버전을 코드에 주입하지 않으므로, 그 버전의 빌드가 TestFlight 에 미리 올라가 있어야 한다). +- 이미 심사 대기 중인 빌드가 있으면 `reject_if_possible: true` 설정에 따라 기존 제출을 반려하고 새로 올린다. +- 수출 규정·IDFA 답변은 `submission_information` 에 하드코딩돼 있다. 광고 SDK를 도입하면 `add_id_info_uses_idfa` 를 갱신해야 한다. +- 앱 이름(`ko/name.txt`)은 App Store 전체에서 고유해야 한다. 최초 등록명과 다르면 업로드가 거절된다. +- 실패 시 `fastlane-logs-{버전}` 아티팩트에 `report.xml` 이 남는다(14일 보관). + +## 필요한 Secrets + +TestFlight 워크플로와 동일한 값에 더해, 심사 연락처 4개를 추가로 등록해야 한다. + +| Secret | 용도 | +| --- | --- | +| `APP_IDENTIFIER`, `APPLE_ID`, `TEAM_ID` | Appfile | +| `MATCH_PASSWORD`, `MATCH_KEYCHAIN_PASSWORD` | 인증서 복호화·키체인 (TestFlight 전용, release 잡에는 불필요) | +| `CONFIG_PRIVATE_REPO_TOKEN` | 인증서 repo·비공개 xcconfig 접근 (TestFlight 전용, release 잡에는 불필요) | +| `APP_STORE_CONNECT_API_KEY_ID` / `_ISSUER_ID` / `_API_KEY_CONTENT` | App Store Connect API (키는 base64) | +| `APP_REVIEW_FIRST_NAME` / `_LAST_NAME` / `_PHONE_NUMBER` / `_EMAIL` | App Review 담당자 연락처 | + +> release 잡은 아카이브·서명을 하지 않으므로 `MATCH_*` 와 `CONFIG_PRIVATE_REPO_TOKEN` 을 쓰지 않는다. 다만 이 값들은 TestFlight 워크플로에 여전히 필요하니 삭제하지 않는다. diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 07cae5d7..e658c5d5 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -8,6 +8,16 @@ BUNDLE_ID = ENV["APP_IDENTIFIER"] || "com.ddd-ios2.Bangawo" TEAM_ID = ENV["TEAM_ID"] OUTPUT_DIR = "./fastlane/output" IPA_FILENAME = "#{APP_NAME}.ipa" +METADATA_DIR = "./fastlane/metadata" +SCREENSHOTS_DIR = "./fastlane/screenshots" + +# 심사 담당자 연락처는 개인정보라 metadata 파일로 커밋하지 않고 환경변수로만 다룬다 +REVIEW_CONTACT_ENV_KEYS = %w[ + APP_REVIEW_FIRST_NAME + APP_REVIEW_LAST_NAME + APP_REVIEW_PHONE_NUMBER + APP_REVIEW_EMAIL +].freeze MATCH_GIT_URL = "https://github.com/Roy-wonji/FastlaneMatch.git" platform :ios do @@ -108,9 +118,14 @@ platform :ios do # Release (App Store) # ────────────────────────────────────────────────────────── - desc "Bangawo-Prod → App Store 심사 제출" + desc "TestFlight 검증 빌드를 App Store 심사 제출 + 자동 출시" lane :release do |options| - UI.user_error!("version 옵션을 지정해주세요. 예: fastlane release version:1.0.0") unless options[:version] + version = options[:version] + UI.user_error!("version 옵션을 지정해주세요. 예: fastlane release version:1.0.0") unless version + UI.user_error!("version 형식이 올바르지 않습니다: #{version} (예: 1.0.0)") unless version =~ /\A\d+\.\d+(\.\d+)?\z/ + + # 미기입 메타데이터가 그대로 심사에 올라가지 않도록 제출 전에 차단한다 + verify_metadata app_store_connect_api_key( key_id: ENV["APP_STORE_CONNECT_API_KEY_ID"], @@ -120,42 +135,96 @@ platform :ios do in_house: false ) - match( - type: "appstore", - readonly: true, - git_url: MATCH_GIT_URL, - storage_mode: "git", - app_identifier: [BUNDLE_ID] + # 새로 아카이브하지 않고, TestFlight 에서 검증 끝난 RC 빌드를 그대로 제출한다. + # version 에 해당하는 TestFlight 최신 빌드를 선택한다 (없으면 검증 안 된 채 올라가므로 즉시 실패). + build_number = latest_testflight_build_number( + app_identifier: BUNDLE_ID, + version: version, + initial_build_number: -1 ) - ensure_workspace + if build_number < 0 + UI.user_error!("#{version} 버전 빌드가 TestFlight 에 없습니다. 먼저 `fastlane beta` 로 RC 를 올려 검증하세요.") + end - build_app( - workspace: WORKSPACE, - scheme: "#{APP_NAME}-Prod", - configuration: "Release", - export_method: "app-store", - output_directory: OUTPUT_DIR, - output_name: IPA_FILENAME, - clean: true, - silent: false, - xcargs: xcargs_flags, - export_options: export_options_hash - ) + UI.message("📦 심사 제출 대상: #{version} (#{build_number})") upload_to_app_store( - app_version: options[:version], - ipa: "#{OUTPUT_DIR}/#{IPA_FILENAME}", - skip_metadata: true, - skip_screenshots: true, + app_version: version, + build_number: build_number.to_s, + # 새 아카이브 대신 위에서 고른 기존 TestFlight 빌드를 선택한다 + skip_binary_upload: true, + skip_metadata: false, + metadata_path: METADATA_DIR, + skip_screenshots: false, + screenshots_path: SCREENSHOTS_DIR, + overwrite_screenshots: true, force: true, submit_for_review: true, - automatic_release: false, + automatic_release: true, precheck_include_in_app_purchases: false, - reject_if_possible: true + reject_if_possible: true, + # 심사 담당자 연락처는 개인정보라 저장소에 두지 않고 ENV 로 주입한다 + # (notes 는 여기 없는 키이므로 review_information/notes.txt 에서 자동 로드된다) + app_review_information: app_review_contact, + # 심사 제출 시 나오는 수출 규정·IDFA 질문에 대한 답변. 없으면 제출 단계에서 멈춘다 + submission_information: { + export_compliance_uses_encryption: false, + add_id_info_uses_idfa: false + } ) - UI.success("🎉 #{options[:version]} 버전 심사 제출 완료!") + UI.success("🎉 #{version} (#{build_number}) 심사 제출 완료! (승인 시 자동 출시)") + end + + desc "메타데이터 미기입/누락 검증 (배포 전 사전 점검)" + lane :verify_metadata do + Dir.chdir("..") do + required_files = [ + "fastlane/metadata/copyright.txt", + "fastlane/metadata/primary_category.txt", + "fastlane/metadata/ko/name.txt", + "fastlane/metadata/ko/description.txt", + "fastlane/metadata/ko/keywords.txt", + "fastlane/metadata/ko/release_notes.txt", + "fastlane/metadata/ko/support_url.txt", + "fastlane/metadata/ko/privacy_url.txt", + "fastlane/metadata/review_information/notes.txt" + ] + + missing = required_files.reject { |path| File.exist?(path) && !File.read(path).strip.empty? } + UI.user_error!("메타데이터 파일이 비어있거나 없습니다:\n- #{missing.join("\n- ")}") unless missing.empty? + + unfilled = required_files.select { |path| File.read(path).include?("TODO_") } + UI.user_error!("메타데이터에 TODO_ 자리표시자가 남아있습니다:\n- #{unfilled.join("\n- ")}") unless unfilled.empty? + + # App Store Connect 의 글자 수 제한. 초과분은 업로드 단계에서야 실패하므로 미리 잡는다 + { "fastlane/metadata/ko/name.txt" => 30, + "fastlane/metadata/ko/subtitle.txt" => 30, + "fastlane/metadata/ko/keywords.txt" => 100, + "fastlane/metadata/ko/promotional_text.txt" => 170, + "fastlane/metadata/ko/description.txt" => 4000, + "fastlane/metadata/ko/release_notes.txt" => 4000 }.each do |path, limit| + next unless File.exist?(path) + + length = File.read(path).strip.length + UI.user_error!("#{path} 가 #{limit}자 제한을 초과했습니다 (현재 #{length}자)") if length > limit + end + + screenshots = Dir.glob("fastlane/screenshots/ko/*.{png,jpg,jpeg}") + UI.user_error!("fastlane/screenshots/ko 에 스크린샷이 없습니다") if screenshots.empty? + + # 심사 담당자 연락처는 파일이 아니라 ENV(로컬은 fastlane/.env, CI 는 Secrets)에서 온다 + missing_env = REVIEW_CONTACT_ENV_KEYS.reject { |key| ENV[key].to_s.strip.length > 0 } + unless missing_env.empty? + UI.user_error!( + "심사 담당자 연락처 환경변수가 비어있습니다:\n- #{missing_env.join("\n- ")}\n" \ + "로컬은 fastlane/.env, CI 는 GitHub Secrets 에 설정하세요." + ) + end + + UI.success("✅ 메타데이터 검증 통과 (스크린샷 #{screenshots.count}장)") + end end end @@ -183,6 +252,15 @@ def xcargs_flags "-allowProvisioningUpdates" end +def app_review_contact + { + first_name: ENV["APP_REVIEW_FIRST_NAME"], + last_name: ENV["APP_REVIEW_LAST_NAME"], + phone_number: ENV["APP_REVIEW_PHONE_NUMBER"], + email_address: ENV["APP_REVIEW_EMAIL"] + } +end + def export_options_hash { signingStyle: "manual", diff --git a/fastlane/metadata/copyright.txt b/fastlane/metadata/copyright.txt new file mode 100644 index 00000000..37d8b4f1 --- /dev/null +++ b/fastlane/metadata/copyright.txt @@ -0,0 +1 @@ +2026 Bangawo \ No newline at end of file diff --git a/fastlane/metadata/ko/description.txt b/fastlane/metadata/ko/description.txt new file mode 100644 index 00000000..225e2403 --- /dev/null +++ b/fastlane/metadata/ko/description.txt @@ -0,0 +1,26 @@ +약속 잡기의 모든 것, 반가워 + +"언제 볼까?" "어디서 만날까?" 단톡방에서 며칠씩 오가던 대화를 반가워 하나로 끝내세요. +날짜 조율부터 모두에게 공평한 만남 장소 추천까지, 그룹 약속에 필요한 과정을 한 곳에 모았습니다. + +■ 날짜 투표 +가능한 날짜를 각자 고르면 참여 현황이 한눈에 정리됩니다. +참여, 불참, 늦참까지 표시할 수 있어 누가 언제 되는지 다시 물어볼 필요가 없습니다. + +■ 중간 지점 추천 +멤버들의 출발지를 입력하면 모두에게 공평한 만남 장소를 찾아드립니다. +누구 한 명만 멀리 가는 약속은 이제 그만. + +■ 이동 거리 확인 +각자 출발지에서 약속 장소까지의 거리를 비교해서 볼 수 있습니다. +장소를 정하기 전에 서로의 이동 부담을 확인하세요. + +■ 장소 검색 +지하철역과 주변 장소를 검색해 약속 장소를 바로 지정할 수 있습니다. + +■ 모임 관리 +모임을 만들고 링크로 친구를 초대하세요. +프로필과 출발지를 등록해 두면 다음 약속부터는 더 빠르게 정할 수 있습니다. + +친구, 동아리, 스터디, 동호회. +정기적으로 모이는 사람들일수록 반가워가 더 편해집니다. \ No newline at end of file diff --git a/fastlane/metadata/ko/keywords.txt b/fastlane/metadata/ko/keywords.txt new file mode 100644 index 00000000..fd202daa --- /dev/null +++ b/fastlane/metadata/ko/keywords.txt @@ -0,0 +1 @@ +약속,모임,일정조율,날짜투표,중간지점,만남장소,장소추천,모임관리,친구,약속잡기 \ No newline at end of file diff --git a/fastlane/metadata/ko/name.txt b/fastlane/metadata/ko/name.txt new file mode 100644 index 00000000..058f68c9 --- /dev/null +++ b/fastlane/metadata/ko/name.txt @@ -0,0 +1 @@ +반가워 \ No newline at end of file diff --git a/fastlane/metadata/ko/privacy_url.txt b/fastlane/metadata/ko/privacy_url.txt new file mode 100644 index 00000000..2208c544 --- /dev/null +++ b/fastlane/metadata/ko/privacy_url.txt @@ -0,0 +1 @@ +https://lightning-weight-c0c.notion.site/3a619ccc6d3a80089f59dcb19af2b673?source=copy_link \ No newline at end of file diff --git a/fastlane/metadata/ko/promotional_text.txt b/fastlane/metadata/ko/promotional_text.txt new file mode 100644 index 00000000..1f5f6a3a --- /dev/null +++ b/fastlane/metadata/ko/promotional_text.txt @@ -0,0 +1 @@ +날짜 투표부터 중간 지점 추천까지, 그룹 약속에 필요한 모든 과정을 반가워 하나로 끝내세요. \ No newline at end of file diff --git a/fastlane/metadata/ko/release_notes.txt b/fastlane/metadata/ko/release_notes.txt new file mode 100644 index 00000000..af51747a --- /dev/null +++ b/fastlane/metadata/ko/release_notes.txt @@ -0,0 +1,6 @@ +반가워의 첫 번째 버전입니다. + +- 모임을 만들고 친구를 초대할 수 있습니다 +- 날짜 투표로 모두가 가능한 날을 찾아보세요 +- 출발지를 등록하면 공평한 중간 지점을 추천해 드립니다 +- 약속 장소까지의 이동 거리를 비교할 수 있습니다 \ No newline at end of file diff --git a/fastlane/metadata/ko/subtitle.txt b/fastlane/metadata/ko/subtitle.txt new file mode 100644 index 00000000..75e2ac97 --- /dev/null +++ b/fastlane/metadata/ko/subtitle.txt @@ -0,0 +1 @@ +날짜부터 장소까지, 그룹 약속의 시작 \ No newline at end of file diff --git a/fastlane/metadata/ko/support_url.txt b/fastlane/metadata/ko/support_url.txt new file mode 100644 index 00000000..fe081c19 --- /dev/null +++ b/fastlane/metadata/ko/support_url.txt @@ -0,0 +1 @@ +https://lightning-weight-c0c.notion.site/3a619ccc6d3a8068a776fe3a66808a40?source=copy_link \ No newline at end of file diff --git a/fastlane/metadata/primary_category.txt b/fastlane/metadata/primary_category.txt new file mode 100644 index 00000000..117214b8 --- /dev/null +++ b/fastlane/metadata/primary_category.txt @@ -0,0 +1 @@ +LIFESTYLE \ No newline at end of file diff --git a/fastlane/metadata/review_information/notes.txt b/fastlane/metadata/review_information/notes.txt new file mode 100644 index 00000000..d7b16067 --- /dev/null +++ b/fastlane/metadata/review_information/notes.txt @@ -0,0 +1,9 @@ +별도의 데모 계정 없이 카카오 계정으로 로그인해 모든 기능을 사용할 수 있습니다. + +주요 확인 경로 +1. 로그인 후 프로필과 출발지를 등록합니다. +2. 모임을 생성하고 초대 링크로 멤버를 추가합니다. +3. 날짜 투표에서 가능한 날짜를 선택하면 참여 현황이 집계됩니다. +4. 멤버들의 출발지를 기준으로 중간 지점과 이동 거리를 확인합니다. + +위치 권한은 출발지 설정과 중간 지점 계산에만 사용하며, 백그라운드에서 위치를 수집하지 않습니다. \ No newline at end of file diff --git a/fastlane/metadata/secondary_category.txt b/fastlane/metadata/secondary_category.txt new file mode 100644 index 00000000..31991aa3 --- /dev/null +++ b/fastlane/metadata/secondary_category.txt @@ -0,0 +1 @@ +SOCIAL_NETWORKING \ No newline at end of file diff --git a/fastlane/screenshots/ko/bangawo_01_overview.png b/fastlane/screenshots/ko/bangawo_01_overview.png new file mode 100644 index 00000000..e27b3467 Binary files /dev/null and b/fastlane/screenshots/ko/bangawo_01_overview.png differ diff --git a/fastlane/screenshots/ko/bangawo_02_date_vote.png b/fastlane/screenshots/ko/bangawo_02_date_vote.png new file mode 100644 index 00000000..f42be435 Binary files /dev/null and b/fastlane/screenshots/ko/bangawo_02_date_vote.png differ diff --git a/fastlane/screenshots/ko/bangawo_03_places.png b/fastlane/screenshots/ko/bangawo_03_places.png new file mode 100644 index 00000000..45a9d83f Binary files /dev/null and b/fastlane/screenshots/ko/bangawo_03_places.png differ diff --git a/fastlane/screenshots/ko/bangawo_04_distance.png b/fastlane/screenshots/ko/bangawo_04_distance.png new file mode 100644 index 00000000..7e69e326 Binary files /dev/null and b/fastlane/screenshots/ko/bangawo_04_distance.png differ