Kurt CapatanMobile Dev
← All work

Fueled · Care2Cure

Care2Cure app icon

Care2Cure

Took a Flutter health app from API integration to a release-ready 1.0.

Role
Lead Mobile Engineer
When
Feb 2026 – May 2026
Platforms
iOS, Android
Industry
Healthcare
Release
Release-ready 1.0.0, handed over to the client. Not released to the public yet.
  • Flutter
  • Dart
  • BLoC
  • Freezed
  • Retrofit
  • Dio
  • Server-Sent Events
  • Sentry
  • Codemagic
The home feed and the Ask AI assistant with suggested questions
Home and the Ask assistant.

About the app

Care2Cure is for the spinal-cord-injury community. Users say who they are and their stage of injury, and the app tailors a feed of trusted articles and videos to them. An AI assistant answers their questions from the app's own content and shows its sources.

What I built

  • A streaming AI chat (the deep dive below).
  • Integrated backend authentication — sign-in, sign-up with email verification, password reset, JWT sessions with automatic logout, account deletion, and deep links.
  • Integrated Sentry and wrote an interceptor that reports only unexpected API errors, so network and expected auth errors never add noise.
  • Took the app to a release-ready 1.0.0 with a teammate, taking the pipeline from nightly Firebase builds to store-ready releases — then wrote a 25-page handoff guide so the client’s developers could build and release without our CI.

Deep dive: a chat that streams answers over Server-Sent Events

The chat answers flow one way, from server to app, so I built on Server-Sent Events: plain HTTP, which reuses our normal Bearer token, interceptors and server setup. WebSockets fit two-way, long-lived connections, which this chat does not need.

The service reads the response as a byte stream, splits it into lines, keeps the last partial line in a buffer until the next chunk arrives, and turns each data: line into a typed result — a conversation ID, the sources, a text chunk, or done. The BLoC appends each chunk to a streaming message bubble and saves the finished message with its sources.

A hard problem: Dio treats 429 and 503 as exceptions, which hides the response body — but the backend puts the user-facing message there. I set validateStatus to accept both codes so the app can read the message and the Retry-After header, and drive a countdown banner from it.

Another developer built the first chat screen and SSE client; I rebuilt and extended it. The backend team built the RAG pipeline, the model calls and the rate limiter.