Hướng dẫn CodePanel
panel.xuongapp.com. Mọi action upload/submit thật đều cần PO bấm xác nhận. Chat với Claude trong tab Lệnh & Build để Claude sửa code, install ads, submit App Store, v.v. — PO duyệt từng turn.
- Truy cập + đăng nhập
- Bố cục chung
- Tab Files
- Tab Status — pipeline + Version planner
- Tab Request — request + rejection + đính kèm file (mới 2026-06-25)
- Tab Lệnh & Build — terminal + chat Claude
- Tab Store listing — metadata + screenshots + AI gen
- Tab Policy — Privacy & Terms
- Tab Checklist — AdMob/SDK/Remote Config
- Workflow: thêm project mới từ GitLab (mới 2026-06-25)
- Workflow: tạo app mới từ đầu đến v1.0 live
- Workflow: tạo version mới đến submit
- Workflow: phản hồi rejection từ Apple
- Workflow: v1.1 — gắn Ads cho app v1.0 đã live
- Tips & Gotchas
- Khắc phục sự cố
1. Truy cập + đăng nhập
CodePanel chạy trên Mac mini của studio và expose ra ngoài qua Cloudflare tunnel:
- URL cố định: https://panel.xuongapp.com
- Access token: hỏi anh Thông (token random ngẫu nhiên, không lưu trong tài liệu này). Format ví dụ:
vW7DCuHj0YqvBETai7iGn6Y45lhOywHi
2 cách đăng nhập
- Mở URL → màn login → paste token vào ô → bấm Đăng nhập. Cookie lưu 30 ngày.
- Hoặc paste URL trực tiếp kèm token:
https://panel.xuongapp.com/?token=XXX— vào thẳng không qua form.
.codepanel/config.json trên Mac.2. Bố cục chung
Mở panel xong PO sẽ thấy:
- Sidebar trái: nút ➕ Thêm project mới đầu list (clone từ GitLab exostudio24, xem workflow 10). Tiếp đó là danh sách project trong
~/Desktop/EXO/. Search ở trên cùng. Mỗi project có badge platform (iOS/Android), branch git hiện tại, số commit chưa push (↑8). - Detail bên phải: chọn 1 project ở sidebar → 7 tab nội dung: Files / Status / Request / Lệnh & Build / Store listing / Policy / Checklist.
- Header detail: tên project + badge platform inline + meta (nhánh + sha + thay đổi chưa commit) + nút pill ⬆ Commit & Push (mobile thu thành icon-only).
Nút 🔄 trên cùng sidebar = refresh danh sách project (sau khi clone hoặc tạo thư mục mới).
3. Tab Files
Trình duyệt file của project. Click thư mục để mở; click file để xem với syntax highlight (highlight.js).
- Không edit được trong panel — đây chỉ là viewer.
- Sửa code thật: mở Xcode/Android Studio trên Mac, hoặc dùng tab Request để Claude tự sửa (xem mục 9).
- Breadcrumb ở trên cùng để nhảy nhanh giữa thư mục.
- SKIP_DIRS tự bỏ qua:
.git, node_modules, Pods, build, DerivedData, .build, .gradle, Carthage.
4. Tab Status — pipeline + Version planner
Tab tổng quan vòng đời app từ tạo project → release. Tab này có 2 phần:
Lưu ý 2026-06-25: Top button "🚀 Submit App Store…" đã BỎ. Path submit duy nhất hiện tại là nút "Nộp review qua ASC API" ở stage "Nộp & review" trong pipeline (xem 4.2 bên dưới) — spawn Claude session + Playwright xử lý App Privacy + Age Rating đầy đủ. Nếu chỉ muốn submit nhanh không cần Privacy (vd v1.1 resubmit không đổi data collection), curl trực tiếp: curl -X POST -H "Authorization: Bearer <token>" -d '{"releaseType":"MANUAL"}' http://localhost:8765/api/projects/<app>/submit.
4.1. Version planner panel iOS
Khi v live trên ASC đang ở trạng thái READY_FOR_SALE / READY_FOR_REVIEW và panel detect project.yml.marketing == live → hiển thị panel "💡 Bắt đầu version mới?":
- Hiển thị: project.yml hiện tại vs live ASC.
- Gợi ý bump (minor default: 1.0 → 1.1).
- Button 🆕 Tạo v1.1 trên ASC + bump project.yml… — click mở modal preview diff.
Modal "Tạo version mới":
- Dropdown chọn marketing version: keep / patch / minor / major.
- Input build number (auto +1).
- Checkbox Copy metadata từ v cũ (mặc định ON, copy
description/keywords/supportUrl/marketingUrl, KHÔNG copywhatsNew). - Preview diff: "MARKETING_VERSION 1.0 → 1.1, build 1 → 2, POST ASC, seed N fields".
- Confirm → atomic chạy: bump
project.yml+*.xcodeproj/project.pbxproj→ ASCcreate_version→ seed metadata. Nếu ASC fail thì auto rollback file local.
4.2. Pipeline stages
List dạng stepper dọc, mỗi dot màu theo state:
| Màu | State | Ý nghĩa |
|---|---|---|
| 🟢 | done | Hoàn thành |
| 🟡 | doing | Đang chạy / partial |
| 🔴 | error | Có lỗi / sai sheet |
| ⚪ | todo | Chưa làm |
| — | unknown | Chưa kiểm tra được (vd ASC chưa cấu hình) |
Mỗi stage có thể kèm nút action để hoàn thành bước đó:
- Project / git / icon — không action (PO làm trong Xcode/Android Studio).
- App ID / ASC record — mở App Store Connect web trong tab mới.
- Metadata / Screenshots / Privacy — jump sang tab Store listing / Policy.
- Build (TestFlight) — bấm chạy Up TestFlight (có confirm dialog).
- Nộp & review — Nộp review qua ASC API → modal Claude submit (xem mục 4.4).
- Released — mở ASC web.
- Ads (sau released) — hiện khi PO đã set sheet AdMob. Jump sang tab Checklist.
4.3. Nộp review qua ASC API (Claude + Playwright)
Path submit DUY NHẤT trong UI hiện tại (top button "🚀 Submit App Store…" đã bỏ 2026-06-25). Truy cập qua nút "Nộp review qua ASC API" ở stage "Nộp & review" cuối pipeline.
Bấm nút → mở modal nhỏ chọn release type → spawn Claude session drive toàn bộ submit:
- Claude gọi
GET /submit/preflightkiểm 7 row: app trên ASC / version editable / build VALID / encryption / metadata / screenshots / review contact. - Auto-fix các row có
fixfield:fix-create-version/fix-encryption/fix-review-infoqua API. - Metadata text rỗng (whatsNew/description/...): Claude propose nội dung + curl
PATCH /listingsau khi PO duyệt 'ok'. - Quét code app suy ra App Privacy data collection (Analytics/IDFA/Location/...) → mở ASC web qua Playwright MCP → click checkbox.
- Age Rating: default 4+ (None cho mọi câu hỏi) nếu app không violence/sexual/horror.
- Submit cuối qua
POST /submitvới releaseType PO chọn — backend dùng v2 reviewSubmissions flow (3 bước: create draft → attach version → PATCH submitted=true). - Report 5-section trên chat thread.
PO theo dõi từng turn ở tab Lệnh & Build (chat mode). Nếu Claude yêu cầu PO login ASC (lần đầu) → PO mở browser login → reply "ok tôi đã đăng nhập" → Claude resume.
Direct API path (không cần Privacy/Age Rating qua Playwright, vd v1.1 resubmit không đổi data): curl POST /submit trực tiếp với release type. Dùng cho resubmit nhanh.
5. Tab Lệnh & Build — chat Claude (Codex-style)
Đổi 2026-06-24: Action grid (git status/pull/xcodegen/schemes/build/...) + ô $ command tùy ý đã bỏ. Tab giờ tập trung 100% vào chat Claude. Các action xưa giờ:
- Commit & Push → nút pill xanh inline header detail (cạnh tên project, hiện khi có thay đổi chưa commit).
- Up TestFlight → stage button trong pipeline tab Status, hoặc combo "🚀 Commit + Up TestFlight" trên issue card next-step.
- Git status/pull/log → mở Terminal trực tiếp (local), hoặc tạo request "Pull code main + diff với local" → Claude xử lý.
- XcodeGen, build sim, schemes, custom shell command → tạo request mô tả ý định, Claude chạy + verify.
5.1. Chat Claude (giao diện Codex-style)
Job Claude (từ tab Request, asc-submit, install-ads, auto-fix v.v.) hiện chat mode: bubble user/assistant đan xen, typography lớn (font system 15.5-16px), code block bo góc với header ngôn ngữ + nút Copy.
- Mỗi tool call Claude gọi hiện inline card: 📖 Read /path, $ Bash command, ✏️ Edit, 🔍 Grep, 🌐 navigate URL. Bấm Mở để xem kết quả tool đầy đủ.
- Activity strip header:
12s · 📖 3 · $ 2 · ✏️ 1— elapsed time + counter tool đã gọi. - Auto-scroll theo dòng cuối khi Claude đang in (Codex-like). PO scroll lên đọc cũ → pause auto-follow; scroll xuống → resume.
- Input pill rounded sticky bottom: nút + bên trái (toggle drop zone đính kèm), textarea giữa (auto-resize), nút ↑ blue circle bên phải. Gõ Enter để gửi, Shift+Enter xuống dòng.
- Drop file vào khung 📎: upload
plist/JSON/cert/logđể Claude đọc — file save<project>/_drops/<ts>-<name>và path tự insert vào reply. - Stop button per bubble — dừng Claude giữa chừng (SIGTERM).
5.2. Soft guard "version trùng live"
Trước khi chạy Up TestFlight / Claude xử lý issue / Install Ads / Firebase Create, panel tự check: nếu project.yml.marketing == liveVersion và chưa có editable version → hiện confirm dialog cảnh báo:
PO override được nếu chỉ dev test, không up TestFlight thật.
6. Tab Store listing — metadata + screenshots + AI gen
6.1. Header rõ version đang chỉnh
- 🟢 Đang chỉnh v1.2 (Chuẩn bị nộp) — version editable, sửa free.
- 🟡 Hiển thị v1.0 (Đã lên store) — không sửa được; PO chỉ xem.
- Banner đỏ "🚫 App chưa có version editable" + "→ Mở tab Status, bấm 🆕 Tạo version mới" — khi app live nhưng project.yml chưa bump.
6.2. Sửa metadata
iOS có 6 field name/subtitle/promo/desc/keywords/whatsNew + Support URL + Marketing URL + Privacy Policy URL. Counter ký tự realtime (đỏ khi quá cap Apple).
Android có title (30), short description (80), full description (4000).
Bấm Lưu metadata → chỉ PATCH field nào thay đổi.
6.3. Upload screenshots
- Dropdown displayType (vd
APP_IPHONE_67cho 6.7" — 1290×2796). - Pick file → bấm Tải ảnh lên. Apple yêu cầu min 3 screenshot mỗi device class.
- Xoá: bấm × ở góc thumbnail.
- Icon App Store (1024) không sửa qua API — lấy từ asset catalog trong build. Đổi AppIcon trong Xcode rồi build lại.
6.4. AI gen ✨
Panel "✨ Tạo bằng Claude" trên cùng tab. Textarea brief mô tả app (1-3 câu), bấm:
- Tạo metadata — Claude gen 6/3 field, auto-fill form. Mất ~40s. Tự set Support URL + Marketing URL =
exostudio24.github.io. - Tạo icon — Claude → HTML → headless Chrome render PNG 1024×1024. Hiện preview, có nút "Tải PNG" (download, không apply qua API).
- Tạo screenshot — chọn displayType. Mất ~98s. Hiện preview + nút Áp dụng → upload thẳng qua API.
Mọi gen job chạy async (poll mỗi 2s vì Cloudflare tunnel drop request dài 100s+).
7. Tab Policy — Privacy & Terms
Gen + deploy Privacy Policy / Terms of Service cho app, host miễn phí trên exo-pages.web.app.
- Form: chọn Privacy hoặc Terms, tên app, slug (auto-gen từ project), contact email, textarea practices mô tả app collect gì.
- Bấm Tạo — Claude gen HTML (60-180s), preview iframe.
- Bấm Lưu file — ghi local
exo-pages/public/<slug>/<privacy|terms>.html. - Bấm Deploy lên Firebase — chạy
firebase deploy --only hostingpush lênexo-pages.web.app. Mất ~20s. - Bấm Đặt URL vào App Store Connect (iOS) — PATCH
privacyPolicyUrlcủaappInfoLocalization.
URL kết quả: https://exo-pages.web.app/<slug>/privacy.
8. Tab Checklist — AdMob / SDK / Remote Config
8.1. Sheet cấu hình AdMob
Mỗi project iOS/Android có 1 Google Sheet config AdMob (1 dòng App ID + N dòng ad units + optional Facebook/TikTok IDs):
- Input URL sheet → bấm Lưu URL.
- Hoặc bấm 🆕 Tạo Sheet mới — form prefill 21 placement chuẩn EXO, submit → tự tạo sheet trong folder Drive shared SA + auto-fill IDs.
- Sheet phải share "Anyone with the link can view".
8.2. AdMob auto-create
Nếu cấu hình OAuth (config.json key admob_oauth_json): panel có nút 🤖 Tạo AdMob app + ad units chạy qua AdMob API v1beta — POST /apps + 21x POST /adUnits trong ~15s. Trả về IDs để fill Sheet generator.
8.3. Install Ads via Claude
Sau khi có sheet + AdMob IDs: panel hiện Install Ads panel (chỉ khi sheet có units):
- Hybrid picker placement (default ALL checked, "Advanced ▾" để chọn subset).
- Stack toggles: Firebase / Facebook / TikTok / Adjust (default ON tất cả).
- Target version: auto-bump minor (1.0 → 1.1, build +1).
- Bấm 🚀 Install Ads via Claude → tạo issue kind=ads-install + spawn Claude.
Claude sẽ: consult skill install-exo-ads → curl sheet CSV → install SDK + gen Swift code (AdsBootstrap, AdManager, PaidImpressionLogger, per-placement loaders) → set Info.plist GADApplicationIdentifier + SKAdNetwork + ATT description → verify sim → re-gen Privacy Policy LOCAL → audit ios-review-policy skill → report 5-section.
PO theo dõi qua chat Lệnh & Build. Privacy Policy CHỈ ghi file local — PO mở tab Policy bấm Deploy tay.
8.4. SDK checks
Section liệt kê SDK Claude detect trong dependency manifest:
- AdMob SDK: Google Mobile Ads.
- Analytics & MMP: Firebase + sub-modules (Analytics/RemoteConfig/Messaging/Crashlytics/Auth), Adjust, AppMetrica.
- Social SDK: Facebook, TikTok.
- AdMob mediation: Meta Audience Network, Mintegral, AppLovin.
State todo = "không cài" — có thể intentional (app không cần SDK đó), không phải lỗi.
8.5. AdMob App ID + Ad units check
Đối chiếu code với sheet:
- App ID:
GADApplicationIdentifierInfo.plist (iOS) hoặccom.google.android.gms.ads.APPLICATION_IDAndroidManifest (Android). Match sheet → done. Khác sheet → error. - Ad units: scan suffix-only
/(\d{9,11})trong code (apps EXO thường splitlet pub = "ca-app-pub-XXX"; let id = pub + "/123"). Match → done. Thiếu → todo (có note "nếu dùng Remote Config thì OK").
8.6. Remote Config check + tạo param qua CLI
Mỗi ad-unit row có sub-line nhỏ phía dưới ID (chỉ row RC-gated theo EXO_PLACEMENTS):
RC: code ✓ · Firebase ✓ true
Decode:
code ✓: app có gọiRemoteConfig.configValue(forKey:"inter_splash").boolValueFirebase ✓: param đã tạo trên Firebase ConsoleFirebase ⚠ chưa tạo param: app dùng nhưng Console chưa có → bấm nút 🔥 Tạo Remote Config param thiếu ở đầu sectionsFirebase ?: panel không gọi được Firebase API (chưa có SA hoặc CLI auth không có).
Tạo qua CLI: panel chạy firebase remoteconfig:get → inject params thiếu với default true → firebase deploy --only remoteconfig. Không cần SA, dùng firebase login sẵn có.
8.7. Event-logging checks
Section "Ad impression — log gửi về đâu" + "Purchase — log gửi về đâu" — pattern match code có gọi Analytics.logEvent / paidEventHandler / TikTokAdRevenueEvent / ADJAdRevenue / v.v.:
- 4 destination: Firebase, Facebook, TikTok, Adjust.
- State unknown nếu SDK destination chưa cài (bỏ qua check).
- Substring match — false-positive trong comment, false-negative khi wrap qua helper.
9. Tab Request — request + rejection + đính kèm file đổi 2026-06-25
Tab cũ tên "Log issue" → đổi tên Request và chuyển sang trái tab "Lệnh & Build". Workflow PO log request → Claude propose plan → PO duyệt → Claude implement → bấm build & up TestFlight.
9.1. Form tạo request gọn vào modal mới
- Tab Request body chỉ còn danh sách request + nút ➕ Tạo request mới ở header (cạnh ⟳ Tải lại).
- Empty state: 📝 "Chưa có request nào" + CTA "➕ Tạo request đầu tiên" to ở giữa.
- Bấm ➕ Tạo request mới → modal mở. Modal có:
- 1 textarea duy nhất (PO không phải bấm radio rejection/general — backend tự detect từ keywords)
- Live detect hint dưới textarea: 🛑 đỏ nếu phát hiện rejection (extract Guideline X.Y.Z + version + store tự động), 📝 xanh nếu request thường
- Đính kèm file/ảnh luôn hiện (drag-drop hoặc click chọn). Accept: PNG/JPG/WebP/GIF + plist/JSON/log/PDF/text/cert. Tối đa 8MB/file. Chip preview với thumbnail (ảnh) hoặc icon emoji (📋 plist/json, 📜 log, 🔐 cert, 📄 pdf).
- Footer: Huỷ + Tạo request. Cmd/Ctrl+Enter submit.
- Submit OK → modal đóng + Claude auto-spawn ngay (Phase 1 propose, xem 9.3).
9.2. Auto-detect loại request từ text mới
Backend chạy 10 regex pattern khi PO submit:
Guideline X.Y.Z(Apple guideline format) → rejection + extract guideline numberApp Store Review,Apple Review Team,Google Play Review→ rejection + extract store- URL
appstoreconnect.apple.com,play.google.com/console→ rejection - VI:
bị từ chối,bị reject,rejected by apple/google→ rejection - Không match nào → request thường
Auto-extract: guideline (vd "5.2.1"), version (vd "1.1 (11)"), store (apple/google). PO vẫn có thể paste freetext — server không bắt buộc structure.
9.3. Claude 2-Phase: LUÔN propose + hỏi PO trước action mới
Khi PO tạo request mới, Claude bắt buộc chạy 2 phase:
Phase 1 — DIAGNOSE & PROPOSE (turn này, KHÔNG edit code):
- Đọc kỹ request + grep/Read 3-6 file relevant nhất (KHÔNG đoán mò)
- In báo cáo format cố định:
📋 Hiểu issue / 🔍 Phân tích / 🛠 Plan đề xuất (Approach + Files sẽ sửa + Edge cases + Risk + Estimate) / ❓ Hỏi PO - STOP — đợi PO trả lời. KHÔNG sửa file, KHÔNG build, KHÔNG commit.
Phase 2 — IMPLEMENT (turn sau, khi PO reply):
- Resume session (qua
--resume sessionId), thấy PO đã confirm - Sửa code → compile → sim verify → markdown report → suggest next-step (commit/up TestFlight)
Ngoại lệ duy nhất skip Phase 1: typo cực kỳ tầm thường (vd "sửa setttings → settings") và Claude 100% chắc chắn không có cách hiểu khác.
9.4. Rejection vẫn dùng diagnose mode A/B/C
Rejection có flow riêng (đã có từ trước, không đổi):
- Phase 1: Claude diagnose (Read/Grep, KHÔNG Edit) + đề xuất 2-3 Phương án A/B/C + checklist resubmit
- PO bấm Chọn Phương án X → followup textarea pre-fill template
- Phase 2: Claude apply code/metadata theo phương án đã chọn
- Resubmit Checklist parse markdown
- [ ] action · @hint. Hint:build / store / policy / asc-web / manual→ icon shortcut ⚡/📷/📝/🔗.
9.5. Issue card đơn giản (3 nút)
- Xem log Claude — mở chat thread streaming
- Archive — ẩn khỏi list (nút 📥 Hiện archived ở header để xem lại)
- Xoá — confirm dialog tiếng Việt
3 nút "Gửi Claude xử lý" / "Build & Up" / "Trả lời" của bản cũ đã bỏ — auto-spawn Claude khi tạo request + reply qua chat thread.
9.6. Multi-turn session Claude
Mỗi request có 1 sessionId UUID — Claude lưu context full conversation ở ~/.claude/projects/:
- Turn 1:
claude -p --session-id <uuid> "<prompt>" - Followup:
claude -p --resume <uuid> "<text>" - Survive server restart: panel restart mất JOBS dict (log streaming) nhưng session disk vẫn intact. Bấm Xem log Claude trên card vẫn resume được.
9.7. Claude tự action ASC qua API
Cho project iOS: prompt có ASC API capabilities block liệt kê endpoint Claude tự gọi:
PATCH /api/projects/<n>/listing— text metadata (description / keywords / promotionalText / whatsNew / supportUrl / marketingUrl / name / subtitle / privacyPolicyUrl). Body shape:{version_localization_id, version: {...}}hoặc flat{whatsNew: "..."}(server tự lookup vloc_id). whatsNew lock ở v1.0 → server trảskipped:["whatsNew"].POST /listing/screenshot— upload screenshot mới (multipart)DELETE /listing/screenshot/<sid>— xoá ảnh cũPOST /submit/set-review-notes— reply tới reviewerPOST /submit/fix-encryption/fix-review-info/fix-create-versionPOST /version/create-new— atomic bump project.yml + ASC versionPOST /run— testflight uploadGET /submit/preflight+POST /submit(v2 reviewSubmissions)
Claude propose action + curl command → PO duyệt "ok" trong chat → Claude execute. KHÔNG dump TODO "@store/@asc-web" cho PO làm tay.
Web-only thật chỉ còn: App Privacy questionnaire, Age Rating, Pricing — Claude dùng Playwright MCP click ASC web.
10. Workflow: thêm project mới từ GitLab mới 2026-06-25
PO có project trên GitLab exostudio24 nhưng chưa clone về máy local (vd: bạn dev khác đã tạo, hoặc PO muốn pull code về máy mới). Workflow này cho phép clone qua UI, không cần mở terminal.
- Đầu sidebar (trên list project) có nút ➕ Thêm project mới (pill viền dashed màu xanh).
- Bấm → modal "Thêm project từ GitLab" mở ra với search field + danh sách 30+ repo trong
exostudio24.
- Mỗi item hiện: tên +
path+ thời gian activity cuối +default_branch+ visibility. - Sort: repo activity gần nhất lên đầu.
- Tìm theo tên: gõ vào search field → list filter realtime.
- Repo đã clone về Desktop/EXO/ → badge ✓ Đã clone (mờ + không có nút Clone).
- Bấm Clone để clone repo chưa có.
- Modal đóng, panel switch tab Lệnh & Build, stream log
git clonerealtime (Receiving objects... %, Resolving deltas... %). - Tốc độ phụ thuộc repo size + network. Repo iOS app điển hình ~30 MB clone trong 10-30s.
- Khi rc=0 (clone success): sidebar refresh, project mới hiện trong list + tự mở (switch tab Files).
- iOS: nếu repo có
project.yml+ thiếu.xcodeproj→ tab Lệnh & Build gõxcodegen generateđể gen Xcode project. - Android: nếu repo dùng gradle →
./gradlew assembleDebugđể verify build OK. - Firebase: GoogleService-Info.plist có thể được gitignore — vào tab Checklist → Firebase placeholder → "🔥 Tạo Firebase + download plist" nếu thiếu.
- Secrets: file
.env/ certs / API keys thường KHÔNG commit → PO cần copy tay từ máy cũ vào folder mới, hoặc PO khác chia sẻ qua kênh secure.
- Clone dùng HTTPS + PAT (gitlab_token trong config). Token KHÔNG xuất hiện trong job log (panel mask thành URL không có credentials).
- Folder đích đã tồn tại → server từ chối 409 (tránh ghi đè code chưa commit). Xoá folder cũ thủ công trước nếu PO muốn re-clone.
- Endpoint backend:
GET /api/gitlab/projects(cache 5 phút) +POST /api/gitlab/clone. Bấm ⟳ Tải lại trong modal để bust cache + fetch GitLab.
11. Workflow: tạo app mới từ đầu đến v1.0 live
Áp dụng khi PO bắt đầu 1 app iOS hoàn toàn mới — chưa có record trên ASC, chưa có code, chưa có icon. Mục tiêu: từ tay trắng đến v1.0 ready trên App Store.
- Tạo Bundle ID trên developer.apple.com → Certificates, IDs & Profiles → Identifiers → New → format
com.exo.<name>. - Tạo App record trên appstoreconnect.apple.com → My Apps → ➕ → fill Bundle ID + SKU + Primary Language. Apple gen App ID (vd 6780491111).
- Tạo thư mục
~/Desktop/EXO/<name>-ios/. - Viết
project.yml(XcodeGen) vớiMARKETING_VERSION: 1.0+CURRENT_PROJECT_VERSION: 1+PRODUCT_BUNDLE_IDENTIFIER: com.exo.<name>. Hoặc tạo .xcodeproj qua Xcode. - git init + commit initial.
- Mở CodePanel → sidebar tự hiện project mới (panel scan
~/Desktop/EXO/mỗi lần load).
- Firebase: tab Checklist → row Firebase placeholder ⚠ → bấm 🔥 Tạo Firebase + download plist. Panel chạy
firebase CLItạo project + register iOS app + downloadGoogleService-Info.plistvào project tree. - Privacy Policy: tab Policy → form chọn Privacy + tên app + slug + email
exostudio.feedback@gmail.com+ practices ("app collect: device identifier qua Firebase Analytics, no personal info"). Bấm Tạo (~60-180s qua Claude). Preview iframe → bấm Lưu file rồi Deploy lên Firebase. URL:exo-pages.web.app/<slug>/privacy.
- Tab Request → bấm ➕ Tạo request mới → modal → textarea mô tả: "Tạo app SwiftUI MVP gồm 3 màn onboarding + màn Home + màn Settings. Theme dark mode. Logic placeholder, focus UI structure trước".
- Bấm Tạo request → modal đóng, panel auto-spawn Claude session, switch tab Lệnh & Build → Claude bubble bắt đầu Phase 1 diagnose + propose plan.
- Theo dõi chat. Reply trong textarea nếu Claude hỏi clarification.
- Khi xong: Claude báo "Files đã sửa: ... Compile + sim verify PASSED" + embed thumbnail screenshot.
- Tab Store listing → cuộn xuống Privacy Policy URL → paste
https://exo-pages.web.app/<slug>/privacy(đã deploy ở bước 3). - Lưu metadata.
- Tab Store listing → panel ✨ Tạo bằng Claude → textarea brief mô tả app → bấm Tạo metadata. Claude điền 6 field iOS (~40s). Lưu metadata.
- Bấm Tạo screenshot → chọn displayType (vd APP_IPHONE_67) → Claude gen → preview → bấm Áp dụng (upload qua ASC API). Lặp cho các displayType cần (iPhone 6.5", 6.1", iPad nếu cần).
- Icon: phải làm tay trong Xcode asset catalog (không gen qua API).
- Header detail click ⬆ Commit & Push (đẩy code lên GitLab) hoặc dùng combo 🚀 nếu issue Claude vừa xong (Status tab stage build).
- Bấm ⬆ Up TestFlight (Status tab stage). Panel chạy archive + altool upload. Mất 5-15 phút.
- Sau khi upload xong, đợi Apple process build (5-15 phút nữa) → state VALID.
- Status tab → stage "Nộp & review" → bấm Nộp review qua ASC API → modal chọn release type (MANUAL recommended cho v1.0).
- Spawn Claude submit session. Claude chạy preflight 7-check + auto-fix create-version/encryption/review-info qua API.
- App Privacy questionnaire: Claude tự grep code app (Analytics/IDFA/Location/...) suy luận data collection → mở ASC web qua Playwright MCP → tick checkbox. Lần đầu: Claude pause + báo "Mở cửa sổ Chromium do Playwright vừa launch, login ASC + 2FA, rồi reply 'tôi đã đăng nhập'". Cookie persist user-data-dir.
- Age Rating: Claude tick None cho mọi câu hỏi (default 4+ cho app EXO không violence/sexual).
- Cuối cùng submit qua v2 reviewSubmissions (3 bước: POST
/v1/reviewSubmissionstạo draft → POST/v1/reviewSubmissionItemsattach version → PATCH submitted=true). API v1appStoreVersionSubmissionsđã bị Apple deprecate.
- Apple review 24-48h. State:
WAITING_FOR_REVIEW → IN_REVIEW → READY_FOR_SALE. - Nếu reject → log request rejection (xem workflow 13) → Claude diagnose + fix → resubmit.
- MANUAL: Apple approve → state
PENDING_DEVELOPER_RELEASE. PO vào ASC web bấm Release this version → live. - AFTER_APPROVAL: Apple approve → auto live.
v1.0 đã live → tiếp tục workflow 14 để làm v1.1 gắn Ads.
12. Workflow: tạo version mới đến submit
WAITING_FOR_REVIEW → IN_REVIEW → READY_FOR_SALE (nếu MANUAL: PENDING_DEVELOPER_RELEASE đợi PO Release).13. Workflow: phản hồi rejection từ Apple
14. Workflow: v1.1 — gắn Ads cho app v1.0 đã live
Áp dụng khi app v1.0 (no-ads) đã live ổn định ≥ 1 tuần và muốn bật monetization. Workflow này chạy song song với workflow 12 (tạo version mới).
MARKETING_VERSION 1.0 → 1.1 + tạo ASC version 1.1.- Tab Checklist → bấm 🤖 Tạo AdMob app + ad units (cần OAuth AdMob đã setup). Panel gọi AdMob API tạo app + 5 ad unit (Open / Banner / Inter / Rewarded / Native). ~15s.
- Bấm Mở Sheet Generator → form pre-filled IDs (app ID + 5 unit IDs) → bấm Tạo Sheet mới. Sheet config (gồm placements + stack flags + ID) tự lưu vào Drive.
- Trở lại Checklist → reload → thấy row Sheet config ✓ + bảng So sánh AdMob ↔ Code ↔ Sheet hiện đủ 5 unit.
- Tab Checklist → bảng RC → nếu thiếu RC keys (vd
ad_open_enabled,ad_banner_enabled), bấm 📡 Tạo RC keys. Panel gọifirebase deploy --only remoteconfigtạo các keys default = true. - Reload → check RC keys đã tồn tại trên Firebase.
- Tab Checklist → panel Install Ads via Claude hiện ra (sau khi Sheet OK).
- Chọn placements (default ALL 5 unit), Stack flags (default ON hết), Target version (auto detect = 1.1).
- Bấm 🚀 Install Ads via Claude → confirm. Spawn Claude session.
- Claude: install
Google-Mobile-Ads-SDKvia SPM, thêmGADApplicationIdentifiervào Info.plist, genAdManager.swift+ 5 service class, wire up vào AppDelegate + các màn placement, build sim verify. ~10-20 phút.
- Claude tự re-gen Privacy Policy LOCAL (thêm mục data collection cho Ads — IDFA, ad_id, device info).
- Tab Policy → preview iframe có content mới → bấm Deploy lên Firebase để publish.
- Privacy URL không đổi (vẫn
exo-pages.web.app/<slug>/privacy) — chỉ content update.
- Sau khi thêm ads, App Privacy declaration phải update.
- Khi Claude submit v1.1 (bước 8), nó tự mở ASC web qua Playwright + tick checkboxes mới: Identifiers → IDFA collected = YES, Linked = YES, Tracking = YES.
- Header ⬆ Commit & Push code ads → ⬆ Up TestFlight.
- Cài TestFlight build lên iPhone thật, verify: open ad hiện khi cold start, banner hiện ở Home, interstitial hiện đúng trigger, rewarded callback đúng.
- Nếu RC enabled, vào Firebase Console tắt 1 placement để verify kill-switch hoạt động.
- Status tab → Nộp review qua ASC API → release type (MANUAL recommended).
- Whats new: viết "Cập nhật trải nghiệm + cải thiện hiệu năng". KHÔNG mention "ads" trong release notes.
- Claude tự update App Privacy (IDFA YES) qua Playwright.
- Apple review thường nhanh (24h) vì chỉ thêm SDK, không đổi feature chính.
- v1.1 live → mở AdMob console → bật eCPM floor + mediation nếu cần.
- Sau 1-2 tuần data, dùng RC kill-switch tinh chỉnh frequency cap nếu user complaint về ads quá nhiều.
15. Tips & Gotchas
- App Store URL: lần đầu setup app, panel set Support URL + Marketing URL =
https://exostudio24.github.io/. PO có thể đổi sau. - whatsNew v1.0: không sửa được. Lần v1.1 trở đi mới sửa được.
- Phantom version trong dropdown: nếu app có version trên ASC ở state Bị từ chối / Đang review thì coi như "editable" nhầm. Đọc badge state ở header tab Store listing để xác nhận.
- Build chưa process: sau Up TestFlight, build cần Apple process 5-15 phút mới trở thành VALID. Preflight sẽ fail bước này → chờ rồi reload.
- Confirm dialog ngữ cảnh: panel show diff cụ thể trước khi action destructive (vd "MARKETING_VERSION 1.0 → 1.1"). Đọc kỹ trước khi OK.
- Session Claude sống qua restart: dù panel restart mất log, session Claude trên disk vẫn còn. Bấm Xem log Claude trên request card → chat thread tự reload + cho reply để resume.
- Drop file Claude: PO có thể drop file (plist/cert/json) vào khung 📎 dưới chat — file save
<project>/_drops/<ts>-<name>và path tự insert vào reply. - Tool call card: trong chat, click "Mở" trên tool card để xem output đầy đủ (kết quả Bash/Read).
- Activity strip:
12s · 📖 3 · $ 2 · ✏️ 1ở header bubble Claude = đang chạy 12 giây, đọc 3 file, gọi 2 lệnh Bash, edit 1 file.
16. Khắc phục sự cố
16.1. "Lỗi tải metadata" / "App chưa có trên ASC"
- Bundle ID trong project chưa khớp với app đăng ký trên ASC.
- Mở App Store Connect → tạo app record với bundle ID đúng → reload tab Store listing.
16.2. "Phiên bản đang ở trạng thái READY_FOR_SALE — có thể không sửa được"
- v live không edit. Tạo version mới qua Status tab → Version planner.
16.3. "Build chưa processed" trong preflight
- Apple đang process build, chờ 5-15 phút sau Up TestFlight.
- Sau khi đợi xong, reply Claude "build đã processed rồi" trong chat thread → Claude tự re-run preflight.
16.4. Claude không respond
- Check tab Lệnh & Build xem badge status job. Nếu "đang chạy" > 10 phút mà không có tool call → có thể Claude treo.
- Bấm Dừng per bubble (SIGTERM process group) → tạo request mới.
- Hoặc mở chat thread → reply "tiếp tục từ chỗ vừa dừng" → resume session (qua sessionId trên disk).
16.5. "Server đã restart, log job đã mất"
- Bình thường — Mac mini reboot hoặc launchd kickstart. JOBS dict in-memory mất nhưng failed-job logs + Claude logs persist
.codepanel/job_logs/<jid>.{log,json}30 ngày / 500 MB. - Conversation reconstruction: mở lại issue → chat thread vẫn render từ disk.
16.6. "Lỗi gọi /api/projects/.../listing"
- Cloudflare tunnel intercept response > 100s → SPA show "lỗi gọi API" dù server thật sự trả 200.
- Refresh trang (Cmd+Shift+R) → status thực tế hiện lại đúng.
16.7. Token bị mất / lộ
- SSH vào Mac mini → mở
~/Desktop/EXO/.codepanel/config.json→ đổi field"token"sang chuỗi random mới. - Hoặc xoá token →
launchctl kickstart -k gui/$UID/com.codepanel.server→ server tự gen mới. - Token mới in ra console khi server start (xem
~/Library/Logs/codepanel-server.log).