Skip to content
··14 phút đọc

App Store Đã Chấp Nhận

Hai tuần trước tôi viết "Vẫn đang build. Vẫn chưa xong." Hôm nay DIALØGUE đã có mặt trên App Store. Đây là những gì 40% cuối cùng thực sự trông như thế nào.

Hai tuần trước tôi kết thúc một bài blog bằng câu: "Vẫn đang build. Vẫn chưa xong. Vẫn đang nghĩ xem sẽ nói gì với con gái."

Tôi hứa sẽ viết tiếp khi app lên App Store. Hoặc khi bị reject. Tôi nói rằng câu chuyện bị từ chối có khi còn hay hơn.

DIALØGUE - AI Podcast Studio giờ đã có mặt trên App Store — một app iOS SwiftUI thuần native biến bất kỳ chủ đề hay file PDF nào thành một tập podcast hoàn chỉnh, được build bằng Claude Code bởi người chưa từng viết một dòng Swift trước đó. Bạn có thể tải xuống ngay bây giờ.

Nhưng không phải ngay lần đầu submit. Phải thừa nhận — tôi đã dự đoán câu chuyện bị reject sẽ thú vị hơn câu chuyện được duyệt. Tôi đã đúng.


Chuyện Gì Xảy Ra Khi Apple Từ Chối Lần Submit Đầu?

Lần submit đầu tiên của tôi bị từ chối. Guideline 2.1 — Performance: App Completeness. Phần in-app purchase bị lỗi.

Tin nhắn review của Apple khá lịch sự — họ nhận ra đây là lần submit đầu tiên của tôi, chúc mừng tôi tham gia developer program, và giải thích vấn đề rõ ràng. Các sản phẩm IAP báo lỗi khi reviewer của họ thử mua hàng.

Vấn đề là: flow mua hàng chạy hoàn toàn bình thường trong quá trình tôi tự test. Lỗi nằm ở môi trường sandbox của Apple — cái này hoạt động khác hoàn toàn so với cả development lẫn production. Cấu hình StoreKit cần phải đồng bộ chính xác với App Store Connect — và của tôi thì không. Tôi đang test với file cấu hình StoreKit local trong khi reviewer lại dùng sandbox thật.

Tôi fix trong ngày đó, resubmit, và lần này qua. Sau đó tôi ship bản v1.0.1 bug fix không lâu sau, cũng được duyệt suôn sẻ.

Tổng cộng ba lần submit. Một lần bị từ chối. Lần bị từ chối đó dạy tôi nhiều hơn về quy trình App Store so với cả hai lần được duyệt cộng lại. Đó là quy luật chung rồi đúng không? Thất bại bao giờ cũng dạy nhiều hơn thành công.


"40% Cuối Cùng" Thực Sự Trông Như Thế Nào?

Trong bài gốc, tôi nói AI đưa bạn đến 60% đoạn đường và 40% còn lại là hoàn toàn do con người. Giờ tôi muốn nói cụ thể hơn, vì tôi có git log để chứng minh.

16 commits. 57 file thay đổi. 4.886 dòng được thêm vào. App tăng từ 69 Swift file lên 88, từ 7.568 dòng lên 11.459. Gần 4.000 dòng "polish" đấy.

Đây là những gì 16 commits đó thực sự chứa — theo thứ tự xảy ra:

Bộ Test Suite Đáng Ra Phải Tồn Tại Từ Ngày Đầu

Scaffold ban đầu không có test nào. Không một cái. Claude build 69 file production code mà không có nổi một test. Commit thực sự đầu tiên của tôi sau bài blog gốc là thêm vào 176 unit test và 19 integration test chạy với local Supabase instance.

Viết những test đó ngay lập tức phát hiện ra bug thật: Show model decode thất bại từ các database column không tồn tại, AudioPlayer không reset khi hết track, một race condition khi reload thư viện, một nil UUID guard bị thiếu trong creation wizard. Mỗi cái trong số này đều sẽ gây crash trên production.

Tôi nghĩ đây là một pattern đáng được đặt tên: AI sinh ra code mà không có test infrastructure. Không phải vì nó không thể viết test — Claude rất giỏi viết test khi bạn yêu cầu — mà vì prompt scaffold ban đầu luôn là "build cái app," không phải "build cái app kèm comprehensive test." Phần test đến từ việc tôi tự quyết định rằng mình không thoải mái khi ship mà thiếu chúng.

DIALØGUE iOS app outline review screen showing 6 podcast segments with Approve and Give Feedback buttons in dark mode
Bước review outline — nơi bạn duyệt hoặc chỉnh sửa phần nghiên cứu của AI trước khi nó generate audio.

Studio: Tính Năng Vốn Chỉ Là Một Cái Stub Trống Rỗng

Tính năng "Studio" ban đầu cho các show định kỳ chỉ là placeholder. Hai commits sau đó, nó trở thành một sản phẩm thật: tạo show với template grid, quản lý episode với status badge và action button, workflow chỉnh sửa và xóa, cấu hình lịch với timezone picker, và voice customization sheet.

Rồi đến Studio Phase 2: thiết kế lại màn hình chi tiết show, retry và delete từng episode, tạo episode thủ công kèm credit check. Cộng thêm 8 XCUITest mới để đảm bảo mọi thứ hoạt động end-to-end.

Đây chính là điều tôi muốn nói khi nói "AI build một codebase, không phải một sản phẩm." Tính năng Studio compile được. Nó render một màn hình. Nhưng bạn không thực sự quản lý được một show podcast định kỳ với nó.

DIALØGUE iOS app showing 9 podcast format templates including Tech News Analysis, Deep Dive, and Investigative Comedy in a dark-mode grid layout
Chín format podcast — từ Tech News Analysis đến Investigative Comedy.

Reimagine Lại Audio Player

Tôi đã đề cập trong bài gốc rằng mình đã xóa cái mini-player. Hóa ra tôi đã sai — cuối cùng tôi build một cái mini-player tốt hơn. Thiết kế cuối cùng có một thanh mini-player cố định phía trên tab bar với progress, skip control, và play/pause. Tap vào đó là bạn có một "Now Playing" sheet mở rộng với seekable slider, speed selector (0.5x đến 2x), transport control, và animation vòng tròn âm thanh.

Phần khó là state isSeeking — nếu không có nó, vị trí của slider và audio observer sẽ "cãi nhau," tạo ra hiệu ứng giật cục. Đó là một dòng state mà phải mất một tiếng để chẩn đoán.

Tôi cũng thêm tính năng tải offline với UX tinh tế: icon màu xanh trên các episode đã tải trong thư viện, toast thông báo hoàn thành, nhãn "Downloaded" trong Now Playing, và swipe để xóa bản download. DownloadManager có một race condition với temp file trong URLSession delegate gây ra lỗi âm thầm — cách fix là một synchronous file move bên trong callback. Không phải loại bug nào bạn nhìn thấy được qua code review.

Security Hardening Toàn Bộ Các Tầng

Cái này thật sự sobering. Một đợt kiểm tra bảo mật toàn bộ stack — không chỉ riêng iOS app — phát hiện lỗ hổng ở nhiều tầng: database function có quá nhiều quyền, các edge case về authentication, lỗ hổng trong xác minh token, và vấn đề validate input ở một số backend service.

Không có cái nào nằm trong code Swift của iOS. Chúng nằm trong backend mà iOS app kết nối đến. Nhưng khi bạn ship một iOS app, toàn bộ stack của bạn giờ đang nằm trong túi người dùng. Điều đó nâng thanh kỳ vọng cho mọi thứ lên rất cao. Code "chạy được" cho một web app bỗng dưng cảm thấy không chấp nhận được khi nó đang đi qua quy trình review của Apple và vào một native app mà người ta mang theo khắp nơi.

StoreKit: Thủ Phạm Khiến Lần Submit Đầu Thất Bại

StoreKit sandbox testing là một vũ trụ riêng, và chính nó đã khiến lần submit đầu của tôi bị reject. Môi trường sandbox hoạt động khác với production. Các transaction đôi khi ở trạng thái "pending" mãi mãi. File cấu hình StoreKit trong Xcode cần sync thủ công. Tôi mất cả một buổi tối debug một purchase flow hoạt động hoàn hảo trong code nhưng lại fail âm thầm trong sandbox — hóa ra là product ID trong App Store Connect có dấu cách thừa ở cuối. Một dấu cách thôi.

Reviewer của Apple gặp lỗi sandbox vì StoreKit configuration của tôi không đồng bộ với App Store Connect. Purchase flow chạy bình thường trên máy tôi — nhưng reviewer đang dùng sandbox thật, không phải file cấu hình StoreKit local của tôi. Tôi fix trong ngày đó, nhưng đây là ví dụ điển hình về khoảng cách giữa "chạy được trên máy mình" và "chạy được trong môi trường của Apple" — không phải chuyện nhỏ.

Chuỗi xác minh purchase là cả một dự án riêng: iOS app gửi biểu diễn JWS (JSON Web Signature) của transaction lên server-side function, cái này thực hiện xác minh chain cryptographic đầy đủ của Apple's signed receipt. Không chỉ decode — mà là validate signature thật sự. Phần này mất hai commit chuyên biệt mới làm đúng.

Privacy và Tuân Thủ App Store

Privacy và compliance là các form, quyết định, và checkbox có hàm ý pháp lý — và không AI nào có thể điền chúng thay bạn. App Tracking Transparency declaration, privacy nutrition label, export compliance cho encryption (có, HTTPS cũng tính), quyền nội dung, tích hợp Turnstile captcha. Claude Code có thể viết Swift, nhưng không thể nói cho bạn biết liệu practices thu thập dữ liệu của bạn có cần nhãn "Data Used to Track You" hay không.

MFA Đầy Đủ và Localization

Phần implement MFA ban đầu bị hỏng hoàn toàn — factor ID trống, chỉ có verify flow. Tôi viết lại thành một TOTP lifecycle hoàn chỉnh: enroll, quét QR code (generate native bằng CoreImage), verify, xem trạng thái, vô hiệu hóa. Đó là 394 dòng MFAView.swift vốn không tồn tại trước đó.

Localization cho 7 ngôn ngữ có nghĩa là 253 UI string được dịch sang tiếng Anh, Tây Ban Nha, Pháp, Nhật, Hàn, Việt, và Trung. Claude làm phần dịch, và nhìn chung khá tốt. Nhưng "khá tốt" trong tiếng Nhật có thể có nghĩa là một button label đúng ngữ pháp nhưng nghe như robot viết. Tôi phát hiện ra vài trường hợp như vậy bằng cách đổi ngôn ngữ điện thoại và thực sự dùng app. Đó là loại test mà AI không thể làm thay bạn — ít nhất là chưa.


DIALØGUE iOS App Có Thể Làm Được Gì?

Với ai chưa đọc câu chuyện build gốc, đây là những gì DIALØGUE làm:

Bạn cho nó một chủ đề — hoặc upload một file PDF — và nó tạo ra một tập podcast được nghiên cứu đầy đủ, có script, có giọng đọc. Hai host AI có một cuộc trò chuyện tự nhiên về chủ đề của bạn, dựa trên nghiên cứu thật. Không cần microphone.

iOS app bao gồm:

  • Wizard tạo 5 bước — chủ đề, format, tùy chỉnh, review outline, review script
  • 30 giọng AI cho 7 ngôn ngữ — Anh, Tây Ban Nha, Pháp, Nhật, Hàn, Việt, Trung
  • 9 format podcast — từ Tech News Analysis đến Investigative Comedy
  • Phát audio với lock screen control — background playback hoạt động liền
  • Apple Sign-In, Google OAuth, và email auth
  • In-app purchase — theo credit, không subscription: 4 credit với $4.99, 9 credit với $9.99, 18 credit với $19.99
  • Studio — thiết lập các show định kỳ tự động generate tập mới
  • Upload PDF — paper nghiên cứu, báo cáo, sách làm nguồn tư liệu

Đây là app SwiftUI native thật sự. Không phải web wrapper. Không phải React Native. Từ 69 Swift file ban đầu, giờ là 88 file và 11.459 dòng code, được bảo đảm bởi 195 test. Tôi thật sự tự hào khi ship nó.

DIALØGUE iOS app library view showing podcast episodes with play buttons, duration, and dark mode UI
Thư viện — các tập podcast đã generate, sẵn sàng để nghe.

Tôi Đã Sai Bao Nhiêu Trong Ước Tính "Polish Phase" Ban Đầu?

Tôi đã viết rằng app "vẫn đang trong giai đoạn phát triển, ở phase polish cuối cùng." Điều đó về mặt kỹ thuật là đúng, nhưng tôi đã đánh giá thấp lượng công việc trong "polish phase" thực ra là công việc mới hoàn toàn.

Nhìn lại git log bây giờ, 16 commits không nghe giống "polish." Nó nghe giống một phase phát triển thứ hai. Riêng bộ test suite — 176 unit test và 19 integration test — đã là cả một dự án. Studio đi từ stub thành tính năng đầy đủ. Audio player được reimagine hai lần. Security hardening đụng đến 40+ backend function. MFA được viết lại từ đầu.

Tôi cũng nói rằng tôi đã xóa mini-player. Tôi đã sai về điều đó nữa — tôi cuối cùng đã build một cái tốt hơn, với Now Playing sheet, speed control, và download indicator. Bản năng ban đầu là "xóa nó đi" là đúng — cái mini-player đầu tiên rất tệ. Nhưng concept thì đúng. Nó chỉ cần được build đúng cách thôi.

Tôi nghĩ sự phân chia trung thực nhất, giờ khi tôi có thể nhìn toàn cảnh, là: AI build nền tảng (60%), con người build sản phẩm (30%), và quy trình submit App Store dạy bạn 10% còn lại.


DIALØGUE Có Sẵn Ở EU Không?

DIALØGUE có sẵn trên toàn thế giới, nhưng việc ra mắt ở EU vẫn đang được Apple xử lý. Digital Markets Act của EU yêu cầu các bước tuân thủ bổ sung — công bố phương thức thanh toán thay thế, tài liệu privacy cụ thể, thông tin đăng ký doanh nghiệp. Tôi đã nộp tất cả, và Apple đang review. Sẽ sớm có mặt ở các quốc gia EU thôi.

Nếu bạn đang ở EU và không muốn đợi, web app hoạt động ở mọi nơi và có đầy đủ tính năng như nhau.


AI-Assisted iOS Development Nhanh Đến Đâu?

DIALØGUE iOS app mất khoảng hai tuần từ commit đầu tiên đến khi được App Store duyệt — một buổi tối AI scaffolding và hai tuần công việc sản phẩm của con người. Tôi tiếp tục duy trì bảng này vì nó tiếp tục dạy tôi những điều mới:

ProjectĐộ phức tạpThời gian build
DIALØGUE v1MVP podcast generator~6 tháng
STRAŦUM10 AI agent, 11 framework, multi-tenant75 ngày
Site redesignWordPress frontend overhaul3 ngày
DIALØGUE v2Rebuild hoàn toàn web app14 ngày
Blog migrationWordPress → Next.js, 490 bài, Sydney RAG4 ngày
DIALØGUE iOSNative iOS app, lần đầu dùng Swift~2 tuần (scaffold: một buổi tối)

Khoảng cách từ scaffold đến ship với DIALØGUE iOS là khoảng hai tuần. Bản thân scaffold chỉ mất một buổi tối. Tỉ lệ đó — một buổi tối AI làm, hai tuần con người làm — nói lên tất cả về nơi chúng ta đang đứng với AI-assisted development hiện tại.

Phần AI liên tục nhanh hơn. Phần con người vẫn gần như như cũ. Tôi đã viết điều đó hai tuần trước và nó vẫn đúng.


Những Kỹ Năng Nào Quan Trọng Khi AI Build Code?

Trong bài gốc, tôi vẫn đang tìm kiếm lời khuyên phù hợp. "Học cách trở thành người mở Simulator" là điều tốt nhất tôi có.

Giờ khi tôi đã thực sự ship được app, tôi nghĩ mình có thể cụ thể hơn một chút.

App tồn tại được là nhờ ba điều mà AI không thể làm:

  1. Tôi đã dùng sản phẩm. Không phải test nó. Dùng nó. Tạo podcast. Nghe chúng trên đường đi làm. Nhận ra rằng màn hình review outline cần hiển thị nguồn nghiên cứu vì tôi muốn biết các sự kiện đó đến từ đâu.

  2. Tôi đưa ra các judgment call không có câu trả lời đúng sai. Xóa mini-player hay giữ lại? Wizard tạo bao nhiêu tùy chọn là quá nhiều? Studio nên là một tab hay một section? Đây không phải quyết định kỹ thuật. Đây là quyết định về taste. Và taste đến từ việc dùng rất nhiều sản phẩm — cả những cái tuyệt vời lẫn những cái tệ hại — và phát triển bản năng về cái gì cảm thấy đúng.

  3. Tôi điều hướng một hệ thống được thiết kế cho con người. App Store Connect, privacy declaration, export compliance, yêu cầu screenshot — không cái nào trong số này có thể tự động hóa. Nó đòi hỏi phải đọc, hiểu ngữ cảnh, và đưa ra judgment call về hàm ý pháp lý và kinh doanh. Kỹ năng đó — điều hướng các hệ thống phức tạp của con người — sẽ không biến mất.

Vậy có lẽ lời khuyên cập nhật là: học cách dùng mọi thứ thật sâu, phát triển taste bằng cách quan tâm đến chất lượng, và làm quen với việc điều hướng những hệ thống không được thiết kế để đơn giản.

Cụ thể hơn "học cách tư duy phản biện." Tôi nghĩ nó gần với sự thật hơn. Tôi vẫn chưa chắc nó đủ không.


Tải DIALØGUE Như Thế Nào?

App miễn phí với các gói mua credit trong app. Không có subscription.

Tải về trên App Store

Có sẵn trên toàn thế giới — EU đang được Apple xử lý và sẽ sớm ra mắt. Web app có sẵn ở mọi nơi.


Câu Hỏi Thường Gặp

DIALØGUE có sẵn trên App Store chưa?

Rồi! DIALØGUE - AI Podcast Studio đã có mặt trên App Store từ tháng 3 năm 2026. Tải miễn phí với các gói mua credit trong app (4 credit với $4.99, 9 credit với $9.99, 18 credit với $19.99). Có sẵn trên toàn thế giới — EU đã được submit và đang được Apple xử lý.

Có sẵn ở EU không?

Đã submit và đang được Apple xử lý. Digital Markets Act của EU yêu cầu các bước tuân thủ bổ sung, và tôi đã hoàn tất thủ tục giấy tờ — chỉ đang đợi Apple review. Sẽ sớm có thôi. Trong khi chờ, web app hoạt động ở mọi nơi bao gồm cả EU.

Apple có reject không?

Có — lần submit đầu bị reject vì in-app purchase bị lỗi (Guideline 2.1: App Completeness). Cấu hình StoreKit sandbox không đồng bộ với App Store Connect, nên các giao dịch báo lỗi khi review. Tôi fix trong ngày đó, resubmit, và được duyệt. Sau đó v1.0.1 cũng qua. Tổng cộng ba lần submit, một lần reject. Lần reject dạy tôi nhiều hơn cả hai lần được duyệt cộng lại.

Toàn bộ quá trình mất bao lâu?

Khoảng hai tuần từ bài blog gốc đến khi App Store duyệt. Claude Code scaffold 69 Swift file trong một buổi tối. 16 commits còn lại thêm 4.886 dòng trên 57 file — test, tính năng Studio, redesign audio player, rewrite MFA, security hardening, xác minh StoreKit, localization, và quy trình submit App Store. App ship với 88 file và 11.459 dòng cùng 195 test.

Phần khó nhất của 40% cuối là gì?

StoreKit sandbox testing. Khoảng cách giữa "cái này chạy được trong code" và "cái này chạy được trong hệ thống transaction của Apple" là rất lớn. Sandbox transaction hoạt động khác production, product ID phải khớp chính xác (kể cả dấu cách thừa), và vòng phản hồi chậm — bạn không thể chỉ chạy một unit test là xong.

Vẫn có thể dùng web app không?

Hoàn toàn được. podcast.chandlernguyen.com có đầy đủ tính năng và hoạt động trên mọi thiết bị. iOS app thêm vào những tiện lợi native — Apple Sign-In, lock screen control, offline download — nhưng trải nghiệm tạo podcast cốt lõi hoàn toàn giống nhau.


Vẫn đang nghĩ xem sẽ nói gì với con gái. Nhưng ít nhất giờ tôi có một app đã ship để chỉ vào khi nói "phần khó là phần của con người."


Thân mến, Chandler

Đọc tiếp

Hành trình
Kết nối
Ngôn ngữ
Tùy chọn