Appearance
The Challenge
Build Chatter, a WhatsApp-like messaging app for iPhone, and ship it to us on TestFlight.
What we provide and what you build
| We provide | You build |
|---|---|
| A hosted messaging API (REST + WebSocket), always online | A native-quality iOS app that uses the API |
Your personal workspace credentials (clientKey, clientSecret) | The App Store Connect record for your app |
| Push notification delivery through APNs, using your key | A TestFlight build, with us invited as testers |
| Media storage, thumbnails, and signed URLs | Tests and a README explaining your decisions |
A built-in echo bot for development and for Apple's review | |
| This documentation, the API guide, and the REST reference | |
| An AI coding assistant: Qwen Code + Qwen3 Coder Next, paid by a prepaid gift card (redeem, setup) |
You do not build or host a server. Your whole effort goes into the app.
Your workspace
Your invitation email contains a clientKey and a clientSecret. Every user, friendship, and message you create lives in your workspace only. Other candidates cannot see your data, and you cannot see theirs. See API overview.
How we will test your app
We install your TestFlight build on two iPhones and run a real-world scenario:
- Each tester creates a new account on their own iPhone.
- The testers find each other and become friends (friend request → accept).
- The testers chat: send messages, watch delivery and read ticks, see typing and online status.
- We go offline, kill the app, switch between Wi-Fi and cellular, and check that nothing is lost, duplicated, or out of order.
The full script is in Our Test Plan. Build for it.
Requirements
Core (all required)
| # | Feature | Acceptance criteria |
|---|---|---|
| C1 | Sign up and log in | Phone number + one-time code. In the challenge environment the code is always 000000. Tokens are stored in the Keychain and refreshed silently. |
| C2 | Profile setup | After first login, the user picks a display name and a unique username. The app blocks the main UI until the profile is complete. Users can edit the profile and "about" text later. |
| C3 | Find people | Search by username (prefix) or exact phone number. Results show the friendship state (none, request sent, request received, friends). |
| C4 | Friend requests | Send, cancel, accept, and decline requests. Incoming requests appear in real time, with a badge. |
| C5 | Friends list | All friends, with online status or "last seen". Remove a friend. Start a chat from a friend. |
| C6 | Chats list | Ordered by last activity. Shows avatar or initials, name, last message preview, time, and unread count. Updates in real time. |
| C7 | 1:1 chat | Send and receive text in real time. Infinite scroll back through history. No duplicates, no gaps. |
| C8 | Message status | Outgoing messages show: clock (sending) → ✓ (sent) → ✓✓ (delivered) → blue ✓✓ (read). Failed sends show a retry action. |
| C9 | Typing and presence | "typing…" in the chat header and chats list. "online" or "last seen today at 14:03" in the chat header. |
| C10 | Offline resilience | Messages written offline are queued and sent on reconnect, in order. Pending messages survive an app kill. Missed messages are fetched after reconnect. |
| C11 | Safety | Block and unblock users. Report a user or a message. (Required by App Store Guideline 1.2.) |
| C12 | Account | Log out. Delete account from inside the app. (Required by App Store Guideline 5.1.1(v).) |
Advanced (pick at least two)
| # | Feature | Notes |
|---|---|---|
| A1 | Push notifications | Strongly recommended. Notifications for new messages and friend requests when the app is in the background. Tap opens the right screen. App icon badge shows total unread. See Push Notifications. |
| A2 | Media and avatars | Send photos and voice notes. Profile photo. Thumbnails while loading. See Media. |
| A3 | Group chats | Create a group from friends, add and remove members, rename, leave. Read ticks when all members have read. |
| A4 | Reply, edit, delete | Swipe to reply with a quote. Edit within 15 minutes. "Delete for me" and "Delete for everyone". |
| A5 | Reactions | Long-press a message to react with an emoji. |
| A6 | Search | Search messages within a chat and across all chats. |
Engineering requirements
- Platform: iOS 17 or later. Swift + SwiftUI is preferred. React Native (Expo) or Flutter is accepted if the result feels native.
- Ordering: Order messages by the server-assigned
seq. Never by device clock. - Idempotency: Every outgoing message carries a client-generated
clientMessageId. Retries never create duplicates. - Local persistence: Chats and messages load instantly from a local database, also when offline.
- Security: Tokens in the Keychain. No
clientSecretin the app binary — it is for your own developer tooling only. - Accessibility: Dynamic Type, VoiceOver labels on interactive elements, Dark Mode.
- Quality: No crashes during our test. No UI freezes on long chats (1,000+ messages).
The App Design page describes an architecture that meets these requirements. You may choose a different one — explain why in your README.
Deliverables
- TestFlight build with
infrastructure@chathealth.com.sginvited as an external tester. See TestFlight Publication. - Private Git repository shared with us, with meaningful commit history.
- README.md with:
- How to build and run the app locally.
- Architecture decisions and trade-offs.
- Which Advanced features you chose, and why.
- What you did not finish, and what you would do next.
- AI usage: what you used Qwen Code for, where it helped, and where you had to correct it.
- Tests: unit tests for the outbox, sync, and message-status logic at minimum. UI tests for the sign-up flow are a plus.
- Screen recording (5–10 minutes) of the TestFlight build on real devices: two users becoming friends, chatting, going offline, and recovering.
The TestFlight build is mandatory
If we cannot install your build from TestFlight, or the build cannot sign up a new user, the submission is incomplete and we cannot evaluate it.
Timeline
- Deadline: 10 calendar days after you receive the invitation.
- Expected effort: 20–28 hours of focused work.
- Plan for Apple: Apple Developer Program enrolment can take a few days. Beta App Review usually takes 24–48 hours. Start enrolment on day 1, and submit your first TestFlight build early — you can upload new builds later.
Evaluation (100 points)
| Area | Points | What we look for |
|---|---|---|
| Core features in our real-device test | 30 | C1–C12 work on two iPhones, end to end. |
| Reliability | 20 | No lost, duplicated, or reordered messages. Correct recovery after offline, app kill, and network switch. |
| Code quality and architecture | 15 | Clear layers, small types, no business logic in views, consistent naming. |
| UX and native feel | 15 | Smooth scrolling, keyboard handling, optimistic UI, empty and error states, accessibility. |
| Testing | 10 | Meaningful tests at the right level. Edge cases of sync and status covered. |
| Shipping and App Store compliance | 10 | Clean TestFlight install, review notes, privacy details, safety and account-deletion features. |
Bonus (up to +10): well-built Advanced features, CI that uploads to TestFlight automatically, snapshot tests, thoughtful animations.
Automatic red flags
- Messages ordered by device time.
- Polling instead of the WebSocket for real-time updates.
- Tokens stored in
UserDefaults. clientSecretshipped inside the app.- App crashes or hangs during our test.
Rules
- AI assistant: use Qwen Code with Qwen3 Coder Next. We provide a gift card with credits. Redeem it, then follow the setup guide. Do not use other AI coding assistants.
- You may use open-source libraries.
- You must be able to explain and defend every part of your app in the follow-up interview, including code the assistant wrote.
- Do not use a third-party chat SDK or backend (Stream, Sendbird, Firebase chat kits, PubNub). Use the Chatter API.
- You pay for your own Apple Developer Program membership.
- Ask questions any time by replying to your invitation email. Write down the assumptions you make in your README.
After you submit
We run the test plan within a few days. Then we schedule a 60-minute interview: a walkthrough of your code, design questions, and a small live change to the app.